#include "GameLogic.h"
#include "Main.h"

#include "Fly.h"
#include "Swatter.h"
#include "EntShow.h"
#define C_GET_READY_SPEED_MS 600

using namespace std;

PlotManager g_plotManager;

void PlotManager::Plot(CL_Rect r, int count, float sinPower)
{
	
	m_plotVec.clear();

	PlotEntry p;

	float wave = FRandomRange(0, 6.14);

	for (int i=0; i < count; i++)
	{
		p.m_pos.x = r.left + (r.get_width() * (float(i)/float(count)));
		wave += (sinPower / float(count));
		p.m_pos.y = r.top + (  (r.get_height()/2) * (1+sin(wave)) );
		m_plotVec.push_back(p);
	}
}

GameLogic::GameLogic()
{
	m_failMod = 1;

	m_day = 0;

	ResetGame();
    m_slotKeyDown = CL_Keyboard::sig_key_down().connect(this, &GameLogic::OnKeyDown);
  
    for (int i=0; i < C_SOUND_COUNT; i++)
    {
        m_sounds[i] = NULL;
    }

	m_sounds[C_SOUND_BEE] = new CL_SoundBuffer("media/bee.wav");
	m_sounds[C_SOUND_TOO_SLOW] = new CL_SoundBuffer("media/start.wav");
 	m_sounds[C_SOUND_SQUISH] = new CL_SoundBuffer("media/squish.wav");
	m_sounds[C_SOUND_START] = new CL_SoundBuffer("media/slow.wav");
	m_sounds[C_SOUND_POWERUP] = new CL_SoundBuffer("media/powerup.wav");
	m_sounds[C_SOUND_RIFF] = new CL_SoundBuffer("media/riff.wav");
	m_sounds[C_SOUND_WONDERBOY] = new CL_SoundBuffer("media/wonderboy.wav");
	m_sounds[C_SOUND_INTRO] = new CL_SoundBuffer("media/intro.wav");
 
	m_spaceFunctionality = C_SPACE_TO_HELP;
	GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 100, NULL, C_SOUND_WONDERBOY);

	//Init();
}

void GameLogic::ResetGame()
{
	m_spaceFunctionality = C_SPACE_NOTHING;

	m_barFreeze = 0;
	m_barTimer = 0;
    m_totalScore = 0;
	m_lastSwipeScore = 0;
	

}

GameLogic::~GameLogic()
{

	m_messageDispatcher.ClearAllMessages();
    Kill();
    for (int i=0; i < C_SOUND_COUNT; i++)
    {
        SAFE_DELETE(m_sounds[i]);
    }
}

void GameLogic::SetupLevelData(int day)
{
	m_flyRect =  CL_Rect (230,93,830,460);

	m_timeAllowed = 1000;
	m_sinMin  = 0.06f;
	m_sinMax = 1;
	m_countMin = m_countMax = 20;
	m_levelText = "Level " + CL_String::from_int(day) +"\n\nPoints needed to pass: ";
	m_wavesLeft = 2;
	m_scoreThisRound = 0;

#ifdef _DEBUG
	day = 2;
#endif

	switch(day)
	{

	case 1:
		m_timeAllowed = 1000;
		m_sinMin  = 1;
		m_sinMax = 3;
		m_countMin = m_countMax = 20;
		m_wavesLeft = 10;
		m_scoreRequired = 3000 * m_failMod;
		m_bg = "media/bg2.jpg";

		m_levelText += CL_String::from_int(m_scoreRequired) +"\n\nYour first day.  You need to keep this pig happy.";

		break;

	case 2:
	//	m_flyRect =  CL_Rect (230,150,830,260);

		m_timeAllowed = 600;
		m_sinMin  = 3;
		m_sinMax = 9;
		m_countMin = 30;
		m_countMax = 40;
		m_wavesLeft = 10;
		m_scoreRequired = 2500* m_failMod;
		m_bg = "media/bg3.jpg";

		m_levelText += CL_String::from_int(m_scoreRequired) +"\n\nThe flies seem to be getting smarter...";

		break;


	case 3:
		m_timeAllowed = 1600;
		m_sinMin  = 10;
		m_sinMax = 15;
		m_countMin = 100;
		m_countMax = 100;
		m_wavesLeft = 10;
		m_scoreRequired = 15000* m_failMod;
		m_bg = "media/bg4.jpg";

		m_levelText += CL_String::from_int(m_scoreRequired) +"\n\nThis will take accuracy and speed!";

		break;
	
	case 4:
		m_timeAllowed = 600;
		m_sinMin  = 5;
		m_sinMax = 15;
		m_countMin = 50;
		m_countMax = 80;
		m_wavesLeft = 10;
		m_scoreRequired = 3000* m_failMod;
		m_bg = "media/bg.jpg";

		m_levelText += CL_String::from_int(m_scoreRequired) +"\n\nYou know what to do!";

		break;
	
	case 5:
		m_timeAllowed = 600;
		m_sinMin  = 6;
		m_sinMax = 12;
		m_countMin = 150;
		m_countMax = 150;

		m_wavesLeft = 10;
		m_scoreRequired = 12000* m_failMod;
		m_bg = "media/bg5.jpg";

		m_levelText += CL_String::from_int(m_scoreRequired) +"\n\nHow can Lenny truly relax with flies all over?";

		break;
	


	default:
		printf("Uh error");

	}

}

