-- Handle displaying all the fish in their habitats

FishingBuddy.Locations = {};

local NUM_THINGIES_DISPLAYED = 20;
FishingBuddy.Locations.FRAME_THINGIEHEIGHT = 16;

local Collapsed = false;
local LocationLineSelected = 0;
local LocationLines = {};
local LocationLastLine = 1;

local function MakeInfo(line, level, collapsible, expanded, hasicon, text, tipinfo, index, id)
   if ( not LocationLines[line] ) then
      LocationLines[line] = {};
   end
   LocationLines[line].level = level;
   LocationLines[line].collapsible = collapsible;
   LocationLines[line].expanded = expanded;
   LocationLines[line].hasicon = hasicon;
   LocationLines[line].text = text;
   LocationLines[line].tipinfo = tipinfo;
   if ( index ) then
      LocationLines[line].index = index;
   else
      LocationLines[line].index = text;
   end
   LocationLines[line].id = id;
   LocationLines[line].valid = true;
end

local function CountLocationLines()
   local linecount = 0;
   local j = 1;
   local limit = LocationLastLine;
   while ( j <= limit ) do
      local info = LocationLines[j];
      j = j + 1;
      if ( info and info.valid ) then
         linecount = linecount + 1;
         if ( info.collapsible and not info.expanded ) then
            local i2 = LocationLines[j];
            while ( i2 and i2.valid and (i2.level > info.level) ) do
               j = j + 1;
               i2 = LocationLines[j];
            end
         end         
      end
   end
   if ( linecount > 0 ) then
      -- I have no idea why this works this way at all
      if ( linecount > NUM_THINGIES_DISPLAYED and linecount < limit ) then
	 return linecount+1;
      else
	 return linecount;
      end
   else
      return 0;
   end
end

local function FishCount(zone, subzone)
   local zidx, sidx = FishingBuddy.GetZoneIndex(zone, subzone);
   local count = 0;
   local total = 0;
   local fh = FishingBuddy_Info["FishingHoles"];
   if( fh[zidx] and fh[zidx][sidx] ) then
      for fishie in fh[zidx][sidx] do
         count = count + 1;
         total = total + fh[zidx][sidx][fishie];
      end
   end
   return count, total;
end
FishingBuddy.FishCount = FishCount;

local function FishiesChanged()
   local fh = FishingBuddy_Info["FishingHoles"];
   local ff = FishingBuddy_Info["Fishies"];
   local line = 1
   local fishcount = table.getn(FishingBuddy.SortedFishies);
   local zonetotals = {};

   for i=1,fishcount,1 do
      local fishid = FishingBuddy.SortedFishies[i].id;
      local fishname = FishingBuddy.StripRaw(ff[fishid].name);
      local locsort = {};
      local total = 0;
      for indexer,count in FishingBuddy.ByFishie[fishid] do
         local _,_,zidx,sidx = string.find(indexer, "(%d+).(%d+)");
         zidx = tonumber(zidx);
         sidx = tonumber(sidx);
         if ( not zonetotals[zidx] ) then
            if ( fh[zidx] and fh[zidx][sidx] ) then
               local tot = 0;
               local fi = fh[zidx][sidx];
               for f in fi do
                  tot = tot + fi[f];
               end
               zonetotals[zidx] = tot;
            end
         end
         local info = {};
	 if ( FishingBuddy_Info["SubZones"][zidx] ) then
	    if ( not FishingBuddy_Info["SubZones"][zidx][sidx] ) then
	       info.text = FishingBuddy_Info["ZoneIndex"][zidx];
	    else
	       info.text = FishingBuddy_Info["SubZones"][zidx][sidx];
	    end
	 else
	    info.text = FishingBuddy.UNKNOWN;
	 end
         info.count = count;
         info.total = zonetotals[zidx];
         if ( not info.total or info.total == 0) then
            info.total = 1;
         end
         tinsert(locsort, info);
         total = total + count;
      end
      local tipinfo = {};
      tipinfo.total = total;
      if ( ff[fishid].level ) then
         tipinfo.level = ff[fishid].level;
      end
      MakeInfo(line, 0, true, true, true, fishname, extra, nil, fishid);
      line = line + 1;
      FishingBuddy.FishSort(locsort);
      for j=1,table.getn(locsort),1 do
         local zone = locsort[j].text;
         local amount = locsort[j].count;
         local total = locsort[j].total;
	 local percent = format(" (%.1f%%)", ( amount / total ) * 100);
         MakeInfo(line, 1, false, false, false, zone..percent, { amount = amount, total = total, title = zone });
         line = line + 1;
      end
   end
   LocationLastLine = line;
