using UnityEngine;
using System.Collections;

public class GameController : MonoBehaviour 
{
	
	enum GameState
	{
		Menu,
		InGame
	};
	
	static GameController s_Instance;
	
	public GameObject[] m_Levels;		
	public GameObject   m_PlayerPrefab;	
	public GameObject	m_Bullet;
	public GameObject   m_EnemyBullet;
	public GameObject   m_ScorePopup;
	public GameObject   m_Coin;
	public GameObject   m_BigCoin;
	public GUISkin	    m_GUISkin;
	
	public AudioClip    m_PressStart;
	public AudioClip    m_CoinCollect;
	
	int		  	 		m_iCurrentLevel 	= 0;
	GameObject	 		m_ActiveLevel   	= null;
	GameObject	 		m_Player		   	= null;
	GameObject	 		m_Camera		   	= null;
	GameObject	 		m_LevelCamera   	= null;
	GameObject	 		m_SpawnPoint	   	= null;
	int					m_iScore			= 0;
	int					m_iLowestScore		= 0;
	int					m_iDefaultScore		= 1000000;
	int					m_iDeathScore		= 25000;
	int					m_iLives			= 0;
	int					m_iDefaultLives		= 3;
	float				m_fScoreFlash		= 0.0f;
	float				m_fHPSAccum			= 0.0f;
	float				m_fHPSTick			= 0.0f;
	float				m_fHPSTickLength	= 1.0f;
	Vector3				m_vCamPos	   		= new Vector3();
	Vector3				m_vCamAtPos	   		= new Vector3();
	GameState			m_eState			= GameState.Menu;
	float				m_fGetReadyTimer	= 0.0f;
	float				m_fDeadTimer		= 0.0f;
	float				m_fGameOverTimer	= 0.0f;
	string				m_strGetReady		= "";
	AudioSource			m_AudioSrc;
	
	public static GameController GetInstance() {return s_Instance;}
	
	// --------------------------------------------------------------------------------------
	// Init
	// --------------------------------------------------------------------------------------
	
	void Start () 
	{		
		s_Instance = this;
		
		m_iLowestScore = m_iDefaultScore;
		
		GameObject.Find ( "[Prefabs]" ).SetActive(false);
		
		foreach( GameObject l in m_Levels )
		{
			l.SetActive(false);
		}
				
		m_Camera = GameObject.Find("Main Camera");
		
		m_AudioSrc = GetComponent<AudioSource>();
		
		//InitGame();
		InitMenu();
	}
	
	
	void InitGame()
	{
		m_iScore = m_iDefaultScore;
		m_iLives = m_iDefaultLives;
		m_iCurrentLevel = 0;		
		m_fScoreFlash = 0.0f;
		m_fHPSAccum = m_fHPSTick = 0.0f;
		InitLevel();
		SpawnPlayer( true );
		m_eState = GameState.InGame;		
	}
	
	
	void InitMenu()
	{
		FlushLevel();
		m_eState = GameState.Menu;
	}
	
	
	// --------------------------------------------------------------------------------------
	// Main update
	// --------------------------------------------------------------------------------------
	
	void Update () 
	{
		float fTimeStep = Time.deltaTime;
		
		if ( m_eState == GameState.InGame )
		{
			UpdateCamera( fTimeStep, false );
			
			if ( m_fDeadTimer<=0.0f && m_fGetReadyTimer<=0.0f && m_fGameOverTimer<=0.0f )
			{
				m_fHPSTick-=fTimeStep;
				if ( m_fHPSTick<=0.0f )				
				{			
					m_fHPSTick+=m_fHPSTickLength;
					
					float fScale = 50.0f;
					int iScore = (int)(m_fHPSAccum * fScale);
					iScore/=10;
					iScore*=10;
					
					if ( iScore>0 )
					{
						AddScore( -iScore, true, m_Player.transform.position );
						m_fHPSAccum = 0.0f;
					}
				}
				
				
				if ( m_Player.GetComponent<Player>().IsDead() )
				{	
					AddScore( -m_iDeathScore, true, m_Player.transform.position );
					
					m_fDeadTimer = 1.5f;
				}
			}
			
			if ( Input.GetKeyDown( KeyCode.Escape ) )
			{
				InitMenu();
			}	
			
			if ( m_fDeadTimer > 0.0f )
			{
				m_fDeadTimer = Mathf.Max( 0.0f, m_fDeadTimer - Time.deltaTime );				
				
				if ( m_fDeadTimer<=0.0f )
				{
					if ( m_iLives>1 )
					{
						m_iLives--;
						SpawnPlayer();
					}
					else
					{
						m_fGameOverTimer = 2.5f;
						if ( m_iScore < m_iLowestScore )
						{
							m_iLowestScore = m_iScore;
						}
					}
				}
			}
			
			if ( m_fGameOverTimer>0.0f )
			{
				m_fGameOverTimer = Mathf.Max( 0.0f, m_fGameOverTimer - Time.deltaTime );				
				
				if ( m_fGameOverTimer<=0.0f )
				{
					InitMenu();				
				}				
			}

		}
		else
		{
			float fRot = Time.timeScale * 0.1f;
			m_Camera.transform.Rotate( fRot*0.1f, fRot*0.5f, fRot*0.05f );
		}				
		
		
		m_fGetReadyTimer = Mathf.Max( 0.0f, m_fGetReadyTimer - Time.deltaTime );				
		m_fScoreFlash = Mathf.Max( 0.0f, m_fScoreFlash - Time.deltaTime*4.0f );				
	}
	
	
	// --------------------------------------------------------------------------------------
	// Flush a level
	// --------------------------------------------------------------------------------------
	
