-- The MIT License (MIT) http://opensource.org/licenses/MIT
-- Copyright (c) 2014-2016 His Dad

-- Some code from the luatz project (MIT Licence)

-- Configuration ==========
--local dateformat = "%Y-%m-%d, %H:%M"
local dateformat_log = "%Y-%m-%d, %H:%M:%S"
local FG_Colour_Not_Complete = "#FFB67D"
local FG_Colour_Complete = "#000000"
local BG_Colour_Not_Complete = "#FFB67D"
local BG_Colour_Complete = "#A4FF5A"
local Colour_Heading_Complete = "#58FA58"
local dname, key, count, ccount, colour, bgcolour

--force_lang = "fr"  --	or "de" or "en"  for debugging

-- ========================
version= "48"
require( "iuplua" )
require( "iupluacontrols" )
iup.SetGlobal("UTF8MODE","YES")
dofile "../../SavedVariables/History.lua"
Trials_Dat={}
Trials_Order={"N","V","VH"}
Grp_Dat={}

Grp_Order={"1N","1V","1VH","2N","2V","2VH"}
Grp1_Order={"1N","1V","1VH"}
Grp2_Order={"2N","2V","2VH"}

for _,i in ipairs(Grp_Order) do
	Grp_Dat[i]={}
end
for _,i in ipairs(Trials_Order) do
	Trials_Dat[i]={}
end

dofile "./data/Keys.lua"		--Linking tables, must do first
dofile "./data/DLC.lua"			--Achievement to Grid lookup, language independent
dofile "./data/Group1.lua"		-- Grp Mode 1 data, N, V, VH
dofile "./data/Group2.lua"		-- Grp Mode 2 data, N, V, VH
dofile "./data/Public.lua"
dofile "./data/Quest.lua"
dofile "./data/Veteran.lua"		-- Auxillary Achievements for Vet Dungeons
dofile "./data/WB.lua"
dofile "./data/Trials.lua"
dofile "./data/Special.lua"		-- Record of non standard Achievment ID's we need to keep.
dofile "./data/utility.lua"		-- utility functions

--generate_id ()			-- Generate the file the addon uses to filter Achievement ID's
-- This is used by the in game part history.lua to only record achievements that are used.
-- Uncomment when need to run.


-- generate achievement lookups from key (cell)
for _,i in ipairs(Grp_Order) do
	Grp_Dat[i].reverse_id = reverse_id(Grp_Dat[i].id)
end

for _,i in ipairs(Trials_Order) do
	Trials_Dat[i].reverse_id = reverse_id(Trials_Dat[i].id)
end

Pub_Dat.reverse_id = reverse_id(Pub_Dat.id)
DLC_Dat.reverse_id = reverse_id(DLC_Dat.id)

lingua= {}		-- Translated data
load_lang = function (lang)
	if lingua[lang] ~= nil
	then return
	end

	local path = "./data/" .. lang .. "/"

	dofile (path .. lang .. ".lua")
	dofile (path .. lang .."-data.lua")			--Achievement Data from game
	lingua[lang] = {}

	lingua[lang].Area_names = Area_names		-- dofile writes to global variables
	lingua[lang].L = L
	lingua[lang].pub_names = pub_names
	lingua[lang].grp_names = grp_names
	lingua[lang].DLC_Location_names = DLC_Location_names
	lingua[lang].Ach_Detail = Ach_Detail
end




--SQ_Dat loaded  from Quest.lua
SQ_Info= {} -- keyed by "LC" string as the  ZONE Identifier
for id,_ in pairs (SQ_dat) do  -- Load all Quest Data by Achievement ID
		local L = SQ_dat[id].L
		local C = SQ_dat[id].C
		local key = tostring(L) .. tostring(C)	-- make name key

		if SQ_Info[key] == nil then
			SQ_Info[key] = {}
			SQ_Info[key].ids = {}	--Array of Achievement ID's
		end
		table.insert(SQ_Info[key].ids,id)
end

--WB_Dat loaded  from WB.lua
WB_Info= {} -- keyed by "LC" string as the  ZONE Identifier
for id,_ in pairs (WB_dat) do  -- Load all WB Data by Achievement ID
		local L = WB_dat[id].L
		local C = WB_dat[id].C
		local key = tostring(L) .. tostring(C)	-- make name key

		if WB_Info[key] == nil then
			WB_Info[key] = {}
			WB_Info[key].ids = {}	--Array of Achievement ID's
		end
		table.insert(WB_Info[key].ids,id)
end




accounts = {}
accounts_list = {}		-- String list for selection dialog
playerNames = {}		-- Get name from ID.

for acc,_ in pairs(History_SV["Default"]) do
	accounts[acc] = {}
	accounts[acc].worlds = {}
	accounts[acc].hasblankworlds = false
	accounts[acc].player = {}
	accounts[acc].playerIDs = {}	-- intermediate table for sorting. WIP. Controls presentation order
	accounts[acc].playerIDs_vet= {}	-- subset of names which are >L50
	table.insert(accounts_list, acc)

  -- ===	Load Language Tables
    accounts[acc].lang = (History_SV["Default"][acc]["$AccountWide"].lang)
	if accounts[acc].lang == nil then
		accounts[acc].lang = "en"
	end

	if force_lang ~= nil then
		accounts[acc].lang = force_lang	-- Force the language for testing
	end
	load_lang(accounts[acc].lang)
	-- Reset Globals
	Area_names = lingua[accounts[acc].lang].Area_names
	L = lingua[accounts[acc].lang].L
	pub_names = lingua[accounts[acc].lang].pub_names
	grp_names = lingua[accounts[acc].lang].grp_names
	DLC_Location_names = lingua[accounts[acc].lang].DLC_Location_names
	Ach_Detail = lingua[accounts[acc].lang].Ach_Detail
-- load worlds
	nworlds = 0
	if History_SV["Default"][acc]["$AccountWide"]["worlds"] ~= nil then
		for i,j in pairs(History_SV["Default"][acc]["$AccountWide"]["worlds"]) do
			nworlds = nworlds +1
			table.insert(accounts[acc].worlds, i)
		end
	end

-- insert marker for older chars
--	table.insert(accounts[acc].worlds, "##NEITHER##")


-- Load Character Data
	for playerID, _ in pairs(History_SV["Default"][acc]["$AccountWide"]["data"]) do

		if playerID == "" then
		print("acct: " .. acc)
		end
		table.insert (accounts[acc].playerIDs, playerID)
		accounts[acc].player[playerID] = {}		-- stub table to hold char data, later becomes "me"
