--[[
************************************************************************
Project				: Broker_AllXP
Author				: torhal
Project Revision	: 1.6.6-release
Project Date		: 20120914033816

File				: Broker_AllXP.lua
Commit Author		: torhal
Commit Revision		: 58
Commit Date			: 20120914033816
************************************************************************
Description	:
	Main addon file. 

TODO		:

************************************************************************
(see bottom of file for changelog)
************************************************************************
--]]

local _G = getfenv(0)
local LibStub = _G.LibStub

local MODNAME = "AllXP"
local FULLNAME = "Broker_AllXP"
local AllXP = LibStub("AceAddon-3.0"):NewAddon(MODNAME, "AceEvent-3.0", "AceHook-3.0")
local L = LibStub:GetLibrary("AceLocale-3.0"):GetLocale(MODNAME)
local AceConfig = LibStub("AceConfig-3.0")
local AceConfigReg = LibStub("AceConfigRegistry-3.0")
local AceConfigDialog = LibStub("AceConfigDialog-3.0")

_G[ MODNAME ] = AllXP
local addon = AllXP

local addonversion = "1.6.6-release"
local addonauthor = "torhal"
local builddate = "20120914033816"

local modularOptions = {}
local tooltip
local LTT = LibStub:GetLibrary("LibQTip-1.0")
local LDBIcon = LibStub("LibDBIcon-1.0")

-- addon globals
addon.me = ""
addon.TPscanned = time()
addon.selectedToon = ""

local db

