-- [ constants ] ================================================================
local KALENTED_TALENT_OFFSET_X    = 16;
local KALENTED_TALENT_OFFSET_Y    = 20;


-- [ variables ] ================================================================
-- Saved Variables
XKalented_TabData                 = {};

-- Local Variables
local fnTalentFrame_Update        = nil;
local iTalentPoints               = 0;
local iPointsSpent                = 0;
local strName                     = "";


-- [ WoW Subclassing ] ==========================================================
-- Set Subclassing
function KO_Kalented_Frame_OnLoad()
  -- [ register slash commands ]
  SlashCmdList["KALENTED"] = KO_Kalented_SlashCommand;
  SLASH_KALENTED1 = "/kalented";

  -- Setup Username and Set Tab Texture
  strName = UnitName("player");
  KO_Kalented_Texture:SetTexture(KO_TEXTURE_TAB);

  -- Load AddOn
  LoadAddOn("Blizzard_TalentUI");

  -- Register Events
  this:RegisterEvent("VARIABLES_LOADED");
end

-- Events
function KO_Kalented_Frame_Event(event, arg1)
  if ( event == "ADDON_LOADED" ) then
    message(ag1);
  end

  if ( event == "VARIABLES_LOADED" ) then
    -- If First Time, create tables
    if ( not XKalented_TabData[strName] ) then
      KO_Kalented_ResetPoints_OnClick();
    else
      KO_Kalented_Level:SetText(XKalented_TabData[strName]["Level"]);
    end

    -- Subclass Talent Window
    fnTalentFrame_Update = TalentFrame_Update;
    TalentFrame_Update = NewTalentFrame_Update;

  end
end

-- Unset Subclassing
function KO_Kalented_Frame_OnUnload()
  if ( fnTalentFrame_Update ) then
    TalentFrame_Update = fnTalentFrame_Update;
    fnTalentFrame_Update = nil;
  end
end

function NewTalentFrame_Update()
  fnTalentFrame_Update();
  KO_Kalented_Update();
end


-- [ WoW commands ] =============================================================
function KO_Kalented_SlashCommand(msg)
local _, _, cmd, arg1 = string.find(msg, "%s*(%S*)%s*(.*)");
  cmd = string.lower(cmd);

  -- List of Commands
  if ( cmd == "help" ) then
    KO_Kalented_Debug_Message("Kalented Help: /kalented <help> <credits> <clear>");
    KO_Kalented_Debug_Message("Use a command by removing the <>");
    KO_Kalented_Debug_Message("-=-=-=-=-");

  -- About Information
  elseif ( cmd == "credits" ) then
    KO_Kalented_Debug_Message("Created by Kaluriel [ kaluriel@gmail.com ].");
    KO_Kalented_Debug_Message("Translations by Filougarou, J.W and sy2451.");
    KO_Kalented_Debug_Message("-=-=-=-=-");
    
  -- Clear Tables
  elseif ( cmd == "clear" ) then
    KO_Kalented_Debug_Clear();
    KO_Kalented_Debug_Message("Database cleared.");
    KO_Kalented_Debug_Message("-=-=-=-=-");
    
  -- Save Class Information
  elseif ( cmd == "retrieve" ) then
    KO_Kalented_Debug_Retrieve();
    KO_Kalented_Debug_Message("Class Talent Data Retrieved.");
    KO_Kalented_Debug_Message("-=-=-=-=-");
    
  -- No Command
  else
    KO_Kalented_Debug_Message("Invalid command entered.");
    KO_Kalented_Debug_Message("-=-=-=-=-");
  end
end


-- [ WoW events ] ===============================================================
-- Reset Points
function KO_Kalented_ResetPoints_OnClick()
  XKalented_TabData[strName] = {};

  for i=1, MAX_TALENT_TABS, 1 do
    XKalented_TabData[strName][i] = {};
    for j=1, MAX_NUM_TALENTS, 1 do
      XKalented_TabData[strName][i][j] = 0;
    end
  end
  XKalented_TabData[strName]["Level"] = UnitLevel("player");
  KO_Kalented_Level:SetText(XKalented_TabData[strName]["Level"]);
  
  KO_Kalented_Update();