--
		local me = accounts[acc].player[playerID]											-- shorter reference: our code
		local thischar = History_SV["Default"][acc]["$AccountWide"]["data"][playerID]	-- shorter reference: History DB
		-- Pull in some char data for processing
		if thischar.name == nil  then --	Old Format
	--	    print("Old Format  " .. playerID)
			me.name = playerID
		else
			me.name = thischar.name
		end
		playerNames[playerID]=me.name

		-- == Gender
		if thischar.Gender =="M" then
			me.gender = L.Male
		elseif thischar.Gender == "F" then
			me.gender = L.Female
		end
		-- ==Level
		local level = thischar.level

		me.level = level
		if (level <=50) then
			me.levelstr = tostring(level)
			me.isvet = false
		else
			me.levelstr = "V" .. tostring(level -50)
			me.isvet = true
			table.insert(accounts[acc].playerIDs_vet,playerID)
		end
		-- == Cumulative TimePlayed
		if thischar.timeplayed == nil then
			me.timeplayed = math.floor(thischar.levels[level].time/60)   -- Old version compat
		else
			me.timeplayed = math.floor(thischar.timeplayed/60)
		end
		-- world

		if thischar.world == nil then
			accounts[acc].hasblankworlds = true		-- causes display of "##NEITHER##
		else
			me.world = thischar.world		-- server
		end

	end

	table.sort(accounts[acc].playerIDs,function(a,b)  return (playerNames[a] < playerNames[b]) end)
	table.sort(accounts[acc].playerIDs_vet,function(a,b) return (playerNames[a] < playerNames[b]) end)
end



--[[ ==========================================
	Iterate over all accounts and PlayerIDs creating display items
--]]
 for acc,_ in pairs (accounts) do

  -- ====  Accountwide Data
  -- Setup Log data
	accounts[acc].logtabs  =iup.tabs{}
	-- Log Display table presentation
	accounts[acc].logtable = {}
	accounts[acc].logtable=iup.matrix{numcol=2, numcol_visible=2,  numlin=0,numlin_visible=8}
	accounts[acc].logtable:setcell(0,0, L.TStamp)
	iup.SetAttribute(accounts[acc].logtable,  "ALIGNMENT0", "ACENTER")
	iup.SetAttribute(accounts[acc].logtable,  "ALIGNMENT2", "ALEFT")
	iup.SetAttribute(accounts[acc].logtable,  "WIDTH0", 80)
	iup.SetAttribute(accounts[acc].logtable,  "WIDTH1", 100)
	iup.SetAttribute(accounts[acc].logtable,  "WIDTH2", 300)
	iup.SetAttribute(accounts[acc].logtable,  "READONLY", "YES")
	-- Load log data

	local Line=0
	local TimeStr = ""
	accounts[acc].logtable.numlin = Line
	for _,j in ipairs (History_SV["Default"][acc]["$AccountWide"]["log"]) do
		Line= Line +1
		accounts[acc].logtable.numlin = Line
		TimeStr = os.date(dateformat_log,j["TimeStamp"])
		accounts[acc].logtable:setcell( Line,0, TimeStr)
		if j["Char"] ~= nil then
			accounts[acc].logtable:setcell( Line,1, j["Char"])
		end
		accounts[acc].logtable:setcell( Line,2, j["text"])
	end

	-- Setup Log Display
	accounts[acc].log_tab=iup.vbox {
			["tabtitle"] =L.LogTab,
			accounts[acc].logtable,
			iup.fill{}
			}
	-- Top Level Panels
	-- accounts[acc].world_zbox = iup.zbox{}  -- display main panel containing worlds (servers)  -- not used ATM
	accounts[acc].mode_zbox = iup.zbox{}  -- display submain panel containing tabs and dungeons
	accounts[acc].char_tabs = iup.tabs{}  -- Top level of Char_Tabs, Character Info in Here
	accounts[acc].dung_tabs = iup.tabs{}  -- Top level of Dung_Tabs, Dungeon  Info in Here


	iup.Append(accounts[acc].mode_zbox, accounts[acc].char_tabs)

	detail_name = iup.label {title="",expand = "HORIZONTAL"}
	detail_desc = iup.label {title="",expand = "HORIZONTAL"}
	Status_bar = iup.label{title=L.Welcome .. " " .. L.Version .. " " .. version .. ".", expand = "HORIZONTAL"}
	iup.Append(accounts[acc].mode_zbox, accounts[acc].dung_tabs)

  -- Mode Buttons (Toggles)
  --[[  These control the display.
   Char mode lists the characters and information for them (default for prior versions)
   Dung Mode lists the dungeons and which characters have done them.
   Buttons are arranged in radio mode
   --]]

   accounts[acc].char_tog = iup.toggle{ title = L.Characters}
  local tog = accounts[acc].char_tog
  function tog:action(x)
	if x == 1 then
	accounts[acc].mode_zbox.value =accounts[acc].char_tabs
	end
  end

  accounts[acc].dung_tog = iup.toggle{ title = L.Dungeons}

  tog = accounts[acc].dung_tog
  function tog:action(x)
	if x == 1 then
	accounts[acc].mode_zbox.value = accounts[acc].dung_tabs
	end
  end
  accounts[acc].mode = iup.frame {
								iup.radio {
								iup.hbox{
										accounts[acc].char_tog,
										accounts[acc].dung_tog,
										},
									}
								}
  accounts[acc].mode.title =  L.Mode
  accounts[acc].mode.margin = "15x5"

  -- Prepare for Dungeon data recording as we iterate through characters.
  accounts[acc].dung = {}		-- put all dungeon mode stuff here. Populate it with character data.
  -- N Normal,   V Vet,    VH   Vet hard mode
  dung = accounts[acc].dung
  dung.pub = {}
  dung.pub.box = {}
  dung.pub.key = {}
  dung.DLC = {}
  dung.DLC.box = {}
  dung.DLC.key = {}
  dung.nPlayers = #accounts[acc].playerIDs
  dung.Grp = {}		-- these ones are indexed.
  dung.Trials = {}

  -- Set up dungeon mode Group Dungeons
  for _,i in ipairs(Grp_Order) do
	dung.Grp[i]= {}
	dung.Grp[i].key ={}   -- key lookup
	dung.Grp[i].box = iup.matrix {numcol=dung.nPlayers,     numlin=_size(Grp_Dat[i].id), widthdef=100}
	iup.SetAttribute(dung.Grp[i].box, "READONLY", "YES")

	dung.Grp[i].tab = iup.vbox {
						["tabtitle"] =L.Grp_TabName[i],
						dung.Grp[i].box,
						iup.fill{},
					}

