-- ------------------------------------------------------------------------------ --
--                                TradeSkillMaster                                --
--                http://www.curse.com/addons/wow/tradeskill-master               --
--                                                                                --
--             A TradeSkillMaster Addon (http://tradeskillmaster.com)             --
--    All Rights Reserved* - Detailed license information included with addon.    --
-- ------------------------------------------------------------------------------ --

local _, TSM = ...
local private = { frameInputLookup = {} }
local Input = TSMAPI_FOUR.Class.DefineClass("Input", TSM.UI.Element)
TSM.UI.Input = Input
local IS_SCRIPT_HOOKED = { OnEscapePressed = true, OnEnterPressed = true, OnEditFocusGained = true, OnEditFocusLost = true }
local TEXT_PADDING = 5



-- ============================================================================
-- Public Class Methods
-- ============================================================================

function Input.__init(self)
	local frame = CreateFrame("EditBox", nil, nil, nil)

	self.__super:__init(frame)

	self._textStr = nil
	self._settingTable = nil
	self._settingKey = nil
	self._validation = nil
	self._userScriptHandlers = {}

	frame:SetShadowColor(0, 0, 0, 0)
	frame:SetTextInsets(TEXT_PADDING, TEXT_PADDING, TEXT_PADDING, TEXT_PADDING)
	frame:SetAutoFocus(false)
	frame:SetScript("OnEscapePressed", private.OnEscapePressed)
	frame:SetScript("OnEnterPressed", private.OnEnterPressed)
	frame:SetScript("OnEditFocusGained", private.OnEditFocusGained)
	frame:SetScript("OnEditFocusLost", private.OnEditFocusLost)

	frame.bgLeft = frame:CreateTexture(nil, "BACKGROUND")
	frame.bgLeft:SetPoint("TOPLEFT")
	frame.bgLeft:SetPoint("BOTTOMLEFT")

	frame.bgRight = frame:CreateTexture(nil, "BACKGROUND")
	frame.bgRight:SetPoint("TOPRIGHT")
	frame.bgRight:SetPoint("BOTTOMRIGHT")

	frame.bgMiddle = frame:CreateTexture(nil, "BACKGROUND")
	frame.bgMiddle:SetPoint("TOPLEFT", frame.bgLeft, "TOPRIGHT")
	frame.bgMiddle:SetPoint("BOTTOMRIGHT", frame.bgRight, "BOTTOMLEFT")

	private.frameInputLookup[frame] = self
end

function Input.Acquire(self)
	self._hintText = TSMAPI_FOUR.UI.NewElement("Text", self._id.."_HintText")
	self._hintText:_GetBaseFrame():SetParent(self:_GetBaseFrame())
	self._hintText:_GetBaseFrame():SetPoint("TOPLEFT", 8, 0)
	self._hintText:_GetBaseFrame():SetPoint("BOTTOMRIGHT", -8, 0)
	self._textStr = ""
	self.__super:Acquire()
end

function Input.Release(self)
	wipe(self._userScriptHandlers)
	self:_GetBaseFrame():ClearFocus()
	self:_GetBaseFrame():SetMultiLine(false)
	self:_GetBaseFrame():SetHitRectInsets(0, 0, 0, 0)
	self._hintText:Release()
	self._hintText = nil
	self._settingTable = nil
	self._settingKey = nil
	self._validation = nil
	self.__super:Release()
end

function Input.SetText(self, text)
	self._textStr = text
	return self
end

function Input.SetHintText(self, text)
	self._hintText:SetText(text)
	return self
end

function Input.SetFocused(self, focused)
	if focused then
		self:_GetBaseFrame():SetFocus()
	else
		self:_GetBaseFrame():ClearFocus()
	end
	return self
end

function Input.SetMultiLine(self, multiLine)
	local frame = self:_GetBaseFrame()
	frame:SetText("")
	frame:SetMultiLine(multiLine)
	frame:SetText(self._textStr)
	return self
end

function Input.SetHitRectInsets(self, left, right, top, bottom)
	self:_GetBaseFrame():SetHitRectInsets(left, right, top, bottom)
	return self
end

function Input.GetText(self)
	return self:_GetBaseFrame():GetText()
end

function Input.SetScript(self, script, handler)
	if IS_SCRIPT_HOOKED[script] then
		self._userScriptHandlers[script] = handler
		return self
	else
		return self.__super:SetScript(script, handler)
	end
end

function Input.GetStringHeight(self)
	-- use the hint text in order to get the string height since EditBox doesn't support it directly
	local prev = self._hintText:GetText() or ""
	self._hintText:SetText(self._textStr)
	local result = self._hintText:GetStringHeight() + TEXT_PADDING * 2
	self._hintText:SetText(prev)
	self._hintText:Draw()
	return result
end

function Input.SetSettingInfo(self, tbl, key, validation)
	self._settingTable = tbl
	self._settingKey = key
	self._validation = validation
	self:SetText(tbl[key])
	return self
end

function Input.Draw(self)
	self.__super:Draw()
	local frame = self:_GetBaseFrame()

	local texturePacks = self:_GetStyle("backgroundTexturePacks")
	if texturePacks then
		TSM.UI.TexturePacks.SetTextureAndWidth(frame.bgLeft, texturePacks.."Left")
		TSM.UI.TexturePacks.SetTexture(frame.bgMiddle, texturePacks.."Middle")
		TSM.UI.TexturePacks.SetTextureAndWidth(frame.bgRight, texturePacks.."Right")
		frame.bgLeft:Show()
		frame.bgMiddle:Show()
		frame.bgRight:Show()
		self:SetStyle("background", "#00000000")
		self:SetStyle("border", "#00000000")
	else
		frame.bgLeft:Hide()
		frame.bgMiddle:Hide()
		frame.bgRight:Hide()
	end
	self:_ApplyFrameStyle(frame)
	self:_ApplyTextStyle(frame)

	-- set the text
	frame:SetText(self._textStr)

	if self._textStr == "" and not frame:HasFocus() then
		self._hintText:Show()
	else
		self._hintText:Hide()
	end

	self._hintText:SetStyle("font", self:_GetStyle("font"))
	self._hintText:SetStyle("fontHeight", self:_GetStyle("fontHeight"))
	self._hintText:SetStyle("justifyH", self:_GetStyle("hintJustifyH"))
	self._hintText:SetStyle("justifyV", self:_GetStyle("hintJustifyV"))
	self._hintText:SetStyle("textColor", self:_GetStyle("hintTextColor"))
	self._hintText:Draw()
end

function Input.SetDisabled(self, disabled)
	if disabled then
		self:_GetBaseFrame():Disable()
	else
		self:_GetBaseFrame():Enable()
	end
	return self
end



-- ============================================================================
-- Local Script Handlers
-- ============================================================================

function private.OnEscapePressed(frame)
	frame:ClearFocus()
	frame:HighlightText(0, 0)

	local self = private.frameInputLookup[frame]

	if self._settingTable and self._settingKey then
		self:Draw()
	end

	if self._userScriptHandlers.OnEscapePressed then
		self._userScriptHandlers.OnEscapePressed(self)
	end
end

function private.OnEnterPressed(frame)
	local self = private.frameInputLookup[frame]
	local text = self:GetText()
	frame:ClearFocus()
	frame:HighlightText(0, 0)

	if self._settingTable and self._settingKey then
		local value = strtrim(text)
		if not self._validation or self._validation(value) then
			self._settingTable[self._settingKey] = value
			self:SetText(value)
		end
	else
		self:SetText(text)
	end
	self:Draw()

	if self._userScriptHandlers.OnEnterPressed then
		self._userScriptHandlers.OnEnterPressed(self)
	end
end

function private.OnEditFocusGained(frame)
	local self = private.frameInputLookup[frame]
	self:Draw()
	if self._userScriptHandlers.OnEditFocusGained then
		self._userScriptHandlers.OnEditFocusGained(self)
	end
end

function private.OnEditFocusLost(frame)
	local self = private.frameInputLookup[frame]
	self:Draw()
	if self._userScriptHandlers.OnEditFocusLost then
		self._userScriptHandlers.OnEditFocusLost(self)
	end
end