end

-- Transfer Points
function KO_Kalented_Transfer_OnClick()
  for i=1, MAX_TALENT_TABS, 1 do
    for j=1, MAX_NUM_TALENTS, 1 do
      if ( j <= GetNumTalents(i) ) then
        local _, _, _, _, rank, _, _, _ = GetTalentInfo(i, j);
        XKalented_TabData[strName][i][j] = rank;
      else
        XKalented_TabData[strName][i][j] = 0;
      end
    end
  end
  XKalented_TabData[strName]["Level"] = UnitLevel("player");
  KO_Kalented_Level:SetText(XKalented_TabData[strName]["Level"]);
 
  KO_Kalented_Update();
end

-- Learn Talent
function KO_Kalented_Button_OnClick(arg1)
  if ( arg1 == "LeftButton" ) then
    if ( KO_Kalented_CanIncrease(this:GetID()) ) then
      XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][this:GetID()] = XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][this:GetID()] + 1;
    end
  elseif ( arg1 == "RightButton" ) then
    if ( KO_Kalented_CanDecrease(this:GetID()) ) then
      XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][this:GetID()] = XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][this:GetID()] - 1;
    end
  end
  KO_Kalented_Update();

   if ( GameTooltip:IsOwned(this) ) then
    KO_Kalented_SetTalentTip();
  end
end