end

local function BothLocationsChanged()
   local fh = FishingBuddy_Info["FishingHoles"];
   local ff = FishingBuddy_Info["Fishies"];
   local sorted = FishingBuddy.SortedZones;
   local line = 1;
   local zonecount = table.getn(sorted);
   for i=1,zonecount,1 do
      local zone = sorted[i];
      local zidx = FishingBuddy.GetZoneIndex(zone);
      if ( fh[zidx] ) then
	 local where = zone;
	 MakeInfo(line, 0, true, true, false, zone, nil, where);
	 line = line + 1;
	 local subsorted = FishingBuddy.SortedByZone[zone];
	 local subcount = table.getn(subsorted);
	 for s=1,subcount,1 do
	    local subzone = subsorted[s];
	    local count, total = FishCount(zone, subzone);
	    if ( total > 0 ) then
	       local zidx, sidx = FishingBuddy.GetZoneIndex(zone, subzone);
	       where = zone.."."..subzone;
	       local tipinfo = {};
	       tipinfo.types = count;
	       tipinfo.total = total;
	       if ( FishingBuddy_Info["FishingSkill"][zidx] and FishingBuddy_Info["FishingSkill"][zidx][sidx] ) then
	          tipinfo.skill = FishingBuddy_Info["FishingSkill"][zidx][sidx];
	       end
	       if ( fh[zidx][sidx] ) then
		  MakeInfo(line, 1, true, true, false, subzone, tipinfo, where);
		  line = line + 1;
		  local fishsort = {};
		  for fishid in fh[zidx][sidx] do
		     local info = {};
		     info.id = fishid;
		     info.text = FishingBuddy.StripRaw(ff[fishid].name);
		     info.count = fh[zidx][sidx][fishid];
		     tinsert(fishsort, info);
		  end
		  FishingBuddy.FishSort(fishsort);
		  for j=1,table.getn(fishsort),1 do
		     local fishie = fishsort[j].text;
		     local id = fishsort[j].id;
		     local amount = fishsort[j].count;
		     local percent = format(" (%.1f%%)", ( amount / total ) * 100);
		     MakeInfo(line, 2, false, false, true, fishie..percent, { amount = amount, total = total, title = fishie }, nil, id);
		     line = line + 1;
		  end
	       end
	    end
	 end
      end
   end
   LocationLastLine = line;
end

local function SubZonesChanged()
   local fh = FishingBuddy_Info["FishingHoles"];
   local ff = FishingBuddy_Info["Fishies"];
   local mapping = {};
   for zone in fh do
      for subzone in fh[zone] do
         mapping[subzone] = zone;
      end
   end
   local line = 1;
   local zonecount = table.getn(FishingBuddy.SortedSubZones);
   for i=1,zonecount,1 do
      local subzone = FishingBuddy.SortedSubZones[i];
      local zone = mapping[subzone];
      local count, total = FishCount(zone, subzone);
      if ( total > 0 ) then
	 local zidx, sidx = FishingBuddy.GetZoneIndex(zone, subzone);
	 local tipinfo = nil;
	 if ( FishingBuddy_Info["FishingSkill"][zidx] and FishingBuddy_Info["FishingSkill"][zidx][sidx] ) then
        tipinfo = { skill = FishingBuddy_Info["FishingSkill"][zidx][sidx] };
	 end
	 MakeInfo(line, 0, true, true, false, subzone, tipinfo);
	 line = line + 1;
	 local fishsort = {};
	 for fishid in fh[zidx][sidx] do
	    local info = {};
	    info.id = fishid;
	    info.text = FishingBuddy.StripRaw(ff[fishid].name);
	    info.count = fh[zidx][sidx][fishid];
	    tinsert(fishsort, info);
	 end
	 FishingBuddy.FishSort(fishsort);
	 for j=1,table.getn(fishsort),1 do
	    local id = fishsort[j].id;
	    local fishie = fishsort[j].text;
	    local amount = fishsort[j].count;
	    local percent = format(" (%.1f%%)", ( amount / total ) * 100);
	    MakeInfo(line, 1, false, false, true, fishie..percent, { amount = amount, total = total, title = fishie} , nil, id);
	    line = line + 1;
	 end
      end
   end
   LocationLastLine = line;
