// Includes
#include "template.h"
#include <sstream>

// Namespace
using namespace AGK;
app App;

enum class block_color {RED, BLUE, GREEN, YELLOW};
block_color cur_color = block_color::RED;

int red_block_sprite = 0, blue_block_sprite = 0, green_block_sprite = 0, yellow_block_sprite = 0;
int match_dummy_hor = 0;
int match_dummy_ver = 0;
int cur_block = 0;
int num_selected = 0;
int block_clicked = 0;
int block_tween = 0;
int swap_tween = 0;
int background = 0;
int title_screen = 0;

int score_floater = 0;
int score_tween = 0;
int player_score = 0;
int score_text = 0;
std::stringstream score_ss;

int select_blocks_sound = 0, remove_blocks_sound = 0, block_collide_sound = 0, swap_sound = 0;
int match3_music_1 = 0;

int top_mark = 0, bottom_mark = 0, left_mark = 0, right_mark = 0;

int game_state = 0;


class block_class
{
public:
	int sprite = 0;
	float x = 0, y = 0;
	float old_vel_y = 0, vel_y = 0;
	float click_delay_counter = 0;
	bool clicked = false;
	block_color color = block_color::RED;
	bool selected = false;
	bool multi_selected = false;
	bool marked = false;

};

std::vector <block_class> blocks;

void select_one_block(int block_num)
{
	agk::SetSpriteColorAlpha(blocks[block_num].sprite, 150);
	blocks[block_num].selected = true;
	num_selected = 1;
	cur_block = block_num;
	cur_color = blocks[block_num].color;
	if (agk::GetSpriteHit(agk::GetSpriteXByOffset(blocks[block_num].sprite), agk::GetSpriteYByOffset(blocks[block_num].sprite) - 64)) agk::SetSpritePositionByOffset(top_mark, agk::GetSpriteXByOffset(blocks[block_num].sprite), agk::GetSpriteYByOffset(blocks[block_num].sprite) - 64);
	if (agk::GetSpriteHit(agk::GetSpriteXByOffset(blocks[block_num].sprite), agk::GetSpriteYByOffset(blocks[block_num].sprite) + 64))agk::SetSpritePositionByOffset(bottom_mark, agk::GetSpriteXByOffset(blocks[block_num].sprite), agk::GetSpriteYByOffset(blocks[block_num].sprite) + 64);
	if (agk::GetSpriteHit(agk::GetSpriteXByOffset(blocks[block_num].sprite) - 64, agk::GetSpriteYByOffset(blocks[block_num].sprite) - 64))agk::SetSpritePositionByOffset(left_mark, agk::GetSpriteXByOffset(blocks[block_num].sprite) - 64, agk::GetSpriteYByOffset(blocks[block_num].sprite));
	if (agk::GetSpriteHit(agk::GetSpriteXByOffset(blocks[block_num].sprite) + 64, agk::GetSpriteYByOffset(blocks[block_num].sprite) - 64))agk::SetSpritePositionByOffset(right_mark, agk::GetSpriteXByOffset(blocks[block_num].sprite) + 64, agk::GetSpriteYByOffset(blocks[block_num].sprite));
}

void select_multiple_blocks(int block_num)
{
	if (blocks[block_num].selected == false && blocks[block_num].multi_selected == false)
	{
		agk::SetSpriteColor(blocks[block_num].sprite, 255, 255, 255, 100);
		blocks[block_num].selected = true;
		blocks[block_num].multi_selected = true;
		num_selected++;
	}
	agk::SetSpritePositionByOffset(match_dummy_hor, agk::GetSpriteXByOffset(blocks[block_num].sprite), agk::GetSpriteYByOffset(blocks[block_num].sprite));
	agk::SetSpritePositionByOffset(match_dummy_ver, agk::GetSpriteXByOffset(blocks[block_num].sprite), agk::GetSpriteYByOffset(blocks[block_num].sprite));
	for (int b = 0; b < blocks.size(); b++)
	{
		if (agk::GetSpriteCollision(match_dummy_hor, blocks[b].sprite) ||
			agk::GetSpriteCollision(match_dummy_ver, blocks[b].sprite))
		{
			if (blocks[b].color == cur_color && blocks[b].multi_selected == false)
			{
				blocks[b].marked = true;
			}
		}
	}
}