-- Update Talents
function KO_Kalented_Update()
  -- Get Level Entered
  XKalented_TabData[strName]["Level"] = KO_Kalented_Level:GetText();

  -- Calculate Remaining Points and display
  iTalentPoints = XKalented_TabData[strName]["Level"] - 9;
  iPointsSpent = 0;

  for i=1, MAX_TALENT_TABS, 1 do
    for j=1, MAX_NUM_TALENTS, 1 do
      if ( PanelTemplates_GetSelectedTab(TalentFrame) == i ) then
        iPointsSpent = iPointsSpent + XKalented_TabData[strName][i][j];
      end
      iTalentPoints = iTalentPoints - XKalented_TabData[strName][i][j];
    end
  end
  if ( iTalentPoints < 0 ) then
    iTalentPoints = 0;
  end

  KO_Kalented_PointsValue:SetText(iTalentPoints);
  KO_Kalented_SpentValue:SetText(iPointsSpent);
  

  -- Setup Background Image
  local _, _, _, strFilename = GetTalentTabInfo(PanelTemplates_GetSelectedTab(TalentFrame));
  local base = "Interface\\TalentFrame\\";
  if ( GetTalentTabInfo(PanelTemplates_GetSelectedTab(TalentFrame)) ) then
    base = base .. strFilename;
  else
    base = base .. "MageFire";
  end
  
  KO_Kalented_BackgroundTopLeft:SetTexture(base .. "-TopLeft");
  KO_Kalented_BackgroundTopRight:SetTexture(base .. "-TopRight");
  KO_Kalented_BackgroundBottomLeft:SetTexture(base .. "-BottomLeft");
  KO_Kalented_BackgroundBottomRight:SetTexture(base .. "-BottomRight");


  -- Setup Talent Buttons
  for i=1, MAX_NUM_TALENTS, 1 do
    pButton = getglobal("KO_Kalented_Talent" .. i);

    if ( i <= GetNumTalents(PanelTemplates_GetSelectedTab(TalentFrame)) ) then
      -- Get Talent Info
      local _, iconTexture, tier, column, _, maxRank, _, _ = GetTalentInfo(PanelTemplates_GetSelectedTab(TalentFrame), i);
      local rank = XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][i];
      local bForceDesaturated, bTierUnlocked = false, false;
 
      -- Set Rank and Position Button
      getglobal("KO_Kalented_Talent" .. i .. "Rank"):SetText(rank);
      pButton:SetPoint("TOPLEFT", pButton:GetParent():GetName(), "TOPLEFT", 63 * (column - 1) + KALENTED_TALENT_OFFSET_X, -63 * (tier - 1) - KALENTED_TALENT_OFFSET_Y);


      -- If no talent points left and rank 0, grey out button
      if ( iTalentPoints <= 0 and rank == 0  ) then
        bForceDesaturated = true;
      end

      -- If 5+ points were spent in the previous tier, highlight button
      if ( iPointsSpent >= (tier - 1) * 5 ) then
        bTierUnlocked = true;
      end
      SetItemButtonTexture(pButton, iconTexture);


      -- Check if Talent meets prereqs
      if ( KO_Kalented_SetPrereqs(tier, column, bForceDesaturated, bTierUnlocked, GetTalentPrereqs(PanelTemplates_GetSelectedTab(TalentFrame), i)) ) then
        if ( rank < maxRank ) then
          -- Rank is green
          getglobal("KO_Kalented_Talent" .. i .. "Slot"):SetVertexColor(0.1, 1.0, 0.1);
          getglobal("KO_Kalented_Talent" .. i .. "Rank"):SetTextColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b);
        else
          -- Rank if yellow (max)
          getglobal("KO_Kalented_Talent" .. i .. "Slot"):SetVertexColor(1.0, 0.82, 0);
          getglobal("KO_Kalented_Talent" .. i .. "Rank"):SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
        end
        getglobal("KO_Kalented_Talent" .. i .. "RankBorder"):Show();
        getglobal("KO_Kalented_Talent" .. i .. "Rank"):Show();
        
        SetItemButtonDesaturated(pButton, nil);
      else
        if ( rank == 0 ) then
          -- Talent not available
          getglobal("KO_Kalented_Talent" .. i .. "RankBorder"):Hide();
          getglobal("KO_Kalented_Talent" .. i .. "Rank"):Hide();
        else
          -- Rank is grey
          getglobal("KO_Kalented_Talent" .. i .. "RankBorder"):SetVertexColor(0.5, 0.5, 0.5);
          getglobal("KO_Kalented_Talent" .. i .. "Rank"):SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
        end
        getglobal("KO_Kalented_Talent" .. i .. "Slot"):SetVertexColor(0.5, 0.5, 0.5);

        SetItemButtonDesaturated(pButton, 1, 0.65, 0.65, 0.65);
      end
      
      pButton:Show();

    else
      -- Button is unused so hide
      pButton:Hide();
    end
  end


  -- Draw the prerq branches and Variable that decides whether or not to ignore drawing pieces
  local ignoreUp;

  TalentFrame_ResetBranchTextureCount();
  TalentFrame_ResetArrowTextureCount();

  for i=1, MAX_NUM_TALENT_TIERS do
    for j=1, NUM_TALENT_COLUMNS do
      local node = TALENT_BRANCH_ARRAY[i][j];
      
      -- Setup offsets
      local xOffset = 63 * (j - 1) + KALENTED_TALENT_OFFSET_X + 2;
      local yOffset = -63 * (i - 1) - KALENTED_TALENT_OFFSET_Y - 2;
    
      if ( node.id ) then
        -- Has talent
        if ( node.up ~= 0 ) then
          if ( not ignoreUp ) then
            KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["up"][node.up], xOffset, yOffset + TALENT_BUTTON_SIZE);
          else
            ignoreUp = nil;
          end
        end

        if ( node.down ~= 0 ) then
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["down"][node.down], xOffset, yOffset - TALENT_BUTTON_SIZE + 1);
        end

        if ( node.left ~= 0 ) then
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["left"][node.left], xOffset - TALENT_BUTTON_SIZE, yOffset);
        end

        if ( node.right ~= 0 ) then
          -- See if any connecting branches are gray and if so color them gray
          local tempNode = TALENT_BRANCH_ARRAY[i][j+1];  
          if ( tempNode.left ~= 0 and tempNode.down < 0 ) then
            KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["right"][tempNode.down], xOffset + TALENT_BUTTON_SIZE, yOffset);
          else
            KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["right"][node.right], xOffset + TALENT_BUTTON_SIZE + 1, yOffset);
          end
        end

        -- Draw arrows
        if ( node.rightArrow ~= 0 ) then
          KO_Kalented_SetArrowTexture(TALENT_ARROW_TEXTURECOORDS["right"][node.rightArrow], xOffset + TALENT_BUTTON_SIZE/2 + 5, yOffset);
        end

        if ( node.leftArrow ~= 0 ) then
          KO_Kalented_SetArrowTexture(TALENT_ARROW_TEXTURECOORDS["left"][node.leftArrow], xOffset - TALENT_BUTTON_SIZE/2 - 5, yOffset);
        end

        if ( node.topArrow ~= 0 ) then
          KO_Kalented_SetArrowTexture(TALENT_ARROW_TEXTURECOORDS["top"][node.topArrow], xOffset, yOffset + TALENT_BUTTON_SIZE/2 + 5);
        end
      else
        -- Doesn't have a talent
        if ( node.up ~= 0 and node.left ~= 0 and node.right ~= 0 ) then
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["tup"][node.up], xOffset , yOffset);
        elseif ( node.down ~= 0 and node.left ~= 0 and node.right ~= 0 ) then
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["tdown"][node.down], xOffset , yOffset);
        elseif ( node.left ~= 0 and node.down ~= 0 ) then
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["topright"][node.left], xOffset , yOffset);
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["down"][node.down], xOffset , yOffset - 32);
        elseif ( node.left ~= 0 and node.up ~= 0 ) then
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["bottomright"][node.left], xOffset , yOffset);
        elseif ( node.left ~= 0 and node.right ~= 0 ) then
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["right"][node.right], xOffset + TALENT_BUTTON_SIZE, yOffset);
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["left"][node.left], xOffset + 1, yOffset);
        elseif ( node.right ~= 0 and node.down ~= 0 ) then
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["topleft"][node.right], xOffset , yOffset);
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["down"][node.down], xOffset , yOffset - 32);
        elseif ( node.right ~= 0 and node.up ~= 0 ) then
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["bottomleft"][node.right], xOffset , yOffset);
        elseif ( node.up ~= 0 and node.down ~= 0 ) then
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["up"][node.up], xOffset , yOffset);
          KO_Kalented_SetBranchTexture(TALENT_BRANCH_TEXTURECOORDS["down"][node.down], xOffset , yOffset - 32);
          ignoreUp = 1;
        end
      end
    end

    KO_Kalented_ScrollFrame:UpdateScrollChildRect();
  end

  -- Hide any unused branch textures
  for i=TalentFrame_GetBranchTextureCount(), MAX_NUM_BRANCH_TEXTURES, 1 do
    getglobal("KO_Kalented_Branch" .. i):Hide();
  end

  -- Hide and unused arrowl textures
  for i=TalentFrame_GetArrowTextureCount(), MAX_NUM_ARROW_TEXTURES, 1 do
    getglobal("KO_Kalented_Arrow" .. i):Hide();
  end
