#include "PongGamePlayScene.h"

#include <stdlib.h>		// srand, rand
#include <time.h>		// time


//PongGamePlayScene.cpp

PongGamePlayScene::PongGamePlayScene(Pong* pong) :
theGame(pong)
{
}

PongGamePlayScene::~PongGamePlayScene()
{
	delete ball;
	delete paddle;
}

bool PongGamePlayScene::setup()
{
	/// hw 6 Create paddle GameObject
	paddleWidth = 40;
	paddleHeight = 100;
	paddle = new GE161::GameObject(
		theGame->window()->clientWidth() * 3/4, theGame->window()->clientHeight() * 3/4);
	GE161::Sprite* paddleSprite = new GE161::Sprite(paddleWidth, paddleHeight);
	paddleFrame = paddleSprite->makeFrame(
				GE161::Game::basePath() + "Paddle.png", 0, 0);
	paddle->attachSprite(paddleSprite);

	// Rolling ball sprite sheet is from http://www.java-gaming.org/index.php?topic=21935.0.
	// It has 32 64x64 frames.

	// Start the ball with its upper left in the middle of the window.
	ball = new GE161::GameObject(
		theGame->window()->clientWidth() / 2, theGame->window()->clientHeight() / 2);
	frameWidth_ = 64;
	frameHeight_ = 64;
	GE161::Sprite* ballSpriteSheet = new GE161::Sprite(frameWidth_, frameHeight_);
	for (int row = 0; row < 4; row++)
	{
		for (int column = 0; column < 8; column++)
		{
			int f = ballSpriteSheet->makeFrame(
				GE161::Game::basePath() + "RollingBall.png",
				column*frameWidth_, row*frameHeight_);
			ballSpriteSheet->addFrameToSequence("Rolling", f);
		}
	}
	ball->attachSprite(ballSpriteSheet);

	x_delta = y_delta = 1;
	bounceCount_ = 0;
	score = 0;					/// hw 6

	// seed the random number generator with the current time
	srand(static_cast<unsigned int>(time(NULL)));

	GE161::Game::registerAsListener(GE161::Event::KEY_DOWN, this); /// hw 6

	scoreText = new GE161::Texty(
		GE161::Game::basePath() + "sample.ttf", 20, true);

	// hw8 - define event type and explosion sprite
	ballHitsPaddleEventType = theGame->LOWEST_USER_EVENT_CODE + 1;
	GE161::Game::registerAsListener(ballHitsPaddleEventType, this);
	explosionFramesRemaining = 0;
	explosion = new GE161::GameObject(0, 0);
	GE161::Sprite* explosionSprite = new GE161::Sprite(50, 50);
	explosionSprite->addFrameToSequence("Wow",
		explosionSprite->makeFrame(
		GE161::Game::basePath() + "Explosion.png", 0, 0));
	explosionSprite->addFrameToSequence("Wow",
		explosionSprite->makeFrame(
		GE161::Game::basePath() + "Explosion.png", 0, 50));
	explosion->attachSprite(explosionSprite);

	// hw 8, part 3 - two goals
	hitLeftGoalEventType = theGame->LOWEST_USER_EVENT_CODE + 2;
	hitRightGoalEventType = theGame->LOWEST_USER_EVENT_CODE + 3;
	GE161::Game::registerAsListener(hitLeftGoalEventType, this);
	GE161::Game::registerAsListener(hitRightGoalEventType, this);
	leftGoalGoingDown = true;
	rightGoalGoingDown = false;
	leftGoal = new GE161::GameObject(5, theGame->window()->clientHeight() / 2);
	GE161::Sprite* leftGoalSprite = new GE161::Sprite(20, 80);
	leftGoalSprite->addFrameToSequence("Goal",
		leftGoalSprite->makeFrame(
		GE161::Game::basePath() + "Goal.png", 0, 0));
	leftGoal->attachSprite(leftGoalSprite);
	rightGoal = new GE161::GameObject(theGame->window()->clientWidth() - 25, 
							theGame->window()->clientHeight() / 2);
	GE161::Sprite* rightGoalSprite = new GE161::Sprite(20, 80);
	rightGoalSprite->addFrameToSequence("Goal",
		rightGoalSprite->makeFrame(
		GE161::Game::basePath() + "Goal.png", 0, 0));
	rightGoal->attachSprite(rightGoalSprite);

	// hw 8 - three snitches
	snitchEventType = theGame->LOWEST_USER_EVENT_CODE + 4;
	GE161::Game::registerAsListener(snitchEventType, this);
	for (int i = 0; i < 3; i++)
	{
		snitch[i] = new GE161::GameObject(
			theGame->window()->clientWidth() / 2, theGame->window()->clientHeight() / 2);
		GE161::Sprite* snitchSprite = new GE161::Sprite(20, 20);
		snitchSprite->addFrameToSequence("Zoom!",
			snitchSprite->makeFrame(
			GE161::Game::basePath() + "Snitch.png", 0, 0));
		snitch[i]->attachSprite(snitchSprite);
		snitchX[i] = rand() % 20 - 10;
		snitchY[i] = rand() % 20 - 10;
	}

	return true;
}

