--[[-----------------------------------------------------------------------------
EditBox Widget
-------------------------------------------------------------------------------]]
local Type, Version = 'EditBox', 21
local AceGUI = LibStub and LibStub('AceGUI-3.0', true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then
  return
end

-- Lua APIs
local tostring, pairs = tostring, pairs

-- WoW APIs
local PlaySound = PlaySound
local GetCursorInfo, ClearCursor, GetSpellName = GetCursorInfo, ClearCursor, GetSpellName
local CreateFrame, UIParent = CreateFrame, UIParent
local _G = _G

-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: AceGUIEditBoxInsertLink, ChatFontNormal, OKAY

--[[-----------------------------------------------------------------------------
Support functions
-------------------------------------------------------------------------------]]
if not AceGUIEditBoxInsertLink then
  -- upgradeable hook
  hooksecurefunc('ChatEdit_InsertLink', function(...)
    return _G.AceGUIEditBoxInsertLink(...)
  end)
end

function _G.AceGUIEditBoxInsertLink(text)
  for i = 1, AceGUI:GetWidgetCount(Type) do
    local editbox = _G['AceGUI-3.0EditBox' .. i]
    if editbox and editbox:IsVisible() and editbox:HasFocus() then
      editbox:Insert(text)
      return true
    end
  end
end

local function ShowButton(self)
  if not self.disablebutton then
    self.button:Show()
    self.editbox:SetTextInsets(0, 20, 3, 3)
  end
end

local function HideButton(self)
  self.button:Hide()
  self.editbox:SetTextInsets(0, 0, 3, 3)
end

--[[-----------------------------------------------------------------------------
Scripts
-------------------------------------------------------------------------------]]
local function Control_OnEnter(frame)
  frame.obj:Fire('OnEnter')
end

local function Control_OnLeave(frame)
  frame.obj:Fire('OnLeave')
end

local function EditBox_OnEscapePressed(frame)
  AceGUI:ClearFocus()
end

local function EditBox_OnEnterPressed(frame)
  local self = frame.obj
  local value = frame:GetText()
  local cancel = self:Fire('OnEnterPressed', value)
  if not cancel then
    PlaySound('igMainMenuOptionCheckBoxOn')
    HideButton(self)
  end
end

local function EditBox_OnReceiveDrag(frame)
  local self = frame.obj
  local type, id, info = GetCursorInfo()
  if type == 'item' then
    self:SetText(info)
    self:Fire('OnEnterPressed', info)
    ClearCursor()
  elseif type == 'spell' then
    local name, rank = GetSpellName(id, info)
    if rank and rank:match('%d') then
      name = name .. '(' .. rank .. ')'
    end
    self:SetText(name)
    self:Fire('OnEnterPressed', name)
    ClearCursor()
  end
  HideButton(self)
  AceGUI:ClearFocus()
end

local function EditBox_OnTextChanged(frame)
  local self = frame.obj
  local value = frame:GetText()
  if tostring(value) ~= tostring(self.lasttext) then
    self:Fire('OnTextChanged', value)
    self.lasttext = value
    ShowButton(self)
  end
end

local function Button_OnClick(frame)
  local editbox = frame.obj.editbox
  editbox:ClearFocus()
  EditBox_OnEnterPressed(editbox)
end

--[[-----------------------------------------------------------------------------
Methods
-------------------------------------------------------------------------------]]
local methods = {
  ['OnAcquire'] = function(self)
    -- height is controlled by SetLabel
    self:SetWidth(200)
    self:SetDisabled(false)
    self:SetLabel()
    self:SetText()
    self:DisableButton(false)
    self:SetMaxLetters(0)
  end,

  -- ["OnRelease"] = nil,

  ['SetDisabled'] = function(self, disabled)
    self.disabled = disabled
    if disabled then
      self.editbox:EnableMouse(false)
      self.editbox:ClearFocus()
      self.editbox:SetTextColor(0.5, 0.5, 0.5)
      self.label:SetTextColor(0.5, 0.5, 0.5)
    else
      self.editbox:EnableMouse(true)
      self.editbox:SetTextColor(1, 1, 1)
      self.label:SetTextColor(1, 0.82, 0)
    end
  end,

  ['SetText'] = function(self, text)
    self.lasttext = text or ''
    self.editbox:SetText(text or '')
    self.editbox:SetCursorPosition(0)
    HideButton(self)
  end,

  ['SetLabel'] = function(self, text)
    if text and text ~= '' then
      self.label:SetText(text)
      self.label:Show()
      self.editbox:SetPoint('TOPLEFT', self.frame, 'TOPLEFT', 7, -18)
      self:SetHeight(44)
      self.alignoffset = 30
    else
      self.label:SetText('')
      self.label:Hide()
      self.editbox:SetPoint('TOPLEFT', self.frame, 'TOPLEFT', 7, 0)
      self:SetHeight(26)
      self.alignoffset = 12
    end
  end,

  ['DisableButton'] = function(self, disabled)
    self.disablebutton = disabled
  end,

  ['SetMaxLetters'] = function(self, num)
    self.editbox:SetMaxLetters(num or 0)
  end,
}

--[[-----------------------------------------------------------------------------
Constructor
-------------------------------------------------------------------------------]]
local function Constructor()
  local num = AceGUI:GetNextWidgetNum(Type)
  local frame = CreateFrame('Frame', nil, UIParent)
  frame:Hide()

  local editbox = CreateFrame('EditBox', 'AceGUI-3.0EditBox' .. num, frame, 'InputBoxTemplate')
  editbox:SetAutoFocus(false)
  editbox:SetFontObject(ChatFontNormal)
  editbox:SetScript('OnEnter', Control_OnEnter)
  editbox:SetScript('OnLeave', Control_OnLeave)
  editbox:SetScript('OnEscapePressed', EditBox_OnEscapePressed)
  editbox:SetScript('OnEnterPressed', EditBox_OnEnterPressed)
  editbox:SetScript('OnTextChanged', EditBox_OnTextChanged)
  editbox:SetScript('OnReceiveDrag', EditBox_OnReceiveDrag)
  editbox:SetScript('OnMouseDown', EditBox_OnReceiveDrag)
  editbox:SetTextInsets(0, 0, 3, 3)
  editbox:SetMaxLetters(256)
  editbox:SetPoint('BOTTOMLEFT', 6, 0)
  editbox:SetPoint('BOTTOMRIGHT')
  editbox:SetHeight(19)

  local label = frame:CreateFontString(nil, 'OVERLAY', 'GameFontNormalSmall')
  label:SetPoint('TOPLEFT', 0, -2)
  label:SetPoint('TOPRIGHT', 0, -2)
  label:SetJustifyH('LEFT')
  label:SetHeight(18)

  local button = CreateFrame('Button', nil, editbox, 'UIPanelButtonTemplate')
  button:SetWidth(40)
  button:SetHeight(20)
  button:SetPoint('RIGHT', -2, 0)
  button:SetText(OKAY)
  button:SetScript('OnClick', Button_OnClick)
  button:Hide()

  local widget = {
    alignoffset = 30,
    editbox = editbox,
    label = label,
    button = button,
    frame = frame,
    type = Type,
  }
  for method, func in pairs(methods) do
    widget[method] = func
  end
  editbox.obj, button.obj = widget, widget

  return AceGUI:RegisterAsWidget(widget)
end

AceGUI:RegisterWidgetType(Type, Constructor, Version)