end

local function LinesChanged()
   if ( FishingBuddy.GetSetting("GroupByLocation") == 1 ) then
      if ( FishingBuddy.GetSetting("ShowLocationZones") == 1 ) then
         BothLocationsChanged();
      else
         SubZonesChanged();
      end
   else
      FishiesChanged();
   end
   for i=LocationLastLine,table.getn(LocationLines) do
      local info = LocationLines[i];
      if ( info ) then
         info.valid = false;
      end
   end
   FishingLocationsFrame.valid = true;
end

-- local MOUSEWHEEL_DELAY = 0.1;
-- local lastScrollTime = nil;
-- function FishingLocationsFrame_OnMouseWheel(value)
--    local now = GetTime();
--    if ( not lastScrollTime ) then
--       lastScrollTime = now - 0.2;
--    end
--    if ( (now - lastScrollTime) > MOUSEWHEEL_DELAY ) then
--       -- call the old mouse wheel function somehow?
--    end
-- end

function FishingLocationsFrame_SetSelection(id, line)
   local info = LocationLines[line];
   FishingLocationHighlightFrame:Hide();
   if info then
      if ( info.collapsible ) then
         info.expanded = not info.expanded;
      else
         LocationLineSelected = line;
         FishingLocationHighlightFrame:SetPoint ( "TOPLEFT" ,  getglobal("FishingLocations"..id):GetName() , "TOPLEFT" , 5 , 0 )
         FishingLocationHighlightFrame:Show()
      end
   end
end

function FishingLocationsFrame_MoveButtonText(i, what)
   local relativeTo = "FishingLocations"..i..what;
   local textfield = getglobal("FishingLocations"..i.."Text");
   textfield:SetPoint("LEFT", relativeTo, "RIGHT", 2, 0);
end

