-- Licence: MIT Licence
-- 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 Colour_Not_Complete = "#FFB67D"
local Colour_Complete = "#000000"
local Colour_Heading_Complete = "#58FA58"
dofile "en.lua"	 -- default english translations
-- ========================
require( "iuplua" )
require( "iupluacontrols" )
dofile "../../SavedVariables/History.lua"

--os.execute( "md ..\\..\\SavedVariables\\History_Bak" )  -- fails silently if already exists.

--os.execute("copy  ..\\..\\SavedVariables\\History.lua ..\\..\\SavedVariables\\History_Bak\\History.lua")

--[[
-- ============== Setup storage for old characters.
archivef = io.open("../../SavedVariables/History.Archive", "r")
if archivef ==nil then	--create empty file
	archivef = io.open("../../SavedVariables/History.Archive", "w")
	archivef:write("Archive = {} \n")
end

archivef:close()
dofile "../../SavedVariables/History.Archive"

-- newf = assert(io.open("../../SavedVariables/History.new", "w"))
-- ==============
--]]
function dump(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
function quote(astring)
	return '"' .. string.gsub(astring,"%'", "\\'") .. '"'
end


function write_saved(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

accounts = {}
accounts_list = {}		-- String list for selection dialog
naccounts = 0
for i,_ in pairs(History_SV["Default"]) do
	accounts[i] = {}
	accounts[i].names = {}	-- intermediate table for sorting. WIP. Array formatted.
	accounts[i].name = {}
	naccounts = naccounts +1
	table.insert(accounts_list, i)
end

function write_data()
  newf = assert(io.open("../../SavedVariables/History.new", "w"))
  newf:write("History_SV=" .. write_saved(History_SV))
  newf:close()
end
--Dump it back out
-- newf:write("History_SV=" .. write_saved(History_SV))
-- newf:close()



-- Load up .names, as a first run through. It's a sortable array.
-- This is used as an indirection to control presentation order
 for acc,_ in pairs (accounts) do
  for char, _ in pairs(History_SV["Default"][acc]["$AccountWide"]["data"]) do
      table.insert (accounts[acc].names, char)
	  accounts[acc].name[char] = {}		-- stub table to hold char data
  end
 end


function print_old()
	for i,j in pairs (History_SV["Default"][myaccount]["$AccountWide"]["old"]) do
		print (i .. " .. " .. dump(j))
	end
end

-- set up some static data
lbl_Status_bar = iup.label{title=L.Welcome, expand = "HORIZONTAL"}
btn_archive = iup.button{title="Archive", FGCOLOR = "#FF0000"}

--[[ ==========================================
	Iterate over all accounts and chars 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 i,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{}
			}
	accounts[acc].tabs =iup.tabs{}  -- Top level of Tabs, Character Info in Here
  -- ====  END Accountwide Data


-- Creates boxes, stage from names to allow optional sorting in future.
	for _,char in ipairs(accounts[acc].names) do
		accounts[acc].name[char] = {}
		local thischar = History_SV["Default"][acc]["$AccountWide"]["data"][char]		-- shorter reference
		-- Pull in some char data for processing
		-- == Gender
		if thischar.Gender =="M" then
			accounts[acc].name[char].gender = L.Male
		elseif thischar.Gender == "F" then
			accounts[acc].name[char].gender = L.Female
		end
		-- ==Level
		local level = thischar.level

		accounts[acc].name[char].level = level
		if (level <=50) then
			accounts[acc].name[char].levelstr = tostring(level)
		else
			accounts[acc].name[char].levelstr = "V" .. tostring(level -50)
		end
		-- == Cumulative TimePlayed
		accounts[acc].name[char].timeplayed = math.floor(thischar.levels[level].time/60)

		-- Generate the leveling box.  ============================
		local leveling_box = {}
		accounts[acc].name[char].leveling_box = iup.matrix {numcol=6, numcol_visible=6,  widthdef=60}
		accounts[acc].name[char].leveling_box:setcell(0,1, L.Level)
		accounts[acc].name[char].leveling_box:setcell(0,2, L.PTime)
		accounts[acc].name[char].leveling_box:setcell(0,3, L.Start)
		accounts[acc].name[char].leveling_box:setcell(0,4, L.Deaths)
		accounts[acc].name[char].leveling_box:setcell(0,5, L.APts)
		accounts[acc].name[char].leveling_box:setcell(0,6, L.Location)
		iup.SetAttribute(accounts[acc].name[char].leveling_box, "WIDTH6", "100")
		iup.SetAttribute(accounts[acc].name[char].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)
			accounts[acc].name[char].leveling_box.numlin = i
			accounts[acc].name[char].leveling_box:setcell(i,1, j)
			accounts[acc].name[char].leveling_box:setcell(i,2, math.floor(timelevel/60))
			accounts[acc].name[char].leveling_box:setcell(i,3, os.date("%Y-%m-%d",thischar.levels[j].begin))
			accounts[acc].name[char].leveling_box:setcell(i,4, thischar.levels[j].deaths)
			accounts[acc].name[char].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
				accounts[acc].name[char].leveling_box:setcell(i,6, thischar.levels[j].map)
			end
		end

		-- Create Grp Dungeon Achievements Box=========================
		accounts[acc].name[char].Grp_box = {}
		accounts[acc].name[char].Grp_box = iup.matrix {numcol=4, numcol_visible=4,  numlin=5, widthdef=90}
		--Set Column titles
		for i=1, 4 do
			accounts[acc].name[char].Grp_box:setcell(0,i, Area_names[i].medium)
		end
		--set lines
		accounts[acc].name[char].Grp_box:setcell(0,0, L.Level)
		accounts[acc].name[char].Grp_box:setcell(1,0, "10+")
		accounts[acc].name[char].Grp_box:setcell(2,0, "17+")
		accounts[acc].name[char].Grp_box:setcell(3,0, "24+")
		accounts[acc].name[char].Grp_box:setcell(4,0, "31+")
		accounts[acc].name[char].Grp_box:setcell(5,0, "38+")

		iup.SetAttribute(accounts[acc].name[char].Grp_box, "READONLY", "YES")

		-- set all text to red

		iup.SetAttribute(accounts[acc].name[char].Grp_box,  "FGCOLOR*:1", Colour_Not_Complete)
		iup.SetAttribute(accounts[acc].name[char].Grp_box,  "FGCOLOR*:2", Colour_Not_Complete)
		iup.SetAttribute(accounts[acc].name[char].Grp_box,  "FGCOLOR*:3", Colour_Not_Complete)
		iup.SetAttribute(accounts[acc].name[char].Grp_box,  "FGCOLOR*:4", Colour_Not_Complete)


		-- set text to black if achievement found.
		for id,_ in pairs (grp_dat) do
			local colour
			if thischar.ach[id] ~= nil then
				colour = "FGCOLOR" .. grp_dat[id].L .. ":" .. grp_dat[id].C
				iup.SetAttribute(accounts[acc].name[char].Grp_box, colour, Colour_Complete)
			end
		end

		--Set background of heading if all done
		if thischar.ach[1073] ~= nil then  --EP Vanquisher
				iup.SetAttribute(accounts[acc].name[char].Grp_box,  "BGCOLOR0:1", Colour_Heading_Complete)
		end

		if thischar.ach[1074] ~= nil then  --DC Vanquisher
				iup.SetAttribute(accounts[acc].name[char].Grp_box,  "BGCOLOR0:2", Colour_Heading_Complete)
		end

		if thischar.ach[1075] ~= nil then  --AD Vanquisher
				iup.SetAttribute(accounts[acc].name[char].Grp_box,  "BGCOLOR0:3", Colour_Heading_Complete)
		end


		for id,_ in pairs (grp_dat) do
				accounts[acc].name[char].Grp_box:setcell(grp_dat[id].L,grp_dat[id].C,grp_dat[id].name)
		end


		accounts[acc].name[char].Grp_box.Redraw= "ALL"

		-- Create Pub Dungeon Achievements Box==========================
		accounts[acc].name[char].Pub_box = iup.matrix {numcol=4, numcol_visible=4,  numlin=5, widthdef=90}
		for i=1, 4 do  -- Load text
			accounts[acc].name[char].Pub_box:setcell(0,i, Area_names[i].medium)
		end
		accounts[acc].name[char].Pub_box:setcell(0,0, L.Level)
		accounts[acc].name[char].Pub_box:setcell(1,0, "12-15")
		accounts[acc].name[char].Pub_box:setcell(2,0, "20-23")
		accounts[acc].name[char].Pub_box:setcell(3,0, "35-36")
		accounts[acc].name[char].Pub_box:setcell(4,0, "40-43")
		accounts[acc].name[char].Pub_box:setcell(5,0, "47-50")

		iup.SetAttribute(accounts[acc].name[char].Pub_box, "READONLY", "YES")

		iup.SetAttribute(accounts[acc].name[char].Pub_box,  "FGCOLOR*:1", Colour_Not_Complete)
		iup.SetAttribute(accounts[acc].name[char].Pub_box,  "FGCOLOR*:2", Colour_Not_Complete)
		iup.SetAttribute(accounts[acc].name[char].Pub_box,  "FGCOLOR*:3", Colour_Not_Complete)
		iup.SetAttribute(accounts[acc].name[char].Pub_box,  "FGCOLOR*:4", Colour_Not_Complete)

		for id,_ in pairs (pub_dat) do
			if thischar.ach[id] ~= nil then
				local colour = "FGCOLOR" .. pub_dat[id].L .. ":" .. pub_dat[id].C
				iup.SetAttribute(accounts[acc].name[char].Pub_box, colour, Colour_Complete)
			end
		end

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

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

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

		for id,_ in pairs (pub_dat) do  -- Load text
				accounts[acc].name[char].Pub_box:setcell(pub_dat[id].L,pub_dat[id].C,pub_dat[id].name)
		end

		accounts[acc].name[char].Pub_box.Redraw= "ALL"

		-- Create Vet Dungeon Achievements Box==========================
		accounts[acc].name[char].Vet_box= iup.matrix {numcol=5, numcol_visible=5,  numlin=5, widthdef=110}

		for i=1, 5 do  -- Load headings
			accounts[acc].name[char].Vet_box:setcell(0,i, Area_names[i].medium)
		end

		iup.SetAttribute(accounts[acc].name[char].Vet_box, "READONLY", "YES")

		iup.SetAttribute(accounts[acc].name[char].Vet_box,  "FGCOLOR*:1", Colour_Not_Complete)
		iup.SetAttribute(accounts[acc].name[char].Vet_box,  "FGCOLOR*:2", Colour_Not_Complete)
		iup.SetAttribute(accounts[acc].name[char].Vet_box,  "FGCOLOR*:3", Colour_Not_Complete)
		iup.SetAttribute(accounts[acc].name[char].Vet_box,  "FGCOLOR*:4", Colour_Not_Complete)
		iup.SetAttribute(accounts[acc].name[char].Vet_box,  "FGCOLOR*:5", Colour_Not_Complete)

		-- Need to keep track of multiple achievements in Vet dungeons. Index them by dungeon LineColumn.
		Vet_Info={}
		for id,_ in pairs (vet_dat) do  -- Load Dungeons Info LC is the Dungeon Identifier
				local L = vet_dat[id].L
				local C = vet_dat[id].C
				Vet_Info[L..C] = {count = 0}
				accounts[acc].name[char].Vet_box:setcell(L,C,vet_dat[id].name .. " (0)")
		end


		for id,_ in pairs (vet_dat) do  -- For Achievements we have..
			if thischar.ach[id] ~= nil then
				local L = vet_dat[id].L
				local C = vet_dat[id].C
				--Set colour of LC
				local colour = "FGCOLOR" .. L .. ":" .. C
				iup.SetAttribute(accounts[acc].name[char].Vet_box, colour, Colour_Complete)

				-- Increment count and display
				Vet_Info[L..C].count = Vet_Info[L..C].count+1
				accounts[acc].name[char].Vet_box:setcell(L,C,vet_dat[id].name .. " (" .. Vet_Info[L..C].count ..")")
			end
		end

		if thischar.ach[1159] ~= nil 	then -- Coh All special.
			iup.SetAttribute(accounts[acc].name[char].Vet_box, "FGCOLOR3:3", Colour_Heading_Complete)
		end

		if thischar.ach[1139] ~= nil 	then -- Craglorn all special.
			iup.SetAttribute(accounts[acc].name[char].Vet_box, "BGCOLOR0:5", Colour_Heading_Complete)
		end

		accounts[acc].name[char].Vet_box.Redraw= "ALL"

		-- Create Locations Box==============================================
		accounts[acc].name[char].Map_box= iup.matrix {numcol=6, numcol_visible=6,  numlin=0, widthdef=70}

		accounts[acc].name[char].Map_box:setcell(0,0, L.Location)
		accounts[acc].name[char].Map_box:setcell(0,1, L.Visits)
		accounts[acc].name[char].Map_box:setcell(0,2, L.FirstVisited)
		accounts[acc].name[char].Map_box:setcell(0,3, L.FirstLevel)
		accounts[acc].name[char].Map_box:setcell(0,4, L.TimesLeveled)
		accounts[acc].name[char].Map_box:setcell(0,5, L.FirstDeath)
		accounts[acc].name[char].Map_box:setcell(0,6, L.Deaths)

		iup.SetAttribute(accounts[acc].name[char].Map_box, "READONLY", "YES")
		iup.SetAttribute(accounts[acc].name[char].Map_box, "ALIGNMENT0", "ALEFT")
		iup.SetAttribute(accounts[acc].name[char].Map_box, "WIDTH0", "100")
		iup.SetAttribute(accounts[acc].name[char].Map_box, "WIDTH1", "40")
		iup.SetAttribute(accounts[acc].name[char].Map_box, "WIDTH4", "55")
		iup.SetAttribute(accounts[acc].name[char].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
			accounts[acc].name[char].Map_box.numlin = Line

			accounts[acc].name[char].Map_box:setcell( Line,0, map)

			if thischar.maps[map].visit ~= nil then
				accounts[acc].name[char].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)
				accounts[acc].name[char].Map_box:setcell( Line,2, firstvisit)
			end

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

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

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

			if thischar.maps[map].deaths ~= nil then
				accounts[acc].name[char].Map_box:setcell( Line,6, thischar.maps[map].deaths )
			end
		Line= Line +1
		end


	 -- ====================================
	--  == Prepare for the user display tabs
		accounts[acc].name[char].tab = iup.vbox{
					["tabtitle"] = char,		-- This vbox will be a tab and the tab text is this

					iup.hbox{		--Top Information bar
							Alignment = "ACENTER",
							iup.label{title=accounts[acc].name[char].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 .. ": ".. accounts[acc].name[char].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 .. accounts[acc].name[char].timeplayed .." " .. L.Hrs},
							iup.fill{}
							},
					iup.label{SEPARATOR="HORIZONTAL"},
					iup.vbox {		--Data tabs for Char
						iup.tabs { iup.vbox {	["tabtitle"] =L.GrpDungeon,
												iup.label{title=L.GrpLab,expand="HORIZONTAL"},
												accounts[acc].name[char].Grp_box,
												iup.fill{}
											},
									iup.vbox {	["tabtitle"] =L.PubDungeon,
												iup.label{title=L.PubLab,expand="HORIZONTAL"},
												accounts[acc].name[char].Pub_box,
												iup.fill{}
											},
									iup.vbox {	["tabtitle"] =L.VetDungeon,
												iup.label{title=L.VetLab,expand="HORIZONTAL"},
												accounts[acc].name[char].Vet_box,
												iup.fill{}
											},

									iup.vbox {	["tabtitle"] =L.Leveling,
										--		iup.label{title="LevLabel",expand="HORIZONTAL"},
												accounts[acc].name[char].leveling_box,
												iup.fill{}
											},
									iup.vbox {	["tabtitle"] =L.Locations,
											--	iup.label{title="LevLabel",expand="HORIZONTAL"},
												accounts[acc].name[char].Map_box,
												iup.fill{}
											},
								},	-- end of tabs for dungeons
							},
					}  -- end of tabs for characters vbox
		iup.Append(accounts[acc].tabs,accounts[acc].name[char].tab)

		local panel =(#accounts[acc].names * 90)
		if panel < 680  then
			panel = 680
		elseif panel >950 then
			panel = 950
		end
		accounts[acc].panelsize =  tostring(panel) ..  "x250"
	end  -- Chars

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

--print_old()



function select_account()
	local selected
		if naccounts > 1 then
			selected = iup.ListDialog (1, L.SelectA,
					2,	--Size
					accounts_list,
					1, --Initial
					1,naccounts	--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 canceled
	dlg = iup.dialog{iup.vbox{accounts[myaccount].tabs,
							iup.hbox{lbl_Status_bar,	-- Bottom Status bar.
									iup.fill{},
									},
							margin="5x5",
							},
					title=L.title .. myaccount,
					size=accounts[myaccount].panelsize
					}

	-- Shows dialog in the center of the screen
	dlg:showxy(iup.CENTER, iup.CENTER)

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