void GameLogic::SetupFlies()
{
	m_fliesKilled = 0;	
	//tell the right/left graphics to disappear
	//GetMessageDispatcher()->SendMsg(C_MESSAGE_ROUND_ENDED, 0);
	GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 0, NULL, C_SOUND_BEE);
	//any existing flies need to fly away and not be scored
	//GetMessageDispatcher()->SendMsg(C_MESSAGE_KILL_FLIES, 0);
	m_fliesSpawned = FRandomRange(m_countMin, m_countMax);
	g_plotManager.Plot(m_flyRect, m_fliesSpawned, FRandomRange(m_sinMin, m_sinMax));

	Fly *pFly = NULL;

	//make some flies?

	for (unsigned int i=0; i < g_plotManager.m_plotVec.size(); i++)
	{
		pFly = new Fly;
		pFly->SetPosTarget(g_plotManager.m_plotVec[i].m_pos);
		m_myEntityManager.Add(pFly);
	}
}

bool GameLogic::Init()
{

	m_messageDispatcher.ClearAllMessages();
	m_myEntityManager.Init();
	ResetGame();
	//make the swatter
	m_myEntityManager.Add(new Swatter());
	GetMessageDispatcher()->SendMsg(C_MESSAGE_INIT_NEXT_ROUND, 50);
	CL_Mouse::hide();

   return true;
}

void GameLogic::OnMessage(Message &msg)
{
    switch(msg.m_msg)
    {
    case C_MESSAGE_SOUND:
        Play(msg.m_parm);
        break;

	case C_MESSAGE_SHOW_ENDING:
		GetApp()->SetupBackground("media/win.jpg",0,0);
		m_spaceFunctionality = C_SPACE_START_GAME;
		m_day = 0;
		m_failMod = 1;
		break;

	case C_MESSAGE_INIT_NEXT_ROUND:
		m_day++;
		SetupLevelData(m_day);
		GetApp()->SetupBackground(m_bg, 0,0);
		GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 500, NULL, C_SOUND_INTRO);
		GetMessageDispatcher()->SendText(m_levelText, 1000, 2600);
		GetMessageDispatcher()->SendMsg(C_MESSAGE_PREPARE_RIGHT, 4000);
		break;

	case C_MESSAGE_TEXT:
		{
			EntShow *pEnt = new EntShow();
		pEnt->SetupText(msg.m_text, CL_Vector2( (float) GetScreenX/2, GetScreenY/2));
		m_myEntityManager.Add(pEnt);

		int timeToLive = 1000;

	if (msg.m_text.size() > 50)
	{
		timeToLive = 3500;	
	}

	if (msg.m_parm != 0) timeToLive = msg.m_parm;

	GetMessageDispatcher()->SendMsg(C_MESSAGE_KILL_ENTITY, timeToLive, pEnt);

		}
		break;

	case C_MESSAGE_PREPARE_RIGHT:
		{

			SetupFlies();
			EntShow *pEnt = new EntShow();
			pEnt->SetupPic("media/bar.png", CL_Vector2(C_EDGE_BORDER,0));
			m_myEntityManager.Add(pEnt);
			GetMessageDispatcher()->SendMsg(C_MESSAGE_KILL_ENTITY, C_GET_READY_SPEED_MS, pEnt);

			g_pSwatter->SetCursorLimit(CL_Rect(0,0,C_EDGE_BORDER,GetScreenY));
			g_pSwatter->SetMovementMode(Swatter::C_MOVE_ANYWHERE);
			GetMessageDispatcher()->SendMsg(C_MESSAGE_START_RIGHT, C_GET_READY_SPEED_MS);
			pEnt = new EntShow();
			pEnt->SetupPic("media/right.png", CL_Vector2(300,650));
			m_myEntityManager.Add(pEnt);
			pEnt->SetKillOnFinish(true);

			
		}

		break;

	case C_MESSAGE_PREPARE_LEFT:
		{
			SetupFlies();
			EntShow *pEnt = new EntShow();
			pEnt->SetupPic("media/bar.png", CL_Vector2( (GetScreenX-C_EDGE_BORDER)-30,0));
			m_myEntityManager.Add(pEnt);
			GetMessageDispatcher()->SendMsg(C_MESSAGE_KILL_ENTITY, C_GET_READY_SPEED_MS, pEnt);

			g_pSwatter->SetCursorLimit(CL_Rect(GetScreenX-C_EDGE_BORDER,0,GetScreenX,GetScreenY));
			g_pSwatter->SetMovementMode(Swatter::C_MOVE_ANYWHERE);

			GetMessageDispatcher()->SendMsg(C_MESSAGE_START_LEFT, C_GET_READY_SPEED_MS);

			pEnt = new EntShow();
			pEnt->SetupPic("media/left.png", CL_Vector2(300,650));
			pEnt->SetKillOnFinish(true);
			m_myEntityManager.Add(pEnt);
		
		}

		break;

	case C_MESSAGE_START_RIGHT:
		{
		
			//limit cursor
			g_pSwatter->SetCursorLimit(CL_Rect(0,0,GetScreenX,GetScreenY));
			g_pSwatter->SetMovementMode(Swatter::C_MOVE_RIGHT_ONLY);
			GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 0, NULL, C_SOUND_START);


			ResetTimer();

		}
		break;

	case C_MESSAGE_START_LEFT:
		{
			//limit cursor
			g_pSwatter->SetCursorLimit(CL_Rect(0,0,GetScreenX,GetScreenY));
			g_pSwatter->SetMovementMode(Swatter::C_MOVE_LEFT_ONLY);
			GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 0, NULL, C_SOUND_START);
		ResetTimer();
		}

		break;
   	
   }
}