void deselect_blocks()
{
	for (int b = 0; b < blocks.size(); b++)
	{
		if (blocks[b].selected || blocks[b].multi_selected)
		{
			agk::SetSpriteColor(blocks[b].sprite, 255, 255, 255, 255);
			blocks[b].selected = false; 
			blocks[b].multi_selected = false;
		}
	}
	num_selected = 0;
	agk::SetSpritePosition(top_mark, -5000, -5000);
	agk::SetSpritePosition(bottom_mark, -5000, -5000);
	agk::SetSpritePosition(left_mark, -5000, -5000);
	agk::SetSpritePosition(right_mark, -5000, -5000);
}
void select_marked_blocks()
{
	for (int b = 0; b < blocks.size(); b++)	if (blocks[b].marked == true) select_multiple_blocks(b);
}

void clear_marked_blocks()
{
	for (int b = 0; b < blocks.size(); b++)
	{
		blocks[b].marked = false;
	}
}

void remove_block_selection()
{
	// CALCULATE SCORE BASED ON NUMBER OF CONNECTED BLOCKS BEING REMOVED AT ONCE
	int score_calc = 2;
	for (int s = num_selected; s > 0; s--)
	{
		score_calc *= 2;
	}
	player_score += score_calc;
	std::stringstream score_floater_ss;
	score_floater_ss.str("");
	score_floater_ss << "+" << score_calc;
	agk::SetTextString(score_floater, score_floater_ss.str().c_str());
	agk::SetTextPosition(score_floater, 900, 450);
	// PLAY SOUND
	agk::PlaySound(remove_blocks_sound);
	// REMOVE THE BLOCKS
	for (int b = 0; b < blocks.size();)
	{
		if (blocks[b].multi_selected)
		{
			// BLOCK REMOVE PARTICLES
			int d_particles = agk::CreateParticles(agk::GetSpriteXByOffset(blocks[b].sprite), agk::GetSpriteYByOffset(blocks[b].sprite));
			agk::SetParticlesImage(d_particles, agk::LoadImage("star-particle.png"));
			agk::SetParticlesSize(d_particles, 150);
			agk::SetParticlesLife(d_particles, 1);
			agk::SetParticlesAngle(d_particles, 90);
			agk::SetParticlesRotationRange(d_particles, -180, 180);
			agk::SetParticlesDirection(d_particles, 0, -25);
			agk::SetParticlesFrequency(d_particles, 75);
			agk::SetParticlesMax(d_particles, 15);
			agk::SetParticlesVelocityRange(d_particles, 3, 6);
			int r_comp = 0, b_comp = 0, g_comp = 0;
			switch (blocks[b].color)
			{
			case block_color::RED:
				r_comp = 255;
				g_comp = 85;
				b_comp = 150;
				break;
			case block_color::BLUE:
				r_comp = 70;
				g_comp = 200;
				b_comp = 255;
				break;
			case block_color::GREEN:
				r_comp = 120;
				g_comp = 255;
				b_comp = 65;
				break;
			case block_color::YELLOW:
				r_comp = 255;
				g_comp = 255;
				break;
			}
			agk::AddParticlesColorKeyFrame(d_particles, 0.0F, r_comp, g_comp, b_comp, 255);
			agk::AddParticlesColorKeyFrame(d_particles, 0.5F, r_comp, g_comp, b_comp, 30);
			agk::AddParticlesColorKeyFrame(d_particles, 1.0F, 255, 255, 255, 0);
			agk::AddParticlesScaleKeyFrame(d_particles, 0.0F, 0.2F);
			agk::AddParticlesScaleKeyFrame(d_particles, 1.0F, 1.5F);
			// DELETE SPRITE AND BLOCK OBJECT
			agk::DeleteSprite(blocks[b].sprite);
			blocks.erase(blocks.begin() + b);
		}
		else
		{
			b++;
		}
	}
}

