--[[---------------------------------------------------------------------------

Copyright (c) 2008 by K. Scott Piel 
All Rights Reserved

E-mail: < kscottpiel@gmail.com >
Web:    < http://www.scottpiel.com >

This file is part of nUI.

    nUI 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.

    nUI 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 nUI.  If not, see <http://www.gnu.org/licenses/>.
	
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

--]]---------------------------------------------------------------------------

if not nUI_Options then nUI_Options = {}; end
if not nUI_DefaultConfig then nUI_DefaultConfig = {}; end

local CreateFrame            = CreateFrame;
local date                   = date;
local GetCurrentMapContinent = GetCurrentMapContinent;
local GetCurrentMapZone      = GetCurrentMapZone;
local GetGameTime            = GetGameTime;
local GetMapZones            = GetMapZones;
local GetPlayerMapPosition   = GetPlayerMapPosition;
local SetMapToCurrentZone    = SetMapToCurrentZone;

nUI_Options.clock = 12;

-------------------------------------------------------------------------------

nUI_DefaultConfig.Location =
{
	enabled = true;
	
	anchor = 
	{
		anchor_pt   = "BOTTOM",
		relative_to = "nUI_Dashboard",
		relative_pt = "BOTTOM",
		xOfs        = 0,
		yOfs        = 8,
	},
	options =
	{
		enabled  = true,
		strata   = nil,
		level    = 2,
		height   = 70,
		width    = 286,
		fontsize = 12,
		color    = { r = 1, g = 0.83, b = 0 },
						
		border =
		{
			backdrop =
			{
				bgFile   = "Interface\\Tooltips\\UI-Tooltip-Background", 
				edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", 
				tile     = true, 
				tileSize = 1, 
				edgeSize = 6, 
				insets   = { left = 0, right = 0, top = 0, bottom = 0 },
			},					
			color =
			{
				border   = { r = 1, g = 1, b = 1, a = 1 },
				backdrop = { r = 0, g = 0, b = 0, a = 0.75 },
			},
		},
	},
};

-------------------------------------------------------------------------------

local background  = CreateFrame( "Frame", "nUI_LocationBackground", nUI_Dashboard.Anchor );
local frame       = CreateFrame( "Frame", "nUI_Location", nUI_Dashboard.Anchor, "SecureFrameTemplate" );
frame.text_anchor = frame:CreateTexture( "$parent_Anchor", "BACKGROUND" );
frame.location    = frame:CreateFontString( "$parent_Label", "ARTWORK" );
frame.coords      = frame:CreateFontString( "$parent_Coords", "ARTWORK" );
frame.clock       = frame:CreateFontString( "$parent_Clock", "ARTWORK" );

background:SetAllPoints( frame );

frame.text_anchor:SetPoint( "CENTER", frame, "CENTER", 0, 0 );
frame.text_anchor:SetWidth( 2 );

frame.location:SetJustifyH( "CENTER" );
frame.location:SetJustifyV( "MIDDLE" );
frame.location:SetPoint( "TOP", frame.text_anchor, "TOP", 0, 0 );

frame.coords:SetJustifyH( "CENTER" );
frame.coords:SetJustifyV( "MIDDLE" );
frame.coords:SetPoint( "TOP", frame.location, "BOTTOM", 0, 0 );

frame.clock:SetJustifyH ("CENTER" );
frame.clock:SetJustifyV( "MIDDLE" );
frame.clock:SetPoint( "TOP", frame.coords, "BOTTOM", 0, 0 );

RegisterStateDriver( frame, "visibility", "[target=mouseover, exists] hide; show" );

MiniMapMailFrame:SetParent( frame );
MiniMapMailFrame:SetScale( 0.65 );
MiniMapMailFrame:ClearAllPoints();
MiniMapMailFrame:SetPoint( "LEFT", frame, "LEFT", 2, -2 );

MiniMapBattlefieldFrame:SetParent( frame );
MiniMapBattlefieldFrame:SetScale( 0.65 );
MiniMapBattlefieldFrame:ClearAllPoints();
MiniMapBattlefieldFrame:SetPoint( "RIGHT", frame, "RIGHT", -2, -2 );

-------------------------------------------------------------------------------

