dofile ( "Scripts/table.lua" )
dofile ( "Scripts/guielement.lua" )

--
-- Input field
--

InputField = {}
InputFieldMT = { __index = InputField }

-- inherit GUIElement
setmetatable ( InputField, { __index = GUIElement } )

function InputField:Create ( x, y, z, width, height, font )

	local inputfield = {}
	setmetatable ( inputfield, InputFieldMT )

	inputfield.x = x
	inputfield.y = y
	inputfield.z = z
	inputfield.width = width
	inputfield.height = height

	inputfield.sprite = Sprite ( x, y )
	inputfield.sprite.depth = z
	display:add_child ( inputfield.sprite )
	inputfield.sprite.canvas:set_font ( font )

	inputfield.key = nil
	inputfield.key_time = 0
	inputfield.key_time_limit = 500
	inputfield.cursor_time = 0
	inputfield.cursor_visible = false
	inputfield.font = font
	inputfield.text = ''
	inputfield.out = ''
	inputfield.selection_1 = 0
	inputfield.selection_2 = 0
	inputfield.offset = 0
	inputfield.timer = Timer ( )
	inputfield.timer.parent = inputfield
	inputfield.timer.on_tick = function ( timer )
		local self = timer.parent
		self.cursor_time = self.cursor_time + timer:get_delta_ms ( )
		if self.cursor_time > 500 then
			self.cursor_time = 0
			self.cursor_visible = not self.cursor_visible
		end

		if self.key then
			self.key_time = self.key_time + timer:get_delta_ms ( )
			if self.key_time > self.key_time_limit then
				self.key_time = 0
				self.key_time_limit = 0
				self:KeyPress ( self.key )
			end
		end

		if self.dragging == true then
			local x = mouse.xaxis
			if x > self.x + self.width then
				if self.offset < string.len ( self.text ) - string.len ( self.out ) then
					self.offset = self.offset + 1
				end
			elseif x < self.x and self.offset > 0 then
				self.offset = self.offset - 1
			end
			self.selection_2 = self:GetSelectionPos ( x )
		end

		self:Paint ( )
	end

	inputfield.dragging = false

	inputfield:Paint ( )

	return inputfield

end

function InputField:Destroy ( )

	display:remove_child ( self.sprite )

end

function InputField:OnChange ( text )

end

function Button:SetPosition ( x, y )
	self.sprite:set_position ( x, y )
	self.x = x
	self.y = y
end

function InputField:Paint ( )

	-- regenerate output text
	if string.len ( self.text ) == 0 then
		self.out = ''
	else
		for i = self.offset + 1, string.len ( self.text ) do
			local sub = string.sub ( self.text, self.offset + 1, i )
			local w = self.font:get_width ( sub )
			if w < self.width then
				self.out = sub
			else
				break
			end
		end
	end

	self.sprite.canvas:clear ( )

	self.sprite.canvas:move_to ( 0, 0 )
	self.sprite.canvas:line_to ( self.width, 0 )
	self.sprite.canvas:line_to ( self.width, self.height )
	self.sprite.canvas:line_to ( 0, self.height )
	self.sprite.canvas:close_path ( )
	self.sprite.canvas:set_line_style ( 1, WHITE, 1 )
	self.sprite.canvas:stroke ( )

	local h = self.font:get_height ( )
	local x = 2
	local y = self.height / 2 - h / 2

	self.sprite.canvas:move_to ( x, self.height / 2 - self.font:get_size ( ) / 2 )
	self.sprite.canvas:write ( self.out )

	local o = string.sub ( self.text, 0, self.offset )
	o = self.font:get_width ( o )

	local sub1 = string.sub ( self.text, 0, self.selection_1 )
	local c1 = self.font:get_width ( sub1 ) - o
	if c1 < 0 then
		c1 = 0
	end
	if c1 > self.width - 2 then
		c1 = self.width - 2
	end
	local sub2 = string.sub ( self.text, 0, self.selection_2 )
	local c2 = self.font:get_width ( sub2 ) - o
	if c2 < 0 then
		c2 = 0
	end
	if c2 > self.width - 2 then
		c2 = self.width - 2
	end

	self.sprite.canvas:move_to ( x + c1, y )
	self.sprite.canvas:line_to ( x + c1, y + h )
	self.sprite.canvas:line_to ( x + c2, y + h )
	self.sprite.canvas:line_to ( x + c2, y )
	self.sprite.canvas:set_fill_style ( RED, 0.5 )
	self.sprite.canvas:fill ( )

	if self.cursor_visible then
		self.sprite.canvas:move_to ( x + c2, y )
		self.sprite.canvas:line_to ( x + c2, y + h )
		self.sprite.canvas:set_line_style ( 2, RED, 1 )
		self.sprite.canvas:stroke ( )
	end

end

function InputField:GetSelectionPos ( x )

	if x < self.x then
		return self.offset
	end
	x = x - self.x
	local last = 0
	for i = 0, string.len ( self.out ) do
		local sub = string.sub ( self.out, 0, i )
		local c = self.font:get_width ( sub )
		if c > x then
			if x - last < c - x then
				i = i - 1
			end
			return i + self.offset
		end
		last = c
	end
	return string.len ( self.out ) + self.offset

