-- Gems, a silly gems-based minigame to kill time.
-- Use /gems to bring up the game.

local Gems_GameIsOver = false;

local Gems_Paused = false;
local Gems_TimerOn = false;
local Gems_TimerFunction;
local Gems_Tick;
local Gems_TimerEnd = 0;
local Gems_PulseTime = 0.5;
local Gems_Score = 0;

local Gems_GemTypes = 10;

local Gems_FallingX = -1;
local Gems_FallingY = 0;

local Gems_GemTextures = {
	"",
	"Interface\\Icons\\INV_Misc_Gem_Topaz_01",
	"Interface\\Icons\\INV_Misc_Gem_Diamond_01",
	"Interface\\Icons\\INV_Misc_Gem_Opal_01",
	"Interface\\Icons\\INV_Misc_Gem_Ruby_01",
	"Interface\\Icons\\INV_Misc_Gem_Amethyst_01",
	"Interface\\Icons\\INV_Misc_Gem_Bloodstone_01",
	"Interface\\Icons\\INV_Misc_Gem_Crystal_01",
	"Interface\\Icons\\INV_Misc_Gem_Emerald_01",
	"Interface\\Icons\\INV_Misc_Gem_Sapphire_01",
	"Interface\\Icons\\INV_Misc_Gem_Stone_01",
	"Interface\\Icons\\INV_Misc_Gem_Variety_01",
	"Interface\\Icons\\INV_Misc_Gem_01",
	"Interface\\Icons\\INV_Misc_Gear_01",
	"Interface\\Icons\\INV_Misc_Rune_01",
	"Interface\\Icons\\INV_Ore_Arcanite_01",
	"Interface\\Icons\\INV_Ore_Copper_01",
	"Interface\\Icons\\INV_Ore_Iron_01",
	"Interface\\Icons\\INV_Ore_Mithril_01",
	"Interface\\Icons\\INV_Ore_Thorium_01",
	"Interface\\Icons\\INV_Ore_Tin_01",
	"Interface\\Icons\\INV_Ore_TrueSilver_01"
}

-- some strings for the key bindings
BINDING_HEADER_GEMS = "Val's Gems";
BINDING_NAME_GEMS_LEFT = "Move Left";
BINDING_NAME_GEMS_RIGHT = "Move Right";
BINDING_NAME_GEMS_DOWN = "Move Down";
	

function Gems_OnLoad()
	-- Register the slash command
	SLASH_GEMS1 = "/gems";
	SlashCmdList["GEMS"] = function(msg)
		Gems_SlashCommand(msg);
	end

	-- hide the frame when escape is pressed
	tinsert(UISpecialFrames,"Gems_Frame");

	Gems_Write("Val's Gems loaded. Type |cffff0000/gems|r to play or |cffff0000/gems help|r for instructions.");
	Gems_NewGame();
end

function Gems_SlashCommand(msg)
	if(msg == nil or msg == "") then
		Gems_Toggle();
	elseif(msg == "help") then
		Gems_Help();
	end
end

function Gems_Help()
	Gems_Write("Help for Val's Gems");
	Gems_Write("=================");
	Gems_Write("The premise of this game is easy - connect 4 of the same gem horizontally, vertically, or diagonally.");
	Gems_Write("Use the < and > buttons to move the falling gems left or right, and the v button to drop the gem to the bottom.");
end

function Gems_Toggle()
	if(getglobal("Gems_Frame"):IsShown()) then
		getglobal("Gems_Frame"):Hide();
	else
		getglobal("Gems_Frame"):Show();
	end
end

function Gems_NewGame()
	
	Gems_GameIsOver = false;
	
	Gems_TimerEnd = 0;
	Gems_Paused = false;

	Gems_FallingX = -1;
	Gems_FallingY = 0;
	Gems_Score = 0;
	Gems_UpdateScore(Gems_Score);
	
	getglobal("Gems_PauseButton"):UnlockHighlight();
	
	for i = 1,64 do
		getglobal("Gems_Cell" .. i).gem = 0;
		Gems_DrawCell(i);
	end

	Gems_ScheduleTimer(Gems_PulseTime, Gems_Pulse);
end

