
/****************************************************************************/
/*Copyright (c) 2011, Florent DEVILLE.                                      */
/*All rights reserved.                                                      */
/*                                                                          */
/*Redistribution and use in source and binary forms, with or without        */
/*modification, are permitted provided that the following conditions        */
/*are met:                                                                  */
/*                                                                          */
/* - Redistributions of source code must retain the above copyright         */
/*notice, this list of conditions and the following disclaimer.             */
/* - Redistributions in binary form must reproduce the above                */
/*copyright notice, this list of conditions and the following               */
/*disclaimer in the documentation and/or other materials provided           */
/*with the distribution.                                                    */
/* - The names of its contributors cannot be used to endorse or promote     */
/*products derived from this software without specific prior written        */
/*permission.                                                               */
/* - The source code cannot be used for commercial purposes without         */
/*its contributors' permission.                                             */
/*                                                                          */
/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/*"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/*LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         */
/*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            */
/*COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       */
/*INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,      */
/*BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          */
/*LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER          */
/*CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT        */
/*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN         */
/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
/*POSSIBILITY OF SUCH DAMAGE.                                               */
/****************************************************************************/

using GE.Visualisation;
using GE.Physics.Shapes;
using GE.Physics;
using GE.Manager;
using Microsoft.Xna.Framework;

namespace GE.World.Entities
{
    class HelichomperEntity : EnemyEntity
    {

        public enum eState
        {
            eStateApproach,
            eStateAttack,
            eStateCount
        }

        /// <summary>
        /// entity inner state
        /// </summary>
        eState _innerState;

        /// <summary>
        /// Animation id
        /// </summary>
        int _iIdAnimation;

        /// <summary>
        /// Last frame displayed
        /// </summary>
        int _iAnimationLastFrame;

        /// <summary>
        /// Animation time
        /// </summary>
        int _iAnimationCurrentTime;

        /// <summary>
        /// Hit box
        /// </summary>
        //DynamicShapeRectangle _shape;

        /// <summary>
        /// Animation for the explosion
        /// </summary>
        int _iIdAnimationExplosion;

        /// <summary>
        /// Life time the enemy waits before attacking
        /// </summary>
        int _iStateApproachLifeTime = 2000;

        /// <summary>
        /// Birth time of the state approach
        /// </summary>
        int _iStateApproachBirthTime;

        Vector2 _v2Speed = new Vector2(2, 0);

        const int _iMaxDistance = 150;

        const int _iMinDistance = 70;
        System.Random _random;

        bool _bPreState;

        Vector2[] _v2Waypoint;
        int _iBirthTimeStateAttack;
        int _iLifeTimeStateAttack;
        int _iCurrantWaypoint;

        int _iDistanceHeight;
#if !GAME
        public static string EDITOR_TILESET { get { return "enemysheet.xml";}}
        public static string EDITOR_SPRITE { get { return "helichomper_blue_1"; } }
#endif
        

        public void setPosition(Vector2 v)
        {
            Position = v;
            _shape._v2position = v;
        }

