CT_Viewport = {
	["initialValues"] = {
		[1] = 563,
		[2] = 937, 
		[3] = 736,
		[4] = 455,
		[5] = 375,
		[6] = 281
	},
	["currOffset"] = {
		0, 0, 0, 0
	}
};
CT_Viewport_Saved = { 0, 0, 0, 0, 0, 0, 0 };

-- Not going to bother adding a localization file :)
CT_VIEWPORT_INFO = "Note: |c00FFFFFFLeft click and drag a yellow bar to move the viewport screen.  To enter a custom value, type in the number and hit enter to set it, then click apply to see your changes.|r";
if ( GetLocale() == "deDE" ) then
	CT_VIEWPORT_INFO = "Note: |c00FFFFFFLeft click and drag a yellow bar to move the viewport screen.  To enter a custom value, type in the number and hit enter to set it, then click apply to see your changes.|r";
elseif ( GetLocale() == "frFR" ) then
	CT_VIEWPORT_INFO = "Note: |c00FFFFFFLeft click and drag a yellow bar to move the viewport screen. To enter a custom value, type in the number and hit enter to set it, then click apply to see your changes.|r";
end

function CT_Viewport_GetQuotient(number)
	number = format("%.2f", number);
	
	for a = 1, 100, 1 do
		for b = 1, 100, 1 do
			if ( format("%.2f", b/a) == number ) then
				return format("%.2f |r(|c00FFFFFF%d/%d|r)", number, b, a);
			elseif ( format("%.2f", a/b) == number ) then
				return format("%.2f r(|c00FFFFFF%d/%d|r)", number, a, b);
			end
		end 
	end
	return number;
end

-- Add to special frames table
tinsert(UISpecialFrames, "CT_ViewportFrame");

-- Slash command to display the frame
SlashCmdList["VIEWPORT"] = function(msg)
	local iStart, iEnd, left, right, top, bottom = string.find(msg, "^(%d+) (%d+) (%d+) (%d+)$");
	if ( left and right and top and bottom ) then
		CT_Viewport_ApplyViewport(tonumber(left), tonumber(right), tonumber(top), tonumber(bottom));
	else
		ShowUIPanel(CT_ViewportFrame);
	end
end
SLASH_VIEWPORT1 = "/viewport";

-- Resizing functions
function CT_Viewport_Resize(anchorPoint, button)
	if ( not button ) then
		button = this;
	end
	button:GetParent():StartSizing(anchorPoint);
	CT_Viewport.isResizing = anchorPoint;
	
	-- A bit hackish, but meh, it works
	if ( anchorPoint == "LEFT" ) then
		button:GetParent():SetMaxResize(CT_Viewport.initialValues[5]-(CT_Viewport.initialValues[2]-CT_ViewportFrameInnerFrame:GetRight()), CT_Viewport.initialValues[6]);
	elseif ( anchorPoint == "RIGHT" ) then
		button:GetParent():SetMaxResize(CT_Viewport.initialValues[5]-(CT_ViewportFrameInnerFrame:GetLeft()-CT_Viewport.initialValues[1]), CT_Viewport.initialValues[6]);
	elseif ( anchorPoint == "TOP" ) then
		button:GetParent():SetMaxResize(CT_Viewport.initialValues[5], CT_Viewport.initialValues[6]-(CT_ViewportFrameInnerFrame:GetBottom()-CT_Viewport.initialValues[4]));
	elseif ( anchorPoint == "BOTTOM" ) then
		button:GetParent():SetMaxResize(CT_Viewport.initialValues[5], CT_Viewport.initialValues[6]-(CT_Viewport.initialValues[3]-CT_ViewportFrameInnerFrame:GetTop()));
	elseif ( anchorPoint == "TOPLEFT" ) then
		button:GetParent():SetMaxResize(CT_Viewport.initialValues[5]-(CT_Viewport.initialValues[2]-CT_ViewportFrameInnerFrame:GetRight()), CT_Viewport.initialValues[6]-(CT_ViewportFrameInnerFrame:GetBottom()-CT_Viewport.initialValues[4]));
	elseif ( anchorPoint == "TOPRIGHT" ) then
		button:GetParent():SetMaxResize(CT_Viewport.initialValues[5]-(CT_ViewportFrameInnerFrame:GetLeft()-CT_Viewport.initialValues[1]), CT_Viewport.initialValues[6]-(CT_ViewportFrameInnerFrame:GetBottom()-CT_Viewport.initialValues[4]));
	elseif ( anchorPoint == "BOTTOMLEFT" ) then
		button:GetParent():SetMaxResize(CT_Viewport.initialValues[5]-(CT_Viewport.initialValues[2]-CT_ViewportFrameInnerFrame:GetRight()), CT_Viewport.initialValues[6]-(CT_Viewport.initialValues[3]-CT_ViewportFrameInnerFrame:GetTop()));
	elseif ( anchorPoint == "BOTTOMRIGHT" ) then
		button:GetParent():SetMaxResize(CT_Viewport.initialValues[5]-(CT_ViewportFrameInnerFrame:GetLeft()-CT_Viewport.initialValues[1]), CT_Viewport.initialValues[6]-(CT_Viewport.initialValues[3]-CT_ViewportFrameInnerFrame:GetTop()));
	end