function Gems_Pulse()
	
	if(Gems_FallingX == -1) then
		Gems_SpawnGem();
	else
		local gemcell = Gems_FallingX * 8 + Gems_FallingY;
		
		if(gemcell > 56) then
			Gems_CheckMatch(Gems_FallingX, Gems_FallingY);
			Gems_FallingX = -1;

		elseif(getglobal("Gems_Cell" .. gemcell+8).gem > 0) then
			Gems_CheckMatch(Gems_FallingX, Gems_FallingY);
			Gems_FallingX = -1

		else
			--Gems_Write("gemcell is " .. gemcell);
			local gemval = getglobal("Gems_Cell" .. gemcell).gem;
			getglobal("Gems_Cell" .. gemcell).gem = 0;
			getglobal("Gems_Cell" .. gemcell+8).gem = gemval;
			Gems_DrawCell(gemcell);
			Gems_DrawCell(gemcell+8);
			Gems_FallingX = Gems_FallingX + 1;
		end
	end
	
	Gems_ScheduleTimer(Gems_PulseTime, Gems_Pulse);
end

function Gems_DrawCell(cellnum)
	local i = getglobal("Gems_Cell" .. cellnum).gem + 1;
	--getglobal("Gems_Cell" .. cellnum):SetBackdropColor(Gems_GemColors[i]["r"], Gems_GemColors[i]["g"], Gems_GemColors[i]["b"]);
	if(i == 1) then
		getglobal("Gems_Cell" .. cellnum):Hide();
	else
		getglobal("Gems_Cell" .. cellnum):Show();
		getglobal("Gems_Cell" .. cellnum):SetNormalTexture(Gems_GemTextures[i]);
	end
end

function Gems_SpawnGem()
	local column = 4;
	local gemval = math.random(1,Gems_GemTypes);
	
	Gems_FallingX = 0;
	Gems_FallingY = column;
	
	--Gems_Write("spawning in " .. column);
	
	getglobal("Gems_Cell" .. Gems_FallingY).gem = gemval;
	Gems_DrawCell(Gems_FallingY);
end

function Gems_MoveLeft()
	local gemcell = Gems_FallingX * 8 + Gems_FallingY;
	if(Gems_FallingY > 1) then
		if(Gems_FallingX == -1 or Gems_FallingX > 6 or getglobal("Gems_Cell" .. gemcell-1).gem > 0) then return end;
		Gems_FallingY = Gems_FallingY - 1;	
		local gemval = getglobal("Gems_Cell" .. gemcell).gem;
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		getglobal("Gems_Cell" .. gemcell-1).gem = gemval;
		Gems_DrawCell(gemcell);
		Gems_DrawCell(gemcell-1);
	end
end

function Gems_MoveRight()
	local gemcell = Gems_FallingX * 8 + Gems_FallingY;
	if(Gems_FallingY < 8) then
		if(Gems_FallingX == -1 or Gems_FallingX > 6 or getglobal("Gems_Cell" .. gemcell+1).gem > 0) then return end;
		Gems_FallingY = Gems_FallingY + 1;
		local gemval = getglobal("Gems_Cell" .. gemcell).gem;
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		getglobal("Gems_Cell" .. gemcell+1).gem = gemval;
		Gems_DrawCell(gemcell);
		Gems_DrawCell(gemcell+1);
	end
end

function Gems_MoveDown()
	if(Gems_FallingX == -1) then
		return;
	end
	local gemcell = Gems_FallingX * 8 + Gems_FallingY;
	local gemval = getglobal("Gems_Cell" .. gemcell).gem;

	while(gemcell <= 56 and getglobal("Gems_Cell" .. gemcell+8).gem == 0) do
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		getglobal("Gems_Cell" .. gemcell+8).gem = gemval;
		Gems_DrawCell(gemcell);
		Gems_DrawCell(gemcell+8);
		gemcell = gemcell + 8;
		Gems_FallingX = Gems_FallingX + 1;
	end
end

function Gems_Collapse()
	local didcollapse = false;
	for y = 1,8 do
		for x = 7,1,-1 do
			--Gems_Write("checking " .. x .. "," .. y .. " (" .. (x*8 + y) .. " - " .. getglobal("Gems_Cell" .. (x*8 + y)).gem);
			if(getglobal("Gems_Cell" .. (x*8 + y)).gem == 0) then
			--	Gems_Write("collapsing");
				getglobal("Gems_Cell" .. (x*8 + y)).gem = getglobal("Gems_Cell" .. ((x-1)*8 + y)).gem;
				getglobal("Gems_Cell" .. ((x-1)*8 + y)).gem = 0;
				Gems_DrawCell(x*8 + y);
				Gems_DrawCell((x-1)*8 + y);
				didcollapse = true;
		--	else
		--		Gems_Write("breaking");
		--		break;
			end
		end
	end
	
	if(didcollapse) then
		for y = 1,8 do
			for x = 7,1,-1 do
				if(getglobal("Gems_Cell" .. (x*8 + y)).gem > 0) then
					Gems_CheckMatch(x,y);
				end
			end
		end
	end
