--[[#tag push NAME]]

local unused = "unused\024\0\0\0\0\0"

local app, rootPath = ...
local l_rootPath = rootPath or ""
if #l_rootPath > 0 and l_rootPath[#l_rootPath]~="\\" and l_rootPath[#l_rootPath]~="/" then
	l_rootPath = l_rootPath.."/"
end

local luad = dofile(l_rootPath.."patcher/skin/luad.lua")
luad.setRootPath(l_rootPath.."patcher/skin")
local malut = luad.require( "malut", "malut.lua" )
local UI = luad.require( "UI", "ui.lua" )
local LuaSkinApi = LuaSkinApi

local pairs = pairs
local type = type
local print = print
local io = io
local string = string
local table = table
local os = os
local function TEXT (text)
	return text
end

--
--test begin
if false then
	malut.printTable(LuaSkinApi)
end
--test end
--

module "LuaSkin"
local here = _M

local l_windowList = luad "layout.lua"
local strTable = luad "strTable.lua"

local function getString_ (str)
	return strTable[str] or str
end
getString = getString_

function makeFullPath (path)
	return l_rootPath .. path
end
local function FILEPATH (path)
	return makeFullPath(path)
end

function getWindow (winName)
	return l_windowList[winName]
end

function setWindowTitle (winName, title)
	local window = l_windowList[winName]
	if window then
		window.m_cwindow:setTitle(getString_(title))
	end
end

function setWindowScale (winName, scaleX, scaleY)
	local rootGroup = getItem(winName, "root")
	if rootGroup then
		rootGroup:setTransform(0, 0, scaleX, scaleY)
	end
end

function getWindowSafeRect (winName)
	local window = l_windowList[winName]
	if window then
		return window:getSafeRect()
	end
end

function getItem (winName, itemName)
	local window = l_windowList[winName]
	if window then
		return window:findItemByName(itemName)
	end
	return nil
end

local function getItemAndWindow_ (winName, itemName)
	local window = l_windowList[winName]
	if window then
		return window:findItemByName(itemName), window
	end
	return nil, nil
end

local function itemFunc (funcName, winName, itemName, bRedraw, ...)
	local item, window = getItemAndWindow_(winName, itemName)
	if item then
		local func = item[funcName]
		if func then
			func(item, ...)
			if bRedraw then
				window:redraw()
			end
		end
	end
end

function setItemText (winName, itemName, text, bRedraw)
	itemFunc("setText", winName, itemName, bRedraw, getString_(text))
end

function setItemEnable (winName, itemName, bEnable)
	itemFunc("enable", winName, itemName, true, bEnable)
end

function setProgress (winName, itemName, progress, bRedraw)
	itemFunc("setProgress", winName, itemName, bRedraw, progress)
end

local l_bUpdateResult
function setAutoUpdateResult (bSuccess)
	l_bUpdateResult = bSuccess
end

function getAutoUpdateResult ()
	return l_bUpdateResult
end

local l_asyncStopThreadCallbacks = {}

function onAsyncStopThreadCallback (id)
	local callback = l_asyncStopThreadCallbacks[id]
	if callback then
		callback()
	end
end

function asyncStopThread (callback)	--StopThread 分为两部分，前一部分会向线程发送停止信号，线程停止后，调用后一部分
	local callbackId = #l_asyncStopThreadCallbacks+1
	if LuaSkinApi.updateFunc("AsyncStopThread", callbackId.."") then
		l_asyncStopThreadCallbacks[callbackId] = function ()
			LuaSkinApi.updateFunc("AsyncStopThreadFinish", "")
			callback()
		end
	end
end

function asyncPlay (callback)
	local callbackId = #l_asyncStopThreadCallbacks+1	--Play 分为两部分，前一部分会向线程发送停止信号，线程停止后，调用后一部分
	if LuaSkinApi.updateFunc("AsyncPlay", callbackId.."") then
		l_asyncStopThreadCallbacks[callbackId] = function ()
			LuaSkinApi.updateFunc("AsyncPlayFinish", "")
			callback()
		end
	end
end

function asyncFullCheck (callback)
	local callbackId = #l_asyncStopThreadCallbacks+1	--FullCheck 分为两部分，前一部分会向线程发送停止信号，线程停止后，调用后一部分
	if LuaSkinApi.updateFunc("AsyncFullCheck", callbackId.."") then
		l_asyncStopThreadCallbacks[callbackId] = function ()
			LuaSkinApi.updateFunc("AsyncFullCheckFinish", "")
			callback()
		end
	end
end

function asyncLocalUpdate (callback)
	local callbackId = #l_asyncStopThreadCallbacks+1	--LocalUpdate 分为两部分，前一部分会向线程发送停止信号，线程停止后，调用后一部分
	if LuaSkinApi.updateFunc("AsyncLocalUpdate", callbackId.."") then
		l_asyncStopThreadCallbacks[callbackId] = function ()
			LuaSkinApi.updateFunc("AsyncLocalUpdateFinish", "")
			callback()
		end
	end
end

function confirmStopUpdateForFullCheckOrLocalUpdate (callback)
	if not LuaSkinApi.checkClient() then	--不能更新，忽略
		return
	end
		
	if not app:IsSilentMode() and LuaSkinApi.needStopUpdateBeforeFullCheckOrLocalUpdate() then	--此时才需要确认
		showWindow("choose", true)
		local window = l_windowList["choose"]
		if window then
			window.m_cwindow:setTopMost(true)
			window:findItemByName("content"):setText(TEXT"更新正在进行中，是否中断更新？")
			window:findItemByName("ok"):setText(TEXT"是")
			window:findItemByName("cancel"):setText(TEXT"否")
			
			window:setCallback(callback)	--callback 将只生效一次
		end
	else	--无需确认
		callback()
	end
end

local function loadStringFromFile (file)
	local fin = io.open(file)
	if fin == nil then
		return nil
	end
	
	local content = fin:read("*all")
	fin:close()
	if #content >= 3 and content:sub(1, 3) == string.char(0xef, 0xbb, 0xbf) then	--utf8 bom
		content = content:sub(4)
	end
	
	return content
end

function loadOption (optionFile)
	local content = loadStringFromFile(optionFile)
	if content then
		return malut.fromCode(content)
	end
end

function saveOption (option, optionFile)
	return malut.toCodeToFile(option, optionFile)
end

function getServerById (id)
	local serverlist = loadOption(FILEPATH"patcher/config/serverlist.cfg") or {}
	for i=1, #serverlist do
		local server = serverlist[i]
		if server.id == id then
			return server
		end
	end
	return nil		-- not found
end

function getServerByName (name)
	local serverlist = loadOption(FILEPATH"patcher/config/serverlist.cfg") or {}
	for i=1, #serverlist do
		local server = serverlist[i]
		if server.name == name then
			return server
		end
	end
	return nil		-- not found
end

-- 如果配置无效，生成默认配置
function checkUpdateConfig ()
	local updateConfig = loadOption(FILEPATH"patcher/config/update.cfg") or {}
	local serverId = updateConfig.serverid
	
	local serverlist = loadOption(FILEPATH"patcher/config/serverlist.cfg") or {}
	local server = serverId and getServerById(serverId) or nil
	
	if not server then
		if #serverlist >= 1 then
			serverId = serverlist[1].id
			updateConfig.serverid = serverId
			server = serverlist[1]
		end
		
		saveOption(updateConfig, FILEPATH"patcher/config/update.cfg")
	end
	
	-- generate serverlist for arc
	local plainServerListPath = FILEPATH"patcher/config/serverlist.txt"
	do
		local fout = io.open(plainServerListPath, "wb")
		if fout then
			--need utf16LE with BOM
			local strBuffer = {}
			for iServer=1, #serverlist do
				local server = serverlist[iServer]
				strBuffer[#strBuffer+1] = ('"%s"\t"%s"\n'):format(server.name, server.address)
			end
			
			fout:write("\255\254")
			fout:write(LuaSkinApi.utf8ToUtf16ForLua(table.concat(strBuffer)))
			fout:close()
		end
	end
	
	-- generate fix.bat
	if server and serverlist.importantlist then
		local fixFile = FILEPATH"patcher/fix.bat"
		local fout = io.open(fixFile, "w")
		if fout then
			local function appendSep (str)
				if str:sub(-1) == "/" then
					return str
				else
					return str.."/"
				end
			end
			
			local content = ('@cd ..\n@start patcher\\filesync.exe -repair "%s" "%s" -packext "%s"'):format(
				appendSep(server.address).."patches/",
				appendSep(serverlist.importantlist).."version.txt",
				app:GetPackFileExt()
			)
			fout:write(content)
			fout:close()
		end
	end
end

function showWindow (winName, bShow)
	local win = l_windowList[winName]
	if not win then return end
	
	if type(win.m_cwindow)=="userdata" then
		win.m_cwindow:show(bShow)
	else
		if bShow then
			app:CreateSkinWindow(winName, win.m_width, win.m_height, win.m_title, winName=="main")
		end
	end
end
local showWindow = showWindow

function hideAllWindow ()
	for name, win in pairs(l_windowList) do
		showWindow( win.m_name, false )
	end
end

function minimizeAllWindow ()
	for name, win in pairs(l_windowList) do
		if type(win.m_cwindow)=="userdata" then
			win.m_cwindow:minimize()
		end
	end
end

function startClient ()
	hideAllWindow()
	asyncPlay(function ()
		-- LuaSkinApi.playSound("patcher/skin/sounds/startgame.wav", true)	-- 与客户端CG冲突
		quit()
	end)
end

-- for any thread, including worker thread
function quit ()
	getWindow("main").m_cwindow:postCloseMessage()
end

-- for ui thread
function closeAllWindow ()
	hideAllWindow()
	
	app:setQuit()
	
	asyncStopThread(function ()
		local winList = l_windowList
		l_windowList = {}
		for name, win in pairs(winList) do
			if win.m_cwindow ~= unused then
				win.m_cwindow:close()
			end
		end
	end)
end

do	--main
	checkUpdateConfig()
	
	-- show main window
	showWindow( "main", true )

	--
	-- test begin
	--~ minimizeAllWindow()
	-- test end
	--
	
	LuaSkinApi.updateFunc("Startup", "")	-- default startup
end