-- Mouseover
	dung.Grp[i].box.dat = Grp_Dat[i]
	dung.Grp[i].box.mousemove_cb = box_mousemove_cb
	dung.Grp[i].box.leavewindow_cb = box_leavewindow_cb

		--set lines Heading
	dung.Grp[i].box:setcell(0,0, L.Location)
	--Set Line titles
	for line,key in ipairs(Grp_Dat[i].key) do
		dung.Grp[i].box:setcell(line, 0, grp_names[key])
	end

	--Create Columns for Chars
	for col ,playerID in ipairs(accounts[acc].playerIDs) do
		dung.Grp[i].box:setcell(0, col, playerNames[playerID])
	end


  end

  -- a table for each dungeon to which we add characters
  for _,i in ipairs(Grp1_Order) do
    for _,key in ipairs(grp1tokey) do
	  dung.Grp[i].key[key] = {}
	  for _,playerID in ipairs(accounts[acc].playerIDs) do
		dung.Grp[i].key[key][playerID] = false
	  end
	end
  end

  for _,i in ipairs(Grp2_Order) do
    for _,key in ipairs(grp2tokey) do
	  dung.Grp[i].key[key] = {}
	  for _,playerID in ipairs(accounts[acc].playerIDs) do
		dung.Grp[i].key[key][playerID] = false
	  end
	end
  end

  -- Set up dungeon mode  Trials
  for _,i in ipairs(Trials_Order) do
		dung.Trials[i]= {}
		dung.Trials[i].key ={}   -- key lookup
		dung.Trials[i].box = iup.matrix {numcol=dung.nPlayers,  numlin=_size(Trials_Dat[i].id), widthdef=100}
		iup.SetAttribute(dung.Trials[i].box, "READONLY", "YES")

		dung.Trials[i].tab = iup.vbox {
							["tabtitle"] =L.Trial_TabName[i],
							dung.Trials[i].box,
							iup.fill{},
						}

	dung.Trials[i].box.dat = Trials_Dat[i]
	dung.Trials[i].box.mousemove_cb = box_mousemove_cb
	dung.Trials[i].box.leavewindow_cb = box_leavewindow_cb


	--set lines Heading
	dung.Trials[i].box:setcell(0,0, L.Location)
	--Set Line titles
	for line,key in ipairs(Trials_Dat[i].key) do
		dung.Trials[i].box:setcell(line, 0, Trials_Names[i][key])
	end

	--Create Columns for Chars
	for col ,playerID in ipairs(accounts[acc].playerIDs) do
		dung.Trials[i].box:setcell(0, col, playerNames[playerID])
	end



    -- a table for each dungeon to which we add characters
	for _,key in ipairs(Trials2key[i]) do
	  dung.Trials[i].key[key] = {}
	  for _,playerID in ipairs(accounts[acc].playerIDs) do
		dung.Trials[i].key[key][playerID] = false
	  end
	end

  end




--  for _,i in ipairs(Pub_Dat.key) do
--	  dung.pub.key[i] = {}
--  end

  for _,i in ipairs(DLC2key) do
	  dung.DLC.key[i] = {}
  end

  -- ================  END Accountwide Data

  --=================  START OF CHARACTER MODE DISPLAY

