-- Copyright (C) 2010 Tyson Brown
-- 
-- This file is part QuestHelper2, an AddOn for World of Warcraft.
-- 
-- QuestHelper2 is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
-- 
-- QuestHelper2 is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
-- 
-- You should have received a copy of the GNU General Public License
-- along with QuestHelper2. If not, see <http://www.gnu.org/licenses/>.

if LibDebug then LibDebug() end
local shared = select(2, ...)
local L = shared.L

local filter_zone, filter_continent = false, false

local player_continent, player_area = nil, nil

-- Maps digsite name to an objective.
local digsite_objective = {}

local visited = {}

local root_objective = shared.createObjective("digsite/base")
root_objective.root = true
root_objective.text = PROFESSIONS_ARCHAEOLOGY
root_objective.obtainable = false
root_objective.complete = true
root_objective.spell_id = 80451

-- There is a copy of this table in dev/dump_flighttimes, if this table
-- is changed please update that table as well.
local ignored_areas = {
  [13] = true, -- Kalimdor
  [14] = true, -- Eastern Kingdoms
  [466] = true, -- Outland
  [485] = true, -- Northrend
  [689] = true, -- Stranglethorn Vale (Want to detect the sub-zones, Cape/Northern, instead.)
  [613] = true, -- Vashj'ir (I don't think there are artifacts here, but if there were, we'd want to check its sub-zones instead.)
}

local function scanArea(area_id)
  SetMapByID(area_id)
  
  for i=1,GetNumMapLandmarks() do
    local name, desc, index, x, y = GetMapLandmarkInfo(i)
    if index == 177 then
      -- This is a digsite; or at least is using the little shovel icon.
      
      local site_area, site_level, site_x, site_y, site_dist = area_id, 0, x, y
      
      local map_x, map_y, map = shared.mapVirtualPosition(area_id, 0, x, y)
      
      for area, info in pairs(shared.static.area_info) do
        if not ignored_areas[area] then
          for level, level_info in pairs(info.levels) do
            local x, y = shared.areaPosition(map_x, map_y, map, area, level)
            
            if x and x >= 0 and x <= 1 and y >= 0 and y <= 1 then
              local dist = (x-.5)^2 + (y-.5)^2
              if not site_dist or dist < site_dist then
                site_area, site_level, site_x, site_y, site_dist = area, level, x, y, dist
              end
            end
          end
        end
      end
      
      if not filter_zone or site_area == player_area then
        visited[name] = true
        
        if not digsite_objective[name] then
          local objective = shared.createObjective("digsite/"..name)
          objective.text = name
          objective.spell_id = 80451 -- Survey
          objective.icon = "Interface\\AddOns\\QuestHelper2\\Icons\\DigSite.tga"
          objective:setLocation(site_area, site_level, site_x, site_y)
          objective:setProgress(0, 3, "COUNTDOWN")
          root_objective:addDependencies(objective)
          objective.enabled = true
          
          objective.callback = function ()
            if not WorldMapFrame:IsVisible() or GetCurrentMapAreaID() ~= site_area then
              -- Show map and set it to the area of this objective.
              if not WorldMapFrame:IsVisible() then ToggleFrame(WorldMapFrame) end
              SetMapByID(site_area)
            else
              -- Hide map frame.
              if WorldMapFrame:IsVisible() then ToggleFrame(WorldMapFrame) end
            end
          end
          
          digsite_objective[name] = objective
        end
      end
    end
  end
end

local function rescanDigsites()
  local unset_digsites_when_done = false
  if not GetCVarBool("digSites") then
    SetCVar("digSites", 1)
    unset_digsites_when_done = true
  end
  
  shared.pushMap()
  
  local f, c = not filter_continent, player_continent
  
  if f or c == 1 then scanArea(13) end -- Kalimdor
  if f or c == 2 then scanArea(14) end -- Eastern Kingdoms
  if f or c == 3 then scanArea(466) end -- Outland
  if f or c == 4 then scanArea(485) end -- Northrend
  
  for digsite, objective in pairs(digsite_objective) do
    if not visited[digsite] then
      objective.complete = true
      root_objective:removeDependencies(objective)
      digsite_objective[digsite] = nil
    end
  end
  
  if next(digsite_objective) then
    root_objective.complete = false
  else
    root_objective.complete = true
  end
  
  table.wipe(visited)
  
  if unset_digsites_when_done then
    SetCVar("digSites", 0)
  end
  
  shared.popMap()
end

local function checkSpellCast(player, spell_name, rank, counter, spell_id)
  if spell_id == 73979 then -- Searching for Artifacts
    local nearest_objective, nearest_distance
    
    local x1, y1, map1 = shared.mapVirtualPosition(shared.whereAmI())
    
    for digsite, objective in pairs(digsite_objective) do
      local x2, y2, map2 = shared.mapVirtualPosition(objective:nearestLocation())
      
      if map1 == map2 then
        local distance = (x2-x1)^2 + (y2-y1)^2
        if not nearest_objective or distance < nearest_distance then
          nearest_objective, nearest_distance = objective, distance
        end
      end
    end
    
    if nearest_objective and nearest_distance^.5 < 700 then
      nearest_objective:setProgress(nearest_objective:getProgress()+1, 3, "COUNTDOWN")
    else
      print("What digsite is this?!")
    end
    
    shared.callOnce(rescanDigsites, 0.25)
  end
end

local function updateFilters()
  filter_continent = shared.settings.digsite_filter_continent
  filter_zone = shared.settings.digsite_filter_zone
  
  if shared.settings.digsite_create_objectives then
    rescanDigsites()
  end
end

local function updatePlayerArea()
  shared.pushMap()
  
  SetMapToCurrentZone()
  
  player_area, player_continent = GetCurrentMapAreaID(), GetCurrentMapContinent()
  
  shared.popMap()
  
  if shared.settings.digsite_create_objectives then
    rescanDigsites()
  end
end

shared.onSetting("digsite_filter_continent", updateFilters)
shared.onSetting("digsite_filter_zone", updateFilters)

shared.onEvent("ZONE_CHANGED_NEW_AREA", shared.onDelay, .25, updatePlayerArea)
shared.onLoad(shared.callOnce, updatePlayerArea)

shared.onSetting("digsite_create_objectives", function (enabled)
  if enabled then
    root_objective.enabled = true
    shared.onEvent("UNIT_SPELLCAST_STOP", checkSpellCast)
    shared.callOnce(rescanDigsites, 0.25)
  else
    root_objective.enabled = false
    shared.cancelEvent("UNIT_SPELLCAST_STOP", checkSpellCast)
    shared.cancelDelayed(rescanDigsites)
    
    for digsite, objective in pairs(digsite_objective) do
      objective.enabled = false
      root_objective:removeDependencies(objective)
      digsite_objective[digsite] = nil
    end
  end
end)
