-- A MapSpot represents one node of a MapSpot type guide.

local ZGV = ZygorGuidesViewer
if not ZGV then return end

local table,string,tonumber,ipairs,pairs,setmetatable = table,string,tonumber,ipairs,pairs,setmetatable

local MapSpot = {}
ZGV.MapSpotProto = MapSpot
ZGV.MapSpotProto_mt = { __index=MapSpot }

local L = ZGV.L

function MapSpot:New(spottype,level)
	return setmetatable({['type']=spottype or "at",['level']=level, ['objects']={}},ZGV.MapSpotProto_mt);
end

function MapSpot:AreRequirementsMet()
	--[[
	local raceclass=true
	if self.requirement then
		raceclass=false
		for i,v in pairs(self.requirement) do if ZGV:RaceClassMatch(v) then raceclass=true break end end
	end
	if not raceclass then return false end

	if self.condition_visible and not self.condition_visible() then return false end

	return true
	--]]
	-- wrong
end

function MapSpot:GetTitle()
	if self.title then return self.title end
	if self.vendor then return self.vendor end
	return "?"
end

function MapSpot:IsInRange()
	return not self.waypoint.hideminimap
	--[[
	local guide=self.parentGuide
	if self.num<#guide.steps then
		return guide.steps[self.num+1]
	else
		guide=ZGV:GetGuideByTitle(self.parentGuide.next)
		if guide then
			return guide.steps[1]
		else
			return nil
		end
	end
	--]]
end

function MapSpot:IsVisible()
	if self.parentSet then
		return self.parentSet.visible and not self.hidden
	else
		return false
	end
end

-- Called for a marker, presumably containing a reference to a MapSpot.
local function MapSpot_waypoint_OnUpdate(waypoint)
	if waypoint.spot then waypoint.spot:OnUpdate() end
end

local function MapSpot_waypoint_OnEnter(waypoint,...)
	if waypoint.spot then waypoint.spot:OnEnter(...) end
end

local function MapSpot_waypoint_OnEvent(waypoint)
	if waypoint.spot then waypoint.spot:OnEvent() end
end

function MapSpot:Show()
	if not self.waypoint then
		self.waypoint = ZGV.Pointer:SetWaypoint(nil,self.map,self.x,self.y,{title=self:GetTitle(),type="poi",icon=ZGV.DIR .. "\\Skins\\minimaparrow-gold-dot",edgeicon=ZGV.DIR .. "\\Skins\\minimaparrow-gold-edge",overworld=false,onminimap="zonedistance"})
		if not self.waypoint then return end
		self.waypoint.spot = self
		self.waypoint.OnUpdate = MapSpot_waypoint_OnUpdate
		self.waypoint.OnEnter = MapSpot_waypoint_OnEnter
		self.waypoint.OnEvent = MapSpot_waypoint_OnEvent
	end
	self:UpdateVisibility()
	return self.waypoint
end

function MapSpot:GetObjectsOfType(objtype,onlyvis)
	if self.objects then
		local ret={}
		for o,obj in ipairs(self.objects) do
			if obj.item and (obj[objtype] or obj.item[objtype] or (objtype=="drop" and not obj.item.ore and not obj.item.skin and not obj.item.herb and not obj.item.vendor and not obj.vendor)) then
				if not onlyvis or not obj.hidden then
					tinsert(ret,obj)
				end
			end
		end
		if #ret>0 then return ret else return nil end
	end
end

local function MapSpot_ObjectToString(obj)
	if obj.type=="item" and not obj.hidden then
		local id = obj.item.id
		local data = id and GetItemInfo(id) or ""
		local perc = ""
		if obj.perc then perc=(" (%d%%)"):format(obj.perc) end
		if obj.toohard then
			local skill=""
			if obj.item.ore then skill=(" (Mining %d)"):format(obj.item.ore) end
			if obj.item.skin then skill=(" (Skinning %d)"):format(obj.item.skin) end
			if obj.item.herb then skill=(" (Herbalism %d)"):format(obj.item.herb) end
			obj.string = data..perc..skill
		else
			obj.string = data..perc
		end
		obj.icon = "|T"..(GetItemIcon(obj.item.id) or "")..":13:13:0:0:64:64:4:60:4:60|t"
		obj.iconstring = obj.icon.." "..obj.string
	else
		obj.string = ""
		obj.iconstring = ""
	end
