using System.Drawing;
using System;

namespace Icarus.Logic.Physics
{
	/// <summary>
    /// I am a singleton which can be used to retrieve
    ///  Physics Engine settings.
    ///  
    /// Members are straightforward to access.
	/// </summary>
	public class PhysicsSettings
	{

        #region Singleton Implementation

        private static PhysicsSettings instance = new PhysicsSettings();
        
        /// <summary>
        /// The isntance of the Physics Settings Singletone
        /// </summary>
        public static PhysicsSettings Instance {
            get { return instance; }
            set { instance = value;}
        }

        #endregion

        #region Declarations

        private Vector fTerminalVelocity;
        private Vector fGravity;
        private Vector vecMercGravity;
        private Color cWhite, cYellow, cBlue, cRed, cGreen, cBlack, cGray;

        /// <summary>
        /// Determines whether god mode s on or not
        /// </summary>
        private bool bGodMode;

        /// <summary>
        /// The number of consecutive collisions allowed before it is 
        /// determined that the physics object is stuck and action should be taken.
        /// </summary>
        private int iConsecutiveCollisionsAllowed;

        /// <summary>
        /// The time a particle can live
        /// </summary>
        private int iParticleLifeSpan;

        /// <summary>
        /// The amount of bounces a particle can make
        /// </summary>
        private int iParticleBounceLimit;

        /// <summary>
        /// Constants used while detecting collisions
        /// </summary>
        public enum enumDirection {
            /// <summary>
            /// Defines the Up direction constant in Collisions
            /// </summary>
            Up, 

            /// <summary>
            /// Defines the Down direction constant in Collisions
            /// </summary>
            Down,

            /// <summary>
            /// Defines the Left direction constant in Collisions
            /// </summary>
            Left, 

            /// <summary>
            /// Defines the Right direction constant in Collisions
            /// </summary>
            Right, 

            /// <summary>
            /// Defines the Up and Left (North-West) Direction
            /// </summary>
            UpLeft, 

            /// <summary>
            /// Defines the Up and Right (North-East) Direction
            /// </summary>
            UpRight, 

            /// <summary>
            /// Defines the Down and Left (South-West) Direction
            /// </summary>
            DownLeft, 

            /// <summary>
            /// Defines the Down and Right (South-East) Direction
            /// </summary>
            DownRight,

            /// <summary>
            /// Defines the center (No) direction
            /// </summary>
            Center
        };

        /// <summary>
        /// Constants used while detecting collisions
        /// </summary>
        public enum enumActions {
            /// <summary>
            /// Used when a Collision should have no changes
            /// on the existence of the object
            /// </summary>
            DoNothing, 
            
            /// <summary>
            /// Defines that the collision should result in removal
            /// of the object in question
            /// </summary>
            Remove,
        
            /// <summary>
            /// Indicates that this obj should be checked for collisions
            /// again before it is moved.
            /// </summary>
            CheckAgain} ;

        /// <summary>
        /// Actions states a player can be in
        /// </summary>
        public enum enumPlayerActionStates {StandingLeft, StandingRight, WalkingLeft, WalkingRight, JumpingLeft, JumpingRight,
                                            FallingLeft, FallingRight, WhippingLeft, WhippingRight, WalkingUpSlopeRight, 
                                            WalkingDownSlopeLeft, WalkingUpSlopeLeft, WalkingDownSlopeRight};

        /// <summary>
        /// The upward velocity added when a player jumps.
        /// </summary>
        private float fJumpVelocity;

        /// <summary>
        /// The forward velocity added when a player jumps forward.
        /// </summary>
        private float fJumpForwardVelocity;

        /// <summary>
        /// The velocity at which a player normally walks
        /// </summary>
        private float fWalkVelocity;

        #endregion


        #region Fields

        /// <summary>
        /// gets or sets whether god mode is on
        /// </summary>
        public bool GodMode
        {
            get { return this.bGodMode; }
            set { this.bGodMode = value; }
        }

        /// <summary>
        /// he forward velocity added when a player jumps forward.
        /// </summary>
        public float JumpForwarVelocity
        {
            get { return this.fJumpForwardVelocity; }
            set { this.fJumpForwardVelocity = value; }
        }

        /// <summary>
        /// The velocity at which a player normally walks
        /// </summary>
        public float WalkVelocity
        {
            get { return this.fWalkVelocity; }
            set { this.fWalkVelocity = value; }
        }

        /// <summary>
        /// The upward velocity a player jumps with.
        /// </summary>
        public float JumpVelocity
        {
            get { return this.fJumpVelocity; }
            set { this.fJumpVelocity = value; }
        }

        /// <summary>
        /// Particle bounce limit.
        /// </summary>
        public int ParticleBounceLimit
        {
            get { return this.iParticleBounceLimit; }
            set { this.iParticleBounceLimit = value; }
        }

