--[[ simpleMinimap by arJUna ]]--
simpleMinimap = AceLibrary("AceAddon-2.0"):new("AceConsole-2.0", "AceDB-2.0", "AceEvent-2.0", "AceHook-2.1", "AceModuleCore-2.0")
local L = AceLibrary("AceLocale-2.2"):new("simpleMinimap")

--[[ setup ]]--
--
function simpleMinimap:OnInitialize()
	self.inside = true
	self.buttons = {
		bgs = MiniMapBattlefieldFrame,
		map = MiniMapWorldMapButton,
		mail = MiniMapMailFrame,
		meet = MiniMapMeetingStoneFrame,
		time = GameTimeFrame,
		track = MiniMapTrackingFrame,
		zoomin = MinimapZoomIn,
		zoomout = MinimapZoomOut
	}
	self.stratas = {
		"BACKGROUND",
		"LOW",
		"MEDIUM",
		"HIGH",
		"DIALOG",
		"FULLSCREEN",
		"FULLSCREEN_DIALOG",
		"TOOLTIP"
	}

	self.defaults = {
		alpha = 1,
		buttonResize = false,
		buttonSize = 33,
		lock = false,
		lockdown = false,
		locationShow = true,
		locationText = true,
		mapPosition = nil,
		radius = 0,
		scale = 1,
		strata = 1,
		buttonPos = {},
		show = {
			bgs = true,
			map = true,
			mail = true,
			meet = true,
			time = true,
			track = true,
			zoom = true
		}
	}

	self.options = {
		type = "group",
		args = {
			title = {
				type = "header",
				order = 1,
				name = "simpleMinimap |cFFFFFFCCv"..self.version,
			},
			spacer1 = {
				type = "header",
				order = 2,
				name=" ",
			},
			alpha = {
				type="range",
				order = 5,
				name = L.alpha,
				desc = L.alpha_desc,
				min=0,
				max=1,
				step=0.05,
				isPercent=true,
				get = function() return self.db.profile.alpha end,
				set = function(x) self.db.profile.alpha=x self:UpdateScreen() end,
			},
			radius = {
				type="range",
				order = 5,
				name = L.radius,
				desc = L.radius_desc,
				min=-20,
				max=20,
				step=2,
				get = function() return self.db.profile.radius end,
				set = function(x) self.db.profile.radius=x self:UpdateScreen() end,
			},
			scale = {
				type="range",
				order = 5,
				name = L.scale,
				desc = L.scale_desc,
				min=0.5,
				max=2,
				step=0.05,
				get = function() return self.db.profile.scale end,
				set = function(x)
					local p = self.db.profile
					if(p.mapPosition) then
						p.mapPosition[1] = (p.scale / x) * p.mapPosition[1]
						p.mapPosition[2] = (p.scale / x) * p.mapPosition[2]
					end
					p.scale = x
					self:UpdateScreen()
				end
			},
			show = {
				type = "group",
				order = 5,
				name = L.show,
				desc = L.show_desc,
				pass = true,
				get = function(key)
					return self.db.profile.show[key]
				end,
				set = function(key, value)
					self.db.profile.show[key] = value
					self:UpdateScreen()
				end,
				args = {
					location = {
						type = "group",
						order = 1,
						name = L.location,
						desc = L.location,
						args = {
							show = {
								type = "toggle",
								order = 1,
								name = L.locationShow,
								desc = L.locationShow_desc,
								get = function() return(self.db.profile.locationShow) end,
								set = function(x) self.db.profile.locationShow=x self:UpdateScreen() end,
							},
							text = {
								type = "toggle",
								order = 2,
								name = L.locationText,
								desc = L.locationText_desc,
								get = function() return(self.db.profile.locationText) end,
								set = function(x) self.db.profile.locationText=x self:UpdateScreen() end,
							}
						}
					},
					bgs = {
						type = "toggle",
						order = 5,
						name = L.bgs,
						desc = L.bgs_desc,
					},
					map = {
						type = "toggle",
						order = 5,
						name = L.map,
						desc = L.map_desc,
					},
					mail = {
						type = "toggle",
						order = 5,
						name = L.mail,
						desc = L.mail_desc,
					},
					meet = {
						type= "toggle",
						order = 5,
						name = L.meet,
						desc = L.meet_desc,
					},
					time = {
						type = "toggle",
						order = 5,
						name = L.time,
						desc = L.time_desc,
					},
					track = {
						type = "toggle",
						order = 5,
						name = L.track,
						desc = L.track_desc,
					},
					zoom = {
						type = "toggle",
						order = 5,
						name = L.zoom,
						desc = L.zoom_desc,
					}
				}
			},
			strata = {
				type="range",
				order = 5,
				name = L.strata,
				desc = L.strata_desc,
				min=1,
				max=7,
				step=1,
				get = function() return(self.db.profile.strata) end,
				set = function(x) self.db.profile.strata=x self:UpdateScreen() end,
			},
			spacer2 = {
				type="header",
				order = 9,
				name=" ",
			},
			spacer3 = {
				type="header",
				order = 10,
				name="   "..L.modules,
			},
			spacer4 = {
				type="header",
				order = 96,
				name=" ",
			},
			lock = {
				type = "toggle",
				order = 97,
				name = L.lock,
				desc = L.lock_desc,
				get = function() return(self.db.profile.lock) end,
				set = function(x) self.db.profile.lock=x self:UpdateScreen() end,
			},
			lockdown = {
				type = "toggle",
				order = 98,
				name = L.lockdown,
				desc = L.lockdown_desc,
				get = function() return(self.db.profile.lockdown) end,
				set = function(x) self.db.profile.lockdown=x self:UpdateScreen() end,
			},
			reset = {
				type="execute",
				order = 99,
				name = L.reset,
				desc = L.reset_desc,
				func=function() StaticPopup_Show("smmRESET") end,
			}
		}
	}
	self:RegisterDB("smmConfig")
	self:RegisterDefaults("profile", self.defaults)
	self:RegisterChatCommand("/simpleminimap", "/smm", self.options, "SIMPLEMINIMAP")

	StaticPopupDialogs["smmRESET"] = {
		text = L.reset_popup, button1 = TEXT(ACCEPT), button2 = TEXT(CANCEL),
		timeout = 30, whileDead = 1, hideOnEscape = 1,
		OnAccept = function()
			self:ResetDB("profile")
			self:UpdateScreen()
		end
	}