void GameLogic::ResetTimer()
{
	m_barFreeze = 0;
	m_barTimer = GetApp()->GetGameTick() + m_timeAllowed;
}

void GameLogic::OnKeyDown(const CL_InputEvent &key)
{
         switch (key.id)
        {
		 case CL_KEY_SPACE:
			switch (m_spaceFunctionality)
			{

			case C_SPACE_TO_HELP:

					m_spaceFunctionality = C_SPACE_START_GAME;
					GetApp()->SetupBackground("media/help.jpg",0,0);
				break;

			case C_SPACE_START_GAME:
				m_spaceFunctionality = C_SPACE_NOTHING;

				Init();
				break;
			}
			 

			 break;
        case  CL_KEY_F11:
            break;
        }
}

void GameLogic::RebuildBuffers()
{
    //note, currently, this can get called before Init() is called!
 //   GetApp()->GetBackgroundCanvas()->get_gc()->clear(CL_Color(0,255,255));
}

void GameLogic::Kill()
{

}

void GameLogic::Update(float step)
{
    m_messageDispatcher.Update();  
    m_myEntityManager.Update(step);
}

void GameLogic::CalculateSwipeScore()
{
	if (m_barTimer == 0)
	{
		//already calculated
		return;
	}

	//tell the right/left graphics to disappear
	GetMessageDispatcher()->SendMsg(C_MESSAGE_ROUND_ENDED, 0);
	//any existing flies need to fly away and not be scored
	GetMessageDispatcher()->SendMsg(C_MESSAGE_KILL_FLIES, 0);

	int timeLeft = int (m_barTimer) - int(GetApp()->GetGameTick());
	if (timeLeft > m_timeAllowed) timeLeft = m_timeAllowed;
	if (timeLeft < 0) timeLeft = 0;
	float ratioLeft =   float(timeLeft) / float(m_timeAllowed);

	if (ratioLeft < 0) ratioLeft = 0;

	m_barFreeze = ratioLeft;
	m_lastSwipeScore = m_fliesKilled * (50* ((0 + ratioLeft)));
	m_totalScore += m_lastSwipeScore;
	m_scoreThisRound += m_lastSwipeScore;

	
	if (m_lastSwipeScore > 0)
   {

	   if (m_fliesKilled == m_fliesSpawned)
	   {
			//they dun good		
		   GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 100, NULL, C_SOUND_POWERUP);
		   GetMessageDispatcher()->SendText("" + CL_String::from_int(m_lastSwipeScore) +" pts (got 'em all!)", 1);

	   } else
	   {
		   GetMessageDispatcher()->SendText("" + CL_String::from_int(m_lastSwipeScore) +" pts", 1);
	   }
	   
   } else
   {
	   GetMessageDispatcher()->SendText("Too slow!", 1);
   }

   	m_barTimer =0;

	m_wavesLeft--;


	if (m_wavesLeft <= 0)
	{
		
		
		//end of round.

		GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 1500, NULL, C_SOUND_RIFF);
		GetMessageDispatcher()->SendText("Level finished.", 1500);

		string msg = "Score Needed: " +CL_String::from_int(m_scoreRequired) +
			"\n\nLevel Score: " + CL_String::from_int(m_scoreThisRound) + "\n\n";


		if (m_scoreRequired > m_scoreThisRound)
		{
			//didn't pass
			msg += "You didn't make your quota!";
			GetMessageDispatcher()->SendText(msg, 3000);

			GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 7000, NULL, C_SOUND_WONDERBOY);
			GetMessageDispatcher()->SendText("You're fired!\n\nYou spend the rest of your days performing\na tedious pointless job at the zoo.\n\nPress SPACE to try this level again.\n\n(score target will be made easier)", 7000,  500000);
			m_spaceFunctionality = C_SPACE_START_GAME;
			m_failMod -= 0.05f;
			if (m_failMod < 0.1) m_failMod = 0.1f;
			m_day--; //have to, because I incrememnt when they restart
		} else
		{
			int r = Random(4);

			switch (r)
			{
			case 0:
				msg += "You're lord of the flies!";
				break;

			case 1:
				msg += "Larvae begone!";
				break;

			case 2:
				msg += "Great work, animals love you!";
				break;

			case 3:
				msg += "Great job of murdering defenseless flies!";
				break;

			default:
				msg += "Excellent work!";
			}
			
			GetMessageDispatcher()->SendText(msg, 3000);

			if (m_day == 5)
			{
				GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 8000, NULL, C_SOUND_WONDERBOY);
		//they just won the game I guess
				GetMessageDispatcher()->SendMsg(C_MESSAGE_SHOW_ENDING, 8000);
				return;
			} else
			{

				GetMessageDispatcher()->SendMsg(C_MESSAGE_INIT_NEXT_ROUND, 6000);
			}

		

		}




	}

}