void make_new_blocks()
{
	for (float x = 640; x < 1280; x += 64)
	{
		block_class new_block; // MAKE A NEW BLOCK OBJECT
		int random_color = rand() % 4; // SET THE BLOCK COLOR RANDOMLY
		switch (random_color)
		{
		case 0:
			new_block.sprite = agk::CloneSprite(red_block_sprite); // MAKE A RED BLOCK
			new_block.color = block_color::RED;
			break;
		case 1:
			new_block.sprite = agk::CloneSprite(blue_block_sprite); // MAKE A BLUE BLOCK
			new_block.color = block_color::BLUE;
			break;
		case 2:
			new_block.sprite = agk::CloneSprite(green_block_sprite); // MAKE A GREEN BLOCK
			new_block.color = block_color::GREEN;
			break;
		case 3:
			new_block.sprite = agk::CloneSprite(yellow_block_sprite); // MAKE A YELLOW BLOCK
			new_block.color = block_color::YELLOW;
			break;
		}
		agk::SetSpritePosition(new_block.sprite, x, 0);
		agk::SetSpritePhysicsOn(new_block.sprite, 2);
		agk::SetSpritePhysicsRestitution(new_block.sprite, 0);
		agk::SetSpritePhysicsFriction(new_block.sprite, 0);
		agk::SetSpritePhysicsCanRotate(new_block.sprite, 0);
		blocks.push_back(new_block);
	}
}