end
--
function simpleMinimap:OnEnable()
	if(not self.frame) then
		local f = CreateFrame("Frame", nil, Minimap)
		f:SetWidth(112)
		f:SetHeight(112)
		f:SetPoint("CENTER")
		f:SetToplevel(true)
		f:EnableMouseWheel(true)
		f:SetScript("OnMouseWheel", function()
			if(arg1>0) then
				Minimap_ZoomIn()
			else
				Minimap_ZoomOut()
			end
		end)
		self.frame = f
	end
	MinimapCluster:SetMovable(true)
	Minimap:RegisterForDrag("LeftButton")
	Minimap:SetScript("OnDragStart", function() self:MapDrag(true) end)
	Minimap:SetScript("OnDragStop", function() self:MapDrag(false) end)
	Minimap:SetClampedToScreen(true)
	MinimapZoneTextButton:RegisterForDrag("LeftButton")
	MinimapZoneTextButton:SetScript("OnDragStart", function() self:MapDrag(true) end)
	MinimapZoneTextButton:SetScript("OnDragStop", function() self:MapDrag(false) end)
	for _, f in pairs(self.buttons) do
		f:SetMovable(true)
		f:RegisterForDrag("LeftButton")
		f:SetScript("OnDragStart", function() self:ButtonDrag(true) end)
		f:SetScript("OnDragStop", function() self:ButtonDrag(false) end)
	end
	self:RegisterEvent("MINIMAP_UPDATE_ZOOM")
	for n,m in self:IterateModules() do self:ToggleModuleActive(m, true) end
	MinimapCluster:StartMoving()
	MinimapCluster:StopMovingOrSizing()
	self:UpdateScreen()
	self.loaded = true
