Input = class("Input")

dofile("../defs/input_defaults.lua")

INPUT_ACTIONS = {"left", "right"}

function Input:new()
	local i = instance(self)
	i.codes = {
		keyboard = {},
		joystick = {},
		mouse = {},
	}
	i.actions = {}
	i.last = {}
	i.current = {}
	i.cursor = {}
	return i
end

function Input:save(path)
	local codes = self.codes
	self.codes = nil
	self.current = nil
	self.cursor = nil
	table.simpleSave(self, path)
	self.codes = codes
	self.last = {}
	self.current = {}
	self.cursor = {}
end

function Input:load(data)
	self.device = data.device
	self.deviceId = data.deviceId
	self.model = data.model
	for action, def in pairs(data.actions) do
		self:set_action(def.device, def.code, action)
	end
end

function Input:set_device(device, id)
	self.device = device
	self.deviceId = id
end

function Input:set_action(device, code, action)
	self.codes[device][code] = action
	self.actions[action] = {device = device, code = code}
end

function Input:has_action(action)
	return self.actions[action]
end

function Input:has_device(device, deviceId)
	if self.device == device and self.deviceId == deviceId then
		return true
	end
end

function Input:get_device_string()
	if self.deviceId then
		return self.device.." "..self.deviceId
	elseif self.device then
		return self.device
	else
		return ""
	end
end


function Input:set_cursor(x,y,cx,cy)
	local cursor = self.cursor
	cursor.x = x
	cursor.y = y
	cursor.camera_x = cx
	cursor.camera_y = cy
end

function Input:get_hint(action)
	local def = self.actions[action]
	if def then
		return Hints.getHint(def.device, def.code, self.deviceId, self.model)
	end
end

function Input:has(device, key, deviceId)
	if self.device == device and self.codes[device][key] and self.deviceId == deviceId then
		return self.codes[device][key]
	end
end

function Input:is_action(device, key, deviceId, action)
	if self.device == device and self.codes[device][key] and self.deviceId == deviceId then
		return self.codes[device][key] == action
	end
end

function Input:is_held(action)
	return self.current[action]
end

function Input:is_pressed(action)
	return self.current[action] and not self.last[action]
end

function Input:is_released(action)
	return self.last[action] and not self.current[action]
end

function Input:check(player)
	--print(2)
	local is = states.get("input")
	local device = self.device
	local deviceId = self.deviceId
	local current = self.current
	local last = self.last
	for device, actions in pairs(self.codes) do
		for code, action in pairs(actions) do

			local nextPressed = is:isPressed(device, deviceId, code)
			local currentPressed = current[action]
			last[action] = currentPressed
			--print("check", device, code, currentPressed)
			if nextPressed ~= currentPressed then
				current[action] = nextPressed
			end
		end
	end
end

function Input:render(x,y, highlightAction)
	local h = 0
	for index, action in ipairs(INPUT_ACTIONS) do
		local def = self.actions[action]
		if def then
			local a = 128
			if index == highlightAction then
				a = 255
			end
			video.renderTextSprites(action, x, y+h + fonts.alignY("small"), 2, "small", a, a*0.8, a*0.8, a*0.8)
			local hint = Hints.getHint(def.device, def.code, self.deviceId)
			video.renderTextSprites(hint or def.code, x+10, y+h + fonts.alignY("small"), 0, "small", 255, 255, 255, 255)
			h = h + 16
		end
	end
	return h
end

Player = class("Player")

function Player:new(id)
	local o = instance(self)
	o.id = id
	o.pressed = 0
	o:refresh_name()
	o.gui = {}
	return o
end

function Player:refresh_name()
	self.name = "Player "..self.id
end

function Player:has_input(device, key, deviceId)
	return self.input and self.input:has(device,key,deviceId)
end

function Player:set_input(input)
	self.input = input
end	

function Player:check_input()
	local input = self.input
	input:check(self)
end


function Player:set_cursor(x,y, cx,cy)
	local input = self.input
	input:set_cursor(x, y, cx,cy)
end

function Player:set_ent(ent)
	self.ent = ent
	self:refresh_gui(ent)
end

local function inventory_slot_layout(self, def, ent)
	local gui_layout = HudLayout:new(def.layout_type)

	local inventory = ent.inventory
	for index, slot_type in pairs(def.slot_types) do
		local slots = inventory:get_slots_of_type(slot_type)
		if slots then
			for _, slot in ipairs(slots) do
				local gui_slot = HudSlot:new(slot, 62, 4, ent)
				gui_layout:add_child(gui_slot)
			end
		end
	end
	return gui_layout
end

