-- see copyright notice in wxLdb.lua

local print = print
local wx = require( "wx" )
_G.print = print -- override wx print function with original one

local setmetatable = setmetatable
local table = table
local debug = debug
local xpcall = xpcall
local pairs = pairs
local ipairs = ipairs
local assert = assert
local tostring = tostring

local ui =
{
	id = require( "ui.id" ),
}

module( "ui.threads" )

local meta = { __index = {} }

local ID_CLIENT_BREAK_ON_CONNECT = ui.id.new()

function new( ... )
	local res = {}
	setmetatable( res, meta )
	res:init( ... )
	return res
end

function meta.__index:init( parentWidget, frame )
	self.events = { onThreadClicked = {}, onBreakOnConnectionChanged = {} }
	self.popups = {}
	setmetatable( self.popups, { __mode = "v" } )
	self.frame = frame
	self.tree = wx.wxTreeCtrl( parentWidget, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxTR_HIDE_ROOT + wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS )
	
	local imageList = wx.wxImageList(16, 16)
	imageList:Add(wx.wxArtProvider.GetBitmap(wx.wxART_GO_FORWARD, wx.wxART_TOOLBAR, wx.wxSize(16, 16)))
	imageList:Add(wx.wxArtProvider.GetBitmap(wx.wxART_EXECUTABLE_FILE, wx.wxART_TOOLBAR, wx.wxSize(16, 16)))
	self.tree:AssignImageList( imageList )
	
	self.root = self.tree:AddRoot( "clients" )
	
	self.tree:Connect( wx.wxEVT_COMMAND_TREE_SEL_CHANGED, function( event )
		if self.disableInputs then return end
		local item = event:GetItem()
		local data = assert( self.nodeData[item:GetValue()] )
		--print( "thread selected: "..data.clientId..", "..data.threadId )
		self:runEvents_( "onThreadClicked", data.clientId, data.threadId )
	end )
	
	self.tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, function( event )
		local item = event:GetItem()
		local data = assert( self.nodeData[item:GetValue()] )
		if data.threadId == "current" then -- right click on a client
			menu = wx.wxMenu()
			self.popups[menu] = data
			menu:Append( ID_CLIENT_BREAK_ON_CONNECT, "Break on connection", "Specify if the client should break execution each time it connects to the server", wx.wxITEM_CHECK )
			menu:Check( ID_CLIENT_BREAK_ON_CONNECT, data.breakOnConnection )
			self.tree:PopupMenu( menu )
		end
	end )
	
	self.frame:Connect( ID_CLIENT_BREAK_ON_CONNECT, wx.wxEVT_COMMAND_MENU_SELECTED, function( event )
		local data = assert( self.popups[event:GetEventObject():DynamicCast( "wxMenu" )] )
		data.breakOnConnection = event:IsChecked()
		self:runEvents_( "onBreakOnConnectionChanged", data.clientId, data.breakOnConnection )
	end )
end

function meta.__index:getRoot()
	return self.tree
end

function meta.__index:registerEvent( eventName, callback )
	assert( self.events[eventName] ~= nil, "Unknown event name "..eventName )
	table.insert( self.events[eventName], callback )
end

function meta.__index:runEvents_( eventName, ... )
	for _, callback in pairs( self.events[eventName] ) do
		callback( ... )
	end
end

function meta.__index:setData( data )
	self.disableInputs = true
	if self.data ~= nil then
		self.tree:DeleteChildren( self.root )
		self.data = nil
	end
		
	if data ~= nil then
		self.data = {}
		self.nodeData = {}
		for _, client in pairs( data ) do
			local cdata = {}
			cdata.node = self.tree:AppendItem( self.root, client.name.." ["..client.ip.."]", 1 )
			if client.active then
				self.tree:SetItemBold( cdata.node, true )
				self.tree:SelectItem( cdata.node, true )
			end
			--print( "client:", cdata.node, cdata.node:GetValue() )
			self.nodeData[cdata.node:GetValue()] = { clientId = client.clientId, threadId = "current", breakOnConnection = client.breakOnConnection }
			cdata.coroutines = {}
			for _, co in ipairs( client.coroutines ) do
				local codata = {}
				local label = ""
				--if co.current then
				--	label = "-> "
				--end
				label = label..co.id
				local imageIdx = -1
				if co.current then
					imageIdx = 0
				end
				codata.node = self.tree:AppendItem( cdata.node, label, imageIdx )
				self.nodeData[codata.node:GetValue()] = { clientId = client.clientId, threadId = co.id }
				--print( "\tthread:", codata.node, codata.node:GetValue() )
				if co.active then
					self.tree:SetItemBold( codata.node, true )
					self.tree:SelectItem( codata.node, true )
				end
				table.insert( cdata.coroutines, codata )
			end
			self.tree:Expand( cdata.node )
			table.insert( self.data, cdata )
		end
	end
	self.disableInputs = false
end