	void FlushLevel()
	{
		if ( m_ActiveLevel!=null )
		{
			Bullet.Flush();
			GameObject.Destroy( m_ActiveLevel );
			m_ActiveLevel = null;
			m_Player      = null;		
		}
	}
	
	
	// --------------------------------------------------------------------------------------
	// Init a level
	// --------------------------------------------------------------------------------------
	
	void InitLevel()
	{
		FlushLevel();
		m_ActiveLevel = Instantiate( m_Levels[m_iCurrentLevel] ) as GameObject;
		m_ActiveLevel.name = "[Current Level]";
		m_ActiveLevel.SetActive(true);
	}
	
	
	
	// --------------------------------------------------------------------------------------
	// SpawnPlayer
	// --------------------------------------------------------------------------------------
	
	void SpawnPlayer( bool bFirstTime = false )
	{
		if ( m_Player ) Object.Destroy(m_Player);
		
		// Init player+camera
		m_Player = Instantiate( m_PlayerPrefab ) as GameObject;
		m_Player.GetComponent<Player>().Init( this );
		m_Player.transform.parent = m_ActiveLevel.transform;
		
		m_SpawnPoint = Util.FindChild( m_ActiveLevel, "PlayerSpawn" );						
		m_Player.transform.localPosition = m_SpawnPoint.transform.localPosition;
		m_Player.transform.localRotation = m_SpawnPoint.transform.localRotation;
		
		m_LevelCamera= Util.FindChild( m_ActiveLevel, "Camera" );
		UpdateCamera( 0.0f, bFirstTime );
		
		m_fGetReadyTimer = 2.5f;
		
		if ( m_iLives == m_iDefaultLives )
			m_strGetReady = "Get Ready!";		
		else
		{
			if ( m_iLives == 1 ) 
				m_strGetReady = "One Death Left!";
			else
				m_strGetReady = m_iLives.ToString() + " Deaths Left";
		}
	}
	
	
	// --------------------------------------------------------------------------------------
	// Init the camera
	// --------------------------------------------------------------------------------------
	
	void UpdateCamera( float fTimeStep, bool bFirstTime )
	{		
		float fScrollScale    = 0.35f;
		float fPlayerPosScale = 0.35f;
		float fCamDistScale   = 0.8f;
		
		
		Vector3 vOfs = fCamDistScale * m_LevelCamera.transform.position;
		Vector3 vTargetAtPos  = (m_Player.transform.position * fPlayerPosScale);
		Vector3 vTargetCamPos = vOfs + (m_Player.transform.position * fScrollScale);
		
		vTargetAtPos.y -= 8.0f;
		
		if ( bFirstTime )
		{
			m_vCamPos   = vTargetCamPos;
			m_vCamAtPos = vTargetAtPos;
		}
		else
		{
			m_vCamAtPos = Vector3.Lerp( m_vCamAtPos, vTargetAtPos, fTimeStep*4.0f );
			m_vCamPos   = Vector3.Lerp( m_vCamPos, vTargetCamPos, fTimeStep*4.0f );
		}
			
		
		
		m_Camera.transform.position = m_vCamPos;
		m_Camera.transform.LookAt(  m_vCamAtPos );			
	}
	
	
	public GameObject GetCamera()
	{
		return m_Camera;
	}
	
	public GameObject GetPlayer()
	{
		return m_Player;
	}
	
	public GameObject GetBullet()
	{
		return m_Bullet;
	}
	
	public GameObject GetEnemyBullet()
	{
		return m_EnemyBullet;
	}
	
	public GameObject GetActiveLevel()
	{
		return m_ActiveLevel;
	}
	
	public GameObject GetCoin( bool bBig )
	{
		return bBig ? m_BigCoin : m_Coin;
	}
	