end

function Gems_CheckMatch(x, y)
	local gemcell = x * 8 + y;
	local gemval = getglobal("Gems_Cell" .. gemcell).gem;
	
	if(gemval == 0) then return	end

	local htotal = Gems_ScanLeft(x, y, gemval) + Gems_ScanRight(x, y, gemval) - 1;
	local dtotal1 = Gems_ScanUpLeft(x, y, gemval) + Gems_ScanDownRight(x, y, gemval) - 1;
	local dtotal2 = Gems_ScanDownLeft(x, y, gemval) + Gems_ScanUpRight(x, y, gemval) - 1;
	local vtotal = Gems_ScanUp(x, y, gemval) + Gems_ScanDown(x, y, gemval) -1;
	
	local scoreval = 0;

	if(htotal >= 4) then
		if(y > 1) then
			Gems_DelLeft(x, y-1, gemval);
		end
		
		if(y < 8) then
			Gems_DelRight(x, y+1, gemval);
		end
		scoreval = scoreval + (htotal - 3) * 5;
	end
	
	if(vtotal >= 4) then
		if(x > 0) then
			Gems_DelUp(x-1, y, gemval);
		end
		
		if(x < 7) then
			Gems_DelDown(x+1, y, gemval);
		end
		scoreval = scoreval + (vtotal - 3) * 5;
	end
	
	if(dtotal2 >= 4) then
		if(x < 7 and y > 1) then
			Gems_DelDownLeft(x+1, y-1, gemval);
		end
		
		if(x > 0 and y < 8) then
			Gems_DelUpRight(x-1, y+1, gemval);
		end
		scoreval = scoreval + (dtotal2 - 3) * 5;
	end
	
	if(dtotal1 >= 4) then
		if(x > 0 and y > 1) then
			Gems_DelUpLeft(x-1, y-1, gemval);
		end
		
		if(x < 7 and y < 8) then
			Gems_DelDownRight(x+1, y+1, gemval);
		end
		scoreval = scoreval + (dtotal1 - 3) * 5;
	end
	
	if(htotal >= 4 or vtotal >=4 or dtotal1 >= 4 or dtotal2 >= 4) then
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		Gems_DrawCell(gemcell);
		Gems_Collapse();
		Gems_UpdateScore(Gems_Score + scoreval);
	end
end

function Gems_ScanLeft(x, y, gemval)
	local total = 0;
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		total = 1;
		
		if(y > 1) then
			total = total + Gems_ScanLeft(x, y-1, gemval);
		end
	end
	return total;
end

function Gems_ScanRight(x, y, gemval)
	local total = 0;
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		total = 1;

		if(y < 8) then
			total = total + Gems_ScanRight(x, y+1, gemval);
		end
	end
		
	return total;
end

function Gems_ScanUp(x, y, gemval)
	local total = 0;
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		total = 1;
	
		if(x > 0) then
			total = total + Gems_ScanUp(x-1, y, gemval);
		end
	end
	return total;
end

function Gems_ScanDown(x, y, gemval)
	local total = 0;
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		total = 1;
	
		if(x < 7) then
			total = total + Gems_ScanDown(x+1, y, gemval);
		end
	end
	return total;
end

function Gems_ScanUpLeft(x, y, gemval)
	local total = 0;
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		total = 1;
	
		if(x > 0 and y > 1) then
			total = total + Gems_ScanUpLeft(x-1, y-1, gemval);
		end
	end
	return total;
end

function Gems_ScanUpRight(x, y, gemval)
	local total = 0;
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		total = 1;
	
		if(x > 0 and y < 8) then
			total = total + Gems_ScanUpRight(x-1, y+1, gemval);
		end
	end
	return total;
end

function Gems_ScanDownLeft(x, y, gemval)
	local total = 0;
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		total = 1;
	
		if(x < 7 and y > 1) then
			total = total + Gems_ScanDownLeft(x+1, y-1, gemval);
		end
	end
	return total;
end

function Gems_ScanDownRight(x, y, gemval)
	local total = 0;
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		total = 1;
	
		if(x < 7 and y < 8) then
			total = total + Gems_ScanDownRight(x+1, y+1, gemval);
		end
	end
	return total;
end

function Gems_DelLeft(x, y, gemval)
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		Gems_DrawCell(gemcell);
		
		if(y > 1) then
			Gems_DelLeft(x, y-1, gemval);
		end
	end