end
--
function simpleMinimap:OnDisable()
	for n,m in self:IterateModules() do self:ToggleModuleActive(m, false) end
	self:UpdateScreen()
	MinimapCluster:SetMovable(false)
	Minimap:RegisterForDrag(nil)
	MinimapZoneTextButton:RegisterForDrag(nil)
	for _, f in pairs(self.buttons) do
		f:SetMovable(false)
		f:RegisterForDrag(nil)
	end
	self.loaded = nil
end
--
function simpleMinimap:OnProfileEnable()
	self:UpdateScreen()
end
---
function simpleMinimap:Debug(text)
	if(ChatFrame2 and text) then ChatFrame2:AddMessage(text, 0, 0.8, 1.0) end
end


--[[ events ]]--
--
function simpleMinimap:MINIMAP_UPDATE_ZOOM()
	local z = Minimap:GetZoom()
	if (GetCVar("minimapZoom") == GetCVar("minimapInsideZoom")) then
		if (z < 3) then
			Minimap:SetZoom(z + 1)
		else
			Minimap:SetZoom(z - 1)
		end
	else
		z = nil
	end
	if (tonumber(GetCVar("minimapInsideZoom")) == Minimap:GetZoom()) then
		self.inside = true
		self:Lockdown(MinimapCluster, "SetAlpha", 1)
	else
		self.inside = false
		self:Lockdown(MinimapCluster, "SetAlpha", self.db.profile.alpha)
	end
	if(z) then Minimap:SetZoom(z) end
end


--[[ frame events ]]--
--
function simpleMinimap:ExpandMinimap(keystate)
	local function swapZoom(frame)
		local z = frame:GetZoom()
		if (z>0) then frame:SetZoom(0) else frame:SetZoom(1) end
		frame:SetZoom(z)
	end
	if (not self.expandedFrame) then
		local f = CreateFrame("Minimap", nil, UIParent)
		f:SetHeight(UIParent:GetHeight() * 0.6)
		f:SetWidth(f:GetHeight())
		f:SetPoint("CENTER")
		f:SetFrameStrata("TOOLTIP")
		f:EnableMouse(false)
		f:EnableMouseWheel(false)
		f:EnableKeyboard(false)
		self.expandedFrame = f
	end
	if (keystate == "down") then
		MinimapCluster:Hide()
		self.expandedFrame:Show()
		swapZoom(self.expandedFrame)
	else
		self.expandedFrame:Hide()
		MinimapCluster:Show()
		swapZoom(Minimap)
	end
end
--
function simpleMinimap:MapDrag(kick)
	if(kick and not self.db.profile.lock) then
		MinimapCluster.isMoving = true
		MinimapCluster:StartMoving()
	elseif(MinimapCluster.isMoving) then
		MinimapCluster.isMoving = false
		MinimapCluster:StopMovingOrSizing()
		MinimapCluster.smmTouched = true
		local x, y = MinimapCluster:GetCenter()
		local z = UIParent:GetEffectiveScale()
		self.db.profile.mapPosition = { x * z, y * z }
		self:UpdateScreen()
	end
end
--
function simpleMinimap:ButtonDrag(kick)
	local function getPos()
		local mx, my = Minimap:GetCenter()
		local cx, cy = GetCursorPosition(UIParent)
		local z = UIParent:GetEffectiveScale()
		local v = math.deg(math.atan2(cy / z - my, cx / z - mx))
		if(v < 0) then
			return v + 360
		elseif(v > 360) then
			return v - 360
		else
			return v
		end
	end
	if(kick and not self.db.profile.lock) then
		this.isMoving = true
		this:SetScript("OnUpdate", function()
			this:ClearAllPoints()
			this:SetPoint("CENTER", Minimap, "CENTER", self:GetButtonPos(getPos()))
		end)
		this:StartMoving()
	elseif(this.isMoving) then
		this.isMoving = false
		this:StopMovingOrSizing()
		this:SetScript("OnUpdate", nil)
		for n, f in pairs(self.buttons) do
			if(f == this) then self.db.profile.buttonPos[n] = getPos() break end
		end
	end
end