void app::Begin(void)
{
	// INITIAL SETUP
	agk::SetVirtualResolution(1920, 1080);
	agk::SetWindowSize(1920, 1080, 0);
	agk::SetWindowPosition(0, 0);
	agk::SetWindowTitle("AGK Match 3 Game");
	agk::SetScissor(0, 0, 1920, 1080);
	agk::SetSyncRate(60, 0);
	agk::SetPhysicsScale(0.02F);
	agk::SetPhysicsGravity(0, 500);
	agk::UpdateDeviceSize(1920, 1080);
	// DISPLAY THE SQUISH MOBILE LOGO
	int squish_logo = agk::CreateSprite(agk::LoadImage("squish-mobile.png"));
	agk::SetSpritePositionByOffset(squish_logo, 960, 540);
	// FADE OUT SQUISH MOBILE LOGO THEN SHOW TITLE SCREEN
	int squish_tween = agk::CreateTweenSprite(4.0F);
	agk::SetTweenSpriteAlpha(squish_tween, 255, 0, 3);
	agk::PlayTweenSprite(squish_tween, squish_logo, 0);
	while (agk::GetSpriteColorAlpha(squish_logo) > 0)
	{
		agk::UpdateAllTweens(agk::GetFrameTime());
		agk::Sync();
	}
	title_screen = agk::CreateSprite(agk::LoadImage("title-screen.jpg"));
	agk::SetSpriteDepth(title_screen, 1);
	agk::Sync();
	// LOAD FONT
	agk::SetTextDefaultFontImage(agk::LoadImage("match3-font.png"));
	// PREPARE SCORE TEXT
	score_text = agk::CreateText("");
	agk::SetTextSize(score_text, 70);
	agk::SetTextPosition(score_text, 1400, 0);
	agk::SetTextSpacing(score_text, -13);
	score_floater = agk::CreateText("");
	agk::SetTextSize(score_floater, 100);
	agk::SetTextSpacing(score_floater, -16);
	score_tween = agk::CreateTweenText(1.0);
	// SETUP BLOCK TWEENS
	block_tween = agk::CreateTweenSprite(0.5);
	swap_tween = agk::CreateTweenSprite(0.5);
	// LOAD BLOCK SPRITES
	red_block_sprite = agk::CreateSprite(agk::LoadImage("block-red.png"));
	agk::SetSpriteSize(red_block_sprite, 62, 62);
	agk::SetSpritePosition(red_block_sprite, -1500, -1500);
	blue_block_sprite = agk::CreateSprite(agk::LoadImage("block-blue.png"));
	agk::SetSpriteSize(blue_block_sprite, 62, 62);
	agk::SetSpritePosition(blue_block_sprite, -1500, -1500);
	green_block_sprite = agk::CreateSprite(agk::LoadImage("block-green.png"));
	agk::SetSpriteSize(green_block_sprite, 62, 62);
	agk::SetSpritePosition(green_block_sprite, -1500, -1500);
	yellow_block_sprite = agk::CreateSprite(agk::LoadImage("block-yellow.png"));
	agk::SetSpriteSize(yellow_block_sprite, 62, 62);
	agk::SetSpritePosition(yellow_block_sprite, -1500, -1500);
	// LOAD BACKGROUND
	background = agk::CreateSprite(agk::LoadImage("retro-game-background.jpg"));
	agk::SetSpriteDepth(background, 500);
	// LOAD GAME SOUNDS
	select_blocks_sound = agk::LoadSound("select-blocks-sound.wav");
	remove_blocks_sound = agk::LoadSound("remove-blocks-sound.wav");
	block_collide_sound = agk::LoadSound("block-collide-sound.wav");
	swap_sound = agk::LoadSound("swap-sound.wav");
	match3_music_1 = agk::LoadMusicOGG("match3-music-2.ogg");
	agk::PlayMusicOGG(match3_music_1, 1);
	agk::SetMusicVolumeOGG(match3_music_1, 60);
	// MAKE MATCH-3 DUMMY SPRITES
	match_dummy_hor = agk::CreateSprite(0);
	agk::SetSpriteSize(match_dummy_hor, 100, 1);
	agk::SetSpriteVisible(match_dummy_hor, 0);
	match_dummy_ver = agk::CreateSprite(0);
	agk::SetSpriteSize(match_dummy_ver, 1, 100);
	agk::SetSpriteVisible(match_dummy_ver, 0);
	// LOAD BLOCK SWAP SPRITES
	top_mark = agk::CreateSprite(agk::LoadImage("swap-icon.png"));
	agk::SetSpriteAngle(top_mark, 90);
	bottom_mark = agk::CreateSprite(agk::LoadImage("swap-icon.png"));
	agk::SetSpriteAngle(bottom_mark, 90);
	left_mark = agk::CreateSprite(agk::LoadImage("swap-icon.png"));
	right_mark = agk::CreateSprite(agk::LoadImage("swap-icon.png"));
	agk::SetSpritePosition(top_mark, -5000, -5000);
	agk::SetSpritePosition(bottom_mark, -5000, -5000);
	agk::SetSpritePosition(left_mark, -5000, -5000);
	agk::SetSpritePosition(right_mark, -5000, -5000);
	agk::SetSpriteDepth(top_mark, 1);
	agk::SetSpriteDepth(bottom_mark, 1);
	agk::SetSpriteDepth(left_mark, 1);
	agk::SetSpriteDepth(right_mark, 1);
}