        public void setState(eState newState)
        {
            _innerState = newState;
            _bPreState = true;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        public HelichomperEntity()
            : base()
        {
            _iIdAnimation = -1;
            _iAnimationLastFrame = -1;
            _iAnimationCurrentTime = -1;

            _shape = Physics.Physics.Instance.createDynamicRectangle(0, 0, Vector2.Zero, this);
            _shape._bCollisionEnable = false;
            _shape._iGroup = (int)ePhysicGroup.ePhysicEnemy;
            _innerState = eState.eStateApproach;

            _random = new System.Random(TimeClock.Clock.instance.millisecs);
            _bPreState = true;
            _v2Waypoint = new Vector2[3];
            
        }

        /// <summary>
        /// Initialise the entity
        /// </summary>
        public override void init()
        {
            _iIdAnimation = Visu.Instance.getAnimationID("Helichomper");
            _iIdAnimationExplosion = Visu.Instance.getAnimationID("Little_Explosion");

            int idTexture = Visu.Instance.getAnimation(_iIdAnimation).indexTexture;
            int idSprite = Visu.Instance.getAnimation(_iIdAnimation).idFirstSprite;

            int width = Visu.Instance.getSpriteWidth(idTexture, idSprite);
            int height = Visu.Instance.getSpriteHeight(idTexture, idSprite);

            _shape.resize(width, height);

            _innerState = eState.eStateApproach;
            base.init();
        }

        /// <summary>
        /// Activator
        /// </summary>
        public override void activate()
        {
            _shape._bCollisionEnable = true;
            _shape._v2position = Position;

            _bActive = true;
            _bPreState = true;

            _iDistanceHeight = _random.Next(100, 150);

            _iStateApproachLifeTime += _random.Next(0, 500);
            _innerState = eState.eStateApproach;
        }

        public override void update()
        {
            switch (_innerState)
            {
                case eState.eStateApproach:
                    updateStateApproach();
                    break;

                case eState.eStateAttack:
                    updateStateAttack();
                    break;
            }

            //check collision
            CollisionResult res = Physics.Physics.Instance.checkFirstRegisteredCollisionEx(_shape, (int)ePhysicGroup.ePhysicPlayer);
            if (res != null)
            {
                res.Entity.hurt(_iDamages);
                //die();
            }
        }

        public override void render()
        {
            Visu.Instance.displayAnimation(_iIdAnimation, ScreenPosition, ref _iAnimationLastFrame, ref _iAnimationCurrentTime);

#if DEBUG
            Vector2[] obb = _shape.getOrientedBoundingBox();
            for (int i = 0; i < 4; i++)
                obb[i] -= World.Instance.CameraPosition;

            Visu.Instance.displayPolygon(obb);


#endif
        }

        public void updateStateApproach()
        {
            if (_bPreState)
            {
                _bPreState = false;
                _iStateApproachBirthTime = TimeClock.Clock.instance.millisecs;
            }

            //if (TimeClock.Clock.instance.millisecs >= _iStateApproachBirthTime + _iStateApproachLifeTime)
            //    setState(eState.eStateAttack);

            Vector2 v2VerticalSpeed = new Vector2(_v2Speed.Y, _v2Speed.X);
            Vector2 v2Distance = World.Instance.PlayerPosition - Position;

            //follow the player, up and down
            float absDistance = System.Math.Abs(v2Distance.Y);
            if (absDistance > _iDistanceHeight)
            {
                if (v2Distance.Y > 0)
                    setPosition(Position + v2VerticalSpeed);
                else
                    setPosition(Position - v2VerticalSpeed);
            }
            else if (absDistance < _iDistanceHeight - v2VerticalSpeed.Y)
            {
                if (v2Distance.Y > 0)
                    setPosition(Position - v2VerticalSpeed);
                else
                    setPosition(Position + v2VerticalSpeed);
            }

            //follow the player : left and right          
            absDistance = System.Math.Abs(v2Distance.X);
            if (absDistance > _iMaxDistance)
            {
                if (v2Distance.X < 0)
                    setPosition(Position - _v2Speed);
                else
                    setPosition(Position + _v2Speed);
            }
            else if (absDistance < _iMinDistance)
            {
                if (v2Distance.X < 0)
                    setPosition(Position + _v2Speed);
                else
                    setPosition(Position - _v2Speed);
            }
            else
            {
                if (TimeClock.Clock.instance.millisecs >= _iStateApproachBirthTime + _iStateApproachLifeTime)
                    setState(eState.eStateAttack);
            }
        }

        public void updateStateAttack()
        {
            if (_bPreState)
            {
                float fDistanceHeight = World.Instance.PlayerPosition.Y - Position.Y;
                _bPreState = false;
                _v2Waypoint[0] = Position;

                if(fDistanceHeight < 0)
                    _v2Waypoint[1] = World.Instance.PlayerPosition - new Vector2(0, 20);
                else
                    _v2Waypoint[1] = World.Instance.PlayerPosition + new Vector2(0, 20);

                _v2Waypoint[2] = Position + new Vector2(_v2Waypoint[1].X - _v2Waypoint[0].X, 0)*2;

                _iBirthTimeStateAttack = TimeClock.Clock.instance.millisecs;
                _iLifeTimeStateAttack = 500;
                _iCurrantWaypoint = 0;
            }

            float fElapsedTime = TimeClock.Clock.instance.millisecs - _iBirthTimeStateAttack;
            float fRatio = fElapsedTime/_iLifeTimeStateAttack;

            if (fRatio >= 1)
            {
                fRatio = 0;
                _iCurrantWaypoint++;
                _iBirthTimeStateAttack = TimeClock.Clock.instance.millisecs;
                if (_iCurrantWaypoint > 1)
                {
                    setState(eState.eStateApproach);
                    return;
                }
            }

            Vector2 newPosition = Vector2.Zero;
            switch(_iCurrantWaypoint)
            {
                case 0:
                    newPosition = Vector2.CatmullRom(_v2Waypoint[0], _v2Waypoint[0], _v2Waypoint[1], _v2Waypoint[2], fRatio);
                    break;

                case 1:
                    newPosition = Vector2.CatmullRom(_v2Waypoint[0], _v2Waypoint[1], _v2Waypoint[2], _v2Waypoint[2], fRatio);
                    break;
            }
            setPosition(newPosition);
        }

        public override void die()
        {
            _bActive = false;
            _shape._bCollisionEnable = false;
            Manager.ExplosionManager.Instance.activate(_iIdAnimationExplosion, Position);
        }

    }
}
