-- this code is based on the FixCTGroups AddOn and modified to fit self requirements
-- http://www.curse-gaming.com/en/wow/addons-4421-1-fixctgroups.html
-- many thanks to Tim Mullin for his great work on the original AddOn

CT_RAMenu_Groups = {
	-- default values
	defaultConfig = {
		dx = -3,
		dy = -20,
		ox = 0,
		oy = 0,
		groups = {
			[ 1] = 0, [ 2] = 0, [ 3] = 0, [ 4] = 0, [ 5] = 0, [ 6] = 0, [ 7] = 0, [ 8] = 0, 
			[ 9] = 0, [10] = 0, [11] = 0, [12] = 0, [13] = 0, [14] = 0, [15] = 0, [16] = 0, 
			[17] = 0, [18] = 0, [19] = 0, [20] = 0, [21] = 0, [22] = 0, [23] = 0, [24] = 0, 
			[25] = 0, [26] = 0, [27] = 1, [28] = 2, [29] = 3, [30] = 4, [31] = 0, [32] = 0, 
			[33] = 0, [34] = 0, [35] = 5, [36] = 6, [37] = 7, [38] = 8, [39] = 0, [40] = 0, 
			[41] = 0, [42] = 0, [43] = 0, [44] = 0, [45] = 0, [46] = 0, [47] = 0, [48] = 0, 
			[49] = 0, [50] = 0, [51] = 0, [52] = 0, [53] = 0, [54] = 0, [55] = 0, [56] = 0, 
			[57] = 0, [58] = 0, [59] = 0, [60] = 0, [61] = 0, [62] = 0, [63] = 0, [64] = 0
		}
	},
	maxSlots = 64,

	-- initialized variables
	targetSlot = nil,
	movingGroup = nil,
	cCTRASetup = {},
	
	-- onLoad frame
	onLoad = function()
		this:RegisterEvent("VARIABLES_LOADED");
	end,

	-- onEvent frame
	onEvent = function()
		if ( event == "VARIABLES_LOADED" ) then
			-- allow frame close by Esc key
			tinsert(UISpecialFrames, this:GetName());

			-- set up config
			if ( CT_RAMenu_GroupsConfig == nil ) then
				CT_RAMenu_GroupsConfig = {};
			end

			local k, v;
			for k, v in pairs(CT_RAMenu_Groups.defaultConfig) do
				if ( k ~= "groups" and not CT_RAMenu_GroupsConfig[k] ) then
					CT_RAMenu_GroupsConfig[k] = v;
				end
			end

			if ( CT_RAMenu_GroupsConfig["groups"] == nil ) then
				CT_RAMenu_GroupsConfig["groups"] = {};

				for index, var in CT_RAMenu_Groups.defaultConfig["groups"] do
					if (CT_RAMenu_GroupsConfig["groups"][index] ~= nil) then
						--already saved
					else
						CT_RAMenu_GroupsConfig["groups"][index] = var;
					end
				end
			end
		end
	end,

	-- onUpdate frame
	onUpdate = function()
		if ( CT_RAMenu_Groups.movingGroup ) then
			local button, slot;
			CT_RAMenu_Groups.targetSlot = nil;

			for i = 1, CT_RAMenu_Groups.maxSlots do
				slot = getglobal("CT_RAMenu_GroupsFrameCellSlot"..i);
				button = slot.button;

				if ( MouseIsOver(slot) ) then
					CT_RAMenu_Groups.targetSlot = slot;

					slot:SetBackdropColor(slot.hover.r, slot.hover.g, slot.hover.b);
					slot:LockHighlight();

					if ( button and button ~= CT_RAMenu_Groups.movingGroup ) then
						button:SetBackdropColor(slot.hover.r, slot.hover.g, slot.hover.b);
					end
				else
					slot:SetBackdropColor(slot.bg.r, slot.bg.g, slot.bg.b);
					slot:UnlockHighlight();

					if ( button and button ~= CT_RAMenu_Groups.movingGroup ) then
						button:SetBackdropColor(button.bg.r, button.bg.g, button.bg.b);
					end
				end
			end
		end
	end,

	-- onShow frame
	onShow = function()
		local i, slot, groupDrag;
		local tempOptions = CT_RAMenu_Options["temp"];

		-- save current group visibilty and make all groups visible
		if ( not tempOptions["ShowGroups"] ) then tempOptions["ShowGroups"] = { }; end
		CT_RAMenu_Groups.cCTRASetup = {};
		CT_RAMenu_Groups.cCTRASetup["allGroupShow"] = CT_RACheckAllGroups:GetChecked();
		for i = 1, 8, 1 do
			CT_RAMenu_Groups.cCTRASetup["groupShow" .. i] = tempOptions["ShowGroups"][i];
		end
		CT_RAMenu_Groups.cCTRASetup["sortType"] = UIDropDownMenu_GetSelectedID(CT_RAMenuFrameGeneralMiscDropDown);

		-- make all groups visible
		CT_RACheckAllGroups:SetChecked(true);
		for i = 1, 8, 1 do
			tempOptions["ShowGroups"][i] = true;
			getglobal("CT_RAOptionsGroupCB" .. i):SetChecked(true);
		end
		CT_RA_SetSortType("virtual");
		CT_RA_UpdateRaidGroup(0);
		CT_RA_UpdateMTs();
		CT_RAOptions_Update();

		-- save current group positions
		CT_RAMenu_Groups.cCTRASetup["groupPosCurrent"] = { };
		for i = 1, 8, 1 do
			groupDrag = getglobal("CT_RAGroupDrag"..i);
			local point, relativeTo, relativePoint, xofs, yofs = groupDrag:GetPoint();
			CT_RAMenu_Groups.cCTRASetup["groupPosCurrent"][i] = {point, relativeTo, relativePoint, xofs, yofs};
		end

		for i = 1, CT_RAMenu_Groups.maxSlots do
			slot = getglobal("CT_RAMenu_GroupsFrameCellSlot" .. i);
			slot.button = nil;

			if ( CT_RAMenu_GroupsConfig["groups"][i] and CT_RAMenu_GroupsConfig["groups"][i] ~= 0 ) then
				button = getglobal("CT_RAMenu_GroupsFrameCell" .. CT_RAMenu_GroupsConfig["groups"][i]);
				
				button.slot = slot;
				slot.button = button;

				button:ClearAllPoints();
				button:SetPoint("TOPLEFT", slot, "TOPLEFT", 0, 0);
			end
		end

		CT_RAMenu_GroupsFrameSpacingX:SetValue(CT_RAMenu_GroupsConfig["dx"]);
		CT_RAMenu_GroupsFrameSpacingY:SetValue(CT_RAMenu_GroupsConfig["dy"]);
		CT_RAMenu_GroupsFrameOffsetX:SetValue(CT_RAMenu_GroupsConfig["ox"]);
		CT_RAMenu_GroupsFrameOffsetY:SetValue(CT_RAMenu_GroupsConfig["oy"]);
	end,

	-- onHide frame
	onHide = function()
		local i, f, button;
		local tempOptions = CT_RAMenu_Options["temp"];

		for i = 1, CT_RAMenu_Groups.maxSlots do
			f = getglobal("CT_RAMenu_GroupsFrameCellSlot"..i);

			if f.button then
				CT_RAMenu_GroupsConfig["groups"][i] = tonumber(getglobal(f.button:GetName().."Label"):GetText());
			else
				CT_RAMenu_GroupsConfig["groups"][i] = 0;
			end
		end

		-- restore group visibility
		CT_RACheckAllGroups:SetChecked(CT_RAMenu_Groups.cCTRASetup["allGroupShow"]);
		for i = 1, 8, 1 do
			tempOptions["ShowGroups"][i] = CT_RAMenu_Groups.cCTRASetup["groupShow" .. i];
			getglobal("CT_RAOptionsGroupCB" .. i):SetChecked(CT_RAMenu_Groups.cCTRASetup["groupShow" .. i]);
		end

		if ( CT_RAMenu_Groups.cCTRASetup["sortType"] == 1 ) then
			CT_RA_SetSortType("group");
		elseif ( CT_RAMenu_Groups.cCTRASetup["sortType"] == 2 ) then
			CT_RA_SetSortType("class");
		elseif ( CT_RAMenu_Groups.cCTRASetup["sortType"] == 3 ) then
			CT_RA_SetSortType("custom");
		elseif ( CT_RAMenu_Groups.cCTRASetup["sortType"] == 4 ) then
			CT_RA_SetSortType("virtual");
		end
		CT_RA_UpdateRaidGroup(0);
		CT_RA_UpdateMTs();
		CT_RAOptions_Update();
	end,

	onClick = function()
		local name = this:GetName();

		if ( name == "CT_RAMenu_GroupsFrameSpacingX" ) then
			CT_RAMenu_GroupsConfig["dx"] = this:GetValue();
			CT_RAMenu_Groups.changePosition("update");
		elseif ( name == "CT_RAMenu_GroupsFrameSpacingY" ) then
			CT_RAMenu_GroupsConfig["dy"] = this:GetValue();
			CT_RAMenu_Groups.changePosition("update");
		elseif ( name == "CT_RAMenu_GroupsFrameOffsetX" ) then
			CT_RAMenu_GroupsConfig["ox"] = this:GetValue();
			CT_RAMenu_Groups.changePosition("update");
		elseif ( name == "CT_RAMenu_GroupsFrameOffsetY" ) then
			CT_RAMenu_GroupsConfig["oy"] = this:GetValue();
			CT_RAMenu_Groups.changePosition("update");
		end
	end,

	-- onDragStart cell
	onDragStartCell = function()
		local cursorX, cursorY = GetCursorPosition();
		this:SetBackdropColor(this.hover.r, this.hover.g, this.hover.b);
		this:SetFrameLevel(this:GetFrameLevel() + 10);
		this:ClearAllPoints();
		this:SetPoint("CENTER", nil, "BOTTOMLEFT", cursorX*GetScreenWidthScale(), cursorY*GetScreenHeightScale());
		this:StartMoving();
		CT_RAMenu_Groups.movingGroup = this;
	end,

	onDragStopCell = function(groupButton)
		if ( not groupButton ) then
			groupButton = this;
		end
		
		groupButton:StopMovingOrSizing();
		groupButton:SetBackdropColor(groupButton.bg.r, groupButton.bg.g, groupButton.bg.b);
		groupButton:SetFrameLevel(groupButton:GetFrameLevel() - 10);
		CT_RAMenu_Groups.movingGroup = nil;

		if ( CT_RAMenu_Groups.targetSlot and CT_RAMenu_Groups.targetSlot:GetID() ~= groupButton.slot:GetID() ) then
			if ( CT_RAMenu_Groups.targetSlot.button ) then
				local oldButton = CT_RAMenu_Groups.targetSlot.button;
				local newSlot   = CT_RAMenu_Groups.targetSlot;
				local oldSlot   = groupButton.slot;

				oldButton:SetPoint("TOPLEFT", groupButton.slot, "TOPLEFT", 0, 0);
				oldButton:SetBackdropColor(oldButton.bg.r, oldButton.bg.g, oldButton.bg.b);
				oldButton.slot = oldSlot;
				oldSlot.button = oldButton;

				groupButton:SetPoint("TOPLEFT", newSlot, "TOPLEFT", 0, 0);
				groupButton.slot   = newSlot;
				newSlot.button = groupButton;
			else
				local newSlot = CT_RAMenu_Groups.targetSlot;
				local oldSlot = groupButton.slot;

				newSlot:UnlockHighlight();

				groupButton:SetPoint("TOPLEFT", newSlot, "TOPLEFT", 0, 0);
				oldSlot.button = nil;

				newSlot.button = groupButton;
				groupButton.slot = newSlot;

				local i, f;
				for i = 1, CT_RAMenu_Groups.maxSlots do
					f = getglobal("CT_RAMenu_GroupsFrameCellSlot"..i);

					if ( f.button ) then
						CT_RAMenu_GroupsConfig["groups"][i] = tonumber(getglobal(f.button:GetName().."Label"):GetText());
					else
						CT_RAMenu_GroupsConfig["groups"][i] = 0;
					end
				end

				CT_RAMenu_Groups.changePosition("update");
			end
		else
			if ( CT_RAMenu_Groups.targetSlot ) then		-- dragged to same slot it was already on
				local slot = CT_RAMenu_Groups.targetSlot;

				slot:SetBackdropColor(slot.bg.r, slot.bg.g, slot.bg.b);
				slot:UnlockHighlight();
			end
			groupButton:SetPoint("TOPLEFT", groupButton.slot, "TOPLEFT", 0, 0);
		end
	end,

	changePosition = function(type)
		if ( type == nil ) then
			return;
		elseif ( type == "update" ) then
			CT_RAMenu_Groups.arrangeGroups();
		elseif ( type == "reset" ) then
			local groupDrag;
			local c = CT_RAMenu_Groups.cCTRASetup["groupPosCurrent"];

			for i = 1, 8, 1 do
				groupDrag = getglobal("CT_RAGroupDrag"..i);
				groupDrag:ClearAllPoints();

				groupDrag:SetPoint(c[i][1], c[i][2], c[i][3], c[i][4], c[i][5]);
				--CT_RAMenu_Groups.cCTRASetup["groupPosCurrent"][i] = {point, relativeTo, relativePoint, xofs, yofs};
			end
		end
	end,

	arrangeGroups = function()
		local i, groupDrag, posX, posY;
		local c = CT_RAMenu_GroupsConfig;
		local g = CT_RAMenu_GroupsConfig["groups"];
		local spacingX = ceil(GetScreenWidth() / 8);
		local spacingY = ceil(GetScreenHeight() / 8);
		local row = 0;
		local col = 0;
		local firstX = 0;
		local firstY = 0;

		-- reset then fix it
		--CT_RAMenu_Groups.changePosition("reset");

		for i = 1, CT_RAMenu_Groups.maxSlots do
			if ( math.mod(i - 1, 8) == 0 ) then
				row = row + 1;
				col = 1;
			else
				col = col + 1;
			end
			if ( g[i] ~= 0 ) then
				if ( firstX == 0 or col < firstX ) then
					firstX = col;
				end
				if ( firstY == 0 or row < firstY ) then
					firstY = row;
				end

				groupDrag = getglobal("CT_RAGroupDrag"..g[i]);
				groupDrag:ClearAllPoints();
				if ( col <= firstX ) then
					posX = spacingX * (col - 1);
				else
					posX = spacingX * (col - 1) + c.dx * (col - firstX);
				end
				if ( row <= firstY ) then
					posY = spacingY * (row - 1);
				else
					posY = spacingY * (row - 1) + c.dy * (row - firstY);
				end
				groupDrag:SetPoint("TOPLEFT", "UIParent", "TOPLEFT", posX + c.ox - 15, -posY - c.oy);
			end
		end

		CT_RAMenu_SaveWindowPositions();
	end,
};