end

function MapSpot:UpdateVisibility()
	local visible,possible=0,0

	if self.objects then
		for o,obj in ipairs(self.objects) do
			possible=possible+1
			if obj.type=="item" then
				local req = ZGV.db.profile.goldreqmode
				local noskill = (obj.item.herb and ZGV:GetSkill("Herbalism").level==0)
					or (obj.item.ore and ZGV:GetSkill("Mining").level==0)
					or (obj.item.skin and ZGV:GetSkill("Skinning").level==0)
				obj.toohard = (obj.item.herb and obj.item.herb>ZGV:GetSkill("Herbalism").level)
					 or (obj.item.ore and obj.item.ore>ZGV:GetSkill("Mining").level)
					 or (obj.item.skin and obj.item.skin>ZGV:GetSkill("Skinning").level)
				
				if req==3 and obj.toohard then
					obj.hidden=true
				elseif req==2 and noskill then
					obj.hidden=true
				else
					obj.hidden=nil
					visible=visible+1
				end
			else
				visible=visible+1
			end

			MapSpot_ObjectToString(obj)
		end
	end
	--ZGV:Debug("Updating visibility for mapspot")

	self.hidden = (possible>0 and visible==0)
	if self.waypoint then self.waypoint.hidden=self.hidden end
end

function MapSpot:Hide()
	if self.waypoint then
		ZGV.Pointer:RemoveWaypoint(self.waypoint)
	end
end

local itemsources={"vendor","drop","ore","herb","skin"}
function MapSpot:FillTooltip(tooltip)
	ZGV:Debug("Filling tooltip (MS set)")  	MS=self
	if self.hidden then return false end

	tooltip:AddLine(self.desc,1,1,1,true)
	if self.objects then
		for s,source in ipairs(itemsources) do
			local objs = self:GetObjectsOfType(source,true)
			if objs then
				local mobs = source=="drop" and self.mobs
				local mobtext
				if mobs then
					mobtext = ""
					for i,mob in ipairs(self.mobs) do
						if #mobtext>0 then mobtext = mobtext .. ", " end
						mobtext = mobtext .. mob.name
					end
				elseif self.vendorid then
					mobtext = self.vendor
				end

				tooltip:AddLine(L['gold_header_'..source]:format(mobtext),0.7,0.7,0.4,true)
				for o,obj in ipairs(objs) do
					if obj.toohard then tooltip:AddLine(obj.iconstring,1,0,0,true) else tooltip:AddLine(obj.iconstring,1,1,1,true) end
				end
			end
		end
	end
	tooltip:SetWidth(200)
end

function MapSpot:OnUpdate()
	if not self.waypoint then return end
	local minimapframe = self.waypoint.minimapFrame
	--print("onupdate "..self.title)
	local oldhide = self.waypoint.hideminimap
	if minimapframe.dist and (minimapframe.dist<ZGV.db.profile.golddetectiondist) then
		self.waypoint.hideminimap=nil
	else
		self.waypoint.hideminimap=true
	end
	if self.waypoint.hideminimap~=oldhide then
		ZGV:UpdateFrame(true)
	end
end

function MapSpot:OnEnter(tooltip)
	return self:FillTooltip(tooltip)
end

function MapSpot:OnLeave(tooltip)
	tooltip:Hide()
end

function MapSpot:OnEvent()
	self:UpdateVisibility()
	--if GetCurrentMapZone()==0 then self.waypoint.hidden=true end
end

function MapSpot:OnClick()
	if self.waypoint then
		ZGV.Pointer:ShowArrow(self.waypoint)
	end
end
