-------------------------------------------------------------------------------
-- ListBox.lua
--
-- A custom control for use with AceConfig.  This control doesn't implement
-- the spec exactly--it just does what it needs to for AuctionLite's purposes.
-------------------------------------------------------------------------------

local _

local AceGUI = LibStub("AceGUI-3.0");
local Version = 1;

local Type = "ListBox";
local ListBox = {};

-- Draw the list box.
local function ListBox_Update(box)
  local scrollFrame = box.scrollFrame;
  local buttons = box.buttons;
  local list = box.obj.list;
  local values = box.obj.values;
  local numButtons = #buttons;
  local numCategories = #list;
  if numCategories > numButtons and not scrollFrame:IsShown() then
    OptionsList_DisplayScrollBar(box);
  elseif numCategories <= numButtons and scrollFrame:IsShown() then
    OptionsList_HideScrollBar(box);
  end

  FauxScrollFrame_Update(scrollFrame, numCategories, numButtons,
                         buttons[1]:GetHeight());

  OptionsList_ClearSelection(box, box.buttons);

  local offset = FauxScrollFrame_GetOffset(scrollFrame);
  for i = 1, numButtons do
    local item = list[i + offset];
    if item then
      OptionsList_DisplayButton(buttons[i], { name = item, id = i + offset });
      if values[i + offset] then
        OptionsList_SelectButton(box, buttons[i]);
      end
    else
      OptionsList_HideButton(buttons[i]);
    end
  end
end

-- Handle a mouse click on an entry.
local function ListButton_OnClick(button)
  local box = button:GetParent();
  local id = button.element.id;
  box.obj:Fire("OnValueChanged", id, not box.obj.values[id]);
  box.obj:Fire("OnClosed");
  ListBox_Update(box);
end

-- Acquire this widget.
function ListBox:OnAcquire()
  self:SetDisabled(false);
end

-- Release this widget for reuse.
function ListBox:OnRelease()
  self.frame:ClearAllPoints();
  self.frame:Hide();
  self:SetDisabled(false);
end

-- Enable/disable the widget.
function ListBox:SetDisabled(disabled)
  self.disabled = disabled;
  if disabled then
    self.box:EnableMouse(false);
    self.label:SetTextColor(0.5, 0.5, 0.5);
  else
    self.box:EnableMouse(true);
    self.label:SetTextColor(1, 0.82, 0);
  end
end

-- Indicate whether it's a multiselect control.
function ListBox:SetMultiselect(multi)
  self.multi = multi;
end

-- Set (and show/hide) the widget label.
function ListBox:SetLabel(text)
  if (text or "") == "" then
    self.frame:SetHeight(196);
    self.box:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 0, 0);
    self.label:Hide();
    self.label:SetText("");
  else
    self.frame:SetHeight(216);
    self.box:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 0, -20);
    self.label:Show();
    self.label:SetText(text);
  end
end

-- Set the contents of the widget.  Must be a integer-indexed list.
function ListBox:SetList(list)
  self.list = list;
  self.values = {};
  ListBox_Update(self.box);
end

-- Unused, since only multiselect is supported for now.
function ListBox:SetValue(value)
  assert(false);
end

-- Activate/deactivate an item.
function ListBox:SetItemValue(key, value)
  if not value then
    value = nil;
  end
  self.values[key] = value;
  ListBox_Update(self.box);
end

-- Build a new widget.  We use OptionsFrameListTemplate as provided by
-- Blizzard, with a few nefarious tweaks.
local function Constructor()
  local num = AceGUI:GetNextWidgetNum(Type);
  local frame = CreateFrame("Frame", "AceGUI30ListBox" .. num, UIParent);
  local self = {};
  for k, v in pairs(ListBox) do self[k] = v end;
  self.num = num;
  self.type = Type;
  self.frame = frame;
  frame.obj = self;
  
  frame:SetHeight(216);

  local box = CreateFrame("Frame", "AceGUI30ListBoxBox" .. num, frame,
                          "OptionsFrameListTemplate");
  box.update = ListBox_Update;
  box:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -20);
  box:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", 0, 0);
  box:SetHeight(196);

  local buttons = box.buttons;
  local maxButtons = math.floor((box:GetHeight() - 8) / box.buttonHeight);
  while #buttons < maxButtons do
    local index = #buttons + 1;
    local button = CreateFrame("Button", box:GetName() .. "Button" ..  index,
                               box, "OptionsListButtonTemplate");
    button:SetPoint("TOPLEFT", buttons[#buttons], "BOTTOMLEFT");
    tinsert(buttons, button);
  end
  local button;
  for _, button in ipairs(buttons) do
    button.text:SetText("Button");
    button:SetPoint("RIGHT", button:GetParent(), "RIGHT");
    button:SetScript("OnClick", ListButton_OnClick);
  end
  box.buttons = buttons;

  self.box = box;
  box.obj = self;

  local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall");
  label:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -2);
  label:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -2);
  label:SetJustifyH("LEFT");
  label:SetHeight(18);
  self.label = label;
  label.obj = self;

  AceGUI:RegisterAsWidget(self);
  return self;
end

AceGUI:RegisterWidgetType(Type, Constructor, Version);
