local _G = getfenv(0)
-- Libraries
local string = _G.string
local format, gsub = string.format, string.gsub
local next, wipe, pairs, select, type = next, wipe, pairs, select, type
local GameTooltip, WorldMapTooltip, GetSpellInfo, CreateFrame, UnitClass = _G.GameTooltip, _G.WorldMapTooltip, _G.GetSpellInfo, _G.CreateFrame, _G.UnitClass
local UIDropDownMenu_CreateInfo, CloseDropDownMenus, UIDropDownMenu_AddButton, ToggleDropDownMenu = _G.UIDropDownMenu_CreateInfo, _G.CloseDropDownMenus, _G.UIDropDownMenu_AddButton, _G.ToggleDropDownMenu
-- ----------------------------------------------------------------------------
-- AddOn namespace.
-- ----------------------------------------------------------------------------
local FOLDER_NAME, private = ...

local LibStub = _G.LibStub
local L = LibStub("AceLocale-3.0"):GetLocale(private.addon_name)
local LH = LibStub("AceLocale-3.0"):GetLocale("HandyNotes", false)
local AceDB = LibStub("AceDB-3.0")

local HandyNotes = LibStub("AceAddon-3.0"):GetAddon("HandyNotes")
local addon = LibStub("AceAddon-3.0"):NewAddon(private.addon_name, "AceEvent-3.0")
addon.constants = private.constants;
addon.constants.addon_name = private.addon_name;

addon.descName = L["HandyNotes - Travel Guide"]
addon.description = L["Shows the portal, zepplin and boat locations on the World Map and the MiniMap."]
addon.pluginName = L["Travel Guide"]

addon.Name = FOLDER_NAME;
_G.HandyNotes_TravelGuide = addon;

-- //////////////////////////////////////////////////////////////////////////
-- get creature's name from server
local mcache_tooltip = CreateFrame("GameTooltip", private.addon_name.."_mcacheToolTip", UIParent, "GameTooltipTemplate")
local creature_cache

-- activation code
local function getCreatureNamebyID(id)
	mcache_tooltip:SetOwner(UIParent, "ANCHOR_NONE")
	mcache_tooltip:SetHyperlink(("unit:Creature-0-0-0-0-%d"):format(id))
	creature_cache = _G[private.addon_name.."_mcacheToolTipTextLeft1"]:GetText()
end
-- //////////////////////////////////////////////////////////////////////////
local MyScanningTooltip = CreateFrame("GameTooltip", "MyScanningTooltip", UIParent, "GameTooltipTemplate")

local QuestTitleFromID = setmetatable({}, { __index = function(t, id)
	MyScanningTooltip:SetOwner(UIParent, "ANCHOR_NONE")
	MyScanningTooltip:SetHyperlink("quest:"..id)
	local title = MyScanningTooltipTextLeft1:GetText()
	MyScanningTooltip:Hide()
	if title and title ~= RETRIEVING_DATA then
		t[id] = title
		return title
	end
end })
-- //////////////////////////////////////////////////////////////////////////
local function work_out_texture(point)
	local icon_key	
	
	if (point.boat) then icon_key = "boat" end
	if (point.aboat) then icon_key = "aboat" end
	if (point.hboat) then icon_key = "hboat" end
	if (point.zeppelin) then icon_key = "zeppelin" end
	if (point.azeppelin) then icon_key = "azeppelin" end
	if (point.hzeppelin) then icon_key = "hzeppelin" end
	if (point.portal) then icon_key = "portal" end
	if (point.tram) then icon_key = "tram" end
	if (point.valliance) then icon_key = "valliance" end
	if (point.vhorde) then icon_key = "vhorde" end
--	if (point.molemachine) then icon_key = "molemachine" end

	if (icon_key and private.constants.icon_texture[icon_key]) then
		return private.constants.icon_texture[icon_key]
	elseif (point.type and private.constants.icon_texture[point.type]) then
		return private.constants.icon_texture[point.type]
	-- use the icon specified in point data
	elseif (point.icon) then
		return point.icon
	else
		return private.constants.defaultIcon
	end
end