end

function CT_Viewport_StopResize(button)
	if ( not button ) then
		button = this;
	end
	button:GetParent():StopMovingOrSizing();
	CT_Viewport.isResizing = nil;
	CT_ViewportFrameAspectRatioNewText:SetText("Aspect Ratio (Current): |c00FFFFFF" .. CT_Viewport_GetQuotient((CT_Viewport.screenRes[1]-CT_Viewport.currOffset[1]-CT_Viewport.currOffset[2])/(CT_Viewport.screenRes[2]-CT_Viewport.currOffset[3]-CT_Viewport.currOffset[4])));
	CT_ViewportFrameAspectRatioDefaultText:SetText("Aspect Ratio (Default): |c00FFFFFF" .. CT_Viewport_GetQuotient(CT_Viewport.screenRes[1]/CT_Viewport.screenRes[2]));
end

-- Get initial size values
function CT_Viewport_GetInitialValues()
	CT_Viewport.initialValues = {
		CT_ViewportFrameInnerFrame:GetLeft(),
		CT_ViewportFrameInnerFrame:GetRight(),
		CT_ViewportFrameInnerFrame:GetTop(),
		CT_ViewportFrameInnerFrame:GetBottom(),
		CT_ViewportFrameInnerFrame:GetRight()-CT_ViewportFrameInnerFrame:GetLeft(),
		CT_ViewportFrameInnerFrame:GetTop()-CT_ViewportFrameInnerFrame:GetBottom()
	};
end

-- Get current resolution in x and y
function CT_Viewport_GetCurrentResolution(...)
	local currRes = arg[GetCurrentResolution()];
	if ( currRes ) then
		local useless, useless, x, y = string.find(currRes, "(%d+)x(%d+)");
		if ( x and y ) then
			return tonumber(x), tonumber(y);
		end
	end
	return nil;
end