void GameLogic::RenderGUI()
{
float ratioLeft;
CL_Rect r (100,10,800,50);
	
if (m_barTimer != 0)
	{
		//calc how much is left
		int timeLeft = int (m_barTimer) - int(GetApp()->GetGameTick());
		if (timeLeft > m_timeAllowed) timeLeft = m_timeAllowed;
		if (timeLeft < 0) timeLeft = 0;

		ratioLeft =   float(timeLeft) / float(m_timeAllowed);

/*
		char st[256];
		sprintf(st, "ratio is %.2f \r\n", ratioLeft);
		OutputDebugStr(st);
*/

		if (timeLeft  == 0)
		{
			ratioLeft = 0;
			CalculateSwipeScore();
			GetMessageDispatcher()->SendMsg(C_MESSAGE_KILL_FLIES, 0);
			GetMessageDispatcher()->SendMsg(C_MESSAGE_SOUND, 0, NULL, C_SOUND_TOO_SLOW);

			//g_pSwatter->SetMovementMode(Swatter::C_MOVE_ANYWHERE);

		}


	} else
{
	ratioLeft = m_barFreeze;
}

	r.right = r.left + (float(r.get_width()) * ratioLeft);
	CL_Display::fill_rect(r, CL_Color(30,200,0,255));
	

    if (ratioLeft > 0)
	{
		GetApp()->GetFont(C_FONT_MAIN)->set_alignment(origin_top_left);
		GetApp()->GetFont(C_FONT_MAIN)->draw(100,17, CL_String::from_int(ratioLeft*100) + "% score mod");
		GetApp()->GetFont(C_FONT_MAIN)->set_alignment(origin_center);
	}

	 GetApp()->GetFont(C_FONT_MAIN)->draw(GetScreenX-250,20, "Score: " + CL_String::from_int(m_totalScore));


}

void GameLogic::Render()
{
    CL_Display::clear(CL_Color(0,0,255));
	GetApp()->GetBackground()->draw(0,0);
	m_myEntityManager.Render();    
	RenderGUI();

}