FishingBuddy.Locations.Update = function(forced)
   if ( not FishingLocationsFrame:IsVisible() ) then
      return;
   end

   if ( forced or not FishingLocationsFrame.valid ) then
      LinesChanged();
   end

   local offset = FauxScrollFrame_GetOffset(FishingLocsScrollFrame);
   FauxScrollFrame_Update( FishingLocsScrollFrame, CountLocationLines(),
                          NUM_THINGIES_DISPLAYED,
                          FishingBuddy.Locations.FRAME_THINGIEHEIGHT,
			  nil, nil, nil,
			  FishingLocationHighlightFrame,
			  230, 230
		       );

   local lastlevel = 0;
   FishingLocationHighlightFrame:Hide();
   local j = 1;
   local o = 1;
   while ( o < offset ) do
      local info = LocationLines[j];
      if ( info ) then
         j = j + 1;
         o = o + 1;
         if ( info.collapsible and not info.expanded ) then
            local i2 = LocationLines[j];
            while ( i2 and i2.level > info.level ) do
               j = j + 1;
               i2 = LocationLines[j];
            end
         end
      end
   end
   for i = 1,NUM_THINGIES_DISPLAYED,1 do
      local locButton = getglobal ( "FishingLocations"..i );
      local info = LocationLines[j];
      if ( info and info.valid ) then
         local icon = getglobal("FishingLocations"..i.."Icon");
         local icontex = getglobal("FishingLocations"..i.."IconTexture");
         locButton.id = i;
         locButton.line = j;

         local leveloffset = (info.level - lastlevel)*16;
         if ( i == 1 ) then
            locButton:SetPoint("TOPLEFT", leveloffset+25, -100);
         else
            local t = i - 1;
            locButton:SetPoint("TOPLEFT", "FishingLocations"..t, "BOTTOMLEFT", leveloffset, 0);
         end
         lastlevel = info.level;

         local text = info.text;
         if text and info.extra then
            text = text .. info.extra;
         end
         locButton.tipinfo = info.tipinfo;

         icon:ClearAllPoints();
         if ( info.collapsible ) then
            icon:SetPoint("LEFT", "FishingLocations"..i, "LEFT", 21, 0);
            locButton:SetTextColor( 1, 0.82, 0 );
            if ( info.expanded ) then
               locButton:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
            else
               locButton:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
            end
            getglobal("FishingLocations"..i.."Highlight"):SetTexture("Interface\\Buttons\\UI-PlusButton-Hilight");
            getglobal("FishingLocations"..i):UnlockHighlight();
         else
            icon:SetPoint("LEFT", "FishingLocations"..i, "LEFT", 3, 0);
            locButton:SetTextColor( .5, .5, .5 );
            locButton:SetNormalTexture("");
            getglobal("FishingLocations"..i.."Highlight"):SetTexture("");
            -- Place the highlight and lock the highlight state
            if ( LocationLineSelected == j ) then
               FishingLocationHighlightFrame:SetPoint("TOPLEFT", "FishingLocations"..i, "TOPLEFT", 21, 0);
               FishingLocationHighlightFrame:Show();
               locButton:LockHighlight();
            else
               locButton:UnlockHighlight();
            end
         end

         locButton.tooltip = nil;
         if ( info.hasicon ) then
            local item, texture, _, _, _ = FishingBuddy.GetFishie(info.id);
            locButton.item = item;
	    locButton.fishid = info.id;
            locButton.name = info.text;
            if( texture ) then
               icontex:SetTexture(texture);
               icon:Show();
               icontex:Show();
            end
            FishingLocationsFrame_MoveButtonText(i, "Icon");
         else
            locButton.item = nil;
	    locButton.fishid = nil;
            locButton.name = nil;
            icontex:SetTexture("");
            icontex:Hide();
            icon:Hide();
            FishingLocationsFrame_MoveButtonText(i, "Highlight");
         end

         if ( info.tipinfo ) then
	    local color = FishingBuddy.Colors.GREEN;
	    if ( locButton.item and
		 not FishingBuddy.IsLinkableItem(locButton.item) ) then
	       color = FishingBuddy.Colors.RED;
	    end
	    text = text.."|c"..color.."*|r";
         end
         locButton:SetText( text );
         locButton:Show();
         j = j + 1;
         if ( info.collapsible and not info.expanded ) then
            local i2 = LocationLines[j];            
            while ( i2 and (i2.level > info.level) ) do
               j = j + 1;
               i2 = LocationLines[j];
            end
         end
      else
         locButton:Hide();
         locButton.id = nil;
         locButton.line = nil;
      end
   end

   if ( LocationLines ) then
      -- Set the expand/collapse all button texture
      local numHeaders = 0;
      local notExpanded = 0;
      for i=1,table.getn(LocationLines),1 do
         local j = i + offset;
         local info = LocationLines[j];
         if ( info and info.collapsible ) then
            numHeaders = numHeaders + 1;
            if ( not info.expanded ) then
               notExpanded = notExpanded + 1;
            end
         end
      end
      FishingLocationsCollapseAllButton:Show();
      -- If all headers are not expanded then show collapse button, otherwise show the expand button
      if ( notExpanded ~= numHeaders ) then
         Collapsed = false;
         FishingLocationsCollapseAllButton:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
      else
         Collapsed = true;
         FishingLocationsCollapseAllButton:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
      end
   else
      FishingLocationsCollapseAllButton:Hide();
   end