local function onLocationEvent()
	
	if event == "VARIABLES_LOADED" then
		
		nUI:registerSkinnedFrame( frame );
		nUI:registerScalableFrame( frame );
	
		-- set up a slash command handler for choosing a 12 or 24 hour clock
		
		local option = nUI_SlashCommands[nUI_SLASHCMD_CLOCK];
		
		nUI_SlashCommands:setHandler( option.command,
			
			function( msg, arg1 )
				
				local clock = tonumber( arg1 or 12 );
				
				if not clock or (clock ~= 12 and clock ~= 24) then
					
					DEFAULT_CHAT_FRAME:AddMessage( nUI_L["nUI: [ %s ] is not a valid clock option... please choose either '12' for a 12 hour clock or '24' for a 24 hour clock."]:format( arg1 ), 1, 0.83, 0 );
					
				elseif nUI_Options.clock ~= clock then
					
					nUI_Options.clock = clock;
					
					DEFAULT_CHAT_FRAME:AddMessage( (option.message):format( clock ), 1, 0.83, 0 );

				end
			end
		);		
				
	end
end

frame:SetScript( "OnEvent", onLocationEvent );
frame:RegisterEvent( "VARIABLES_LOADED" );

-------------------------------------------------------------------------------

local timer = 0;

local function onLocationUpdate( who, elapsed )

	timer = timer + elapsed;
	
	if timer >= 0.1 then -- 10fps update

		timer = 0;
		
		if not WorldMapFrame:IsVisible() then

			-- map coordinates
			
			local mapX, mapY   = GetPlayerMapPosition( "player" );
			local inInstance,_ = IsInInstance();
			
			if mapX == 0 and mapY == 0 then
					
				SetMapToCurrentZone();			
				mapX, mapY = GetPlayerMapPosition( "player" );
	
			end
	
			local coords = ("%0.1f - %0.1f"):format( mapX * 100, mapY * 100 );
			
			if frame.coords.value ~= coords
			then

				frame.coords.value = coords;				
				frame.coords:SetText( coords );
			
			end
			
			-- map location
			
			local location = GetMinimapZoneText();
			
			if frame.location.value ~= location then
				
				frame.location.value = location;				
				frame.location:SetText( location );
				
			end
			
			-- clock
			
			local server_hour, server_minute = GetGameTime();
			local local_hour, local_minute = tonumber( date( "%H" ) ), tonumber( date( "%M" ) );
			local time_str = "";
			
			if nUI_Options.clock == 12 then
		
				local server_suffix, local_suffix = nUI_L["am"], nUI_L["am"];
					
				if server_hour >= 12 then
					server_hour   = server_hour - 12;
					server_suffix = nUI_L["pm"];
				end
				
				if server_hour == 0 then
					server_hour = 12;
				end
				
				if local_hour >= 12 then
					local_hour   = local_hour - 12;
					local_suffix = nUI_L["pm"];
				end
				
				if local_hour == 0 then
					local_hour = 12;
				end
			
				time_str = nUI_L["(S) <hour>:<minute><suffix> - <hour>:<minute><suffix> (L)"]:format( server_hour, server_minute, server_suffix, local_hour, local_minute, local_suffix );
		
			else
			
				time_str = nUI_L["(S) <hour>:<minute> - <hour>:<minute> (L)"]:format( server_hour, server_minute, local_hour, local_minute );
				
			end

			if frame.clock.value ~= time_str then
				
				frame.clock.value = time_str;
				frame.clock:SetText( time_str );
				
			end			
			
			-- and size the anchor if required
			
			local height = frame.location:GetHeight() + frame.coords:GetHeight() + frame.clock:GetHeight();
			
			if frame.text_anchor.height ~= height then
				frame.text_anchor.height = height;
				frame.text_anchor:SetHeight( height );
			end
		end	
	end
end

-------------------------------------------------------------------------------

frame.applyScale = function( scale )
	
	local anchor   = scale and frame.anchor or nil;
	local scale    = scale or frame.scale or 1;
	local options  = frame.options;
	
	if options then
	
		local height   = options.height * scale * nUI.scale;
		local width    = options.width * scale * nUI.scale;
		local fontsize = (options.fontsize or 12) * scale * nUI.scale * 1.75;
		
		if frame.width    ~= width
		or frame.height   ~= height
		or frame.fontsize ~= fontsize 
		then
			
			frame.height   = height;
			frame.width    = width;
			frame.fontsize = fontsize;
			
			frame:SetHeight( height );
			frame:SetWidth( width );
			
			frame.location:SetFont( nUI_L["font2"], fontsize, "OUTLINE" );
			frame.coords:SetFont( nUI_L["font1"], fontsize * 0.9, "OUTLINE" );
			frame.clock:SetFont( nUI_L["font1"], fontsize * 0.9, "OUTLINE" );
	
			frame.text_anchor:SetHeight( frame.location:GetHeight() + frame.coords:GetHeight() + frame.clock:GetHeight() );
			
		end
	end