--[[ screen updates ]]--
--
function simpleMinimap:UpdateScreen()
	local p = self.db.profile
	if(not self:IsActive()) then
		if(self.loaded) then
			p = self.defaults
		else
			return
		end
	end
-- set minimap
	self:Lockdown(MinimapCluster, "SetScale", p.scale)
	self:Lockdown(MinimapCluster, "SetFrameStrata", self.stratas[p.strata])
	self:Lockdown(MinimapCluster, "SetAlpha", p.alpha)
	if(p.mapPosition) then
		local z = UIParent:GetEffectiveScale()
		self:Lockdown(MinimapCluster, "ClearAllPoints")
		self:Lockdown(MinimapCluster, "SetPoint", "CENTER", UIParent, "BOTTOMLEFT", p.mapPosition[1] / z, p.mapPosition[2] / z)
		MinimapCluster.smmTouched = true
	elseif(MinimapCluster.smmTouched) then
		self:Lockdown(MinimapCluster, "ClearAllPoints")
		self:Lockdown(MinimapCluster, "SetPoint", "TOPRIGHT", UIParent)
		MinimapCluster:SetUserPlaced(false)
		MinimapCluster.smmTouched = nil
	end
-- set minimap location bar
	if(p.locationShow) then
		self:Lockdown(MinimapToggleButton, "Show")
		self:Lockdown(MinimapBorderTop, "Show")
		self:Lockdown(MinimapZoneTextButton, "Show")
	else
		self:Lockdown(MinimapToggleButton, "Hide")
		self:Lockdown(MinimapBorderTop, "Hide")
		if(p.locationText) then
			self:Lockdown(MinimapZoneTextButton, "Show")
		else
			self:Lockdown(MinimapZoneTextButton, "Hide")
		end
	end
-- set minimap buttons
	for n, f in pairs(self.buttons) do
		if(n == "zoomin" or n == "zoomout") then
			if(p.show.zoom) then
				f:Show()
			else
				f:Hide()
			end
		else
			if(not p.show[n]) then
				if(not f.smmHide) then
					f.smmHide, f.smmShow = f.Hide, f.Show
					f.smmDoShow = f:IsShown()
					f.Hide = function() f.smmDoShow = false end
					f.Show = function() f.smmDoShow = true end
				end
				f:smmHide()
			elseif(f.smmHide) then
				f.Hide, f.Show = f.smmHide, f.smmShow
				if(f.smmDoShow) then f:Show() end
				f.smmHide, f.smmShow, f.smmDoShow = nil, nil, nil
			end
		end
		if(p.buttonPos[n]) then
			if(not f.smmOldPos) then
				local fx, fy = f:GetCenter()
				local mx, my = Minimap:GetCenter()
				if(fx and mx) then
					f.smmOldPos = { fx - mx, fy - my }
				end
			end
			f:ClearAllPoints()
			f:SetPoint("CENTER", Minimap, "CENTER", self:GetButtonPos(p.buttonPos[n]))
		elseif(f.smmOldPos) then
			f:ClearAllPoints()
			f:SetPoint("CENTER", Minimap, "CENTER", f.smmOldPos[1], f.smmOldPos[2])
			f.smmOldPos = nil
		end
	end
-- let any modules update the screen also
	for n,m in self:IterateModules() do m:UpdateScreen() end
end


--[[ internal functions ]]--
--
function simpleMinimap:Lockdown(frame, method, ...)
	if(self:IsActive() and self.db.profile.lockdown) then
		if(not frame["smm"..method]) then
			frame["smm"..method] = frame[method]
			frame[method] = function() end
		end
		return frame["smm"..method](frame, ...)
	else
		if(frame["smm"..method]) then
			frame[method] = frame["smm"..method]
			frame["smm"..method] = nil
		end
		return frame[method](frame, ...)
	end
end
--
function simpleMinimap:GetButtonPos(vector)
	local v = math.rad(vector)
	local o = 80 + self.db.profile.radius
	return math.cos(v) * o, math.sin(v) * o
end


--[[ module stuff ]]--
--
function simpleMinimap.modulePrototype:UpdateScreen() end