-- Creates boxes, stage from names to allow sorting
	for _,playerID in ipairs(accounts[acc].playerIDs) do
		local me = accounts[acc].player[playerID]											-- shorter reference: our code
		local thischar = History_SV["Default"][acc]["$AccountWide"]["data"][playerID]	-- shorter reference: History DB


		-- Generate the leveling box.  ============================

		me.leveling_box = iup.matrix {numcol=6, numcol_visible=6,  widthdef=60}
		me.leveling_box:setcell(0,1, L.Level)
		me.leveling_box:setcell(0,2, L.PTime)
		me.leveling_box:setcell(0,3, L.Start)
		me.leveling_box:setcell(0,4, L.Deaths)
		me.leveling_box:setcell(0,5, L.APts)
		me.leveling_box:setcell(0,6, L.Location)
		iup.SetAttribute(me.leveling_box, "WIDTH6", "100")
		iup.SetAttribute(me.leveling_box, "READONLY", "YES")


		-- levels as stored are unsorted, so create a level table which is sorted,
		local levels = {}
		for i,_ in pairs(thischar.levels) do
			table.insert(levels, i)
		end

		table.sort(levels)

		for i,j in ipairs(levels) do		-- traverse in sorted order
			local timelevel = math.floor(thischar.levels[j].time)
			me.leveling_box.numlin = i
			me.leveling_box:setcell(i,1, j)
			me.leveling_box:setcell(i,2, math.floor(timelevel/60))
			me.leveling_box:setcell(i,3, os.date("%Y-%m-%d",thischar.levels[j].begin))
			me.leveling_box:setcell(i,4, thischar.levels[j].deaths)
			me.leveling_box:setcell(i,5, thischar.levels[j].Ach_Points)
			-- Do we have map name for this level?
			if thischar.levels[j].map ~= nil then
				me.leveling_box:setcell(i,6, thischar.levels[j].map)
			end
		end
		-- Create Grp Dungeon Boxes ====================================
		me.Grp ={}		-- Put them all together

		for _, i in ipairs(Grp_Order) do		-- For Each Grp Dungeon
			me.Grp[i] = {}						--  Dungeon data storage
			me.Grp[i].vet = Grp_Dat[i].vet
			me.Grp[i].box = iup.matrix {numcol=4, numcol_visible=4,  numlin=Grp_Dat[i].lines, widthdef=100}
			iup.SetAttribute(me.Grp[i].box, "READONLY", "YES")

			me.Grp[i].box.dat = Grp_Dat[i]		-- for mouseover
			me.Grp[i].box.mousemove_cb = box_mousemove_cb
			me.Grp[i].box.leavewindow_cb = box_leavewindow_cb

			--Set Column titles in box
			for j=1, 4 do
				me.Grp[i].box:setcell(0,j, Area_names[j].long)
			end


			-- set background to red
		--	iup.SetAttribute(me.Grp[i].box,  "BGCOLOR", BG_Colour_Not_Complete)

			-- set text to black if achievement found.

			for id, Gdat in pairs (Grp_Dat[i].id) do
				local bgcolour,key
				if thischar.ach[id] ~= nil then
					bgcolour = "BGCOLOR" .. Gdat.L .. ":" .. Gdat.C
					iup.SetAttribute(me.Grp[i].box, bgcolour, BG_Colour_Complete)
					-- Add char to dungeon
					key = tostring(Gdat.L .. Gdat.C)
					if  dung.Grp[i].key[key] == nil then
						print ("dung.Grp[i].key[key]   key:  " .. key .. " is nil.")
					end
					dung.Grp[i].key[key][playerID] = true
				else
					bgcolour = "BGCOLOR" .. Gdat.L .. ":" .. Gdat.C
					iup.SetAttribute(me.Grp[i].box, bgcolour, BG_Colour_Not_Complete)
				end
			end

			-- Create display tab
			me.Grp[i].tab = iup.vbox {
						["tabtitle"] =L.Grp_TabName[i],
						me.Grp[i].box,
						iup.fill{},
				}
		end

		-- these IDs are in Specials.lua
		--Set background of heading if all done
		if thischar.ach[1073] ~= nil then  --EP Vanquisher
				iup.SetAttribute(me.Grp["1N"].box,  "BGCOLOR0:1", Colour_Heading_Complete)
		end

		if thischar.ach[1074] ~= nil then  --DC Vanquisher
				iup.SetAttribute(me.Grp["1N"].box ,  "BGCOLOR0:2", Colour_Heading_Complete)
		end

		if thischar.ach[1075] ~= nil then  --AD Vanquisher
				iup.SetAttribute(me.Grp["1N"].box ,  "BGCOLOR0:3", Colour_Heading_Complete)
		end

		for _,i in ipairs(Grp_Order) do
			for _, id in pairs (Grp_Dat[i].id) do
				local key = tostring(id.L).. tostring(id.C)	-- make name key
				me.Grp[i].box:setcell(id.L, id.C, grp_names[key])
			end
		end

		-- Create Trials Dungeon Boxes ====================================
		me.Trials ={}		-- Put them all together

		for _, i in ipairs(Trials_Order) do		-- For Each Dungeon
			me.Trials[i] = {}						-- Dungeon data storage
			me.Trials[i].vet = Trials_Dat[i].vet
			me.Trials[i].box = iup.matrix {numcol=1, numcol_visible=1, numlin=_size(Trials_Dat[i].id), widthdef=120}
			iup.SetAttribute(me.Trials[i].box, "READONLY", "YES")
			me.Trials[i].box.dat = Trials_Dat[i]		-- for mouseover
			me.Trials[i].box.mousemove_cb = box_mousemove_cb
			me.Trials[i].box.leavewindow_cb = box_leavewindow_cb

			--Set Column titles in box
			for line,key in ipairs (Trials2key[i]) do  -- Load Dungeons Name. Info LC is the Dungeon Identifier
					me.Trials[i].box:setcell(line,0, Trials_Names[i][key])
			end


			iup.SetAttribute(me.Trials[i].box,  "BGCOLOR*:1", BG_Colour_Not_Complete)
			--iup.SetAttribute(me.Trials[i].box,  "FGCOLOR*:1", "DEFAULT")
			-- set text if achievement found and change background
			for id, Gdat in pairs (Trials_Dat[i].id) do
				local bgcolour
				if thischar.ach[id] ~= nil then
					bgcolour = "BGCOLOR" .. Gdat.L .. ":" .. Gdat.C
					me.Trials[i].box:setcell(Gdat.L,Gdat.C, L.YesLabel)
					iup.SetAttribute(me.Trials[i].box, bgcolour, BG_Colour_Complete)
					-- Add char to dungeon
					dung.Trials[i].key[Gdat.key][playerID] = true
				else
					me.Trials[i].box:setcell(Gdat.L,Gdat.C, L.NoLabel)
				end

			end

			-- Create display tab
			me.Trials[i].tab = iup.vbox {
						["tabtitle"] =L.Trial_TabName[i],
						me.Trials[i].box,
						iup.fill{},
				}
		end


		-- Create Pub Dungeon Achievements Box==========================
		me.Pub_box = iup.matrix {numcol=4, numcol_visible=4,  numlin=5, widthdef=100}
		iup.SetAttribute(me.Pub_box, "READONLY", "YES")
		me.Pub_box.dat = Pub_Dat
		me.Pub_box.mousemove_cb = box_mousemove_cb
		me.Pub_box.leavewindow_cb = box_leavewindow_cb

		for i=1, 4 do  -- Load text
			me.Pub_box:setcell(0,i, Area_names[i].long)
		end

		iup.SetAttribute(me.Pub_box,  "BGCOLOR" , BG_Colour_Not_Complete)

		for id,_ in pairs (Pub_Dat.id) do
			local bgcolour = "BGCOLOR" .. Pub_Dat.id[id].L .. ":" .. Pub_Dat.id[id].C
			if thischar.ach[id] ~= nil then
				iup.SetAttribute(me.Pub_box, bgcolour, BG_Colour_Complete)
				-- Add char to dungeon
				local key = tostring(Pub_Dat.id[id].L .. Pub_Dat.id[id].C)
				if dung.pub.key[key] == nil then	-- Add if needed
					dung.pub.key[key]  = {}
				end
				dung.pub.key[key][playerID] = true
			else
				iup.SetAttribute(me.Pub_box, bgcolour, BG_Colour_Not_Complete)
			end
		end

		if thischar.ach[1068] ~= nil then  --EP Conqueror
				iup.SetAttribute(me.Pub_box,  "BGCOLOR0:1", Colour_Heading_Complete)
		end

		if thischar.ach[1070] ~= nil then  --DC Conqueror
				iup.SetAttribute(me.Pub_box,  "BGCOLOR0:2", Colour_Heading_Complete)
		end

		if thischar.ach[1069] ~= nil then  --AD Conqueror
				iup.SetAttribute(me.Pub_box,  "BGCOLOR0:3", Colour_Heading_Complete)
		end

		for id,dat in pairs (Pub_Dat.id) do  -- Load text
				local key = tostring(tostring(dat.L) .. tostring(dat.C))	-- make name key
				local dname = pub_names[key]
					if dname == nil then
				dname = "key " .. key .." not found in pub_names"
				end
				me.Pub_box:setcell(dat.L,dat.C,dname)
		end

		-- Create Locations Box==============================================
		me.Map_box= iup.matrix {numcol=6, numcol_visible=6,  numlin=0, widthdef=70}

		me.Map_box:setcell(0,0, L.Location)
		me.Map_box:setcell(0,1, L.Visits)
		me.Map_box:setcell(0,2, L.FirstVisited)
		me.Map_box:setcell(0,3, L.FirstLevel)
		me.Map_box:setcell(0,4, L.TimesLeveled)
		me.Map_box:setcell(0,5, L.FirstDeath)
		me.Map_box:setcell(0,6, L.Deaths)

		iup.SetAttribute(me.Map_box, "READONLY", "YES")
		iup.SetAttribute(me.Map_box, "ALIGNMENT0", "ALEFT")
		iup.SetAttribute(me.Map_box, "WIDTH0", "100")
		iup.SetAttribute(me.Map_box, "WIDTH1", "40")
		iup.SetAttribute(me.Map_box, "WIDTH4", "55")
		iup.SetAttribute(me.Map_box, "WIDTH6", "40")


		local map_names = {}
		for map,_ in pairs(thischar.maps) do
			table.insert(map_names,map)
		end

		table.sort(map_names)
		local Line =1
		for _, map in ipairs(map_names) do
			me.Map_box.numlin = Line

			me.Map_box:setcell( Line,0, map)

			if thischar.maps[map].visit ~= nil then
				me.Map_box:setcell( Line,1, thischar.maps[map].visit)
			end

			if thischar.maps[map].firstvisitdate ~= nil then
				local firstvisit = os.date(dateformat,thischar.maps[map].firstvisitdate)
				me.Map_box:setcell( Line,2, firstvisit)
			end

			if thischar.maps[map].firstlevel ~= nil then
				me.Map_box:setcell( Line,3, thischar.maps[map].firstlevel)
			end

			if thischar.maps[map].timeslevel ~= nil then
				me.Map_box:setcell( Line,4, thischar.maps[map].timeslevel)
			end

			if thischar.maps[map].firstdeathlevel ~= nil then
				me.Map_box:setcell( Line,5, thischar.maps[map].firstdeathlevel)
			end

			if thischar.maps[map].deaths ~= nil then
				me.Map_box:setcell( Line,6, thischar.maps[map].deaths )
			end
		Line= Line +1
		end
