using System;
using System.Collections;
using System.Threading;

namespace Icarus.Logic.GameEngine 
{
	/// <summary>
	/// I am the heart of the Icarus Game Engine
	/// I basically cause everything to start moving, sort of like a Spark Plug.
	/// I am a Singleton and I get started when the user turns the key by 
	/// executing the executable created by the Runner project.
	/// </summary>
	public class GameEngine 
	{

		#region Instance Variables
		/// <summary>
		/// This is the stack of game states we have running.
		/// </summary>
		private Stack mGameStates;

		/// <summary>
		/// This tells us if we are running, paused or stopped.
		/// </summary>
		private int iDoRun = -1;
		#endregion

		#region Singleton Stuff
		private static GameEngine instance = new GameEngine();

		/// <summary>
		/// Private Constructor for the Game Engine
		/// It is a Singleton so noone should ever touch the Constructor
		/// </summary>
		private GameEngine() 
		{
			this.mGameStates = new Stack();
			
			//We need to do this instead of using PushState function, because now the stack is empty.
			this.mGameStates.Push(new RootState());
		}

		/// <summary>
		/// The Singleton GameEngine instance
		/// </summary>
		public static GameEngine Instance 
		{
			get { return instance; }
		}
		#endregion


		#region Game State Controls
		//TODO: When pushing and popping the states, should we check the state of the engine?
		//      Like, suppose we are paused and push a state. Should we call pause on it so it doesn't do anything silly?

		/// <summary>
		/// The current state of the game engine.
		/// </summary>
		public IGameState CurrentState 
		{
			get { return (IGameState) this.mGameStates.Peek(); }
		}

		/// <summary>
		/// Pushes a game state onto the game state stack. The state on top of the stack is always the active one.
		/// </summary>
		/// <param name="state">The new active state.</param>
		public void PushState(IGameState state)
		{
			//Pause the current state:
			this.CurrentState.Pause();

			//Enter the new state:
			state.Enter();

			//Push the new state on the stack:
			this.mGameStates.Push(state);

			this.CurrentState.Unpause();
		}

		/// <summary>
		/// Pops the current state off the state stack. The previous active state will become active once again.
		/// </summary>
		public void PopState()
		{
			//Exit current state:
			this.CurrentState.Exit();

			//Pop state:
			this.mGameStates.Pop();

			//Unpause the next state:
			this.CurrentState.Unpause();
		}

		/// <summary>
		/// Renders the current state.
		/// </summary>
		/// <param name="parameters">Render parameters</param>
		public void RenderCurrentState(Icarus.Graphics.Animation.IRenderParameters parameters)
		{
			this.CurrentState.RenderState(parameters);
		}
		#endregion

		#region Run Controls
		/// <summary>
		/// Start the game engine.
		/// </summary>
		public void Play() 
		{
			this.CurrentState.Unpause();
			this.iDoRun = 1; 
		}

		/// <summary>
		/// Pause the game engine.
		/// </summary>
		public void Pause() 
		{ 
			this.iDoRun = -1;
			this.CurrentState.Pause();
		}

		/// <summary>
		/// Stop the game engine. Note that this will pop all the states, so we stop cleanly.
		/// </summary>
		public void Stop() 
		{
			//Pop all the states so we stop cleanly:
			while (!this.CurrentState.GetType().Equals(typeof(RootState)))
			{
				this.PopState();
			}

			this.iDoRun = 0;
		}
		#endregion

        #region Main Game Engine Loop
		/// <summary>
		/// The function that needs to be run in its own thread. This controls the game engine.
		/// </summary>
		public void RunThread() 
		{
			while (this.iDoRun != 0) 
			{
				DateTime start = DateTime.Now;
				int delay = (int) ((float)GameSettings.Instance.sv_updateRate / GameSettings.Instance.sv_timescale);

				if (this.iDoRun > 0) 
				{
					this.CurrentState.Step(delay);
				}

				int millis = DateTime.Now.Subtract(start).Milliseconds;
				if (millis < delay) 
				{
					Thread.Sleep(delay - millis);
				}
			}
		}
		#endregion
	}
}
