//	World7.cpp - One of the worlds.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  Niall Moody
//	
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#include "MiscHelper.h"
#include "World7.h"
#include "Random.h"

//------------------------------------------------------------------------------
World7::World7():
World(ThreeFloats(143.0f/255.0f, 141.0f/255.0f, 40.0f/255.0f),
	  ThreeFloats(241.0f/255.0f, 231.0f/255.0f, 76.0f/255.0f),
	  ThreeFloats(224.0f/255.0f, 145.0f/255.0f, 52.0f/255.0f),
	  ThreeFloats(242.0f/255.0f, 244.0f/255.0f, 179.0f/255.0f),
	  ThreeFloats(1.0f, 0.62f, 0.33f),
	  TwoFloats(1696.0f, -700.0f)),
currentRing(0),
mousePos(0.0f),
middleCount(1),
innerOrbit(192.0f),
innerIndex(0.0f),
worldScale(0.1f),
done(false)
{
	int i, j;
	int correctI, correctJ;

	setRing1Pos(TwoFloats(1696.0f-640.0f, -700.0f-360.0f));

	correctedColours[1] = getRing2Col();
	correctedColours[2] = getRing3Col();

	desiredMiddlePos.x = Random::getGlobal().getRandomFloat() * 1280.0f;
	desiredMiddlePos.y = Random::getGlobal().getRandomFloat() * 720.0f;

	correctI = (int)(Random::getGlobal().getRandomFloat() * 2.9999f);
	correctJ = (int)(Random::getGlobal().getRandomFloat() * 1.9999f);

	outerCols[correctJ][correctI] = ThreeFloats(215.0f/255.0f, 84.0f/255.0f, 170.0f/255.0f);

	for(j=0;j<2;++j)
	{
		for(i=0;i<3;++i)
		{
			if(!((i == correctI) && (j == correctJ)))
			{
				outerCols[j][i].x = Random::getGlobal().getRandomFloat();
				outerCols[j][i].y = Random::getGlobal().getRandomFloat();
				outerCols[j][i].z = Random::getGlobal().getRandomFloat();
			}
		}
	}

	//Make sure the mouse isn't right on the correct colour from the start.
	correctPos.x = 64.0f + ((float)correctI * ((1280.0f-128.0f)/2.0f));
	correctPos.y = 64.0f + ((float)correctJ * ((720.0f-128.0f)/2.0f));
	mousePos.x = Random::getGlobal().getRandomFloat() * 1280.0f;
	mousePos.y = Random::getGlobal().getRandomFloat() * 720.0f;
	while(mousePos.getDistance(correctPos) < 192.0f)
	{
		mousePos.x = Random::getGlobal().getRandomFloat() * 1280.0f;
		mousePos.y = Random::getGlobal().getRandomFloat() * 720.0f;
	}
	calcColours();
}

//------------------------------------------------------------------------------
World7::~World7()
{

}

//------------------------------------------------------------------------------
void World7::mouseMove(const TwoFloats& pos)
{
	mousePos = pos;
	if(currentRing == 0)
	{
		mousePos.x = 1280.0f - mousePos.x;
		mousePos.y = 720.0f - mousePos.y;
	}
	else if(currentRing == 1)
		calcColours();
	else if(currentRing == 2)
		detector.setMousePos(pos);
}