end

function Gems_DelRight(x, y, gemval)
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		Gems_DrawCell(gemcell);

		if(y < 8) then
			Gems_DelRight(x, y+1, gemval);
		end
	end
end

function Gems_DelUp(x, y, gemval)
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		Gems_DrawCell(gemcell);
	
		if(x > 0) then
			Gems_DelUp(x-1, y, gemval);
		end
	end
end

function Gems_DelDown(x, y, gemval)
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		Gems_DrawCell(gemcell);
	
		if(x < 7) then
			Gems_DelDown(x+1, y, gemval);
		end
	end
end

function Gems_DelUpLeft(x, y, gemval)
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		Gems_DrawCell(gemcell);
	
		if(x > 0 and y > 1) then
			Gems_DelUpLeft(x-1, y-1, gemval);
		end
	end

end

function Gems_DelUpRight(x, y, gemval)
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		Gems_DrawCell(gemcell);
	
		if(x > 0 and y < 8) then
			Gems_DelUpRight(x-1, y+1, gemval);
		end
	end
end

function Gems_DelDownLeft(x, y, gemval)
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		Gems_DrawCell(gemcell);
	
		if(x < 7 and y > 1) then
			Gems_DelDownLeft(x+1, y-1, gemval);
		end
	end
end

function Gems_DelDownRight(x, y, gemval)
	local gemcell = x * 8 + y;
	if(getglobal("Gems_Cell" .. gemcell).gem == gemval) then
		getglobal("Gems_Cell" .. gemcell).gem = 0;
		Gems_DrawCell(gemcell);
	
		if(x < 7 and y < 8) then
			Gems_DelDownRight(x+1, y+1, gemval);
		end
	end
end

function Gems_UpdateScore(newscore)
	Gems_Score = newscore;
	--Gems_Write("Score is now " .. Gems_Score);
	getglobal("Gems_ScoreString"):SetText(Gems_Score);
end

function Gems_PauseToggle()
	if(Gems_Paused == false) then
		Gems_Paused = true;
		Gems_TimerOn = false;
		this:LockHighlight();
	else
		Gems_Paused = false;
		Gems_TimerOn = true;
		this:UnlockHighlight();
	end
end

function Gems_ScheduleTimer(time, func)
	Gems_TimerFunction = func;
	Gems_TimerEnd = GetTime() + time;
	Gems_TimerOn = true;
end

function Gems_OnUpdate()
	if (not Gems_TimerOn) then return end
	local Gems_Tick = GetTime();
	if (Gems_TimerEnd - Gems_Tick < 0) then
		Gems_TimerOn = false;
		Gems_TimerFunction();
	end
end

function Gems_Difficulty_Initialize()
	local info;
	info = {
		text = "Easy";
		func = Gems_Difficulty_OnClick;
	};
	UIDropDownMenu_AddButton(info);
	
	info = {
		text = "Medium";
		func = Gems_Difficulty_OnClick;
	};
	UIDropDownMenu_AddButton(info);
	
	info = {
		text = "Hard";
		func = Gems_Difficulty_OnClick;
	};
	UIDropDownMenu_AddButton(info);
	
	info = {
		text = "Crazy";
		func = Gems_Difficulty_OnClick;
	};
	UIDropDownMenu_AddButton(info);

end

function Gems_Difficulty_OnLoad()
	UIDropDownMenu_Initialize(Gems_Difficulty, Gems_Difficulty_Initialize);
	UIDropDownMenu_SetSelectedID(Gems_Difficulty, 1);
	UIDropDownMenu_SetWidth(60);
end

function Gems_Difficulty_OnClick()
	local oldID = UIDropDownMenu_GetSelectedID(Gems_Difficulty);
	UIDropDownMenu_SetSelectedID(Gems_Difficulty, this:GetID());
	if(oldID ~= this:GetID()) then
		Gems_ChangeDifficulty();
	end
end

function Gems_Write(msg)
	if (DEFAULT_CHAT_FRAME) then
		DEFAULT_CHAT_FRAME:AddMessage(msg);
	end
end

function Gems_ChangeDifficulty()
	local id = UIDropDownMenu_GetSelectedID(Gems_Difficulty);
	if(id == 1) then
		Gems_GemTypes = 10
	elseif(id == 2) then
		Gems_GemTypes = 13
	elseif(id == 3) then
		Gems_GemTypes = 15
	elseif(id == 4) then
		Gems_GemTypes = 20
	end
	
	Gems_NewGame();
end