-- Create WorldBoss Achievements Box==========================
		me.WB_box= iup.matrix {numcol=4, numcol_visible=4,  numlin=5, widthdef=110}

		for i=1, 4 do  -- Load headings, not Trials
			me.WB_box:setcell(0,i, Area_names[i].long)
		end
		me.WB_box:setcell(0,0, L.Zone)
		me.WB_box:setcell(1,0, "1")
		me.WB_box:setcell(2,0, "2")
		me.WB_box:setcell(3,0, "3")
		me.WB_box:setcell(4,0, "4")
		me.WB_box:setcell(5,0, "5")
		iup.SetAttribute(me.WB_box, "READONLY", "YES")
		iup.SetAttribute(me.WB_box, "ALIGNMENT0", "ACENTER")


		-- Need to keep track of multiple achievements for WB in Zones. Index them by zone LineColumn.
		WB_Area={}
    local dname, key, count, ccount
-- Scan over all Slots, see what we have
		for C=1, 4 do
			ccount = 0		-- per column
			for L = 1, 5 do
				key = tostring(L) .. tostring(C)	-- make name key
				dname = Locations[key]				-- Zone Locations
				if dname == nil then
					break	-- only 1 in Coldharbour,1 morrowind, not worry about empty slots
				end

				count = 0
				if WB_Info[key] == nil then
					break	-- Some Locations not necessarily have WB
				end
				for _, id in ipairs (WB_Info[key].ids) do	-- get the WB of the zone

					if  thischar.ach[id] ~= nil then	-- Have we got it?
						count =count +1
					end
				end
				ccount = ccount + count		-- Track the faction (Column)
				me.WB_box:setcell(L,C,dname .. " (" .. tostring(count) .. ")")

				colour = "FGCOLOR" .. L .. ":" .. C
				bgcolour = "BGCOLOR" .. L .. ":" .. C
				if count == #WB_Info[key].ids then		-- Got them all??
					iup.SetAttribute(me.WB_box, colour   , FG_Colour_Complete)  -- Yup
					iup.SetAttribute(me.WB_box, bgcolour , BG_Colour_Complete)
				end
			end   -- L

			--Set Column Heading Colours
			if ccount >= 15 then
				iup.SetAttribute(me.WB_box, "BGCOLOR0:" .. tostring(C), Colour_Heading_Complete)
			end
		end		-- C
