MerchantTradeConfirmationDialog = {}
MerchantTradeConfirmationDialog.__index = MerchantTradeConfirmationDialog

function MerchantTradeConfirmationDialog.create(itemName, itemPrice, merchantEntity, uniqueIndex, shutdownCallback)
	local ret = { connectors = {} }
	setmetatable(ret, MerchantTradeConfirmationDialog)

	ret.shutdownCallback = shutdownCallback
	ret.itemPrice = tonumber(itemPrice)
	ret.merchantEntity = merchantEntity

	ret.widget = guiManager:createWidget()
	ret.widget:loadMainSheet("IngameMerchantTradeConfirmationDialog.layout", "IngameMerchantWidget/TradeConfirmationDialog/" .. uniqueIndex .. "/")
	ret.uniqueIndex = uniqueIndex

	ret.window = ret.widget:getMainWindow()
	ret.label = ret.window:getChild("Label")
	ret.label:setText("Are you sure you want to buy '" .. itemName .. "' from '" .. merchantEntity:getName() .. "' for " .. itemPrice .. " coins?")

	ret.confirmButton = ret.window:getChild("ConfirmButton")
	ret.confirmButton:subscribeEvent("Clicked", MerchantTradeConfirmationDialog.handleConfirmClicked, ret)
	ret.cancelButton = ret.window:getChild("CancelButton")
	ret.cancelButton:subscribeEvent("Clicked", MerchantTradeConfirmationDialog.handleCancelClicked, ret)

	ret.window:subscribeEvent("CloseClicked", MerchantTradeConfirmationDialog.handleCloseClicked, ret)

	ret.widget:show()

	return ret
end

function MerchantTradeConfirmationDialog:closeDialog()
	guiManager:destroyWidget(self.widget)
	self.widget = nil
	self.shutdownCallback()
end

--This method retrieves amount of coins current player has
function MerchantTradeConfirmationDialog:getAmountOfCoins()
	local avatarEntity = emberOgre:getWorld():getAvatar():getEmberEntity()
	local money = 0

	local numContained = avatarEntity:numContained()
	if numContained ~= 0 then
		for i = 0, numContained - 1 do
			local containedEntity = avatarEntity:getContained(i)

			if containedEntity:getType():getName() == "coin" then
				money = money + 1
			end
		end
	end

	return money
end

--Returns true if current player can afford the item this confirmation dialog was spawned for
function MerchantTradeConfirmationDialog:checkCoins()
	return self:getAmountOfCoins() >= self.itemPrice
end

--Gives the needed amount of coins to the merchant, merchant should give the player the desired item
--(The one this confirmation dialog was spawned for)
function MerchantTradeConfirmationDialog:giveCoins()
	if not self:checkCoins() then
		return false
	end

	local avatarEntity = emberOgre:getWorld():getAvatar():getEmberEntity()
	local given = 0

	local numContained = avatarEntity:numContained()
	if numContained ~= 0 then
		for i = 0, numContained - 1 do
			local containedEntity = avatarEntity:getContained(i)

			if containedEntity:getType():getName() == "coin" then
				emberOgre:doWithEntity(self.merchantEntity:getId(), function(targetMerchantEntity)
					--TODO implement using an Offer op or similar. It's not ok to have the protocol just be to add stuff in other entities.
					--emberServices:getServerService():place(containedEntity, targetMerchantEntity)
				end)

				given = given + 1
			end

			if given >= self.itemPrice then
				break
			end
		end
	end

	if given >= self.itemPrice then
		return true
	else
		return false
	end
end

function MerchantTradeConfirmationDialog:handleConfirmClicked(args)
	-- if false is returned from giveCoins it can only mean that user doesn't have enough coins
	if self:giveCoins() then
		self:closeDialog()
	else
		self.label:setText("You don't have enough coins to proceed.")
	end

	return true
end

