PUI = LibStub("AceAddon-3.0"):NewAddon("PowerUI", "AceConsole-3.0", "AceEvent-3.0")
login = true
local PUI_DEFAULTS = {
	profile = {
		UnitFrames = {
			player = {
				x = 5,
				y = -10,
				ref = "TOPLEFT",
				scale = 1
			},
			target = {
				x = 275,
				y = -10,
				ref = "TOPLEFT",
				scale = 1
			},
			focus = {
				x = 275,
				y = -300,
				ref = "TOPLEFT",
				scale = 1
			},
			party = {
				x = 5,
				y = 50,
				ref = "LEFT",
				scale = 1.3
			},
			classIcons = true,
			classColors = true
		},
		ActionBars = {
			modify = true,
			macroText = true,
			CastBar = {
				x = 0,
				y = 250,
				ref = "BOTTOM",
				scale = 1
			},
			rangeIndicator = true
		},
		chat = true,
		fps = false
	}
}

function PUI:isColorsActive()
	return self.db.profile.UnitFrames.classColors;
end

function PUI:RefreshConfig()
	PUI:PLAYER_ENTERING_WORLD();
end

function PUI:OnInitialize()
	self.db = LibStub("AceDB-3.0"):New("PUIDB", PUI_DEFAULTS)
	self.db.RegisterCallback(self, "OnProfileChanged", "RefreshConfig")
	self.db.RegisterCallback(self, "OnProfileCopied", "RefreshConfig")
	self.db.RegisterCallback(self, "OnProfileReset", "RefreshConfig")
	
	local options = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
	LibStub("AceConfig-3.0"):RegisterOptionsTable("PowerUI", options)
	self.optionsFrame = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("PowerUI", "PowerUI")
	self:RegisterChatCommand("PUI", "ChatCommand")
	self:RegisterChatCommand("PowerUI", "ChatCommand")
	
	PUI:Print("loaded.")
end

function PUI:OnEnable()
	self:RegisterEvent("PLAYER_ENTERING_WORLD")
end

function PUI:OnDisable()
	ReloadUI()
end