local GUIS = {
	paperdoll = {
		slot_types = {
			"head",
			"neck",
			"torso",
			"hands",
			"finger",
			"belt",
			"legs",
			"feet",
		},
		layout_type = "bottom_left_horisontal_down",
		generate = inventory_slot_layout,
	},
	hotbar = {
		slot_types = {
			"hotbar",
		},
		layout_type = "bottom_horisontal_side",
		generate = inventory_slot_layout,
	},
	stash = {
		slot_types = {
			"stash",
		},
		layout_type = "right_top_down",
		generate = inventory_slot_layout,
	},
	active = {
		slot_types = {
			"primary",
			"secondary",
		},
		layout_type = "bottom_horisontal_centered",
		generate = inventory_slot_layout,
	},
	gold = {
		slot_types = {
			"gold",			
		},
		layout_type = "bottom_horisontal_left",
		generate = inventory_slot_layout,
	},
	skills = {
		layout_type = "bottom_horisontal_centered",
		generate = function(self, def, ent)
		end,
	}
}

local function slot_slot_layout(self, def, ent)
	local shop = ent.shop
	local title = shop:get_display_name() or "Mystery Shop"
	local gui_layout = HudWindow:new(def.layout_type, title)
	local inventory = shop.inventory
	for index, slot_type in pairs(def.slot_types) do
		local slots = inventory:get_slots_of_type(slot_type)
		if slots then
			for _, slot in ipairs(slots) do
				local gui_slot = HudSlot:new(slot, 62, 4, ent)
				gui_layout:add_child(gui_slot)
			end
		end
	end
	return gui_layout
end

local SHOP_GUIS = {
	shop = {
		slot_types = {
			"for_sale",			
		},
		layout_type = "mid_centered",		
		generate = slot_slot_layout,
	},
}

function Player:set_game(game)
	self.game = game
end

function Player:generate_guis(defs, ent)
	local gui = self.gui
	for index, def in pairs(defs) do
		local elem = def.generate(self, def, ent)
		gui[index] = elem
	end
	self:sort_gui()
end

function Player:refresh_gui(ent)	
	self:generate_guis(GUIS, ent)
end

function Player:remove_gui(index)
	self.gui[index] = nil
end

function Player:set_shop_keeper_gui(keeper)
	local old = self.keeper
	if old then
		--bla
		self:remove_gui("shop")
	end

	self.keeper = keeper

	if keeper then
		self:generate_guis(SHOP_GUIS, keeper)
	end
end

function Player:sort_gui()
	local gui = self.gui
	local window_margin = 15
	local x,y = window_margin,window_margin
	local w,h = window.w-window_margin*2, window.h-window_margin*2
	for index, layout in pairs(gui) do
		layout:layout_inside(x,y,w,h)
		layout:set_game(self.game)
	end
end

function Player:update_gui(dt, x, y)
	local best_element = nil
	for index, layout in pairs(self.gui) do
		layout:update(dt)
		local found = layout:find_interactive(x,y)
		if found then
			best_element = found
		end
	end
	if best_element ~= self.hovered_element then
		self:set_hovered_element(best_element)
	end
end

function Player:get_hovered_element()
	return self.hovered_element
end

function Player:get_hovered_action()
	local hovered_element = self.hovered_element
	if hovered_element then
		return hovered_element:get_pressed_action()
	end
end
function Player:set_pressed_element(element)
	local old = self.pressed_element
	if old then
		old:set_pressed(false)		
	end
	self.pressed_element = element
	if element then
		element:set_pressed(true)		
	end
end

function Player:set_hovered_element(element)
	local old = self.hovered_element
	if old then
		old:set_hovered(false)
		self:set_hud_info(nil)
	end
	self.hovered_element = element
	if element then
		element:set_hovered(true)

		local hud_info
		local ent = self.ent
		if element.ent == ent then
			hud_info = element:get_hud_info()
		else
			local slot = element.slot
			if slot then
				local inventory = ent.inventory
				local slot_type = slot:get_item_slot_type()
				local cmp = slot_type and inventory:get_selected_item_of_type(slot_type)
				hud_info = element:get_hud_info(cmp)
			else
			 	hud_info = element:get_hud_info()
			end
		end
		if hud_info then			
			self:set_hud_info(hud_info)
		end
	end
end

function Player:set_hud_info(hud_info)
	self.hud_info = hud_info
end

function Player:render_gui(scale, angle, a,r,g,b)
	local ent = self.ent
	if ent.light then
		a,r,g,b = ent.light:fade_variables(a,r,g,b, 0.5)
	end	
	for index, layout in pairs(self.gui) do
		layout:render(layout.x, layout.y, scale, angle, a, r, g, b)
	end
end


local fade_co

function Player:render_hud(scale, angle, a,r,g,b)	
	local hud_info = self.hud_info
	if hud_info then
		local ent = self.ent
		if ent.light then
			a,r,g,b = ent.light:fade_variables(a,r,g,b, 0.5)
		end	
		local cursor = self.input.cursor
		local x,y = cursor.x, cursor.y
		local w,h = hud_info:get_dimensions()
		local ox,oy = window.get_best_ui_offset(x,y,w,h)
		hud_info:render(x + ox,y + oy, scale, 1, angle, a, r, g, b)		
	end
end