local get_point_info = function(point)
	local icon
	if point then
		local label = point.label or point.label2 or UNKNOWN
		if (point.portal == true and point.quest) then
			if IsQuestFlaggedCompleted(point.quest) then
				icon = work_out_texture(point)
			else
				local left, right, top, bottom = GetObjectIconTextureCoords("4773") --MagePortalHorde
					icon = {
					icon = [[Interface\MINIMAP\OBJECTICONSATLAS]],
					tCoordLeft = left,
					tCoordRight = right,
					tCoordTop = top,
					tCoordBottom = bottom,
				}
			end
		elseif (point.portal == true and point.lvl) then	
			if (UnitLevel("player") >= point.lvl) then
					icon = work_out_texture(point)	
			else 
				local left, right, top, bottom = GetObjectIconTextureCoords("4773") --MagePortalHorde
					icon = {
					icon = [[Interface\MINIMAP\OBJECTICONSATLAS]],
					tCoordLeft = left,
					tCoordRight = right,
					tCoordTop = top,
					tCoordBottom = bottom,
				}
			end
				else icon = work_out_texture(point)		
		end
			return label, label2, icon, quest, lvl, point.scale, point.alpha
	end
end 

local get_point_info_by_coord = function(uMapID, coord)
	return get_point_info(private.DB.points[uMapID] and private.DB.points[uMapID][coord])
end


local function handle_tooltip(tooltip, point)
	if point then
		if (point.label) then
			if (point.npc and profile.query_server) then
				tooltip:SetHyperlink(("unit:Creature-0-0-0-0-%d"):format(point.npc))
			else
				tooltip:AddLine(point.label)
			end
		end
		if (point.label1 and profile.show_note) then
				tooltip:AddDoubleLine(point.label1)
			else
				tooltip:AddLine(point.label2)
			end
		if (point.note and profile.show_note) then
			tooltip:AddLine("("..point.note..")", nil, nil, nil, false) --when true text is wrapping
		end
		if (point.spell) then
			local spellName = GetSpellInfo(point.spell)
			if (spellName) then
				tooltip:AddLine(spellName, 1, 1, 1, true)
			end
		end	
		if (point.lvl and UnitLevel("player") < point.lvl) then
			tooltip:AddLine(L["Requires at least player level: "]..point.lvl, 1, 0, 0, true)
		end
		if (point.quest and profile.query_server and IsQuestFlaggedCompleted(point.quest) ==false and QuestTitleFromID[point.quest] ~= nil) then
			tooltip:AddLine(L["Unlocked with quest: ["]..QuestTitleFromID[point.quest].."] (ID: "..point.quest..")",1,0,0)
		elseif (point.quest and profile.query_server and IsQuestFlaggedCompleted(point.quest) ==false and QuestTitleFromID[point.quest] == nil) then
			tooltip:AddLine(L["RETRIEVING DATA..."],1,0,1)	
	end
	else
		tooltip:SetText(UNKNOWN)
	end
	tooltip:Show()
end

local handle_tooltip_by_coord = function(tooltip, uMapID, coord)
	return handle_tooltip(tooltip, private.DB.points[uMapID] and private.DB.points[uMapID][coord])
end

-- //////////////////////////////////////////////////////////////////////////
local PluginHandler = {}
local info = {}

function PluginHandler:OnEnter(uMapID, coord)
	local tooltip = self:GetParent() == WorldMapButton and WorldMapTooltip or GameTooltip
	if ( self:GetCenter() > UIParent:GetCenter() ) then -- compare X coordinate
		tooltip:SetOwner(self, "ANCHOR_LEFT")
	else
		tooltip:SetOwner(self, "ANCHOR_RIGHT")
	end
	handle_tooltip_by_coord(tooltip, uMapID, coord)
end

function PluginHandler:OnLeave(uMapID, coord)
	if self:GetParent() == WorldMapButton then
		WorldMapTooltip:Hide()
	else
		GameTooltip:Hide()
	end
end

local function hideNode(button, uMapID, coord)
	private.hidden[uMapID][coord] = true
	addon:Refresh()
end

local function closeAllDropdowns()
	CloseDropDownMenus(1)
end

local function addTomTomWaypoint(button, uMapID, coord)
	if TomTom then
		local x, y = HandyNotes:getXY(coord)
		TomTom:AddWaypoint(uMapID, x, y, {
			title = get_point_info_by_coord(uMapID, coord),
			persistent = nil,
			minimap = true,
			world = true
		})
	end
end