end

local function TrackFishToggle(fishid, how)
   local tab = FishingBuddy_Info["FishTracking"][how];
   if ( not tab[fishid] ) then
      local ff = FishingBuddy_Info["Fishies"];
      FishingBuddy.TrackThis(how, fishid, ff[fishid].color, ff[fishid].name);
   else
      if ( not tab[fishid].nevermore ) then
         tab[fishid].nevermore = true;
      else
         tab[fishid].nevermore = nil;
      end
   end
end

local function MakeTrackFishToggle(fishid, how)
   local id = fishid;
   local h = how;
   return function() TrackFishToggle(id, h); end;
end

local function TrackFishEntry(fishid, how)
   local fi = FishingBuddy_Info["FishTracking"];
   local info = {};
   info.text = FishingBuddy["TRACKFISH"..how];
   info.func = MakeTrackFishToggle(fishid, how);
   info.checked = ( fi[how][fishid] and not fi[how][fishid].nevermore );
   return info;
end

local function FishOptionsInitialize()
   local menu = getglobal("FishingBuddyLocationsMenu");
   if ( menu.fishid ) then
      local fishid = menu.fishid;
      local ff = FishingBuddy_Info["Fishies"];
      UIDropDownMenu_AddButton(TrackFishEntry(fishid, "HOURLY"));
      UIDropDownMenu_AddButton(TrackFishEntry(fishid, "WEEKLY"));

      local info = {};
      info.text = FishingBuddy.HIDEINWATCHER;
      info.func = FishingBuddy.WatchFrame.MakeToggle(fishid);
      info.checked = ( not FishingBuddy_Info["HiddenFishies"][fishid] );
      UIDropDownMenu_AddButton(info);
   end
end

FishingBuddy.Locations.Button_OnClick = function(button)
   if ( button == "LeftButton" ) then
      if( IsShiftKeyDown() and this.item ) then
         FishingBuddy.ChatLink(this.item, this.name, this.color);
      elseif ( this.id and this.line ) then
         FishingLocationsFrame_SetSelection(this.id, this.line);
         FishingBuddy.Locations.Update();
      end
   elseif ( this.fishid and button == "RightButton" ) then
      local menu = getglobal("FishingBuddyLocationsMenu");
      
      menu.fishid = this.fishid;
      UIDropDownMenu_Initialize(menu, FishOptionsInitialize, "MENU");
      FishingBuddy.ToggleDropDownMenu(1, nil, menu, this, 0, 0);
   end
end

function FishingLocationsCollapseAllButton_OnClick()
   if not Collapsed then
      FishingLocsScrollFrameScrollBar:SetValue(0);
      LocationLineSelected = 1;
   end
   for _,info in LocationLines do
      info.expanded = Collapsed;
   end
   Collapsed = not Collapsed;
   FishingBuddy.Locations.Update();
end

