dump = function (o)
   if type(o) == 'table' then
      local s = '{ '
      for k,v in pairs(o) do
         if type(k) ~= 'number' then k = '"'..k..'"' end
         s = s .. '['..k..'] = ' .. dump(v) .. ','
      end
      return s .. '} '
   else
      return tostring(o)
   end
end


-- Minimally effective quoting
quote = function (astring)
    local quoted1 = string.gsub(astring,'\"', '\\"')
    local quoted2 = '"' .. string.gsub(quoted1,"%'", "\\'") .. '"'
	local linefeed = string.gsub(quoted2,"\n", "\\n")
	return linefeed
end


write_saved = function (o)
--	local escaped
   if type(o) == 'table' then
      local s = '{\n'
      for k,v in pairs(o) do
         if type(k) ~= 'number' then
		 k = '"'..k..'"'
		 end
         s = s .. '['..k..'] = ' .. write_saved(v) .. ',\n'
      end
      return s .. '}\n'
   elseif
		type(o) == 'string' then
		return quote(o)
   else
		return tostring(o)
   end
end

_size = function (t)		-- return number of elements in table
	local i = 0
	for _,_ in pairs(t) do
		i = i +1
	end
	return i
end

reverse_id = function (Adata)	-- given a grp-id table like this
	--[[

	Grp_Dat["1N"].id = {
	[294]= {L=1, C=1},		-- "Fungal Grotto I Vanquisher",
	[78]= {L=2, C=1},		-- "Darkshade Caverns I Vanquisher"
	[272]= {L=3, C=1},		-- "Arx Corinium Vanquisher"
	[357]= {L=4, C=1},		-- "Direfrost Keep Vanquisher"
	[393]= {L=5, C=1},		-- "Blessed Crucible Vanquisher"

	return a table like this
	["11"] = 294
	["21"] = 78
	]]
	local rev = {}
	for ach, lc in pairs (Adata) do
		local key
		key = lc.L .. lc.C
		if rev[key] == nil then
			rev[key] = ach
		else
			print ("error dup " .. key)
		end
	end
	return rev
end

blank_detail = function()
			detail_name.title = ""
			detail_desc.title = ""
end

box_mousemove_cb = 	function (self, l, c)
-- we have previously added .dat to the box
		if self.dat == nil then
			detail_name.title = "box.dat is nil"
			return
		end

		if l == 0 or c == 0 then
			blank_detail()
			return
		end

		local key = l .. c

		local ach = self.dat.reverse_id[key]

		if ach == nil then
			blank_detail()
	--		detail_name.title = "No reverse lookup on " .. key	-- Normal on Group 2 and Pub panel with enpty spaces
			return
		end

		if Ach_Detail[ach] == nil then
			detail_name.title = "No Achievement for " .. ach
			return
		end
		detail_name.title = "(" .. ach .. ")  " .. Ach_Detail[ach].name
		detail_desc.title = Ach_Detail[ach].description

	end


box_leavewindow_cb = function (self)
	blank_detail()
end

generate_id=function()
--write a combined list of achievement id we look for to add to the in-game part (cut and paste) for filtering
	outfile=io.open("data/ids.lua", "w")

	if outfile == nil then
		print ("Couldn't open id.lua file for writing.")
	end
	outfile:write("hist.IDs = {" .. "\n")

	for _,i in ipairs(Grp_Order) do
		outfile:write("-- GRP " .. i ..  "\n")
		for j,_ in pairs (Grp_Dat[i].id) do
			outfile:write("[" .. j .. "] = true,\n")
		end
	end

	for _,i in ipairs(Craglorn_Order) do
		outfile:write("-- Craglorn " .. i .. "\n")
		for j,_ in pairs (Craglorn_Dat[i].id) do
			outfile:write("[" .. j .. "] = true,\n")
		end
	end

	outfile:write("-- DLC " .. "\n")
	for j,_ in pairs (DLC_Dat.id) do
		outfile:write("[" .. j .. "] = true,\n")
	end

	outfile:write("-- SQ " .. "\n")
	for j,_ in pairs (SQ_dat) do
		outfile:write("[" .. j .. "] = true,\n")
	end

	outfile:write("-- Pub " .. "\n")
	for j,_ in pairs (Pub_Dat.id) do
		outfile:write("[" .. j .. "] = true,\n")
	end

	outfile:write("-- WB " .. "\n")
	for j,_ in pairs (WB_dat) do
		outfile:write("[" .. j .. "] = true,\n")
	end

	outfile:write("-- Specials " .. "\n")
	for j,_ in pairs (Special_dat) do
		outfile:write("[" .. j .. "] = true,\n")
	end
	outfile:write("}" .. "\n")
	outfile:close()
end