int PongGamePlayScene::draw()
{
	ball->moveX(x_delta);
	ball->moveY(y_delta);
	ball->draw("Rolling");
	paddle->draw(paddleFrame);			/// hw 6
	scoreText->write(std::string("Score: ") + std::to_string(score), 20, 20);
	if (explosionFramesRemaining > 0)
	{
		explosion->draw("Wow");
		explosionFramesRemaining--;
	}

	// hw8, goal logic
	if (leftGoalGoingDown)
	{
		leftGoal->moveY(2);
		if (leftGoal->getY() + leftGoal->getHeight() > theGame->window()->clientHeight())
		{
			leftGoalGoingDown = false;
		}
	}
	else
	{
		leftGoal->moveY(-2);
		if (leftGoal->getY() < 0)
		{
			leftGoalGoingDown = true;
		}
	}
	if (rightGoalGoingDown)
	{
		rightGoal->moveY(3);
		if (rightGoal->getY() + rightGoal->getHeight() > theGame->window()->clientHeight())
		{
			rightGoalGoingDown = false;
		}
	}
	else
	{
		rightGoal->moveY(-3);
		if (rightGoal->getY() < 0)
		{
			rightGoalGoingDown = true;
		}
	}
	if (ball->overlapsWith(*leftGoal))
	{
		theGame->sendEvent(hitLeftGoalEventType, nullptr);
	}
	if (ball->overlapsWith(*rightGoal))
	{
		theGame->sendEvent(hitRightGoalEventType, nullptr);
	}
	leftGoal->draw("Goal");
	rightGoal->draw("Goal");
	
	// hw8, snitch logic
	for (int i = 0; i < 3; i++)
	{
		snitch[i]->moveX(snitchX[i]);
		snitch[i]->moveY(snitchY[i]);
		snitch[i]->draw("Zoom!");
		if (snitch[i]->getX() < 0 || snitch[i]->getX() > theGame->window()->clientWidth())
			snitchX[i] = -snitchX[i];
		if (snitch[i]->getY() < 0 || snitch[i]->getY() > theGame->window()->clientHeight())
			snitchY[i] = -snitchY[i];
		if (ball->overlapsWith(*snitch[i]))
		{
			int* whichSnitchData = new int[1] {i};
			theGame->sendEvent(snitchEventType, whichSnitchData);
		}
	}

	// If the ball has hit an edge of the window, bounce randomly.
	if (ball->getX() < 0)
	{
		x_delta = rand() % 5 + 2;
		bounceCount_++;
	}
	if (ball->getY() < 0)
	{
		y_delta = rand() % 5 + 2;
		bounceCount_++;
	}
	if (ball->getX() + frameWidth_ >= theGame->window()->clientWidth())
	{
		x_delta = -(rand() % 5 + 2);
		bounceCount_++;
		//score++;		/// hw 6   commented out for hw 8
	}
	if (ball->getY() + frameHeight_ >= theGame->window()->clientHeight())
	{
		y_delta = -(rand() % 5 + 2);
		bounceCount_++;
	}

	/// hw 6
	if (ball->overlapsWith(*paddle))
	{
		// This doesn't always work perfectly, because if x and y delta
		// are small, after bouncing (sign reversal) they may still overlap
		// the ball, leading to a funny vibration.
		x_delta = -x_delta;
		y_delta = -y_delta;
		/// hw 8
		int* locationData = new int[2] 
			{ (ball->getCenterX() + paddle->getCenterX()) / 2,
				(ball->getCenterY() + paddle->getCenterY()) / 2 };
		theGame->sendEvent(ballHitsPaddleEventType, locationData);
	}

	if (score < 20)			/// hw 6 & 8
	{
		return GE161::Game::CONTINUE_SCENE;
	}
	else     // bounced out
	{
		return -1;  // stop game
	}
}

/// hw 6
void PongGamePlayScene::onEvent(GE161::Event& event)
{
	if (event.type == GE161::Event::KEY_DOWN)  // this test isn't necessary
	{
		if (event.key == "LEFT")
			paddle->moveX(-4);
		else if (event.key == "RIGHT")
			paddle->moveX(4);
		else if (event.key == "UP")
			paddle->moveY(-4);
		else if (event.key == "DOWN")
			paddle->moveY(4);
		else if (event.key == "BACKSPACE")		/// hw 6
			// this puts the ball's upper left in the middle of the window
			ball->setPos(theGame->window()->clientWidth() / 2,
						 theGame->window()->clientHeight() / 2);
	}
	else if (event.type == ballHitsPaddleEventType)	/// hw 8
	{
		explosionFramesRemaining = 15;
		//explosion->setPos(100, 100);
		explosion->setPos(
			event.userEventData[0] - explosion->getWidth() / 2,
			event.userEventData[1] - explosion->getHeight() / 2);
	}
	else if (event.type == hitLeftGoalEventType)	/// hw 8
	{
		score += 5;
		// this puts the ball's upper left in the middle of the window
		ball->setPos(theGame->window()->clientWidth() / 2,
			theGame->window()->clientHeight() / 2);
	}
	else if (event.type == hitRightGoalEventType)	/// hw 8
	{
		score -= 2;
		// this puts the ball's upper left in the middle of the window
		ball->setPos(theGame->window()->clientWidth() / 2,
			theGame->window()->clientHeight() / 2);
	}
	else if (event.type == snitchEventType)	/// hw 8
	{
		int whichSnitch = event.userEventData[0];
		snitch[whichSnitch]->setPos(10, 10);
		// speed up the ball
		x_delta *= 1.25;
		y_delta *= 1.25;
	}
}