function MerchantTradeConfirmationDialog:handleCancelClicked(args)
	self:closeDialog()
	return true
end

function MerchantTradeConfirmationDialog:handleCloseClicked(args)
	return self:handleCancelClicked(args)
end

MerchantWindow = {}
MerchantWindow.__index = MerchantWindow

function MerchantWindow.create(entity, uniqueIndex, shutdownCallback, ingameMerchantWidget)
	local ret = { connectors = {}, merchantTradeConfirmationDialogs = {} }
	setmetatable(ret, MerchantWindow)

	ret.ingameMerchantWidget = ingameMerchantWidget
	ret.shutdownCallback = shutdownCallback
	ret.widget = guiManager:createWidget()
	ret.uniqueIndex = uniqueIndex
	ret.widget:loadMainSheet("IngameMerchantWidget.layout", "IngameMerchantWidget/MerchantWindow/" .. uniqueIndex .. "/")

	ret.widget:hide()

	ret.window = ret.widget:getMainWindow()
	ret.label = ret.window:getChild("Label")
	ret.goods = CEGUI.toMultiColumnList(ret.window:getChild("AvailableGoods"))
	ret.goods:subscribeEvent("MouseDoubleClick", MerchantWindow.handleGoodsDoubleClicked, ret)

	ret:setTargetEntity(entity)

	ret.window:subscribeEvent("CloseClicked", MerchantWindow.handleCloseClicked, ret)

	local message = Ember.OgreView.Gui.HelpMessage.new("Merchant Window", "You have opened a merchant window, browse the wares and double click to buy items of your choice.", "merchant window", "merchantWindow")
	Ember.OgreView.Gui.QuickHelp.getSingleton():updateText(message)

	return ret
end

function MerchantWindow:shutdown()
	for key, value in pairs(self.merchantTradeConfirmationDialogs) do
		if value then
			value:closeDialog()
		end
	end
	self.merchantTradeConfirmationDialogs = {}

	disconnectAll(self.connectors)
	guiManager:destroyWidget(self.widget)

	self.shutdownCallback()
end

function MerchantWindow:setTargetEntity(entity)
	disconnectAll(self.connectors)

	if (entity) then
		self.window:setText("Trading dialog with '" .. entity:getName() .. "'.")
		self.widget:show()
		connect(self.connectors, entity.Say, MerchantWindow.handleEntitySay, self)
		--console:runCommand("/say " .. entity:getName() .. ": list me price")
		console:runCommand(string.format("/sayto %s list me price", entity:getId()))
		self.merchantEntity = entity
	else
		self.widget:hide()
	end
end

function MerchantWindow:addItemForSale(itemName, price, quantityAvailable)
	if quantityAvailable < 0 then
		quantityAvailable = "inf"
	end

	local existing = false
	local rowCount = self.goods:getRowCount()
	--we assume we will have to create a new row, in other case we set this to the row
	--index of the preexisting row with our item
	local rowNumber = rowCount

	for i = 0, rowCount - 1 do
		if self.goods:getItemAtGridReference(CEGUI.MCLGridRef.new(i, 0)):getText() == itemName then
			existing = true
			rowNumber = i

			break
		end
	end

	if not existing then
		self.goods:addRow()

		local item

		item = Ember.OgreView.Gui.ColouredListItem.new(itemName)
		self.goods:setItem(item, 0, rowNumber);

		item = Ember.OgreView.Gui.ColouredListItem.new(price)
		self.goods:setItem(item, 1, rowNumber)

		item = Ember.OgreView.Gui.ColouredListItem.new(quantityAvailable)
		self.goods:setItem(item, 2, rowNumber)
	else
		self.goods:getItemAtGridReference(CEGUI.MCLGridRef.new(rowNumber, 1)):setText(price)
		self.goods:getItemAtGridReference(CEGUI.MCLGridRef.new(rowNumber, 2)):setText(quantityAvailable)
	end
end