end


-- [ WoW functions ] ============================================================
function KO_Kalented_SetPrereqs(iTier, iColumn, bForceDesaturated, bTierUnlocked, ...)
local bLearnable, bPrereqsMet = false, false;

  if ( bTierUnlocked and not bForceDesaturated ) then
    bPrereqsMet = true;
  end

  for i=1, arg.n, 3 do
    local x, y = arg[i + 1], arg[i];

    bLearnable = false;
    for j=1, MAX_NUM_TALENTS, 1 do
      local _, _, tier, column, _, maxRank, _, _ = GetTalentInfo(PanelTemplates_GetSelectedTab(TalentFrame), j);
      if ( column == x and tier == y ) then
        if ( XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][j] == maxRank ) then
          bLearnable = true;
        end
      end
    end

    if ( not bLearnable or bForceDesaturated ) then
      bPrereqsMet = false;
    end

    TalentFrame_DrawLines(iTier, iColumn, y, x, bPrereqsMet);
  end

  return bPrereqsMet;
end

function KO_Kalented_SetTalentTip()
  local _, _, _, _, _, maxRank, _, _ = GetTalentInfo(PanelTemplates_GetSelectedTab(TalentFrame), this:GetID());
  GameTooltip:SetTalent(PanelTemplates_GetSelectedTab(TalentFrame), this:GetID());
  GameTooltipTextLeft2:SetText("Rank " .. XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][this:GetID()] .. "/" .. maxRank);
end

