
--
--  TjSharedMediaDropDown.lua
--    by Tuhljin
--
--

local THIS_VERSION = 0.10

if (not TjSharedMediaDropDown or TjSharedMediaDropDown.Version < THIS_VERSION) then
  assert(TjDropDownMenu, "TjSharedMediaDropDown requires TjDropDownMenu library.")
  local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0")
  assert(SharedMedia, "TjSharedMediaDropDown requires LibSharedMedia-3.0.")

  TjSharedMediaDropDown = TjSharedMediaDropDown or {}
  local SMDD = TjSharedMediaDropDown
  SMDD.Version = THIS_VERSION;

  SMDD.menus = SMDD.menus or {}
  local menus = SMDD.menus
  SMDD.emptyList = SMDD.emptyList or { { text = NONE, value = 0, checked = 1 } }
  local emptyList = SMDD.emptyList
  SMDD.menurev = SMDD.menurev or {}
  local menurev = SMDD.menurev
  
  local internal_SetMenu

  local function copytab(from, to)
    for k,v in pairs(from) do
      if(type(v) == "table") then
        to[k] = {}
        copytab(v, to[k]);
      else
        to[k] = v;
      end
    end
  end

  local function getList(mediatype, refresh)
    local menuList = menus[mediatype]
    local rev = menurev[mediatype] or 0
    if (refresh) then
      wipe(menuList)
    elseif (menuList) then
      return menuList, rev;
    else
      menus[mediatype] = {}
      menuList = menus[mediatype]
    end
    local mediaList = SharedMedia:List(mediatype)
    if (not mediaList) then
      copytab(emptyList, menuList)
    else
      local blizztab
	  local alphatab = {}
      for i,mt in ipairs(mediaList) do
        if (mt == "None" or mt == NONE) then
          tinsert(menuList, 1, { text = mt, value = 0 })
        elseif (strsub(mt, 1, 10) == "Blizzard: ") then
          if (not blizztab) then
            blizztab = {}
            menuList[#(menuList)+1] = { text = "Blizzard:", menuList = blizztab,
                                        keepShownOnClick = 1, hasArrow = 1, TjDDM_notCheckable = 1 }
          end
          blizztab[#(blizztab)+1] = { text = strsub(mt, 11), value = mt }
        else
		  --menuList[#(menuList)+1] = { text = mt, value = mt }
		  local k = strsub(mt, 1, 1)
		  alphatab[k] = alphatab[k] or {}
		  alphatab[k][#(alphatab[k])+1] = mt
        end
      end
	  for k,list in pairs(alphatab) do
	    local subtab = {}
	    menuList[#(menuList)+1] = { text = k, menuList = subtab,
                                    keepShownOnClick = 1, hasArrow = 1, TjDDM_notCheckable = 1 }
		for i,mt in ipairs(list) do
		  subtab[i] = { text = mt, value = mt }
	    end
	  end
    end
    if (not SMDD.regcallback) then
      SharedMedia.RegisterCallback(SMDD, "LibSharedMedia_Registered");
      SMDD.regcallback = true
    end
    rev = rev + 1
    menurev[mediatype] = rev  -- Increment this menu's revision number
    return menuList, rev
  end


  local function OpenMenu_hook(self, ...)
    if (self.TjSMDD.mediatype) then
      local mediatype = self.TjSMDD.mediatype
      if (menurev[mediatype] > self.TjSMDD.menurev[mediatype]) then  -- A newer revision of this menu exists
        local value = self:GetSelectedValue()
        local list, rev = getList(mediatype)
        local menuList = wipe(self.TjDDM.menuList)
        copytab(list, menuList)
        internal_SetMenu = true
        self:SetMenu()  -- Setup menu functions
        self.TjSMDD.menurev[mediatype] = rev  -- New revision in place.
        self:SetSelectedValue(value)  -- Restore selected value
      end
    end
    self.TjSMDD.OpenMenu_orig(self, ...)
  end

  local function SetMenu_hook(self, ...)
    if (internal_SetMenu) then
      internal_SetMenu = nil
    else
      self.TjSMDD.mediatype = nil
    end
    self.TjSMDD.SetMenu_orig(self, ...)
  end

  local function Fetch(self)
    local mediatype = self.TjSMDD.mediatype
    if (mediatype) then
      return SharedMedia:Fetch(mediatype, self:GetSelectedValue())
    end
  end

  local function ConvertToSMDD(dropdown, mediatype, menuList)
    local list, rev = getList(mediatype)
    menuList = menuList or {}
    copytab(list, menuList)
    dropdown:SetMenu(menuList, true)
    dropdown.TjSMDD = {}
    dropdown.TjSMDD.mediatype = mediatype
    dropdown.TjSMDD.menus = {}
    dropdown.TjSMDD.menus[mediatype] = menuList
    dropdown.TjSMDD.menurev = {}
    dropdown.TjSMDD.menurev[mediatype] = rev

    dropdown.TjSMDD.SetMenu_orig = dropdown.SetMenu
    dropdown.SetMenu = SetMenu_hook
    dropdown.TjSMDD.OpenMenu_orig = dropdown.OpenMenu
    dropdown.OpenMenu = OpenMenu_hook

    dropdown.SetMediaType = SMDD.SetMediaType
    dropdown.Fetch = Fetch
  end

  -- LibSharedMedia Callback
  function SMDD:LibSharedMedia_Registered(event, mediatype, name)
    if (menurev[mediatype]) then
      getList(mediatype, true)
    end
  end


-- API
---------

  function SMDD.SetMediaType(frame, mediatype, replaceMenu)
    if (type(frame) ~= "table" or type(mediatype) ~= "string" or (replaceMenu and type(replaceMenu) ~= "table")) then
      error("Invalid argument(s). Usage: TjSharedMediaDropDown.SetMediaType(frame, string[, table]) -or- frame:SetMediaType(string[, table])")
    end
    assert(frame.TjDDM, "SetMediaType(): Invalid argument. Frame must be a primary dropdown frame created by TjDropDownMenu or TjSharedMediaDropDown.")
    mediatype = strlower(mediatype)
    if (not frame.TjSMDD) then
      local menuList = replaceMenu and wipe(replaceMenu) or nil
      ConvertToSMDD(frame, mediatype, menuList);
    elseif (frame.TjSMDD.mediatype == mediatype) then
      return;
    else
      local menuList = frame.TjSMDD.menus[mediatype]
      if (menuList) then
        frame.TjSMDD.mediatype = mediatype
        internal_SetMenu = true
        frame:SetMenu(menuList)
      else
        local list, rev = getList(mediatype)
        menuList = replaceMenu and wipe(replaceMenu) or {}
        copytab(list, menuList)
        frame.TjSMDD.menus[mediatype] = menuList
        frame.TjSMDD.menurev[mediatype] = rev
        frame.TjSMDD.mediatype = mediatype
        frame.TjDDM.selectedValue = nil
        internal_SetMenu = true
        frame:SetMenu(menuList, true)
      end
    end
  end

  function SMDD.CreateSMDropDown(name, parent, mediatype, x, y, displayMode, autoHideDelay, EasyMenuSubFunc)
    if (name ~= nil and type(name) ~= "string") then
      error("CreateSMDropDown(): Argument 1 invalid (name). Expected string or nil. Got "..type(name)..".")
    elseif (type(mediatype) ~= "string") then
      error("CreateSMDropDown(): Argument 3 invalid (mediatype). Expected string. Got "..type(mediatype)..".")
    end
    mediatype = strlower(mediatype)
    local menuList = {}
    local frame = TjDropDownMenu.CreateDropDown(name, parent, menuList, x, y, displayMode, autoHideDelay, EasyMenuSubFunc)
    ConvertToSMDD(frame, mediatype, menuList)
    return frame
  end


-- Register with TjOptions
-----------------------------

  if (TjOptions and TjOptions.RegisterItemType) then
    local function CreateSMDD_a(name, parent, data, arg)
      data.menu = {}
      data.width = data.width or 170
    end

    local function CreateSMDD_b(frame, handletip, xOffset, yOffset, btmBuffer, name, parent, data, arg)
      data.mediatype = data.mediatype or "background"
      SMDD.SetMediaType(frame, data.mediatype, data.menu)
    end

    TjOptions.RegisterItemType("sharedmedia", THIS_VERSION, "dropdown",
      { create_prehook = CreateSMDD_a, create_posthook = CreateSMDD_b })
  end

end