function MerchantWindow:handleEntitySay(root)
	--we are only listening to our target entity so whatever gets here is indeed the target entity speaking
	local rootObject = root:get()

	if not rootObject:hasAttr("say") then
		return
	end

	--message now contains what our target entity said
	local message = rootObject:getAttr("say"):asString()

	if string.find(message, "The price of [%a]+ is [%d]+") then
		local item = ""
		local price = 0
		local quantityAvailable = -1

		_, _, item, price = string.find(message, "The price of ([%a]+) is ([%d]+)")

		self:addItemForSale(item, price, quantityAvailable)
	end
end

function MerchantWindow:handleGoodsDoubleClicked(args)
	local selection = self.goods:getFirstSelectedItem()

	if selection then
		local selectedRowIndex = self.goods:getItemRowIndex(selection)
		local itemName = ""
		local itemPrice = 0

		if selectedRowIndex ~= -1 then
			local selectedItemName = self.goods:getItemAtGridReference(CEGUI.MCLGridRef.new(selectedRowIndex, 0))
			if selectedItemName then
				itemName = selectedItemName:getText()
			end

			local selectedItemPrice = self.goods:getItemAtGridReference(CEGUI.MCLGridRef.new(selectedRowIndex, 1))
			if selectedItemPrice then
				itemPrice = selectedItemPrice:getText()
			end
		end

		if itemName ~= "" and itemPrice ~= 0 then
			console:runCommand("/say I would like to buy " .. itemName)

			local windowIndex = self.ingameMerchantWidget.confirmationDialogIndex
			local shutdownCallback = function()
				-- setting the table entry to nil effectively removes it from the table
				self.merchantTradeConfirmationDialogs[windowIndex] = nil
			end

			-- the confirmation dialog itself will give the coins and finish the transaction
			self.merchantTradeConfirmationDialogs[windowIndex] = MerchantTradeConfirmationDialog.create(itemName, itemPrice, self.merchantEntity, windowIndex, shutdownCallback)

			self.ingameMerchantWidget.confirmationDialogIndex = self.ingameMerchantWidget.confirmationDialogIndex + 1
		end
	end
end

function MerchantWindow:handleCloseClicked(args)
	self:shutdown()
end

IngameMerchantWidget = {}
IngameMerchantWidget.__index = IngameMerchantWidget

function IngameMerchantWidget.create()
	local ret = { connectors = {} }
	-- this is a table of references to "alive" merchant windows
	-- we keep this around to prevent Lua from garbage collecting the windows when they are active
	ret.merchantWindows = {}
	setmetatable(ret, IngameMerchantWidget)

	ret:buildWidget()

	ret.tradeWindowIndex = 0
	ret.confirmationDialogIndex = 0

	return ret
end

function IngameMerchantWidget:buildWidget()
	connect(self.connectors, guiManager.EventEntityAction, function(action, entity)
		if (action == "merchant") then
			local windowIndex = self.tradeWindowIndex
			local shutdownCallback = function()
				-- setting the table entry to nil effectively removes it from the table
				self.merchantWindows[windowIndex] = nil
			end
			self.merchantWindows[windowIndex] = MerchantWindow.create(entity, windowIndex, shutdownCallback, self)

			self.tradeWindowIndex = self.tradeWindowIndex + 1
		end
	end)
end

function IngameMerchantWidget:shutdown()
	for key, value in pairs(self.merchantWindows) do
		value:shutdown()
	end
	self.merchantWindows = {}
	disconnectAll(self.connectors)
end

IngameMerchantWidget.startConnector = emberOgre.EventCreatedAvatarEntity:connect(function()
	local ingameMerchantWidget = IngameMerchantWidget.create()

	connect(ingameMerchantWidget.connectors, emberOgre.EventWorldDestroyed, function()
		ingameMerchantWidget:shutdown()
		ingameMerchantWidget = nil
		collectgarbage()
	end
	)
end
)