FishingBuddy.Locations.Button_OnEnter = function()
   if( GameTooltip.locbutfini ) then
      return;
   end
   if ( this.item or this.tooltip or this.tipinfo ) then
      GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
   end

   local gottitle;
   if( this.item or this.tooltip ) then
      gottitle = true;
      if ( this.item and this.item ~= "" ) then
         if ( FishingBuddy.IsLinkableItem(this.item) ) then
            GameTooltip:SetHyperlink("item:"..this.item);
         else
            this.tooltip = {}
            this.tooltip[1] = { ["text"] = this.name };
            this.tooltip[2] = { ["text"] = FishingBuddy.NOTLINKABLE, ["r"] = 1.0, ["g"] = 0, ["b"] = 0 };
            FishingBuddy.AddTooltip(this.tooltip);
            this.item = nil;
         end
      elseif ( this.tooltip ) then
         FishingBuddy.AddTooltip(this.tooltip, 1, 1, 1);
      end
   end
   if ( this.tipinfo ) then
      local ti = this.tipinfo;
      local line;
      if ( ti.title ) then
	 GameTooltip:AddLine(ti.title);
      elseif ( not gottitle ) then
	 GameTooltip:AddLine(this:GetText());
      end
      if ( ti.types ) then
	 GameTooltip:AddLine(string.format(FishingBuddy.FISHTYPES, ti.types));
      end
      if ( ti.amount ) then
	 line = string.format(FishingBuddy.CAUGHTTHISMANY, ti.amount);
      end
      if ( ti.total ) then
	 if ( not line ) then
	    line = "";
	 else
	    line = line.."/";
	 end
	 line = line..string.format(FishingBuddy.CAUGHTTHISTOTAL, ti.total);
      end
      if ( ti.percent ) then
	 if ( not line ) then
	    line = "";
	 else
	    line = line.." ";
	 end
	 line = line.."("..ti.percent.."%)";
      end
      if ( line ) then
	 GameTooltip:AddLine(line, 1, 1, 1);
      end
      if ( ti.skill ) then
	 line = string.format(FishingBuddy.MINIMUMSKILL, ti.skill);
	 GameTooltip:AddLine(line, 0, 1, 0);
      end
   end
   GameTooltip.locbutfini = 1;
   GameTooltip:Show();
end

FishingBuddy.Locations.Button_OnLeave = function()
   if( this.item or this.tooltip or this.tipinfo ) then
      GameTooltip:Hide();
   end
   GameTooltip.locbutfini = nil;
end

FishingBuddy.Locations.DisplayChanged = function()
   FishingLocsScrollFrameScrollBar:SetValue(0);
   LocationLineSelected = 1;
   FishingBuddy.Locations.Update(true);
end

local function UpdateButtonDisplay()
   if ( FishingBuddy.GetSetting("GroupByLocation") == 1 ) then
      FishingLocationsSwitchButton:SetText(FishingBuddy.SHOWFISHIES);
      FishingBuddyOptionSLZ:Show();
   else
      FishingLocationsSwitchButton:SetText(FishingBuddy.SHOWLOCATIONS);
      FishingBuddyOptionSLZ:Hide();
   end
end

FishingBuddy.Locations.SwitchDisplay = function()
   -- backwards logic check, we're about to change...
   local setting = FishingBuddy.GetSetting("GroupByLocation");
   setting = 1 - setting;
   FishingBuddy.SetSetting("GroupByLocation", setting);
   UpdateButtonDisplay();
   FishingBuddy.Locations.DisplayChanged();
end

FishingBuddy.Locations.SwitchButton_OnEnter = function()
   if ( FishingBuddy.GetSetting("GroupByLocation") == 1 ) then
      GameTooltip:SetText(FishingBuddy.SHOWFISHIES_INFO);
   else
      GameTooltip:SetText(FishingBuddy.SHOWLOCATIONS_INFO);
   end
   GameTooltip:Show();
end

FishingBuddy.Locations.OnLoad = function()
   this:RegisterEvent("VARIABLES_LOADED");
   FishingLocationsSwitchButton:SetText(FishingBuddy.SHOWFISHIES);
   -- Set up checkbox
   FishingBuddyOptionSLZ.name = "ShowLocationZones";
   FishingBuddyOptionSLZ.text = FishingBuddy.CONFIG_SHOWLOCATIONZONES_ONOFF;
   FishingBuddyOptionSLZ.tooltip = FishingBuddy.CONFIG_SHOWLOCATIONZONES_INFO;

   
end

FishingBuddy.Locations.OnShow = function()
   if ( FishingBuddy.IsLoaded() ) then
      UpdateButtonDisplay();
      FishingBuddy.Locations.Update();
   end
end

FishingBuddy.Locations.OnEvent = function()
   -- this crashes the client when enabled
   -- this:EnableMouseWheel(0);
end

FishingBuddy.Locations.DataChanged = function(zone, subzone, fishie)
   FishingLocationsFrame.valid = false;   
end

FishingBuddy.ShowLocLine = function(j)
   FishingBuddy.Dump(LocationLines[j]);
end