void mouse_input()
{
	if (agk::GetPointerReleased())
	{
		block_clicked = agk::GetSpriteHit(agk::GetPointerX(), agk::GetPointerY());
		if (block_clicked)
		{
			for (int b = 0; b < blocks.size(); b++)
			{
				// FIRST CLICK ON A BLOCK
				if (block_clicked == blocks[b].sprite && blocks[b].selected == false && blocks[b].multi_selected == false)
				{
					clear_marked_blocks();
					deselect_blocks();
					select_one_block(b);
					agk::PlaySound(select_blocks_sound);
					break;
				}
				// SECOND CLICK ON A BLOCK TO HIGHLIGHT CONNECTED BLOCKS OF SAME COLOR
				if (block_clicked == blocks[b].sprite && blocks[b].selected == true && blocks[b].multi_selected == false)
				{
					deselect_blocks();
					cur_color = blocks[b].color;
					blocks[b].selected = false;
					num_selected = 0;
					blocks[b].marked = true;
					agk::PlaySound(select_blocks_sound);
					break;
				}
				// THIRD CLICK TO CLEAR THE HIGHLIGHTED GROUP OF BLOCKS
				if (block_clicked == blocks[b].sprite && blocks[b].multi_selected == true)
				{
					if (num_selected >= 3)
					{
						remove_block_selection();
						deselect_blocks();
					}
				}
			}
			// CLICKED ON ADJACENT BLOCK (SWAP BLOCKS)
			if (block_clicked == top_mark ||
				block_clicked == bottom_mark ||
				block_clicked == left_mark ||
				block_clicked == right_mark)
			{
				for (int b = 0; b < blocks.size(); b++) agk::SetSpritePhysicsOff(blocks[b].sprite);
				int* swap_mark = &block_clicked;
				for (int b = 0; b < blocks.size(); b++)
				{
					if (agk::GetSpriteCollision(*swap_mark, blocks[b].sprite))
					{
						float orig_x = agk::GetSpriteX(blocks[cur_block].sprite);
						float orig_y = agk::GetSpriteY(blocks[cur_block].sprite);
						float swap_x = agk::GetSpriteX(blocks[b].sprite);
						float swap_y = agk::GetSpriteY(blocks[b].sprite);
						agk::SetTweenSpriteAlpha(block_tween, 100, 255, 5);
						agk::SetTweenSpriteAlpha(swap_tween, 100, 255, 5);
						agk::SetTweenSpriteX(block_tween, orig_x, swap_x, 5);
						agk::SetTweenSpriteY(block_tween, orig_y, swap_y, 5);
						agk::SetTweenSpriteX(swap_tween, swap_x, orig_x, 5);
						agk::SetTweenSpriteY(swap_tween, swap_y, orig_y, 5);
						deselect_blocks();
						agk::PlaySound(swap_sound);
						agk::PlayTweenSprite(block_tween, blocks[cur_block].sprite, 0);
						agk::PlayTweenSprite(swap_tween, blocks[b].sprite, 0);
					}
				}
			}
		}
	}
}

int app::Loop(void)
{
	if (game_state == 0) // TITLE SCREEN STATE
	{
		if (agk::GetPointerPressed())
		{
			agk::DeleteSprite(title_screen);
			game_state = 1;
		}
	}
	if (game_state == 1) // MAIN GAMEPLAY STATE
	{
		if (blocks.size() > 0 && !agk::GetTweenSpritePlaying(block_tween, blocks[cur_block].sprite))
		{
			for (int b = 0; b < blocks.size(); b++)
			{
				agk::SetSpritePhysicsOn(blocks[b].sprite, 2);
			}
			bool allow_mouse = true;
			for (int b = 0; b < blocks.size(); b++)
			{
				blocks[b].vel_y = agk::GetSpritePhysicsVelocityY(blocks[b].sprite);
				if (blocks[b].click_delay_counter > 0) blocks[b].click_delay_counter -= 1;
				if (blocks[b].vel_y - blocks[b].old_vel_y < 0)
				{
					if (blocks[b].click_delay_counter <= 0) if (!agk::GetSoundsPlaying(block_collide_sound)) agk::PlaySound(block_collide_sound);
					blocks[b].click_delay_counter = 50;
				}
				blocks[b].old_vel_y = blocks[b].vel_y;
				if (agk::GetSpritePhysicsVelocityY(blocks[b].sprite) > 2) allow_mouse = false;
			}
			if (allow_mouse) mouse_input();
			select_marked_blocks();

			score_ss.str("");
			score_ss << "Score: " << player_score;
			agk::SetTextString(score_text, score_ss.str().c_str());
		}
		else
		{
		}
		// FLOAT SCORE
		agk::SetTextPosition(score_floater, agk::GetTextX(score_floater), agk::GetTextY(score_floater) - 2);
		if (agk::ScreenFPS() > 40) if (blocks.size() < 80) make_new_blocks();
	}
			
		agk::UpdateAllTweens(agk::GetFrameTime());
		agk::Sync();

		if (agk::GetRawKeyState(27))
		{
			return 1;
		}
		else return 0;
	
}
void app::End(void)
{
	exit(0);
}