-- Apply the viewport settings
function CT_Viewport_ApplyViewport(left, right, top, bottom, r, g, b)
	if ( not left ) then
		right = ((CT_Viewport.initialValues[2]-CT_ViewportFrameInnerFrame:GetRight())/CT_Viewport.initialValues[5])*CT_Viewport.screenRes[1];
		left = ((CT_ViewportFrameInnerFrame:GetLeft()-CT_Viewport.initialValues[1])/CT_Viewport.initialValues[5])*CT_Viewport.screenRes[1];
		top = ((CT_Viewport.initialValues[3]-CT_ViewportFrameInnerFrame:GetTop())/CT_Viewport.initialValues[6])*CT_Viewport.screenRes[2];
		bottom = ((CT_ViewportFrameInnerFrame:GetBottom()-CT_Viewport.initialValues[4])/CT_Viewport.initialValues[6])*CT_Viewport.screenRes[2];
	end
	if ( right < 0 ) then
		right = 0;
	end
	if ( left < 0 ) then
		left = 0;
	end
	if ( top < 0 ) then
		top = 0;
	end
	if ( bottom < 0 ) then
		bottom = 0;
	end
	
	r = ( r or 0 );
	g = ( g or 0 );
	b = ( b or 0 );
	
	CT_Viewport_Saved = { left, right, top, bottom, r, g, b }; -- Need to reverse top and bottom because of how it works
	WorldFrame:ClearAllPoints();
	WorldFrame:SetPoint("TOPLEFT", (UIParent:GetWidth()/CT_Viewport.screenRes[1])*left, -(UIParent:GetHeight()/CT_Viewport.screenRes[2])*top);
	WorldFrame:SetPoint("BOTTOMRIGHT", -(UIParent:GetWidth()/CT_Viewport.screenRes[1])*right, (UIParent:GetHeight()/CT_Viewport.screenRes[2])*bottom);
	CT_ViewportOverlay:SetVertexColor(r, g, b, 1);
end

-- Apply saved settings to the inner viewport
function CT_Viewport_ApplyInnerViewport(left, right, top, bottom, r, g, b)
	CT_ViewportFrameLeftEB:SetText(floor(left+0.5));
	CT_ViewportFrameRightEB:SetText(floor(right+0.5));
	CT_ViewportFrameTopEB:SetText(floor(top+0.5));
	CT_ViewportFrameBottomEB:SetText(floor(bottom+0.5));
	CT_Viewport.currOffset = {
		floor(left+0.5), floor(right+0.5), floor(top+0.5), floor(bottom+0.5)
	};
	CT_ViewportFrameAspectRatioNewText:SetText("Aspect Ratio (Current): |c00FFFFFF" .. CT_Viewport_GetQuotient((CT_Viewport.screenRes[1]-left-right)/(CT_Viewport.screenRes[2]-top-bottom)));
	CT_ViewportFrameAspectRatioDefaultText:SetText("Aspect Ratio (Default): |c00FFFFFF" .. CT_Viewport_GetQuotient(CT_Viewport.screenRes[1]/CT_Viewport.screenRes[2]));
	left = left*(CT_Viewport.initialValues[5]/CT_Viewport.screenRes[1]);
	right = right*(CT_Viewport.initialValues[5]/CT_Viewport.screenRes[1]);
	top = top*(CT_Viewport.initialValues[6]/CT_Viewport.screenRes[2]);
	bottom = bottom*(CT_Viewport.initialValues[6]/CT_Viewport.screenRes[2]);
	CT_ViewportFrameInnerFrame:ClearAllPoints();
	CT_ViewportFrameInnerFrame:SetPoint("TOPLEFT", "CT_ViewportFrameBorderFrame", "TOPLEFT", left+4, -(top+4));
	CT_ViewportFrameInnerFrame:SetPoint("BOTTOMRIGHT", "CT_ViewportFrameBorderFrame", "BOTTOMRIGHT", -(right+4), bottom+4);
	local frameTop, frameBottom, frameLeft, frameRight = CT_ViewportFrameInnerFrame:GetTop(), CT_ViewportFrameInnerFrame:GetBottom(), CT_ViewportFrameInnerFrame:GetLeft(), CT_ViewportFrameInnerFrame:GetRight();
	if ( frameTop and frameBottom and frameLeft and frameRight ) then
		CT_ViewportFrameInnerFrame:SetHeight(frameTop-frameBottom);
		CT_ViewportFrameInnerFrame:SetWidth(frameRight-frameLeft);
	else
		CT_ViewportFrame.awaitingValues = 1;
	end
end