function KO_Kalented_CanIncrease(id)
local _, _, tier, column, _, maxRank, _, _ = GetTalentInfo(PanelTemplates_GetSelectedTab(TalentFrame), id);

  -- Check there is enough talents, and the talent isn't at max, and there is enough points to active this field
  if( iTalentPoints > 0 and XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][id] < maxRank and iPointsSpent >= (tier - 1) * 5 ) then
    -- If there are prereqs, check they are filled
    if ( GetTalentPrereqs(PanelTemplates_GetSelectedTab(TalentFrame), id) ) then
      local arg = {GetTalentPrereqs(PanelTemplates_GetSelectedTab(TalentFrame), id)};
      for i=1, table.getn(arg), 3 do
        for j=1, MAX_NUM_TALENTS, 1 do
          local _, _, pTier, pColumn, _, pMaxRank, _, _ = GetTalentInfo(PanelTemplates_GetSelectedTab(TalentFrame), j);
          if ( pColumn == arg[i + 1] and pTier == arg[i] ) then
            if ( XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][j] == pMaxRank ) then
              return true;
            else
              return false;
            end
          end
        end
      end

      return false;
    end

    return true;
  end

  return false;
end

function KO_Kalented_CanDecrease(id)
  -- Check to see if it has 0 points left in talent
  if ( XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][id] == 0 ) then
    return false;
  end

  -- Check to see if there are any talents in the next tier
  local _, _, tier, _, _, _, _, _ = GetTalentInfo(PanelTemplates_GetSelectedTab(TalentFrame), id);
  for i=id, GetNumTalents(PanelTemplates_GetSelectedTab(TalentFrame)), 1 do
    local _, _, pTier, _, _, _, _, _ = GetTalentInfo(PanelTemplates_GetSelectedTab(TalentFrame), i);
    if ( pTier > tier and XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][i] > 0 ) then
      return false;
    end
  end

  -- Check for Prereqs
  local _, _, pTier, pColumn, _, pMaxRank, _, _ = GetTalentInfo(PanelTemplates_GetSelectedTab(TalentFrame), id);
  if ( GetTalentPrereqs(PanelTemplates_GetSelectedTab(TalentFrame), id + 1) and XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][id] == pMaxRank ) then
    local arg = {GetTalentPrereqs(PanelTemplates_GetSelectedTab(TalentFrame), id + 1)};

    for i=1, table.getn(arg), 3 do
      if ( pColumn == arg[i + 1] and pTier == arg[i] ) then
        if ( XKalented_TabData[strName][PanelTemplates_GetSelectedTab(TalentFrame)][id + 1] > 0 ) then
          return false;
        end
      end
    end
  end

  return true;
end

function KO_Kalented_SetArrowTexture(texCoords, xOffset, yOffset)
local pArrow = getglobal("KO_Kalented_Arrow" .. TalentFrame.arrowIndex);
  if ( pArrow ) then
    pArrow:SetTexCoord(texCoords[1], texCoords[2], texCoords[3], texCoords[4]);
    pArrow:SetPoint("TOPLEFT", "KO_Kalented_ArrowFrame", "TOPLEFT", xOffset, yOffset);
    pArrow:Show();
  end

  TalentFrame.arrowIndex = TalentFrame.arrowIndex + 1;
end

function KO_Kalented_SetBranchTexture(texCoords, xOffset, yOffset)
local pBranch = getglobal("KO_Kalented_Branch" .. TalentFrame.textureIndex);
  if ( pBranch ) then
    pBranch:SetTexCoord(texCoords[1], texCoords[2], texCoords[3], texCoords[4]);
    pBranch:SetPoint("TOPLEFT", "KO_Kalented_ScrollChildFrame", "TOPLEFT", xOffset, yOffset);
    pBranch:Show();
  end

  TalentFrame.textureIndex = TalentFrame.textureIndex + 1;
end


-- [ Debug functions ] ==========================================================
function KO_Kalented_Debug_Message(strMessage)
  DEFAULT_CHAT_FRAME:AddMessage("::Kalented:: " .. strMessage, 1.0, 0.25, 0.25);
end

function KO_Kalented_Debug_Clear()
  -- Clear Database
  XKalented_TabData = {};

  -- Reset
  KO_Kalented_ResetPoints_OnClick();
end

function KO_Kalented_Debug_Retrieve()

end