---
-- Create WorldBoss Achievements Detail Boxes=======================

		me.WB_Detail_box = {}
		me.WB_Detail_Zbox = iup.zbox{}


		for key, dat  in pairs(WB_Info) do	-- for each zone
			me.WB_Detail_box[key]= iup.matrix {numcol=2, numcol_visible=2,  numlin=#dat.ids}

			me.WB_Detail_box[key]:setcell(0,0, L.Ach_ID)
			me.WB_Detail_box[key]:setcell(0,1, L.Name)
			me.WB_Detail_box[key]:setcell(0,2, L.Detail)
			iup.SetAttribute(me.WB_Detail_box[key], "READONLY", "YES")
			iup.SetAttribute(me.WB_Detail_box[key], "ALIGNMENT0", "ACENTER")
			iup.SetAttribute(me.WB_Detail_box[key], "ALIGNMENTLIN0", "ALEFT")
			iup.SetAttribute(me.WB_Detail_box[key], "ALIGNMENT1", "ALEFT")
			iup.SetAttribute(me.WB_Detail_box[key], "ALIGNMENT2", "ALEFT")
			iup.SetAttribute(me.WB_Detail_box[key],"WIDTH0", "30")
			iup.SetAttribute(me.WB_Detail_box[key],"WIDTH1", "150")
			iup.SetAttribute(me.WB_Detail_box[key],"WIDTH2", "300")
			for line, id in ipairs (dat.ids) do	-- get the Ach of zone
				me.WB_Detail_box[key]:setcell(line,0, tostring(id))

				if Ach_Detail[id] == nil then
					name = "UNKN"
					Desc = ""
				else
					name = Ach_Detail[id].name
					Desc = Ach_Detail[id].description
				end
				me.WB_Detail_box[key]:setcell(line,1, name)
				me.WB_Detail_box[key]:setcell(line,2, Desc)

				-- Set Detail Colours on achievement
				if thischar.ach[id] == nil  then
					iup.SetAttribute(me.WB_Detail_box[key],"FGCOLOR" .. tostring(line) .. ":*", FG_Colour_Not_Complete)	-- Nope
				else
					iup.SetAttribute(me.WB_Detail_box[key],"BGCOLOR" .. tostring(line) .. ":*", BG_Colour_Complete)		-- Yes
				end
			end
			iup.Append(me.WB_Detail_Zbox, me.WB_Detail_box[key])
		end


		function me.WB_box:enteritem_cb(L,C)
			me.WB_Detail_Zbox.value = me.WB_Detail_box[tostring(L) .. tostring(C)]
		end



-- Create SkillQuest Achievements Box==========================

		me.SQ_box= iup.matrix {numcol=4, numcol_visible=4,  numlin=5, widthdef=110}
		for i=1, 4 do  -- Load headings
			me.SQ_box:setcell(0,i, Area_names[i].long)
		end
		me.SQ_box:setcell(0,0, L.Zone)
		me.SQ_box:setcell(1,0, "1")
		me.SQ_box:setcell(2,0, "2")
		me.SQ_box:setcell(3,0, "3")
		me.SQ_box:setcell(4,0, "4")
		me.SQ_box:setcell(5,0, "5")
		iup.SetAttribute(me.SQ_box, "READONLY", "YES")
		iup.SetAttribute(me.SQ_box, "ALIGNMENT0", "ACENTER")

		iup.SetAttribute(me.SQ_box,  "FGCOLOR*:1", FG_Colour_Not_Complete)
		iup.SetAttribute(me.SQ_box,  "FGCOLOR*:2", FG_Colour_Not_Complete)
		iup.SetAttribute(me.SQ_box,  "FGCOLOR*:3", FG_Colour_Not_Complete)
		iup.SetAttribute(me.SQ_box,  "FGCOLOR*:4", FG_Colour_Not_Complete)
		iup.SetAttribute(me.SQ_box,  "FGCOLOR*:5", FG_Colour_Not_Complete)

		-- Need to keep track of multiple achievements for SQ in Zones. Index them by zone LineColumn.

		for C=1, 4 do
			ccount = 0		-- per column
			for L = 1, 5 do
				key = tostring(L) .. tostring(C)	-- make name key
				dname = Locations[key]				-- Zone Locations
				if dname == nil then
					break	-- only 1 in Coldharbour,1 morrowind not worry about empty slots
				end

				count = 0
				if SQ_Info[key] == nil then
					break	-- Some Locations not necessarily have Skill Quests
				end
				for _, id in ipairs (SQ_Info[key].ids) do	-- get the quests of the zone

					if  thischar.ach[id] ~= nil then	-- Have we got it?
						count =count +1
					end
				end
				ccount = ccount + count		-- Track the faction (Column)
				me.SQ_box:setcell(L,C,dname .. " (" .. tostring(count) .. ")")

				colour = "FGCOLOR" .. L .. ":" .. C
				bgcolour = "BGCOLOR" .. L .. ":" .. C
				if count == #SQ_Info[key].ids then		-- Got them all??
					iup.SetAttribute(me.SQ_box, colour   , FG_Colour_Complete)  -- Yup
					iup.SetAttribute(me.SQ_box, bgcolour , BG_Colour_Complete)
				end
			end   -- L

			--Set Column Heading Colours
			if ccount >= 15 then
				iup.SetAttribute(me.SQ_box, "BGCOLOR0:" .. tostring(C), Colour_Heading_Complete)
			end
		end		-- C
---
-- Create SkillQuest Achievements Detail Boxes=======================

		me.SQ_Detail_box = {}
		me.SQ_Detail_Zbox = iup.zbox{}

		local  link
		for key, dat in pairs(SQ_Info) do	-- for each zone
			me.SQ_Detail_box[key]= iup.matrix {numcol=2, numcol_visible=2,  numlin=#dat.ids}

			me.SQ_Detail_box[key]:setcell(0,0, L.Ach_ID)
			me.SQ_Detail_box[key]:setcell(0,1, L.Name)
			me.SQ_Detail_box[key]:setcell(0,2, L.Link)
			iup.SetAttribute(me.SQ_Detail_box[key], "READONLY", "YES")
			iup.SetAttribute(me.SQ_Detail_box[key], "ALIGNMENT0", "ACENTER")
			iup.SetAttribute(me.SQ_Detail_box[key], "ALIGNMENTLIN0", "ALEFT")
			iup.SetAttribute(me.SQ_Detail_box[key], "ALIGNMENT1", "ALEFT")
			iup.SetAttribute(me.SQ_Detail_box[key], "ALIGNMENT2", "ALEFT")
			iup.SetAttribute(me.SQ_Detail_box[key],"WIDTH0", "30")
			iup.SetAttribute(me.SQ_Detail_box[key],"WIDTH1", "150")
			iup.SetAttribute(me.SQ_Detail_box[key],"WIDTH2", "250")
			for line, id in ipairs (dat.ids) do	-- get the quests of the zone
				me.SQ_Detail_box[key]:setcell(line,0, tostring(id))

				if Ach_Detail[id] == nil then
					name = "UNKN"
				else
					name = Ach_Detail[id].name
				end
				link = SQ_dat[id].link1
				me.SQ_Detail_box[key]:setcell(line,1, name)
				me.SQ_Detail_box[key]:setcell(line,2, link)
				-- Set Detail Colours on achievement
				if thischar.ach[id] == nil  then
					iup.SetAttribute(me.SQ_Detail_box[key],"FGCOLOR" .. tostring(line) .. ":*", FG_Colour_Not_Complete)	-- Nope
				else
					iup.SetAttribute(me.SQ_Detail_box[key],"BGCOLOR" .. tostring(line) .. ":*", BG_Colour_Complete)		-- Yes
				end

			iup.Append(me.SQ_Detail_Zbox, me.SQ_Detail_box[key])
			end
		-- Click on Link,
		local thisSQDetail = me.SQ_Detail_box[key]	-- The function def below doesn't like the [key]
		function thisSQDetail:click_cb(L,C)
				if C == 2 then
					iup.Help(self:getcell(L,C))		-- Launch Browser
				else
					return IUP_IGNORE
				end
			end

		end

		function me.SQ_box:enteritem_cb(L,C)
			me.SQ_Detail_Zbox.value = me.SQ_Detail_box[tostring(L) .. tostring(C)]
		end
--========== DLC

		me.DLC_box= iup.matrix {numcol=5, numcol_visible=5,  numlin=4, widthdef=105}
		iup.SetAttribute(me.DLC_box, "READONLY", "YES")
		me.DLC_box.dat = DLC_Dat
		me.DLC_box.mousemove_cb = box_mousemove_cb
		me.DLC_box.leavewindow_cb = box_leavewindow_cb
		--Set Column titles

		me.DLC_box:setcell(0,1, Area_names[6].long)		-- Orsinium
		me.DLC_box:setcell(0,2, Area_names[8].long)		-- IC
		me.DLC_box:setcell(0,3, Area_names[9].long)		-- Hist
		me.DLC_box:setcell(0,4, Area_names[10].long)	-- Horns
		me.DLC_box:setcell(0,5, Area_names[11].long)	-- Bones
--		me.DLC_box:setcell(0,6, Area_names[12].long)	-- VVardenfell
		me.DLC_box:setcell(0,6, Area_names[13].long)	-- Summer

		for id,_ in pairs (DLC_Dat.id) do
				local L = DLC_Dat.id[id].L
				local C = DLC_Dat.id[id].C
				local key = tostring(L).. tostring(C)	-- make name key
				me.DLC_box:setcell(L, C, DLC_Location_names[key])
		end


		-- set text to black and bg to green if achievement found.
		for id,_ in pairs (DLC_Dat.id) do
			local bgcolour = "BGCOLOR" .. DLC_Dat.id[id].L .. ":" .. DLC_Dat.id[id].C
			if thischar.ach[id] ~= nil then
				iup.SetAttribute(me.DLC_box, bgcolour, BG_Colour_Complete)
				-- Add char to dungeon
				key = tostring(DLC_Dat.id[id].L .. DLC_Dat.id[id].C)
				dung.DLC.key[key][playerID] = true
			else
				iup.SetAttribute(me.DLC_box, bgcolour, BG_Colour_Not_Complete)
			end
		end

		if thischar.ach[1248] ~= nil then  --"Hero of Wrothgar",
				iup.SetAttribute(me.DLC_box,  "BGCOLOR0:1", Colour_Heading_Complete)
		end

	 -- ====================================
	--  == Prepare for the character data display tabs
		me.tab = iup.vbox{
					["tabtitle"] = me.name,		-- This vbox will be a tab and the tab text is this

					iup.hbox{		--Top Information bar
							Alignment = "ACENTER",
							iup.label{title=thischar.world,PADDING="10X0"},
							iup.label{title=me.gender, FONT="Times,BOLD,10"},
							iup.label{title=thischar.Race .." / ".. thischar.Class, PADDING="10X0", FONT="Times,BOLD,10"},
							iup.label{title=thischar.Alliance, PADDING="10X0"},
							iup.label{title=L.Level .. ": ".. me.levelstr, PADDING="10X0"},
							iup.label{title=L.Created .. os.date(dateformat,thischar.Created), PADDING="10X0"},
							iup.label{title=L.LLog .. os.date(dateformat,thischar.LoginTime), PADDING="10X0"},
							iup.label{title=L.TPlayed .. me.timeplayed .." " .. L.Hrs},
							iup.fill{}
							},
					iup.label{SEPARATOR="HORIZONTAL"}
					}

		me.data_tabs = iup.tabs{} --Data tabs for Char
		-- All Grp Dungeons
		for _,i in ipairs (Grp_Order) do
			if me.isvet or me.Grp[i].vet == false then
				-- non vet chars only see non-vet dungeons
				iup.Append(me.data_tabs, me.Grp[i].tab)
			end
		end

		-- All Trials Dungeons
		for _,i in ipairs (Trials_Order) do
			if me.isvet or me.Trials[i].vet == false then
				-- non vet chars only see non-vet dungeons
				iup.Append(me.data_tabs, me.Trials[i].tab)
			end
		end

		iup.Append(me.data_tabs,	iup.vbox {	["tabtitle"] =L.PubDungeon,
												iup.label{title=L.PubLab,expand="HORIZONTAL"},
												me.Pub_box,
												iup.fill{}
											})
		if me.isvet then
		--[[
		iup.Append(me.data_tabs, iup.vbox {	["tabtitle"] =L.VetDungeon,
												iup.label{title=L.VetLab,expand="HORIZONTAL"},
												me.Vet_box,
												iup.fill{}
											})

--]]
		end

		iup.Append(me.data_tabs, iup.vbox {	["tabtitle"] =L.Leveling,
										--		iup.label{title="LevLabel",expand="HORIZONTAL"},
												me.leveling_box,
												iup.fill{}
											})

		iup.Append(me.data_tabs, iup.vbox {	["tabtitle"] =L.Locations,
											--	iup.label{title="LevLabel",expand="HORIZONTAL"},
												me.Map_box,
												iup.fill{}
											})

		iup.Append(me.data_tabs, iup.vbox {	["tabtitle"] =L.WBosses,
												iup.label{title=L.WBLab,expand="HORIZONTAL"},
												me.WB_box,
												iup.label{title=L.WB_Detail},
												me.WB_Detail_Zbox,
												iup.fill{}
											})

		iup.Append(me.data_tabs, iup.vbox {	["tabtitle"] =L.SkillQuests,
												iup.label{title=L.SkillLab,expand="HORIZONTAL"},
												me.SQ_box,
												iup.label{title=L.SQ_Detail},
												me.SQ_Detail_Zbox,
												iup.fill{}
											})
		iup.Append(me.data_tabs, iup.vbox {	["tabtitle"] =L.DLC,
												iup.label{title=L.DLCLab,expand="HORIZONTAL"},
												me.DLC_box,
												iup.fill{}
											})


		iup.Append(me.tab,me.data_tabs)

		iup.Append(accounts[acc].char_tabs,me.tab)

		local wide =((dung.nPlayers+1) * 110)
		if wide < 690  then
			wide = 690
		elseif wide >960 then
			wide =  960
		end

		accounts[acc].panelsize =  tostring(wide) ..  "x350"
	end  -- Chars

-- Add to end of Characters
iup.Append(accounts[acc].char_tabs, accounts[acc].log_tab)

--=================  END OF CHARACTER MODE DISPLAY
--=================  START OF DUNGEON MODE DISPLAY

   -- Generic function for populating these tables
	populate = function(ADung,Grp_key)
		if ADung.key == nil  then
			print ("ADung.key  is nil (fatal)")
		end
		for line, key in ipairs(Grp_key) do  -- for lines going down, get the key
		-- does that char exist in the table. Check by PlayerID
			for col,playerID in ipairs(accounts[acc].playerIDs) do	-- over each char in order
				if ADung.key[key] == nil  then
				ADung.key[key] = {}
				end

				if ADung.key[key][playerID]  then
					ADung.box:setcell(line,col, L.YesLabel)
					iup.SetAttribute(ADung.box,"BGCOLOR" .. tostring(line) .. ":" .. tostring(col), BG_Colour_Complete)
				else
					ADung.box:setcell(line,col, L.NoLabel)
					iup.SetAttribute(ADung.box,"BGCOLOR" .. tostring(line) .. ":" .. tostring(col), BG_Colour_Not_Complete)
				end
			end
		end
	end

	-- Create Pub Dungeon Character Box=========================

	dung.pub.box = iup.matrix {numcol=dung.nPlayers,  numlin=#Pub_Dat.key, widthdef=100}
	dung.pub.box.dat = Pub_Dat
	dung.pub.box.mousemove_cb = box_mousemove_cb
	dung.pub.box.leavewindow_cb = box_leavewindow_cb

	--Set Line titles
	for line,key in ipairs(Pub_Dat.key) do
		dung.pub.box:setcell(line, 0, pub_names[key])
	end
	--set lines
	dung.pub.box:setcell(0,0, L.Location)

	--Create Columns for Chars
	for col ,playerID in ipairs(accounts[acc].playerIDs) do
		dung.pub.box:setcell(0, col, playerNames[playerID])
	end

	iup.SetAttribute(dung.pub.box, "READONLY", "YES")

	-- Populate with character data ============================
	-- print ("Populating Pub")
	populate(dung.pub,Pub_Dat.key)

	-- Create Pub Dungeon Tab ==================================

	dung.pub.tab = iup.vbox {
						["tabtitle"] =L.Pub,
						dung.pub.box,
						iup.fill{},
				}

	iup.Append(accounts[acc].dung_tabs, dung.pub.tab)

	-- Grp Dungeons  ===========================================

	for _,i in ipairs (Grp_Order) do
		iup.Append(accounts[acc].dung_tabs, dung.Grp[i].tab)
		-- Populate with character data ============================
		-- print ("populate Grp,i: " .. i)
		populate(dung.Grp[i], Grp_Dat[i].key)
	end

	-- Create DLC Dungeon Character Box=========================

	dung.DLC.box = iup.matrix {numcol=dung.nPlayers ,  numlin=#DLC2key, widthdef=100}

	dung.DLC.box.dat = DLC_Dat
	dung.DLC.box.mousemove_cb = box_mousemove_cb
	dung.DLC.box.leavewindow_cb = box_leavewindow_cb

	--Set Line titles
	for i, key in ipairs(DLC2key) do
		dung.DLC.box:setcell(i, 0, DLC_Location_names[key])
	end
	--set lines
	dung.DLC.box:setcell(0,0, L.Location)
	--Create Columns for Chars
	for i,playerID in ipairs(accounts[acc].playerIDs ) do
		dung.DLC.box:setcell(0, i, playerNames[playerID])
	end

	iup.SetAttribute(dung.DLC.box, "READONLY", "YES")

	-- Populate with character data ============================
	for line,key in ipairs(DLC2key) do		-- over each dungeon
	    -- does that char exist in the table.
		for i,playerID in ipairs(accounts[acc].playerIDs ) do	-- over each char in order
			if dung.DLC.key[key][playerID] == nil then
				dung.DLC.box:setcell(line,i, "N")
				iup.SetAttribute(dung.DLC.box,"BGCOLOR" .. tostring(line) .. ":" .. tostring(i), BG_Colour_Not_Complete)
			else
				dung.DLC.box:setcell(line,i, "Y")
				iup.SetAttribute(dung.DLC.box,"BGCOLOR" .. tostring(line) .. ":" .. tostring(i), BG_Colour_Complete)
			end
		end
	end


	-- Create DLC Dungeon Tab ==================================
	dung.DLC.tab = iup.vbox {
						["tabtitle"] =L.DLC,
						dung.DLC.box,
						iup.fill{},
				}
	iup.Append(accounts[acc].dung_tabs, dung.DLC.tab)



	if #accounts[acc].playerIDs_vet > 0  then  -- skip vet and trials if no eligible chars

		-- Create Trials  Tab ============================================
		for _,i in ipairs (Trials_Order) do
			iup.Append(accounts[acc].dung_tabs, dung.Trials[i].tab)
			-- Populate with character data ============================
		--	print ("populate Trials")
			populate(dung.Trials[i], Trials_Dat[i].key)
		end
	end -- has vet chars

end -- Accounts

table.sort(accounts_list)

function select_account()
	local selected
		if #accounts_list > 1 then
			selected = iup.ListDialog (1, L.SelectA,
					#accounts_list,	--Size
					accounts_list,
					1, --Initial
					1,#accounts_list	--MaxCol MaxLine
					)

			if selected <0 then
				return nil		-- Cancelled
			else
				return accounts_list[selected+1]
			end
		else
		return accounts_list[1]		-- only 1 account, no need for Dialog
		end
end


-- Create dialog to choose account
myaccount=select_account()


if myaccount ~=nil then
	-- Create dialog if not cancelled
	dlg = iup.dialog{iup.vbox{
							accounts[myaccount].mode,
							accounts[myaccount].mode_zbox,
							detail_name,		-- Hover over information
							detail_desc,
							Status_bar,	-- Bottom Status bar.
							margin="5x5",
							ngap="3",
							},
					title=L.title .. myaccount ,
					size=accounts[myaccount].panelsize,
					}
	-- Shows dialog in the centre of the screen
	dlg:showxy(iup.CENTER, iup.CENTER)

	if (iup.MainLoopLevel()==0) then
	  iup.MainLoop()
	end
end