end

-------------------------------------------------------------------------------

frame.applyAnchor = function( anchor )
	
	local anchor = anchor or frame.anchor or {};
	local anchor_pt   = anchor.anchor_pt or "CENTER";
	local relative_to = anchor.relative_to or frame:GetParent():GetName();
	local relative_pt = anchor.relative_pt or anchor_pt;
	local xOfs        = (anchor.xOfs or 0) * nUI.scale;
	local yOfs        = (anchor.yOfs or 0) * nUI.scale;
	
	frame.anchor = anchor;
	
	if frame.xOfs ~= xOfs
	or frame.yOfs ~= yOfs
	or frame.anchor_pt ~= anchor_pt
	or frame.relative_to ~= relative_to
	or frame.relative_pt ~= relative_pt
	then
		
		frame.anchor_pt   = anchor_pt;
		frame.relative_to = relative_to;
		frame.relative_pt = relative_pt;
		frame.xOfs        = xOfs;
		frame.yOfs        = yOfs;
		
		frame:ClearAllPoints();
		frame:SetPoint( anchor_pt, relative_to, relative_pt, xOfs, yOfs );
		
	end
end

-------------------------------------------------------------------------------

frame.applyOptions = function( options )
	
	frame.options = options;
	
	if not options or not options.enabled then
		
--		nUI:debug( "nUI_Location: player location is disabled", 1 );
		
		frame:SetAlpha( 0 );
		frame:SetScript( "OnUpdate", nil );
		
	else
	
--		nUI:debug( "nUI_Location: player location is enabled", 1 );
		
		background:SetFrameStrata( options.strata or frame:GetParent():GetFrameStrata() );
		background:SetFrameLevel( frame:GetParent():GetFrameLevel() + (options.level or 1) );
		
		frame:SetFrameStrata( background:GetFrameStrata() );
		frame:SetFrameLevel( background:GetFrameLevel()+1 );
		
		MiniMapMailFrame:SetFrameStrata( frame:GetFrameStrata() );
		MiniMapMailFrame:SetFrameLevel( frame:GetFrameLevel()+1 );
		
		MiniMapBattlefieldFrame:SetFrameStrata( frame:GetFrameStrata() );
		MiniMapBattlefieldFrame:SetFrameLevel( frame:GetFrameLevel()+1 );
		
		frame:SetAlpha( 1 );
		frame:SetScript( "OnUpdate", onLocationUpdate );
		
		local color = options.color or { r = 1, g = 0.83, b = 0 };
		
		frame.location:SetTextColor( color.r, color.g, color.b, 1 );
		frame.coords:SetTextColor( color.r, color.g, color.b, 1 );
		frame.clock:SetTextColor( color.r, color.g, color.b, 1 );
		
		-- if there's a border, set it
		
		if options.border then
				
			local border_color = options.border.color.border;
			local backdrop_color = options.border.color.backdrop;
			
			frame:SetBackdrop( options.border.backdrop );
			frame:SetBackdropBorderColor( border_color.r, border_color.g, border_color.b, border_color.a );
			frame:SetBackdropColor( backdrop_color.r, backdrop_color.g, backdrop_color.b, backdrop_color.a );
	
		else 
			
			frame:SetBackdrop( nil );
			
		end
		
		-- if there's a background, set it
		
		if options.background then
				
			local border_color = options.background.color.border;
			local backdrop_color = options.background.color.backdrop;
			
			background:SetBackdrop( options.background.backdrop );
			background:SetBackdropBorderColor( border_color.r, border_color.g, border_color.b, border_color.a );
			background:SetBackdropColor( backdrop_color.r, backdrop_color.g, backdrop_color.b, backdrop_color.a );
	
		else 
			
			background:SetBackdrop( nil );
			
		end
		
		frame.applyScale( options.scale or frame.scale or 1 );
		
	end
end

-------------------------------------------------------------------------------

frame.applySkin = function( skin )
	
	local skin = skin and skin.Location or nUI_DefaultConfig.Location;
	
	if skin and skin.enabled then
		
--		nUI:debug( "nUI_Location: setting skin", 1 );
		
		frame.applyOptions( skin.options );
		frame.applyAnchor( skin.anchor );
	
	else
		
		frame:SetScript( "OnUpdate", nil );
		frame:SetAlpha( 0 );
		
	end
end