do
	local currentMapID = nil
	local currentCoord = nil
	local function generateMenu(button, level)
		if (not level) then return end
		if (level == 1) then
			-- Create the title of the menu
			info = UIDropDownMenu_CreateInfo()
			info.isTitle 		= true
			info.text 		= "HandyNotes - " ..addon.pluginName
			info.notCheckable 	= true
			UIDropDownMenu_AddButton(info, level)

			if TomTom then
				-- Waypoint menu item
				info = UIDropDownMenu_CreateInfo()
				info.text = LH["Add this location to TomTom waypoints"]
				info.notCheckable = true
				info.func = addTomTomWaypoint
				info.arg1 = currentMapID
				info.arg2 = currentCoord
				UIDropDownMenu_AddButton(info, level)
			end

			-- Hide menu item
			info = UIDropDownMenu_CreateInfo()
			info.text		= HIDE 
			info.notCheckable 	= true
			info.func		= hideNode
			info.arg1		= currentMapID
			info.arg2		= currentCoord
			UIDropDownMenu_AddButton(info, level)

			-- Close menu item
			info = UIDropDownMenu_CreateInfo()
			info.text		= CLOSE
			info.func		= closeAllDropdowns
			info.notCheckable 	= true
			UIDropDownMenu_AddButton(info, level)
		end
	end
	local HL_Dropdown = CreateFrame("Frame", private.addon_name.."DropdownMenu")
	HL_Dropdown.displayMode = "MENU"
	HL_Dropdown.initialize = generateMenu

	function PluginHandler:OnClick(button, down, uMapID, coord)
		if (button == "RightButton" and not down) then
			currentMapID = uMapID
			currentCoord = coord
			ToggleDropDownMenu(1, nil, HL_Dropdown, self, 0, 0)
		end
	end
end

do

local currentMapID = nil
	local function iter(t, prestate)
		if not t then return nil end
		local state, value = next(t, prestate)
		while state do 
			if value and private:ShouldShow(state, value, currentMapID) then
				local label, label2, icon, quest, lvl, scale, alpha = get_point_info(value)
				scale = (scale or 1) * (icon and icon.scale or 1) * profile.icon_scale
				alpha = (alpha or 1) * (icon and icon.alpha or 1) * profile.icon_alpha
				return state, nil, icon, scale, alpha
			end
			state, value = next(t, state)
		end
		return nil, nil, nil, nil, nil, nil
	end
	function PluginHandler:GetNodes2(uMapID, minimap)
		currentMapID = uMapID
		return iter, private.DB.points[uMapID], nil
	end
	function private:ShouldShow(coord, point, currentMapID)
		if (private.hidden[currentMapID] and private.hidden[currentMapID][coord]) then
			return false
		end
		-- this will check if any node is for specific class
		if (point.class and point.class ~= select(2, UnitClass("player"))) then
			return false
		end
		-- this will check if any node is for specific faction
		if (point.faction and point.faction ~= select(1, UnitFactionGroup("player"))) then
			return false
		end
		if (point.portal and not private.db.show_portal) then return false; end
		if (point.tram and not private.db.show_tram) then return false; end
		if (point.boat and not private.db.show_boat) then return false; end
		if (point.aboat and not private.db.show_aboat) then return false; end
		if (point.hboat and not private.db.show_hboat) then return false; end
		if (point.valliance and not private.db.show_valliance) then return false; end
		if (point.vhorde and not private.db.show_vhorde) then return false; end
		if (point.zeppelin and not private.db.show_zepplin) then return false; end
		if (point.azeppelin and not private.db.show_azepplin) then return false; end
		if (point.hzeppelin and not private.db.show_hzepplin) then return false; end
--		if (point.molemachine and not private.db.show_molemachine) then return false; end
		return true
	end
end

-- //////////////////////////////////////////////////////////////////////////
function addon:OnInitialize()
	self.db = AceDB:New(private.addon_name.."DB", private.constants.defaults)
	
	profile = self.db.profile
	private.db = profile
	private.hidden = self.db.char.hidden

	-- Initialize database with HandyNotes
	HandyNotes:RegisterPluginDB(addon.pluginName, PluginHandler, private.config.options)
end

function addon:OnEnable()
end

function addon:Refresh()
	self:SendMessage("HandyNotes_NotifyUpdate", addon.pluginName)
end

function addon:ZONE_CHANGED()
	addon:Refresh()
end

function addon:ZONE_CHANGED_INDOORS()
	addon:Refresh()
end

function addon:NEW_WMO_CHUNK()
	addon:Refresh()
end
--[[
function addon:CLOSE_WORLD_MAP()
	closeAllDropdowns()
end
]]
-- //////////////////////////////////////////////////////////////////////////