//------------------------------------------------------------------------------
void World7::subclassTick()
{
	TwoFloats tempPos;
	const TwoFloats centre(640.0f, 360.0f);
	const TwoFloats mainPos(1696.0f, -700.0f);

	switch(currentRing)
	{
		case 0:
			{
				tempPos = getRing1Pos() - (mainPos-centre);
				if(tempPos != mousePos)
				{
					tempPos += (mousePos-tempPos) * 0.05f;

					if(tempPos.getDistance(mousePos) < 4.0f)
						tempPos = mousePos;

					if(tempPos.getDistance(centre) < 32.0f)
					{
						tempPos = centre;
						++currentRing;
					}

					setRing1Pos(tempPos + (mainPos-centre));
				}
			}
			break;
		case 1:
			if(worldScale >= 0.28f)
			{
				if(mousePos.getDistance(correctPos) < 192.0f)
				{
					correctedColours[0] = ThreeFloats(241.0f/255.0f, 231.0f/255.0f, 76.0f/255.0f);
					setRingColours(correctedColours);
					++currentRing;
					desiredMiddlePos = centre;
					middleCount = -1;
				}
				else
					calcColours();
			}
			break;
		case 2:
			if(detector.update())
			{
				if(worldScale < 0.66f)
				{
					worldScale += 0.0005f;
					innerOrbit = (1.0f-((worldScale - 0.46f)/(0.66f-0.46f))) * 192.0f;
					setOverallScale(worldScale);
				}

				if(worldScale >= 0.66f)
				{
					done = true;
					++currentRing;
				}
			}
			else if(worldScale > 0.46f)
				worldScale -= 0.001f;
			break;
	}

	//Jump middle ring at random.
	if(middleCount > -1)
	{
		--middleCount;
		if(!middleCount)
		{
			middleCount = 10 + Random::getGlobal().getRandomInt(30);

			desiredMiddlePos.x = Random::getGlobal().getRandomFloat() * 1280.0f;
			desiredMiddlePos.y = Random::getGlobal().getRandomFloat() * 720.0f;
		}
	}

	//Update middle ring.
	tempPos = getRing2Pos() - (mainPos-centre);
	if(tempPos != desiredMiddlePos)
	{
		tempPos += ((desiredMiddlePos-tempPos) * 0.1f);
		if(tempPos.getDistance(desiredMiddlePos) < 1.0f)
			tempPos = desiredMiddlePos;

		setRing2Pos(tempPos + (mainPos-centre));
	}

	//Update inner ring.
	tempPos.x = sinf(innerIndex * 2.0f * NIALL_PI) * innerOrbit;
	tempPos.y = cosf(innerIndex * 2.0f * NIALL_PI) * innerOrbit;
	tempPos += getRing1Pos();
	setRing3Pos(tempPos);

	innerIndex += 0.001f;
	if(innerIndex > 1.0f)
		innerIndex -= 1.0f;

	switch(currentRing)
	{
		case 0:
			break;
		case 1:
			if(worldScale < 0.28f)
				worldScale += 0.005f;
			break;
		case 2:
			if(worldScale < 0.46f)
				worldScale += 0.005f;
			break;
		/*case 3:
			if(worldScale < 0.66f)
				worldScale += 0.01f;
			break;*/
	}
	setOverallScale(worldScale);
}

//------------------------------------------------------------------------------
void World7::calcColours()
{
	TwoFloats tempPos;
	int mouseX, mouseY;
	ThreeFloats topRow;
	ThreeFloats bottomRow;
	ThreeFloats finalCol;

	if(mousePos.x < 64.0f)
		tempPos.x = 0.0f;
	else if(mousePos.x > (1280.0f-64.0f))
		tempPos.x = 2.0f;
	else
		tempPos.x = (2.0f*(mousePos.x-64.0f)/(1280.0f-128.0f));

	if(mousePos.y < 64.0f)
		tempPos.y = 0.0f;
	else if(mousePos.y > (720.0f-64.0f))
		tempPos.y = 1.0f;
	else
		tempPos.y = (mousePos.y-64.0f)/(720.0f-128.0f);

	mouseX = (int)tempPos.x;
	mouseY = (int)tempPos.y;

	tempPos.x -= (float)mouseX;
	tempPos.y -= (float)mouseY;

	if(tempPos.x == 0.0f)
		topRow = outerCols[mouseY][mouseX];
	else
	{
		topRow = outerCols[mouseY][mouseX] * (1.0f-tempPos.x);
		topRow += outerCols[mouseY][mouseX+1] * tempPos.x;
	}

	if(tempPos.y == 0.0f)
	{
		correctedColours[0] = topRow;
		setRingColours(correctedColours);
	}
	else
	{
		if(tempPos.x == 0.0f)
			bottomRow = outerCols[mouseY+1][mouseX];
		else
		{
			bottomRow = outerCols[mouseY+1][mouseX] * (1.0f-tempPos.x);
			bottomRow += outerCols[mouseY+1][mouseX+1] * tempPos.x;
		}

		finalCol = topRow * (1.0f-tempPos.y);
		finalCol += bottomRow * tempPos.y;
		correctedColours[0] = finalCol;

		setRingColours(correctedColours);
	}
}