end

function InputField:SetSelectionPos ( x )

	if x < 0 then
		self.selection_1 = 0
		self.selection_2 = 0
	elseif x >= string.len ( self.text ) then
		self.selection_1 = string.len ( self.text )
		self.selection_2 = string.len ( self.text )
	else
		self.selection_1 = x
		self.selection_2 = x
	end

	-- shift offset to the left/right
	-- so that the cursor doesn't run off the screen
	while true do
		local sub = string.sub ( self.text, self.offset, self.selection_1 )
		local w = self.font:get_width ( sub )
		if w < self.width then
			break
		end
		self.offset = self.offset + 1
	end

	if self.selection_1 - 1 < self.offset then
		self.offset = self.selection_1 - 1
		if self.offset < 0 then
			self.offset = 0
		end
	end

end

function InputField:ClearSelection ( )
	if self.selection_1 ~= self.selection_2 then
		local s, e
		if self.selection_1 < self.selection_2 then
			s = self.selection_1
			e = self.selection_2
		else
			s = self.selection_2
			e = self.selection_1
		end
		self.text = string.sub ( self.text, 0, s ) .. string.sub ( self.text, e + 1 )

		self.selection_1 = s
		self.selection_2 = s
	end
end

function InputField:MouseRelease ( button, x, y )

end

function InputField:MousePress ( button, x, y )

	self.selection_1 = self:GetSelectionPos ( x )
	self.selection_2 = self.selection_1
	self:Paint ( )

end

function InputField:Dragging ( button, x, y )

	self.selection_2 = self:GetSelectionPos ( x )

	self:Paint ( )

end

function InputField:BeginDrag ( button, x, y )
	self.dragging = true
end

function InputField:EndDrag ( button, x, y )
	self.dragging = false
end

function InputField:SingleClick ( button, x, y )

end

function InputField:DoubleClick ( button, x, y )
	
	self.selection_1 = 0
	self.selection_2 = string.len ( self.text )
	self:Paint ( )

end

function InputField:WheelMove ( z )

end

function InputField:KeyRelease ( key )
	self.key = nil
end

function InputField:SelectAll ( )
	self.selection_1 = 0
	self.selection_2 = string.len ( self.text )
end

function InputField:KeyPress ( key )

	if self.dragging == true then
		return
	end

	if self.key == nil then
		self.key = key
		self.key_time = 0
		self.key_time_limit = 500
	end

	if keyboard:is_down ( KEY_LCTRL ) or keyboard:is_down ( KEY_RCTRL ) then
		if key == KEY_A then
			self:SelectAll ( )
		end
	elseif ( key == KEY_LEFT or key == KEY_UP ) then
		if self.selection_2 < self.selection_1 then
			local s = self.selection_1
			self.selection_1 = self.selection_2
			self.selection_2 = s
		end

		self.selection_1 = self.selection_1 - 1
		self.selection_2 = self.selection_1

		self:SetSelectionPos ( self.selection_1 )

	elseif ( key == KEY_RIGHT or key == KEY_DOWN ) then
		if self.selection_2 < self.selection_1 then
			local s = self.selection_1
			self.selection_1 = self.selection_2
			self.selection_2 = s
		end

		self.selection_2 = self.selection_2 + 1
		self.selection_1 = self.selection_2

		self:SetSelectionPos ( self.selection_1 )

	elseif key == KEY_DEL or key == KEY_NUMDEL then
		if self.selection_1 == self.selection_2 and self.selection_2 < string.len ( self.text ) then
			self.selection_2 = self.selection_2 + 1
		end
		self:ClearSelection ( )
		self:SetSelectionPos ( self.selection_2 )
		self:OnChange ( self.text )
	elseif key == KEY_BACK then
		if self.selection_1 == self.selection_2 and self.selection_1 > 0 then
			self.selection_1 = self.selection_1 - 1
		end
		self:ClearSelection ( )
		self:SetSelectionPos ( self.selection_1 )
		self:OnChange ( self.text )
	else
		local c
		if keyboard:is_down ( KEY_LSHIFT ) or keyboard:is_down ( KEY_RSHIFT ) then
			c = upper[key]
		else
			c = lower[key]
		end
		if c ~= nil and c ~= ''  then
			self:ClearSelection ( )

			local sz = string.sub ( self.text, 0, self.selection_1 )
			sz = sz .. c
			sz = sz .. string.sub ( self.text, self.selection_1 + 1 )
			self.text = sz
			self.selection_1 = self.selection_1 + 1
			self.selection_2 = self.selection_2 + 1
			self:SetSelectionPos ( self.selection_1 )
			self:OnChange ( self.text )
		end
	end

	self:Paint ( )
end

function InputField:GainFocus ( )
	self.cursor_visible = true
	self.timer:start ( 100, true )
	self:Paint ( )
end

function InputField:LoseFocus ( )
	self.cursor_visible = false
	self.timer:pause ( )
	self:Paint ( )
end

function InputField:SetValue ( text )
	self.text = text
	self.selection_1 = 0
	self.selection_2 = 0
	self:Paint ( )
end