function PUI:PLAYER_ENTERING_WORLD()
	hooksecurefunc("PlayerFrame_SetLocked", function()
		local point, relativeTo, relativePoint, xOffset, yOffset = PlayerFrame:GetPoint()
		local DB = self.db.profile.UnitFrames.player
		DB.x = xOffset
		DB.y = yOffset
		DB.ref = point
	end)
	hooksecurefunc("TargetFrame_SetLocked", function()
		local point, relativeTo, relativePoint, xOffset, yOffset = TargetFrame:GetPoint()
		local DB = self.db.profile.UnitFrames.target
		DB.x = xOffset
		DB.y = yOffset
		DB.ref = point
	end)
	hooksecurefunc("FocusFrame_SetLock", function()
		local point, relativeTo, relativePoint, xOffset, yOffset = FocusFrame:GetPoint()
		local DB = self.db.profile.UnitFrames.focus
		DB.x = xOffset
		DB.y = yOffset
		DB.ref = point
	end)
	
	-- START UPDATE FRAME POSITIONS	
	local function PlayerSetPosition()
		local point, relativeTo, relativePoint, xOffset, yOffset = PlayerFrame:GetPoint();
		self.db.profile.UnitFrames.player.x = xOffset;
		self.db.profile.UnitFrames.player.y = yOffset;
		self.db.profile.UnitFrames.player.ref = point;
	end
	
	local function TargetSetPosition()
		local point, relativeTo, relativePoint, xOffset, yOffset = TargetFrame:GetPoint();
		self.db.profile.UnitFrames.target.x = xOffset;
		self.db.profile.UnitFrames.target.y = yOffset;
		self.db.profile.UnitFrames.target.ref = point;
	end
	
	local function FocusSetPosition()
		local point, relativeTo, relativePoint, xOffset, yOffset = FocusFrame:GetPoint();
		self.db.profile.UnitFrames.focus.x = xOffset;
		self.db.profile.UnitFrames.focus.y = yOffset;
		self.db.profile.UnitFrames.focus.ref = point;
	end
	-- END UPDATE FRAME POSITIONS
	
	local DB = self.db.profile.UnitFrames
	PlayerFrame:SetMovable(true)
	PlayerFrame:SetUserPlaced(true)
	PlayerFrame:ClearAllPoints()
	PlayerFrame:SetPoint(DB.player.ref, UIParent, DB.player.ref, DB.player.x, DB.player.y)
	PlayerFrame:SetScale(DB.player.scale)
	hooksecurefunc("PlayerFrame_Update", PlayerSetPosition);
	hooksecurefunc("TargetFrame_Update", TargetSetPosition);
	
	TargetFrame:SetMovable(true)
	TargetFrame:SetUserPlaced(true)
	TargetFrame:ClearAllPoints()
	TargetFrame:SetPoint(DB.target.ref, UIParent, DB.target.ref, DB.target.x, DB.target.y)
	TargetFrame:SetScale(DB.target.scale)
	TargetFrameToT:ClearAllPoints()
	TargetFrameToT:SetPoint("BOTTOMRIGHT",TargetFrame,-15,-10)
	
	FocusFrame:ClearAllPoints()
	FocusFrame:SetPoint(DB.focus.ref, UIParent, DB.focus.ref, DB.focus.x, DB.focus.y)
	FocusFrame:SetScale(DB.focus.scale)
	FocusFrameToT:ClearAllPoints()
	FocusFrameToT:SetPoint("BOTTOMRIGHT",FocusFrame,-15,-10)
	
	if self.db.profile.ActionBars.modify == true then
		ActionBarUpButton:Hide()
		ActionBarDownButton:Hide()
		MainMenuBarPageNumber:Hide()
		MainMenuBarLeftEndCap:Hide()
		MainMenuBarRightEndCap:Hide()
		MainMenuBarMaxLevelBar:Hide()
		for i=2,3 do _G["MainMenuBarTexture"..i]:Hide() end
		for i=2,3 do _G["MainMenuMaxLevelBar"..i]:Hide() end
		
		MainMenuBar:RegisterEvent("PLAYER_EXITING_VEHICLE")
		MultiBarBottomLeft:RegisterEvent("PLAYER_EXITING_VEHICLE")
		MultiBarBottomRight:RegisterEvent("PLAYER_EXITING_VEHICLE")
		
		MainMenuBar:SetMovable(true)
		MainMenuBar:SetUserPlaced(true)
		MainMenuBar:ClearAllPoints()
		MainMenuBar:SetPoint("BOTTOMLEFT", UIParent, "BOTTOM", -250, 35)
		CharacterMicroButton:SetMovable(true)
		CharacterMicroButton:SetUserPlaced(true)
		CharacterMicroButton:ClearAllPoints()
		CharacterMicroButton:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -350, 15)
		MainMenuBarBackpackButton:ClearAllPoints()
		MainMenuBarBackpackButton:SetPoint("BOTTOMRIGHT", MainMenuMicroButton, "TOPRIGHT", -3, -15)
		hooksecurefunc("MainMenuBar_OnEvent", function(self, event, ...)
			if event == "PLAYER_EXITING_VEHICLE" and not InCombatLockdown() then
				self:ClearAllPoints()
				self:SetPoint("BOTTOMLEFT", UIParent, "BOTTOM", -250, 35)
				MainMenuBarBackpackButton:ClearAllPoints()
				MainMenuBarBackpackButton:SetPoint("BOTTOMRIGHT", MainMenuMicroButton, "TOPRIGHT", -3, -15)
			end
		end)
				
		MultiBarBottomLeft:SetMovable(true)
		MultiBarBottomLeft:SetUserPlaced(true)
		MultiBarBottomLeft:ClearAllPoints()
		BotLeftYOffset = 17
		if ReputationWatchBar:IsShown() == true then
			BotLeftYOffset = 27
		end
		MultiBarBottomLeft:SetPoint("BOTTOMLEFT", ActionButton1, "TOPLEFT", 0, BotLeftYOffset)
		MultiBarBottomLeft:SetFrameStrata("BACKGROUND")
		local function MultiBar1Event(self, event, ...)
			if event == "PLAYER_EXITING_VEHICLE" and not InCombatLockdown() then
				self:ClearAllPoints()
				self:SetPoint("BOTTOMLEFT", ActionButton1, "TOPLEFT", 0, BotLeftYOffset)
			end
		end
		MultiBarBottomLeft:HookScript("OnEvent", MultiBar1Event)
				
		MultiBarBottomRight:SetMovable(true)
		MultiBarBottomRight:SetUserPlaced(true)
		MultiBarBottomRight:ClearAllPoints()
		MultiBarBottomRight:SetPoint("BOTTOM",MultiBarBottomLeft,"TOP",0,5)
		MultiBarBottomRight:SetFrameStrata("BACKGROUND")
		local function MultiBar2Event(self, event, ...)
			if event == "PLAYER_EXITING_VEHICLE" and not InCombatLockdown() then
				self:ClearAllPoints()
				self:SetPoint("BOTTOM",MultiBarBottomLeft,"TOP",0,5)
			end
		end
		MultiBarBottomRight:HookScript("OnEvent", MultiBar2Event)
				
					-- Pet Bars
		PetActionBarFrame:SetMovable(true)
		PetActionBarFrame:SetUserPlaced(true)
		PetActionBarFrame:ClearAllPoints()
		PetActionBarFrame:SetPoint("BOTTOMLEFT", MultiBarBottomRightButton2, "TOPLEFT", -15, 7)
		--PetActionBarFrame.SetPoint = function() end
		local function PetBarUpdate(self, event, ...)
			if not InCombatLockdown() then
				self:ClearAllPoints()
				self:SetPoint("BOTTOMLEFT", MultiBarBottomRightButton2, "TOPLEFT", -15, 7)
			end
		end
		PetActionBarFrame:HookScript("OnEvent", PetBarUpdate)
				
					-- Stance Bars
		StanceBarFrame:SetMovable(true)
		StanceBarFrame:SetUserPlaced(true)
		StanceBarFrame:ClearAllPoints()
		StanceBarFrame:SetPoint("BOTTOM", PetActionButton1, "TOP", 0, 7)
		StanceBarFrame:SetFrameStrata("BACKGROUND")
		local function StanceBarEvent(self, event, ...)
			if not InCombatLockdown() then
				StanceBarFrame:SetPoint("BOTTOM", PetActionButton1, "TOP", 0, 7)
				StanceBarFrame:SetFrameStrata("BACKGROUND")
			end
		end
		StanceBarFrame:HookScript("OnEvent", StanceBarEvent);
				
					-- Exp and Rep bars
		for i = 1, 19 do
			if i%2 == 0 then
				_G["MainMenuXPBarDiv"..i]:ClearAllPoints();
				_G["MainMenuXPBarDiv"..i]:SetPoint("LEFT", MainMenuExpBar, "LEFT", (25*i)-4, 0);
			else
				_G["MainMenuXPBarDiv"..i]:Hide();
			end
		end
		ExhaustionLevelFillBar:Hide()
		MainMenuExpBar:SetMovable(true)
		MainMenuExpBar:SetUserPlaced(true)
		MainMenuExpBar:SetWidth(500)
		MainMenuExpBar:ClearAllPoints()
		--MainMenuXPBarTextureMid:SetHeight(25)
		MainMenuExpBar:SetPoint("BOTTOM", MainMenuBar, "TOP", -256, -10)
		if login == true then
			ReputationWatchBar:SetMovable(true)
			ReputationWatchBar:SetUserPlaced(true)
			ReputationWatchBar:SetWidth(500)
			ReputationWatchBar:ClearAllPoints()
			ReputationWatchBar:SetPoint("BOTTOM", MainMenuExpBar, "TOP", 0, 3)
			--ReputationWatchStatusBar:SetMovable(true)
			--ReputationWatchStatusBar:SetUserPlaced(true)
			--ReputationWatchStatusBar:SetWidth(500)
			--ReputationXPBarTexture0:SetWidth(251)
			--ReputationXPBarTexture1:SetWidth(250)
			--ReputationXPBarTexture2:SetAlpha(0)
			--ReputationXPBarTexture3:SetAlpha(0)
			ReputationWatchBar.SetPoint = function() end
		end
		--ReputationWatchStatusBar:SetHeight(10)
		--ReputationWatchStatusBar.SetHeight = function() end
		local function RepShow(self)
			MultiBarBottomLeft:SetPoint("BOTTOMLEFT", ActionButton1, "TOPLEFT", 0, 27)
		end
		ReputationWatchBar:HookScript("OnShow", RepShow)
		local function RepHide(self)
			MultiBarBottomLeft:SetPoint("BOTTOMLEFT", ActionButton1, "TOPLEFT", 0, 17)
		end
		ReputationWatchBar:HookScript("OnHide", RepHide)
		
		-- temp fix lel
		HonorWatchBar.StatusBar:Hide()
		local function ArtifactUpdate(self)
			ArtifactWatchBar:SetMovable(true)
			ArtifactWatchBar:SetUserPlaced(true)
			ArtifactWatchBar:SetWidth(500)
			ArtifactWatchBar:ClearAllPoints()
			ArtifactWatchBar:SetPoint("TOP", MainMenuBar, "BOTTOM", -256, 0)
			ArtifactWatchBar.StatusBar:SetMovable(true)
			ArtifactWatchBar.StatusBar:SetUserPlaced(true)
			ArtifactWatchBar.StatusBar:SetWidth(500)
			ArtifactWatchBar.StatusBar:SetHeight(10)
			ArtifactWatchBar.StatusBar.WatchBarTexture0:SetWidth(251) -- for loop utilizing _G[...] didn't work
			ArtifactWatchBar.StatusBar.WatchBarTexture1:SetWidth(250)
			ArtifactWatchBar.StatusBar.WatchBarTexture2:SetAlpha(0) -- Neither Hide() nor SetWidth(0) works
			ArtifactWatchBar.StatusBar.WatchBarTexture3:SetAlpha(0)
			ArtifactWatchBar.StatusBar.XPBarTexture0:SetWidth(251) -- Gets renamed at level 110?
			ArtifactWatchBar.StatusBar.XPBarTexture1:SetWidth(250)
			ArtifactWatchBar.StatusBar.XPBarTexture2:SetAlpha(0)
			ArtifactWatchBar.StatusBar.XPBarTexture3:SetAlpha(0)
		end
		ArtifactWatchBar:HookScript("OnUpdate", ArtifactUpdate)
		
		-- Out of Range full-icon coloration
		if self.db.profile.ActionBars.rangeIndicator == true then
		hooksecurefunc("ActionButton_OnEvent",function(self, event, ...)
			if ( event == "PLAYER_TARGET_CHANGED" ) then
				self.newTimer = self.rangeTimer
			end
		end)

		hooksecurefunc("ActionButton_UpdateUsable",function(self)
			local icon = self.icon
			local valid = IsActionInRange(self.action)
			if ( valid == false ) then
				icon:SetVertexColor(1.0, 0.1, 0.1)
			end
		end)

		hooksecurefunc("ActionButton_OnUpdate",function(self, elapsed)
			local rangeTimer = self.newTimer
			if ( rangeTimer ) then
				rangeTimer = rangeTimer - elapsed
				if ( rangeTimer <= 0 ) then
					ActionButton_UpdateUsable(self)
					rangeTimer = TOOLTIP_UPDATE_TIME
				end
				self.newTimer = rangeTimer
			end
		end)
		end
		
		ExtraActionButton1:SetMovable(true);
		ExtraActionButton1:SetUserPlaced(true);
		ExtraActionButton1:ClearAllPoints()
		ExtraActionButton1:SetPoint("BOTTOM", StanceBarFrame, "TOP", 0, 5)
		local function EABUpdate(self, event, ...)
			if not InCombatLockdown() then
				ExtraActionButton1:ClearAllPoints()
				ExtraActionButton1:SetPoint("BOTTOM", StanceBarFrame, "TOP", 0, 5)
			end
		end
		ExtraActionButton1:HookScript("OnEvent", EABUpdate)
		
		-- Cast Bar -----------------------------
		DB = self.db.profile.ActionBars.CastBar
		CastingBarFrame:SetMovable(true)
		CastingBarFrame:SetUserPlaced(true)
		CastingBarFrame:ClearAllPoints()
		CastingBarFrame:SetPoint(DB.ref, UIParent, DB.ref, DB.x, DB.y)
		hooksecurefunc("CastingBarFrame_OnUpdate",function()
			if (CastingBarFrame.casting) then
				CastingBarFrame:ClearAllPoints()
				CastingBarFrame:SetPoint(DB.ref, UIParent, DB.ref, DB.x, DB.y)
			end
		end)
		
		if self.db.profile.ActionBars.macroText == false then
			for i=1,12 do _G["ActionButton"..i.."Name"]:SetAlpha(0) _G["MultiBarBottomRightButton"..i.."Name"]:SetAlpha(0) _G["MultiBarBottomLeftButton"..i.."Name"]:SetAlpha(0) _G["MultiBarRightButton"..i.."Name"]:SetAlpha(0) _G["MultiBarLeftButton"..i.."Name"]:SetAlpha(0) end
		end
	end
	
	if self.db.profile.UnitFrames.classIcons == true then
		hooksecurefunc("UnitFramePortrait_Update", function(self)
			if self.portrait and UnitIsPlayer(self.unit) and self.unit ~= "player" and self.unit ~= "pet" and self.unit ~= nil then
				local t = CLASS_ICON_TCOORDS[select(2, UnitClass(self.unit))]
				if t then
					self.portrait:SetTexture("Interface\\TargetingFrame\\UI-Classes-Circles")
					self.portrait:SetTexCoord(unpack(t))
				end
			else
				if self.portrait ~= nil then
					SetPortraitTexture(self.portrait, self.unit)
					self.portrait:SetTexCoord(0,1,0,1)
				end
			end
		end)
		
	end
	
	if self.db.profile.chat == true then
		for i=1,NUM_CHAT_WINDOWS do _G["ChatFrame"..i]:SetFont("Fonts\\ARIALN.TTF",15,"OUTLINE")end
		hooksecurefunc("FloatingChatFrame_Update",function(id, ...)
			_G["ChatFrame"..id]:SetFont("Fonts\\ARIALN.TTF",15,"OUTLINE")
		end)
	end
	
	Minimap:EnableMouseWheel(true)
	Minimap:SetScript('OnMouseWheel', function(self, delta)
		if delta > 0 then
			Minimap_ZoomIn()
		else
			Minimap_ZoomOut()
		end
	end)
	
	local DB = PUI.db.profile.UnitFrames.party
	for i=1,4 do _G["PartyMemberFrame"..i]:ClearAllPoints() end
	PartyMemberFrame1:SetPoint(DB.ref,UIParent,DB.ref,DB.x,DB.y)
	PartyMemberFrame2:SetPoint(DB.ref,UIParent,DB.ref,DB.x,DB.y-70)
	PartyMemberFrame3:SetPoint(DB.ref,UIParent,DB.ref,DB.x,DB.y-140)
	PartyMemberFrame4:SetPoint(DB.ref,UIParent,DB.ref,DB.x,DB.y-210)
	for i=1,4 do _G["PartyMemberFrame"..i]:SetScale(DB.scale) end
	for i=1,4 do _G["PartyMemberFrame"..i.."PetFrame"]:SetAlpha(0) end
	hooksecurefunc("PartyMemberFrame_UpdatePet", function(...)
		for i=1,4 do _G["PartyMemberFrame"..i.."PetFrame"]:SetAlpha(0) end
	end)
	
	FramerateLabel:ClearAllPoints();
	FramerateLabel:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", 5, 5);
	if (self.db.profile.fps) then
		ToggleFramerate()
	end
	
	
	PlayerFrameManaBar.FeedbackFrame:Hide()
	login = false;
end

function PUI:ChatCommand(input)
	if (input == "gui") then
		if not InCombatLockdown() then
			curProfile = self.db:GetCurrentProfile()
			PUI_OpenConfig(self, curProfile)
		else
			PUI:Print("Cannot open options during combat")
		end
	elseif (input == "profile") then
		InterfaceOptionsFrame_OpenToCategory("PowerUI");
		InterfaceOptionsFrame_OpenToCategory("PowerUI");
	elseif (input == "fps") then
		self.db.profile.fps = not self.db.profile.fps
		ToggleFramerate();
	else
		PUI:Print("Commands available:\r\124cffff00ff/pui gui\124r  ::  Opens the settings menu\r\124cffff00ff/pui profile\124r  ::  Opens the menu for chagning, resetting, and copying profiles\r\124cffff00ff/pui fps\124r  ::  Shows FPS counter at bottom left of screen");
	end
end