	public void AddScore( int iScore, bool bPopup, Vector3 vPos)
	{
		m_iScore+=iScore;
		
		GameObject popup = Instantiate( m_ScorePopup ) as GameObject;
		vPos.y += 2.5f;
		popup.GetComponent<ScorePopup>().Init( iScore );
		popup.transform.parent = m_ActiveLevel.transform;
		popup.transform.localPosition = vPos;
		
		if ( iScore>0 ) m_fScoreFlash = 1.0f;
	}
	
	public void AddActiveHPS( float fHPS )
	{
		m_fHPSAccum+=fHPS;
	}
	
	
	public void CollectCoin()
	{
		m_AudioSrc.PlayOneShot( m_CoinCollect );
	}
	 
    public void OnGUI () 
	{		
		GUI.skin = m_GUISkin;
		Util.BeginGUI();
	
		if ( m_eState == GameState.Menu )
		{
			// Main menu
			OnGUIMainMenu();
		}
		else
		{
			// In-game UI
			Color colTitle = new Color( 1.0f,0.8f,0.8f,1.0f );
			Color colWhite = new Color( 1.0f,1.0f,1.0f,1.0f );
			Color colRed   = new Color( 1.0f,0.0f,0.0f,1.0f );				
		
			float fLeft = Util.GetLeft();
			GUI.color = colTitle;
			GUI.Label (new Rect ( fLeft, 10, 250,30), "Score", "SmallLabel"  );		
			GUI.color = Color.Lerp( colWhite, colRed, m_fScoreFlash );
	        GUI.Label (new Rect ( fLeft, 30, 250,60), m_iScore.ToString("#,##0") );
			
			float fRight = Util.GetRight();
			GUI.color = colTitle;
			GUI.Label (new Rect ( fRight-150, 10, 150,30), "Lives", "SmallLabel"  );		
			GUI.color = colWhite;
	        GUI.Label (new Rect ( fRight-150, 30, 150,60), m_iLives.ToString() );
			
			
			if ( m_fGetReadyTimer > 0.0f )
			{
				float fCtr = 960.0f*0.5f;
							
				GUI.color = colWhite;
				
				if ( m_fGetReadyTimer<1.0f)
				{
					Color col = GUI.color ;
					col.a = m_fGetReadyTimer;
					GUI.color = col;
				}
					
				GUI.Label (new Rect ( fCtr-500, 370, 1000,60), m_strGetReady );
			}
			
			
			if ( m_fGameOverTimer > 0.0f )
			{
				float fCtr = 960.0f*0.5f;
					
				GUI.color = colTitle;				
				GUI.Label (new Rect ( fCtr-500, 230, 1000,60), "Game Over!" );
				
				if ( m_iScore<=m_iLowestScore )
				{
					GUI.color = colWhite;							
					GUI.Label (new Rect ( fCtr-500, 280, 1000,60), "New Low Score!: " + m_iScore.ToString("#,##0") );
				}
			}
			
		}
		
		Util.EndGUI();
    }
	
	
	public void OnGUIMainMenu()
	{
		// In-game UI
		Color colTitle = new Color( 1.0f,0.8f,0.8f,1.0f );
		Color colWhite = new Color( 1.0f,1.0f,1.0f,1.0f );		
		float fCtr = 960.0f*0.5f;
		
		GUI.color = colWhite;
		GUI.Label (new Rect ( fCtr-500, 110, 1000,50), "Weapons of Minimal Destruction" );		
		
		GUI.color = colTitle;
		GUI.Label (new Rect ( fCtr-500, 150, 1000,30), "Made by bluescrn for Ludum Dare #26", "SmallLabel"  );		
		
		GUI.color = colTitle;
		GUI.Label (new Rect ( fCtr-500, 200, 1000,30), "Low Score:", "SmallLabel"  );		
		GUI.color = colWhite;
		GUI.Label (new Rect ( fCtr-500, 222, 1000,50),  m_iLowestScore.ToString("#,##0") );	
		
		GUI.color = colWhite;
		GUI.Label (new Rect ( fCtr-500, 300, 1000,30), "Aim for a minimal score - Kill only the biggest threats!", "SmallLabel"  );		
		GUI.Label (new Rect ( fCtr-500, 320, 1000,30), "Decrease your score by keeping lots of enemies alive!", "SmallLabel" );
		GUI.Label (new Rect ( fCtr-500, 360, 1000,30), "Avoid nasty score-giving coin pickups!", "SmallLabel"  );
		GUI.Label (new Rect ( fCtr-500, 380, 1000,30), "Can you achieve a negative score?", "SmallLabel"  );
		
		if ( GUI.Button(new Rect ( fCtr-200, 425, 400,60), "Start Game" ))
		{
			InitGame();			
			m_AudioSrc.PlayOneShot( m_PressStart );
		}
		
		GUI.color = colTitle;
		GUI.Label (new Rect ( fCtr-500, 500, 1000,30), "Controls: WASD to move, Mouse to aim/fire", "SmallLabel"  );
	
	}
}