        /// <summary>
        /// Particle life limit in ms.
        /// </summary>
        public int ParticleLifeSpan
        {
            get { return this.iParticleLifeSpan; }
            set { this.iParticleLifeSpan = value; }
        }

        /// <summary>
        /// Provides access to the number of consecutive collisions
        /// an object is allowed to make before a special action has
        /// to be taken. This is just for particles... a player could
        /// collide with something many times and not be stuck
        /// </summary>
        public int ConsecutiveCollisionsAllowed
        {
            get { return this.iConsecutiveCollisionsAllowed; }
            set { this.iConsecutiveCollisionsAllowed = value; }
        }

        /// <summary>
        /// Provides access to white color for collision comparisons.
        /// </summary>
        public Color White
        {
            get { return this.cWhite; }
        }

        /// <summary>
        /// Provides access to red color for collision comparisons.
        /// </summary>
        public Color Red
        {
            get { return this.cRed; }
        }

        /// <summary>
        /// Provides access to green color for collision comparisons.
        /// </summary>
        public Color Green
        {
            get { return this.cGreen; }
        }

        /// <summary>
        /// Provides access to blue color for collision comparisons.
        /// </summary>
        public Color Blue
        {
            get { return this.cBlue; }
        }

        /// <summary>
        /// Provides access to yellow color for collision comparisons.
        /// </summary>
        public Color Yellow
        {
            get { return this.cYellow; }
        }

        /// <summary>
        /// Provides access to gray color for collision comparisons.
        /// </summary>
        public Color Gray
        {
            get { return this.cGray; }
        }

        /// <summary>
        /// Provides access to black color for collision comparisons.
        /// </summary>
        public Color Black
        {
            get { return this.cBlack; }
        }

        /// <summary>
        /// This sets the GLOBAL Terminal Velocity of an Object
        /// 
        /// This is used if a Physics Object's Terminal Velocity is null
        /// 
        /// A value of 0 or smaller means there is no Terminal Velocity
        /// 
        /// Default is:
        /// v = 0*i + (10.0*default(sv_gravity))*j + 0*k
        /// 
        /// Note that Team RETRO's classic game physics can easily be
        ///  implemented by setting the terminal velocity equal to the
        ///  gravity (i.e. move up and down at same rate)
        ///  
        /// </summary>
        public Vector sv_terminalVelocity 
        {
            get { return this.fTerminalVelocity; }
            set { this.fTerminalVelocity = value;}
        }
        
        
        /// <summary>
        /// This sets the current GLOBAL gravity to be used
        /// 
        /// This gravity is used if the player gravity is set to null
        /// 
        /// Can be negative (accelerate upwards), zero means no gravity
        /// 
        /// This is a constant acceleration in the j direction
        /// 
        /// Default is:
        /// v = 0*i + 9.81*j + 0*k
        /// 
        /// Note that Classic gameplay issues such as underwater and space
        ///  Physics can be implemented by varying the gravity (hint, hint
        ///  underwater Mario level (: )
        /// 
        /// </summary>
        public Vector sv_gravity {
            get { return this.fGravity; }
            set { this.fGravity = value;}
        }


        /// <summary>
        /// The gravity that should be used for Merc
        /// </summary>
        public Vector sv_mercGravity
        {
            get { return this.vecMercGravity; }
            set { this.vecMercGravity = value; }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes the Physics Settings to the default values
        /// </summary>
		private PhysicsSettings()
		{
			this.fGravity = new Vector();
            this.vecMercGravity = new Vector();
            this.fTerminalVelocity = new Vector();

            fGravity.j = 0.0f;//By default PO's have no gravity
            vecMercGravity.j = 4.0f;//Mercs gravity
            fTerminalVelocity.j = fTerminalVelocity.i = fTerminalVelocity.k = 30f;

            cWhite = System.Drawing.Color.White;
            cRed = System.Drawing.Color.Red;
            cGreen = System.Drawing.Color.Green;
            cBlue = System.Drawing.Color.Blue;
            cYellow = System.Drawing.Color.Yellow;
            cGray = System.Drawing.Color.Gray;
            cBlack = System.Drawing.Color.Black;
            
            fWalkVelocity = 8.0f;
            fJumpVelocity = -10.0f * vecMercGravity.j;
            fJumpForwardVelocity = fWalkVelocity * 1.5f;

            iConsecutiveCollisionsAllowed = 5;

            iParticleBounceLimit = 10;
            iParticleLifeSpan = 1500;//1.5 secs

            
		}

        /// <summary>
        /// Load the Physics Settings from fileName
        /// 
        /// Loads defaults then overwrites them with values in File
        /// </summary>
        /// <param name="fileName">name of File to load</param>
        private PhysicsSettings(string fileName) : this() {
        }

        #endregion

	}
}