-- Change a side of the viewport
function CT_Viewport_ChangeViewportSide()
	local value = tonumber(this:GetText());
	if ( not value ) then
		return;
	end
	value = abs(value);
	local id = this:GetID();
	local left, right, top, bottom, width, height = CT_Viewport.currOffset[1], CT_Viewport.currOffset[2], CT_Viewport.currOffset[3], CT_Viewport.currOffset[4];
	if ( id == 1 ) then
		-- Left
		CT_Viewport_ApplyInnerViewport(value, right, top, bottom);
	elseif ( id == 2 ) then
		-- Right
		CT_Viewport_ApplyInnerViewport(left, value, top, bottom);
	elseif ( id == 3 ) then
		-- Top
		CT_Viewport_ApplyInnerViewport(left, right, value, bottom);
	elseif ( id == 4 ) then
		-- Bottom
		CT_Viewport_ApplyInnerViewport(left, right, top, value);
	end
end

-- Handlers
	-- OnLoad
function CT_ViewportFrame_OnLoad()
	local x, y = CT_Viewport_GetCurrentResolution(GetScreenResolutions());
	if ( x and y ) then
		local modifier = x/y;
		if ( modifier ~= (4/3) ) then
			local newViewportHeight = CT_Viewport.initialValues[6]/(x/y);
			CT_ViewportFrameInnerFrame:SetHeight(newViewportHeight);
			CT_ViewportFrameBorderFrame:SetHeight(newViewportHeight+8);
		end
		CT_Viewport.screenRes = { x, y };
		CT_ViewportFrame:SetHeight(210+CT_ViewportFrameBorderFrame:GetHeight());
		CT_Viewport.awaitingValues = 1;
	end
	CT_ViewportFrameInnerFrame:SetBackdropBorderColor(1, 1, 0, 1);
	CT_ViewportFrameBorderFrame:SetBackdropBorderColor(1, 0, 0, 1);
	CT_ViewportFrameInnerFrameBackground:SetVertexColor(1, 1, 0, 0.1);
	
	CT_ViewportOverlay = WorldFrame:CreateTexture("CT_ViewportOverlay", "BACKGROUND");
	CT_ViewportOverlay:SetTexture(1, 1, 1, 1);
	CT_ViewportOverlay:SetPoint("TOPLEFT", "UIParent", "TOPLEFT", -1, 1);
	CT_ViewportOverlay:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMRIGHT", 1, -1);
	this:RegisterEvent("VARIABLES_LOADED");
end

	-- OnUpdate