local haveFired = false
local maxLevel = _G.MAX_PLAYER_LEVEL_TABLE[_G.GetExpansionLevel()]
local startXP = -1 -- starting XP (if we've just levelled up, this will be 0)
local cachedXP = 0 -- true session XP, disregarding level ups
local savedLevel -- to test if we've levelled up
local sessionXP -- really only XP since last level up
local leftToLevel -- max XP for level gain (if we've levelled up, this is from the PREVIOUS level)
local lastKnownXP -- so we can calculate how much XP they gained on level up

local sortingMethods = {
	[1] = _G.NAME,
	[2] = _G.LEVEL,
	[3] = L["Rested"],
}

function addon.Print( msg )
	local _, fh = DEFAULT_CHAT_FRAME:GetFont()
	fh = math.ceil( fh )
	local icon = "\124TInterface\\Addons\\" .. FULLNAME .. "\\icon:" .. fh .. "\124t"
	if ( msg ~= nil ) then
	   if( DEFAULT_CHAT_FRAME ) then
	      DEFAULT_CHAT_FRAME:AddMessage( icon .. " " .. MODNAME .. " : " .. msg, 0.6, 1.0, 1.0 )
	   end
	end
end

function addon.Debug( msg )
	if ( msg ~= nil ) then
		if ( db.options.display.debug ) then
			addon.Print( "DEBUG: " .. msg )
		end
	end
end

-- coloring agents
local function Orange(text)
	return "|cffdea51c" .. text .. "|r"
end

local function White(text)
	return "|cffffffff" .. text .. "|r"
end

local function Yellow(text)
	return "|cffffff00" .. text .. "|r"
end

local function Cyan(text)
	return "|cff00ffff" .. text .. "|r"
end

local function Pink(text)
	return "|cffff8080" .. text .. "|r"
end

local function ClassColor(class_name, class_index)
	-- if class coloring is off, just return white
	if db.options.display.classcolors and class_index ~= "" then
		return "|c" .. _G.RAID_CLASS_COLORS[class_index].colorStr .. class_name .. "|r"
	else
		return White(class_name)
	end
end

local function Shorten( number )
	if ( db.options.display.shortnumbers ) then
		if ( number > 999999 ) then
			return string.format( "%.2fm", ( number / 1000000 ) )
		elseif ( number > 999 ) then
			return string.format( "%.2fk", ( number / 1000 ) )
		end
	end
	return string.format( "%d", number )
end

local function DHMS( secs )
	if ( secs == 0 ) then return L["??"] end
	local days = floor( secs / (60 * 60 * 24) ); secs = secs - ( days * 60 * 60 * 24 )
	local hours = floor( secs / (60 * 60) ); secs = secs - ( hours * 60 * 60 )
	local mins = floor( secs / 60 )
	local retval = ""
	if ( days ~= 0 ) then retval = days .. L["DAY_ABBREV"] end
	if ( hours ~= 0 ) then retval = retval .. hours .. L["HOURS_ABBREV"] end
	if ( mins ~= 0 ) then retval = retval .. mins .. L["MINS_ABBREV"] end
	return retval
end

local function AllXP_PurgeCharacter()
	addon.Debug( "In purge -> " .. addon.selectedToon )
	if ( addon.selectedToon ~= "" ) then
		addon.db.realm[addon.selectedToon] = nil
		addon.Print( string.format( L["Character data for %s purged"], addon.selectedToon ) )
		addon.selectedToon = ""
	end
end

local function HideToon()
	addon.Debug( "In hide -> " .. addon.selectedToon )
	if ( addon.selectedToon ~= "" ) then
		addon.db.realm[addon.selectedToon].options.display.hidden = true
		addon.Print( string.format( L["%s hidden. To unhide, login as that character and unhide in options."],
			addon.selectedToon ) )
		addon.selectedToon = ""
	end
end

-- Added a static popup for confirmation of delete actions...
StaticPopupDialogs["ALLXP_CONFIRM_RESET_DATA"] = {
	text = "",
	button1 = _G.YES,
	button2 = _G.NO,
	OnAccept = function( self )
		AllXP_PurgeCharacter()
		self:Hide()
	end,
	EditBoxOnEscapePressed = function( self )
		self:Hide()
	end,
	timeout = 0,
	exclusive = 1,
	whileDead = 1,
	hideOnEscape = 1
}

local function AllXP_MouseHandler( cell, arg, button )
	addon.Debug( "Received .. " .. arg ) 
	if ( IsAltKeyDown() ) then
		if ( button == "LeftButton" ) then
			-- do resetting stuff
			addon.Debug( "alt-left-click received" )
			addon.selectedToon = arg
			StaticPopupDialogs["ALLXP_CONFIRM_RESET_DATA"].text =
				string.format( L["Purge player data for %s. Are you sure?"], arg )
			StaticPopup_Show( "ALLXP_CONFIRM_RESET_DATA" )
		else 
			-- Right Button
			addon.selectedToon = arg
			HideToon()
		end
	end
end

local function drawTooltip()
	tooltip:Hide()
	tooltip:Clear()

	-- tooltip display code here...

	local dbod = db.options.display
	-- 	Name	Level	CurrXP/MaxXP	XPPerc	RestedXP
	local numcols = 1
	local combinedTime = 0
	local lineNum = 0
	local t = {}
	t[1] = "LEFT"
	if ( dbod.level ) then numcols = numcols + 1; table.insert( t, "CENTER" ) end
	if ( dbod.xpvalues ) then
		numcols = numcols + 3
		table.insert( t, "RIGHT" )
		table.insert( t, "CENTER" )
		table.insert( t, "LEFT" )
	end
	if ( dbod.xppercent ) then numcols = numcols + 1; table.insert( t, "CENTER" ) end
	if ( dbod.session ) then numcols = numcols + 1; table.insert( t, "CENTER" ) end
	if ( dbod.showTP ) then numcols = numcols + 1; table.insert( t, "CENTER" ) end
	if ( dbod.showTPTL ) then numcols = numcols + 1; table.insert( t, "CENTER" ) end
	if ( dbod.rested ) then numcols = numcols + 1; table.insert( t, "RIGHT" ) end
	if ( dbod.showLocation ) then numcols = numcols + 1; table.insert( t, "RIGHT" ) end
	tooltip:SetColumnLayout( numcols, unpack( t ) ) 
	
	tooltip:AddHeader( "a" )
	tooltip:SetCell( 1, 1, MODNAME, "CENTER", numcols )
	tooltip:AddLine( " " )

	-- Title line...
	t = nil; t = {}; t[1] = _G.NAME
	if ( dbod.level ) then table.insert( t, _G.LEVEL ) end
	if ( dbod.xpvalues ) then
		table.insert( t, " " )
		table.insert( t, L["XP"] )
		table.insert( t, " " )
	end
	if ( dbod.xppercent ) then table.insert( t, L["%"] ) end
	if ( dbod.session ) then table.insert( t, L["Session"] ) end
	if ( dbod.showTP ) then table.insert( t, _G.PLAYED ) end
	if ( dbod.showTPTL ) then table.insert( t, L["This Level"] ) end
	if ( dbod.rested ) then table.insert( t, L["Rested"] ) end
	if ( dbod.showLocation ) then table.insert( t, L["Location"] ) end
	tooltip:AddHeader( unpack( t ) ) 
	
	-- sorting on non-numerically keyed tables is for to lol at. Thus, make my own. How sad.
	local dbf = addon.db.realm
	local nDBF = {}

	for k, v in pairs( dbf ) do
		local t = {}
		-- remember, there might be missing elements if thats toon's db is old
		t.name = k
		if ( v.data ) then
			t.class = v.data.class or "PRIEST"
			t.timestamp = v.data.timestamp or 0
			t.level = v.data.level or 0
			t.XPmax = v.data.XPmax or 0
			t.XP = v.data.XP or 0
			t.rested = v.data.rested or 0
			t.totaltime = v.data.totaltime or 0
			t.leveltime = v.data.leveltime or 0
			t.location = v.data.location or L["??"]
			if ( v.options.display ) then
				t.hidden = v.options.display.hidden or false
			else
				t.hidden = false
			end
		else
			t.class = "PRIEST"
			t.timestamp = 0
			t.level = 0
			t.XPmax = 0
			t.XP = 0
			t.rested = 0
			t.totaltime = 0
			t.leveltime = 0
			t.location = L["??"]
			t.hidden = false
		end

		if ( ( db.options.display.excludeMaxLevel == true ) and ( t.level == maxLevel ) ) then 
			-- This toon is max level, and the option is checked to exclude those folks, don't do anything
		else
			if ( t.hidden == true ) then
				-- This toon is marked "hidden", so don't display
			else
				table.insert( nDBF, t )
			end
		end
	end
	-- Sort ...
	if ( db.options.display.sorting == 1 ) then			-- Name
		table.sort( nDBF, function( a, b ) return a.name < b.name end )
	elseif ( db.options.display.sorting == 2 ) then		-- Level
		table.sort( nDBF, function( a, b ) return a.level > b.level end ) 
	elseif ( db.options.display.sorting == 3 ) then		-- Rested
		table.sort( nDBF, function( a, b )
			aPerc = ( a.rested / a.XPmax ) * 100
			if ( a.timestamp ~= 0 ) then aPerc = aPerc + ( ( time() - a.timestamp ) / 5760 ) end
			if ( aPerc > 150 ) then aPerc = 150 end
			bPerc = ( b.rested / b.XPmax ) * 100
			if ( b.timestamp ~= 0 ) then bPerc = bPerc + ( ( time() - b.timestamp ) / 5760 ) end
			if ( bPerc > 150 ) then bPerc = 150 end
			return aPerc > bPerc
		end )
	else												-- Played
		table.sort( nDBF, function( a, b ) return a.totaltime > b.totaltime end )
	end
	for k, v in pairs( nDBF ) do
		t = nil; t = {}
		-- There's extra logic in here because the db versions can still be backrevved. Its unfortunate, but I 
		-- don't really have a nice, clean way around it.
		t[1] = ClassColor( v.name, v.class )

		if ( dbod.level ) then
			if ( v.level ~= 0 ) then
				table.insert( t, Yellow( v.level ) )
			else
				table.insert( t, Yellow( L["??"] ) )
			end
		end

		if ( dbod.xpvalues ) then
			if ( v.XP ~= 0 ) then
				table.insert( t, Cyan( Shorten( v.XP ) ) )
				table.insert( t, Cyan( "/" ) )
				table.insert( t, Cyan( Shorten( v.XPmax ) ) )
			else
				table.insert( t, Cyan( L["??"] ) )
				table.insert( t, Cyan( "/" ) )
				table.insert( t, Cyan( L["??"] ) )
			end
		end

		if ( dbod.xppercent ) then
			if ( v.XPmax ~= 0 ) then
				table.insert( t, Orange( string.format( "%.2f%%", ( ( v.XP / v.XPmax ) * 100 ) ) ) )
			else
				table.insert( t, Orange( L["??"] .. L["%"] ) )
			end
		end

		if ( dbod.session ) then
			if ( v.name == addon.me ) then
				table.insert( t, Cyan( Shorten( ( cachedXP + sessionXP ) ) ) )
			else
				table.insert( t, "" )
			end
		end

		if ( dbod.showTP ) then
			table.insert( t, Yellow( DHMS( v.totaltime ) ) )
			combinedTime = combinedTime + v.totaltime
		end

		if ( dbod.showTPTL ) then
			table.insert( t, Cyan( DHMS( v.leveltime ) ) )
		end

		if ( dbod.rested ) then
			if ( ( v.rested ~= 0 ) and ( v.XPmax ~= 0 ) ) then
				local rPerc = ( v.rested / v.XPmax ) * 100
				if ( v.timestamp ~= 0 ) then
					rPerc = rPerc + ( ( time() - v.timestamp ) / 5760 )
				end
				if ( rPerc > 150 ) then rPerc = 150 end
				table.insert( t, Pink( string.format( "%.1f%%", rPerc ) ) )
			else
				table.insert( t, Pink(  L["??"] .. L["%"] ) ) 
			end
		end
		if ( dbod.showLocation ) then
			table.insert( t, Yellow( v.location ) )
		end
		lineNum = tooltip:AddLine( unpack( t ) )
		tooltip:SetLineScript( lineNum, "OnMouseDown", AllXP_MouseHandler, v.name )
	end

	if ( dbod.showTP and dbod.showTTP ) then
		t = nil; t = {}; t[1] = Yellow( L["Total Played"] )
		if ( dbod.level ) then table.insert( t, " " ) end
		if ( dbod.xpvalues ) then
			table.insert( t, " " )
			table.insert( t, " " )
			table.insert( t, " " )
		end
		if ( dbod.xppercent ) then table.insert( t, " " ) end
		table.insert( t, Yellow( DHMS( combinedTime ) ) )
		if ( dbod.showTPTL ) then table.insert( t, " " ) end
		if ( dbod.rested ) then table.insert( t, " " ) end
		tooltip:AddLine( unpack( t ) ) 
	end
	tooltip:AddLine(" ")
	lineNum = tooltip:AddLine( "b" )
	tooltip:SetCell( lineNum, 1, L["Alt-Left-Click to purge character data"], "LEFT", numcols )
	lineNum = tooltip:AddLine( "b2" )
	tooltip:SetCell( lineNum, 1, L["Alt-Right-Click to hide a character"], "LEFT", numcols )
	lineNum = tooltip:AddLine( "c" )
	tooltip:SetCell( lineNum, 1, L["Click for Configuration"], "LEFT", numcols )
end

-- LDB stuff
local LDB = LibStub( "LibDataBroker-1.1" )
local launcher = LDB:NewDataObject( MODNAME, {
	type = "data source",
	text = "",
	label = FULLNAME,
	icon = "Interface\\Addons\\" .. FULLNAME .. "\\icon",
	OnClick = function( clickedframe, button )
				addon:ShowConfig()
	end,
	OnEnter = function ( self )
		tooltip = LTT:Acquire( MODNAME.."TT", 3, "LEFT", "CENTER", "RIGHT" ) -- or GameTooltip
		tooltip:SetScale( db.options.display.tipscale )
		drawTooltip()
		tooltip:SetAutoHideDelay( .1, self )
		tooltip:EnableMouse()
		tooltip:SmartAnchorTo( self )
		tooltip:Show()
	end,
	OnLeave = function ( self )
		-- autohidedelay should handle hide and release.
		-- keeping a stub here
		return
	end,
} )

local function refreshLauncherText()
	local v = db.data
	local level = v.level or 0
	if ( ( db.options.display.xponbar == true ) and ( level < maxLevel ) ) then
		local xp = v.XP or 0
		local xpmax = v.XPmax or 0
		local dispXP = Shorten( xp )
		local dispXPmax = Shorten( xpmax )
		local rested = v.rested or 0
		local ts = v.timestamp or 0
		local xptext = ""
		local resttext = ""
		-- text split into 2 pieces. XP and rested. Deal with separately 
		if ( xpmax ~= 0 ) then
			if ( db.options.display.xpbarperc == true ) then
				local xpPerc = ( xp / xpmax ) * 100
				xptext = Cyan( string.format( "%.2f%%", xpPerc ) )
			else
				xptext = Cyan( string.format( "%s/%s", dispXP, dispXPmax ) )
			end
			if ( rested == 0 ) then
				resttext = Cyan( "(0%)" )
			else
				local rPerc = ( rested / xpmax ) * 100
				if ( ts ~= 0 ) then
					rPerc = rPerc + ( ( time() - ts ) / 5760 )
				end
				if ( rPerc > 150 ) then rPerc = 150 end
				resttext = Pink( string.format( "(%.1f%%)", rPerc ) )
			end
		else 
			xptext = Yellow( "??/??" )
			resttext = Yellow( "(??)" )
		end
		launcher.text = xptext .. resttext
	else
		launcher.text = ""
	end
end

function addon.upgradeDB()
	local olddb = addon.db.realm[addon.me]
	if ( olddb.options.display.dbVersion == "1.0" ) then
		-- original version
		olddb.data = {}
		olddb.data.level =0
		olddb.data.XP =0
		olddb.data.rested =0
		olddb.data.XPmax =0
		olddb.options.display.dbVersion = "1.1"
		addon.Print( string.format( L["Database upgraded to %s"], "1.1" ) )
	end
	if ( olddb.options.display.dbVersion == "1.1" ) then
		_, olddb.data.class = UnitClass( "player" )
		olddb.options.display.dbVersion = "1.2"
		addon.Print( string.format( L["Database upgraded to %s"], "1.2" ) )
	end
	if ( olddb.options.display.dbVersion == "1.2" ) then
		olddb.data.timestamp = 0
		olddb.options.display.dbVersion = "1.3"
		addon.Print( string.format( L["Database upgraded to %s"], "1.3" ) )
	end
	if ( olddb.options.display.dbVersion == "1.3" ) then
		olddb.options.display.shortnumbers = false
		olddb.options.display.xpvalues = true
		olddb.options.display.xppercent = true
		olddb.options.display.rested = true
		olddb.options.display.classcolors = true
		olddb.options.display.level = true
		olddb.options.display.dbVersion = "1.4"
		addon.Print( string.format( L["Database upgraded to %s"], "1.4" ) )
	end
	if ( olddb.options.display.dbVersion == "1.4" ) then
		olddb.options.display.showTP = false
		olddb.options.display.showTPTL = false
		olddb.data.totaltime = 0
		olddb.data.leveltime = 0
		olddb.options.display.dbVersion = "1.5"
		addon.Print( string.format( L["Database upgraded to %s"], "1.5" ) )
	end
	if ( olddb.options.display.dbVersion == "1.5" ) then
		olddb.options.display.hideTPchat = true
		olddb.options.display.dbVersion = "1.6"
		addon.Print( string.format( L["Database upgraded to %s"], "1.6" ) )
	end
	if ( olddb.options.display.dbVersion == "1.6" ) then
		olddb.options.display.xponbar = false
		olddb.options.display.dbVersion = "1.7"
		addon.Print( string.format( L["Database upgraded to %s"], "1.7" ) )
	end
	if ( olddb.options.display.dbVersion == "1.8" ) then
		olddb.options.display.showLocation = false
		olddb.data.location = ""
		olddb.options.display.dbVersion = "1.9"
		addon.Print( string.format( L["Database upgraded to %s"], "1.9" ) )
	end
	if ( olddb.options.display.dbVersion == "1.9" ) then
		olddb.options.display.xpbarperc = false
		olddb.options.display.dbVersion = "2.0"
		addon.Print( string.format( L["Database upgraded to %s"], "2.0" ) )
	end
	if ( olddb.options.display.dbVersion == "2.0" ) then
		olddb.options.display.hideTPchat = nil
		olddb.options.display.dbVersion = "2.1"
		addon.Print( string.format( L["Database upgraded to %s"], "2.1" ) )
	end
	-- This is a one time check at this version to see if we need to migrate setting from older db
	if ( olddb.options.display.dbVersion == "2.1" ) then
		-- see if we have settings for this toon
		local oldfdb = addon.db.factionrealm[addon.me]
		if ( oldfdb == nil ) then
			-- no old settings to move over. They either already were, or there's nothing to do.
			olddb.options.display.dbVersion = "2.2"
		else
			for k, v in pairs( oldfdb.options.display ) do
				olddb.options.display[k] = v
			end
			olddb.options.display.dbVersion = "2.2"
			addon.db.factionrealm[addon.me] = nil
			addon.Print( string.format( L["Please note: this addon now tracks across factions."] ) )
			addon.Print( string.format( L["Your settings have been migrated."] ) )
			addon.Print( string.format( L["Your other characters will be visible again once you login to each."] ) )
		end
		addon.Print( string.format( L["Database upgraded to %s"], "2.2" ) )
	end
	if ( olddb.options.display.dbVersion == "2.2" ) then
		olddb.options.display.session = true
		olddb.options.display.dbVersion = "2.3"
		addon.Print( string.format( L["Database upgraded to %s"], "2.3" ) )
	end
	if ( olddb.options.display.dbVersion == "2.3" ) then
		olddb.options.display.excludeMaxLevel = false
		olddb.options.display.dbVersion = "2.4"
		addon.Print( string.format( L["Database upgraded to %s"], "2.4" ) )
	end
	if ( olddb.options.display.dbVersion == "2.4" ) then
		-- It is possible that they've already hidden this player from another toon
		if ( olddb.options.display.hidden ) then
			-- yup, they have, do nothing
		else
			olddb.options.display.hidden = false
		end
		olddb.options.display.dbVersion = "2.5"
		addon.Print( string.format( L["Database upgraded to %s"], "2.5" ) )
	end
	if ( olddb.options.display.dbVersion == "2.5" ) then
		olddb.options.display.minimap_icon = nil
		olddb.options.display.minimap_icon = {}
		olddb.options.display.minimap_icon.hide = true
		olddb.options.display.dbVersion = "2.6"
		addon.Print( string.format( L["Database upgraded to %s"], "2.6" ) )
	end
end

local ORIG_ChatFrame_DisplayTimePlayed = ChatFrame_DisplayTimePlayed
local requestingTimePlayed = false

function ChatFrame_DisplayTimePlayed(theFrame, totalTime, levelTime)
	if requestingTimePlayed then
		requestingTimePlayed = false
		addon.Debug( "Total time : " .. totalTime .. " / Level time : " .. levelTime )
		db.data.totaltime = totalTime
		db.data.leveltime = levelTime
		addon.TPscanned = time()
	else
		ORIG_ChatFrame_DisplayTimePlayed(theFrame, totalTime, levelTime)
	end
end

function addon:ZONE_CHANGED( ... )
	db.data.location = GetZoneText()
end

function addon:PLAYER_XP_UPDATE( ... )

	local currLevel = UnitLevel( "player" )
	db.data.level = currLevel
	db.data.rested = GetXPExhaustion() or 0
	db.data.XP = UnitXP( "player" )
	db.data.XPmax = UnitXPMax( "player" )

	if ( startXP == -1 ) then
		startXP = db.data.XP
		lastKnownXP = startXP
		leftToLevel = db.data.XPmax
		savedLevel = db.data.level
		sessionXP = 0
	else
		if ( currLevel == savedLevel ) then
			sessionXP = db.data.XP - startXP
			lastKnownXP = db.data.XP
		else
			savedLevel = currLevel
			sessionXP = sessionXP + ( leftToLevel - lastKnownXP )
			cachedXP = cachedXP + sessionXP
			leftToLevel = db.data.XPmax
			lastKnownXP = db.data.XP
			sessionXP = db.data.XP
			startXP = 0
		end
	end

end

-- Gracefully handle expansions going live while logged-in.
function addon:UPDATE_EXPANSION_LEVEL()
	maxLevel = _G.MAX_PLAYER_LEVEL_TABLE[_G.GetExpansionLevel()]
end

-- options stuff
local displayOptions = nil
local sortOptions = nil
local function giveDisplay()
	if (not displayOptions) then
		displayOptions = {
			order = 2,
			type = "group",
			name = L["Display Options"],
			desc = L["DISPLAY_OPTIONS_DESC"],
			args = {
				header1 = {
					order	= 21,
					type	= "header",
					name	= L["Display Options"],
				},
				desc = {
					order	= 22,
					type	= "description",
					name	= L["DISPLAY_OPTIONS_DESC"],
				},
				xpvalues = {
					order	= 25,
					type	= "toggle",
					name	= L["Display XP Values"],
					desc	= L["DISPLAY_XPVALUES_DESC"],
					get		= function() return db.options.display.xpvalues end,
					set		= function() db.options.display.xpvalues = not db.options.display.xpvalues end,
				},
				xppercent = {
					order	= 26,
					type	= "toggle",
					name	= L["Display XP Percent"],
					desc	= L["DISPLAY_XPPERC_DESC"],
					get		= function() return db.options.display.xppercent end,
					set		= function() db.options.display.xppercent = not db.options.display.xppercent end,
				},
				rested = {
					order	= 27,
					type	= "toggle",
					name	= L["Display Rested XP"],
					desc	= L["DISPLAY_RESTED_DESC"],
					get		= function() return db.options.display.rested end,
					set		= function() db.options.display.rested = not db.options.display.rested end,
				},
				level = {
					order	= 30,
					type	= "toggle",
					name	= L["Display Level"],
					desc	= L["DISPLAY_LEVEL_DESC"],
					get		= function() return db.options.display.level end,
					set		= function() db.options.display.level = not db.options.display.level end,
				},
				session = {
					order	= 31,
					type	= "toggle",
					name	= L["Display Session XP"],
					desc	= L["DISPLAY_SESSION_DESC"],
					get		= function() return db.options.display.session end,
					set		= function() db.options.display.session = not db.options.display.session end,
				},
				timeplayed = {
					order	= 41,
					type	= "toggle",
					name	= L["Display Time Played"],
					desc	= L["DISPLAY_TIMEPLAYED_DESC"],
					get		= function() return db.options.display.showTP end,
					set		= function() db.options.display.showTP = not db.options.display.showTP end,
				},
				levelplayed = {
					order	= 42,
					type	= "toggle",
					name	= L["Display Time This Level"],
					desc	= L["DISPLAY_TIMELEVEL_DESC"],
					get		= function() return db.options.display.showTPTL end,
					set		= function() db.options.display.showTPTL = not db.options.display.showTPTL end,
				},
				totaltimeplayed = {
					order	= 46,
					type	= "toggle",
					name	= L["Display Total Time Played"],
					desc	= L["DISPLAY_TOTALTIMEPLAYED_DESC"],
					get		= function() return db.options.display.showTTP end,
					set		= function() db.options.display.showTTP = not db.options.display.showTTP end,
					disabled = function() return not db.options.display.showTP end,
				},
				showLocation = {
					order	= 47,
					type	= "toggle",
					name	= L["Display Location"],
					desc	= L["DISPLAY_LOCATION_DESC"],
					get		= function() return db.options.display.showLocation end,
					set		= function() db.options.display.showLocation = not db.options.display.showLocation end,
				},
				excludeMaxLevel = {
					order	= 48,
					type	= "toggle",
					name	= L["Exclude Max Level Players"],
					desc	= L["DISPLAY_EXCLUDE_MAXLEVEL_DESC"],
					get		= function() return db.options.display.excludeMaxLevel end,
					set		= function() db.options.display.excludeMaxLevel = not db.options.display.excludeMaxLevel end,
				},
				hidden = {
					order	= 49,
					type	= "toggle",
					name	= L["Hide This Toon"],
					desc	= L["DISPLAY_HIDE_THIS_TOON_DESC"],
					get		= function() return db.options.display.hidden end,
					set		= function() db.options.display.hidden = not db.options.display.hidden end,
				},
				header2 = {
					order	= 101,
					type	= "header",
					name	= L["Tooltip Options"],
				},
				desc2 = {
					order	= 102,
					type	= "description",
					name	= L["TOOLTIP_OPTIONS_DESC"],
				},
				tooltipscale = {
					order	= 103,
					type	= "range",
					name	= L["Tooltip Scale"],
					desc	= L["TOOLTIP_SCALE_DESC"],
					min		= .7,
					max		= 1.3,
					step	= .05,
					bigStep = .05,
					get		= function() return db.options.display.tipscale end,
					set		= function( info, v ) 
								db.options.display.tipscale = v
								tooltip:SetScale( v )
							  end,
				},
				shortnums = {
					order	= 104,
					type	= "toggle",
					name	= L["Enable Short Numbers"],
					desc	= L["DISPLAY_SHORTNUMS_DESC"],
					get		= function() return db.options.display.shortnumbers end,
					set		= function()
						db.options.display.shortnumbers = not db.options.display.shortnumbers
						refreshLauncherText()
					end,
				},
				classcolors = {
					order	= 105,
					type	= "toggle",
					name	= L["Display Class Colors"],
					desc	= L["DISPLAY_CLASSCOLORS_DESC"],
					get		= function() return db.options.display.classcolors end,
					set		= function() db.options.display.classcolors = not db.options.display.classcolors end,
				},
				sorting = {
					order	= 106,
					type	= "select",
					name	= L["Sorting"],
					desc	= L["SORTING_DESC"],
					get		= function() return db.options.display.sorting end,
					set		= function( info, value ) db.options.display.sorting = value end,
					values	= {
						[1] = _G.NAME,
						[2] = _G.LEVEL,
						[3] = L["Rested"],
						[4] = _G.PLAYED,
					},
				},
				header3 = {
					order	= 200,
					type	= "header",
					name	= L["Minimap Icon Options"],
				},
				desc3 = {
					order	= 201,
					type	= "description",
					name	= L["MINIMAP_OPTIONS_DESC"],
				},
				minimap_icon = {
					order	= 202,
					type	= "toggle",
					width	= "full",
					name	= L["Show Minimap Icon"],
					desc	= L["Draws the icon on the minimap."],
					get	= function()
							return not db.options.display.minimap_icon.hide
						  end,
					set	= function(info, value)
							db.options.display.minimap_icon.hide = not value
							  LDBIcon[value and "Show" or "Hide"](LDBIcon, MODNAME)
						  end,
				},
				header4 = {
					order	= 301,
					type	= "header",
					name	= L["Misc Options"],
				},
				desc4 = {
					order	= 302,
					type	= "description",
					name	= L["MISC_OPTIONS_DESC"],
				},
				debugopt = {
					order	= 303,
					type	= "toggle",
					name	= L["Enable DEBUG"],
					desc	= L["DISPLAY_DEBUG_DESC"],
					get		= function() return db.options.display.debug end,
					set		= function() db.options.display.debug = not db.options.display.debug end,
				},
				xponbar = {
					order	= 305,
					type	= "toggle",
					name	= L["Display XP Values on Bar"],
					desc	= L["DISPLAY_BARVALUES_DESC"],
					get		= function() return db.options.display.xponbar end,
					set		= function()
						db.options.display.xponbar = not db.options.display.xponbar
						refreshLauncherText()
					end,
				},
				xpbarperc = {
					order	= 306,
					type	= "toggle",
					name	= L["Bar XP as %"],
					desc	= L["DISPLAY_BARXPPERC_DESC"],
					get		= function() return db.options.display.xpbarperc end,
					set		= function() 
						db.options.display.xpbarperc = not db.options.display.xpbarperc
						refreshLauncherText()
					end,
					disabled	= function() return not db.options.display.xponbar end,
				},

			},
		}
	end
	return displayOptions
end

local function giveSort()
	if (not sortOptions) then
		sortOptions = {
			order = 3,
			type = "group",
			name = L["Sorting Options"],
			desc = L["SORTING_OPTIONS_DESC"],
			args = {
				header1 = {
					order	= 31,
					type	= "header",
					name	= L["Sorting Options"],
				},
				desc = {
					order	= 32,
					type	= "description",
					name	= L["SORTING_OPTIONS_DESC"],
				},
				sName = {
					order	= 33,
					type	= "toggle",
					name	= L["Sort by Name"],
					desc	= L["SORT_NAME_DESC"],
					get		= function() return db.options.display.debug end,
					set		= function() db.options.display.debug = not db.options.display.debug end,
				},
				sLevel = {
					order	= 34,
					type	= "toggle",
					name	= L["Sort by Level"],
					desc	= L["SORT_LEVEL_DESC"],
					get		= function() return db.options.display.classcolors end,
					set		= function() db.options.display.classcolors = not db.options.display.classcolors end,
				},
				sRested = {
					order	= 35,
					type	= "toggle",
					name	= L["Sort by Rested XP"],
					desc	= L["SORT_RESTED_DESC"],
					get		= function() return db.options.display.level end,
					set		= function() db.options.display.level = not db.options.display.level end,
				},
			},
		}
	end
	return displayOptions
end

local options = nil
local function fullOptions()
	if (not options) then
		options = {
			type = "group",
			name = MODNAME,
			args = {
				general = {
					order	= 1,
					type	= "group",
					name	= L["General Information"],
					desc	= L["GENERAL_INFO_DESC"],
					args	= {
						header1 = {
							order	= 11,
							type	= "header",
							name	= L["General Information"],
						},
						desc = {
							order	= 12,
							type	= "description",
							name	= L["GENERAL_INFO_DESC"],
						},
						author = {
							order	= 13,
							type	= "description",
							name	= L["Author : "] .. addonauthor .. "\n",
						},
						version = {
							order	= 14,
							type	= "description",
							name	= L["Version : "] .. addonversion .. "\n",
						},
						builddate = {
							order	= 15,
							type	= "description",
							name	= L["Build Date : "] .. builddate .. "\n",
						},
						dbversion = {
							order	= 15,
							type	= "description",
							name	= L["Database Version : "] .. db.options.display.dbVersion .. "\n",
						},
						translators = {
							order	= 16,
							type	= "description",
							name	= string.format( L["Helpful Translators (thank you) : %s"],
											"lastdans (frFR), Freydiss88 (deDE), next96(koKR)," ..
											"xska(ruRU), tnt2ray(zhCN), yllelder (esES)," ..
											"andy52005(zhTW)" .. "\n" )
						},
					},
				},
			},
		}
	end
	
	for k,v in pairs(modularOptions) do
		options.args[k] = (type(v) == "function") and v() or v
	end

	return options
end

function addon:SetupOptions()
	AceConfigReg:RegisterOptionsTable(MODNAME, fullOptions)
	self.optionsFrame = AceConfigDialog:AddToBlizOptions(MODNAME, nil, nil, "general")

	-- Fill up our modular options...
	self:RegisterModuleOptions("Display", giveDisplay(), L["Display Options"])
end

function addon:RegisterModuleOptions(name, optionsTable, displayName)
	modularOptions[name] = optionsTable
	self.optionsFrame[name] = AceConfigDialog:AddToBlizOptions(MODNAME, displayName, MODNAME, name)
end

function addon:ShowConfig()
	-- Open the profiles tab before, so the menu expands
	InterfaceOptionsFrame_OpenToCategory( self.optionsFrame["Display"] )
end

function addon.startScanning()
	local totalElapsed = 0

	if ( not AllXP_ScannerFrame ) then
		AllXP_ScannerFrame = CreateFrame( "Frame" )
	end

	AllXP_ScannerFrame:SetScript( "OnUpdate", function(self, elapsed)
		totalElapsed = totalElapsed + elapsed
		-- update once every 30 seconds. I may change this later
		if ( ( totalElapsed < 2 ) and ( haveFired == false ) ) then
			haveFired = true
			-- update our current db values
			local currLevel = UnitLevel( "player" )
			db.data.level = currLevel
			db.data.rested = GetXPExhaustion() or 0
			db.data.XP = UnitXP( "player" )
			db.data.XPmax = UnitXPMax( "player" )

			if ( startXP == -1 ) then
				startXP = db.data.XP
				lastKnownXP = startXP
				leftToLevel = db.data.XPmax
				savedLevel = db.data.level
				sessionXP = 0
			else
				if ( currLevel == savedLevel ) then
					sessionXP = db.data.XP - startXP
					lastKnownXP = db.data.XP
				else
					savedLevel = currLevel
					sessionXP = sessionXP + ( leftToLevel - lastKnownXP )
					cachedXP = cachedXP + sessionXP
					leftToLevel = db.data.XPmax
					lastKnownXP = db.data.XP
					sessionXP = db.data.XP
					startXP = 0
				end
			end

			db.data.timestamp = time()
			_, db.data.class = UnitClass( "player" )
			db.data.totaltime = db.data.totaltime + ( time() - addon.TPscanned )
			db.data.leveltime = db.data.leveltime + ( time() - addon.TPscanned )
			db.data.location = GetZoneText()
			addon.TPscanned = time()

			refreshLauncherText()
		elseif ( totalElapsed > 30 ) then
			totalElapsed = 0
			haveFired = false
		end
	end )
end

function addon:OnInitialize()
	-- Do Frame Creation stuff here
	-- addon:CreateFrames()
end

function addon:OnEnable()
    -- Called when the addon is loaded
	addon.me = UnitName( "player" )

	self.db = LibStub( "AceDB-3.0" ):New( MODNAME .. "_DB", nil, "Default" )
	-- do we have any data yet; for this toon? If not, init its table
	if not ( self.db.realm[addon.me] ) then
		self.db.realm[addon.me] = {
		-- Your saved variables stuff here
			options = {
				display = {
					debug = false,
					tipscale = 1,
					dbVersion = "2.6",
					shortnumbers = false,
					xpvalues = true,
					xppercent = true,
					rested = true,
					classcolors = true,
					level = true,
					showTP = false,
					showTPTL = false,
					sorting = 3,
					xponbar = false,
					xpbarperc = false,
					showTTP = false,
					showLocation = false,
					excludeMaxLevel = false,
					hidden = false,
					minimap_icon = {
						hide = true,
					}
				},
			},
			data = {
				class = "",
				level = 0,
				XP = 0,
				rested = 0,
				XPmax = 0,
				timestamp = 0,
				totaltime = 0,
				leveltime = 0,
				location = "",
			},
		}
	end
	-- check if we need to upgrade the db
	addon.upgradeDB()
	db = self.db.realm[addon.me]

	addon:SetupOptions()
	-- Event listeners
    -- addon:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
	addon:RegisterEvent("ZONE_CHANGED")
	addon:RegisterEvent("PLAYER_XP_UPDATE")
	addon:RegisterEvent("UPDATE_EXPANSION_LEVEL")
	requestingTimePlayed = true
	RequestTimePlayed()

	-- Kick off our onupdate frame to start watching our XP
	addon.startScanning()
	
	-- libdbicon stuff
	if LDBIcon then
		LDBIcon:Register( MODNAME, launcher, db.options.display.minimap_icon )
	end
	
end

--[[
************************************************************************
CHANGELOG:
4/27/11 :
	TOC bump
	added LibDBIcon
4/5/11 :
	Added "hidden" flag per toon
	Setting it to true will hide this toon from the display of all toons
09/11/10 :
	bump TOC (and add X-Compatible-With for Cata)
	fixed ChatFrame_DisplayTimePlayed stuff (thanks mscottforbes)
	changing from factionrealm to realm (Ticket 8)
	adding session gains
08/08/09 :
	bumped TOC
	added alt-click to purge data from SV
	cleaned up display options
	fix ?? rested xp thing
	enable percentage display on LDB bar
03/18/09 :
	add in code to show XP/MaxXP(rested) on LDB bar
	added totals time played line to tooltip
	added zhTW (thanks andy52005)
	changed libqtip path 
12/06/08 : 
	Initial version
************************************************************************
]]--