function CT_ViewportFrame_OnUpdate(elapsed)
	if ( not this.hasAppliedViewport ) then
		this.hasAppliedViewport = 1;
		CT_ViewportFrameInnerFrame:ClearAllPoints();
		CT_ViewportFrameInnerFrame:SetPoint("TOPLEFT", "CT_ViewportFrameBorderFrame", "TOPLEFT", 4, -4);
		CT_ViewportFrameInnerFrame:SetPoint("BOTTOMRIGHT", "CT_ViewportFrameBorderFrame", "BOTTOMRIGHT", -4, 4);
	elseif ( this.hasAppliedViewport == 1 ) then
		this.hasAppliedViewport = 2;
		if ( CT_Viewport.awaitingValues ) then
			CT_Viewport_GetInitialValues();
			CT_Viewport.awaitingValues = nil;
			CT_ViewportFrameInnerFrame:SetMinResize(CT_Viewport.initialValues[5]/2, CT_Viewport.initialValues[6]/2);
			CT_ViewportFrameLeftEB.limitation = CT_Viewport.screenRes[1]/2;
			CT_ViewportFrameRightEB.limitation = CT_Viewport.screenRes[1]/2;
			CT_ViewportFrameTopEB.limitation = CT_Viewport.screenRes[2]/2;
			CT_ViewportFrameBottomEB.limitation = CT_Viewport.screenRes[2]/2;
		end
		CT_ViewportFrame_OnShow();
	end
	if ( CT_Viewport.isResizing ) then
		local right = ((CT_Viewport.initialValues[2]-CT_ViewportFrameInnerFrame:GetRight())/CT_Viewport.initialValues[5])*CT_Viewport.screenRes[1];
		local left = ((CT_ViewportFrameInnerFrame:GetLeft()-CT_Viewport.initialValues[1])/CT_Viewport.initialValues[5])*CT_Viewport.screenRes[1];
		local top = ((CT_Viewport.initialValues[3]-CT_ViewportFrameInnerFrame:GetTop())/CT_Viewport.initialValues[6])*CT_Viewport.screenRes[2];
		local bottom = ((CT_ViewportFrameInnerFrame:GetBottom()-CT_Viewport.initialValues[4])/CT_Viewport.initialValues[6])*CT_Viewport.screenRes[2];
		if ( right < 0 ) then
			right = 0;
		end
		if ( left < 0 ) then
			left = 0;
		end
		if ( top < 0 ) then
			top = 0;
		end
		if ( bottom < 0 ) then
			bottom = 0;
		end
		CT_ViewportFrameLeftEB:SetText(floor(left+0.5));
		CT_ViewportFrameRightEB:SetText(floor(right+0.5));
		CT_ViewportFrameTopEB:SetText(floor(top+0.5));
		CT_ViewportFrameBottomEB:SetText(floor(bottom+0.5));
		CT_Viewport.currOffset = {
			floor(left+0.5), floor(right+0.5), floor(top+0.5), floor(bottom+0.5)
		};
		if ( not this.update ) then
			this.update = 0;
		else
			this.update = this.update - elapsed;
		end
		if ( this.update <= 0 ) then
			CT_ViewportFrameAspectRatioNewText:SetText("Aspect Ratio (Current): |c00FFFFFF" .. CT_Viewport_GetQuotient((CT_Viewport.screenRes[1]-left-right)/(CT_Viewport.screenRes[2]-top-bottom)));
			CT_ViewportFrameAspectRatioDefaultText:SetText("Aspect Ratio (Default): |c00FFFFFF" .. CT_Viewport_GetQuotient(CT_Viewport.screenRes[1]/CT_Viewport.screenRes[2]));
			this.update = 0.1;
		end
	else
		this.update = nil;
	end
end

	-- OnShow
function CT_ViewportFrame_OnShow()
	if ( CT_ViewportFrameInnerFrame:GetLeft() ) then
		local left, right, top, bottom, width, height, r, g, b = CT_Viewport_Saved[1], CT_Viewport_Saved[2], CT_Viewport_Saved[3], CT_Viewport_Saved[4], CT_Viewport_Saved[5], CT_Viewport_Saved[6], CT_Viewport_Saved[7];
		CT_Viewport_ApplyInnerViewport(left, right, top, bottom, r, g, b);
	end
end

	-- OnEvent
function CT_ViewportFrame_OnEvent(event)
	if ( event == "VARIABLES_LOADED" ) then
		CT_Viewport_ApplyViewport(CT_Viewport_Saved[1], CT_Viewport_Saved[2], CT_Viewport_Saved[3], CT_Viewport_Saved[4], CT_Viewport_Saved[5], CT_Viewport_Saved[6], CT_Viewport_Saved[7]);
	end
end

-- Hook SetScreenResolution to update
CT_Viewport_oldSetScreenResolution = SetScreenResolution;
function CT_Viewport_newSetScreenResolution(newResolution)
	CT_Viewport_oldSetScreenResolution(newResolution);
	CT_ViewportFrame_OnLoad();
	CT_ViewportFrame.hasAppliedViewport = nil;
end
SetScreenResolution = CT_Viewport_newSetScreenResolution;

-- Add to CT Control panel if available
if ( CT_RegisterMod ) then
	CT_RegisterMod("Viewport", "Modify Viewport", 5, "Interface\\Icons\\Spell_Arcane_TeleportStormWind", "Shows the Viewport dialog, where you can modify the game viewport.", "switch", nil, function() if ( CT_ViewportFrame:IsVisible() ) then HideUIPanel(CT_ViewportFrame) else ShowUIPanel(CT_ViewportFrame) end end);
end