using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;


using InfServer.Game;
using InfServer.Protocol;
using InfServer.Scripting;
using InfServer.Bots;

using Assets;
using Axiom.Math;
using Bnoerj.AI.Steering;

namespace InfServer.Script.GameType_MA
{   // Script Class
    /// Provides the interface between the script and bot
    ///////////////////////////////////////////////////////
    public partial class CAMLGM : Bot
    {   ///////////////////////////////////////////////////
        // Member Variables
        ///////////////////////////////////////////////////
        //private Bot _bot;							//Pointer to our bot class
        private Random _rand;

        private Player _target;                     //The player we're currently stalking
        protected bool bOverriddenPoll;         //Do we have custom actions for poll?

        protected List<Vector3> _path;			//The path to our destination
        protected int _pathTarget;				//The next target node of the path
        protected int _tickLastPath;			//The time at which we last made a path to the player

        protected SteeringController steering;	//System for controlling the bot's steering
        private float _seperation;
        private int _tickLastWave;
        private bool _bDetonated;
        private int _tickFired;
        private Vector3 _distractedTarget;
        private ItemInfo explosionItem;



        public CAMLGM(VehInfo.Car type, Helpers.ObjectState state, Arena arena)
            : base(type, state, arena,
            new SteeringController(type, state, arena))
        {
            Random rnd = new Random();
            _seperation = (float)rnd.NextDouble();
            steering = _movement as SteeringController;
            _rand = new Random();

        }

        public void init(Player target, int itemID)
        {
            _target = target;
            _weapon.equip(AssetManager.Manager.getItemByID(itemID));
            _tickFired = Environment.TickCount;
        }



        /// <summary>
        /// Allows the script to maintain itself
        /// </summary>
        public override bool poll()
        {
            if (bOverriddenPoll)
                return base.poll();

            if (_movement == null)
            {
                _movement = new MovementController(_type, _state, _arena);
                steering = _movement as SteeringController;
                return base.poll();
            }

            //Dead? Do nothing
            if (IsDead)
            {
                steering.steerDelegate = null;
                return base.poll();
            }

            if (_bDetonated)
            {
                kill(null);
            }

            int now = Environment.TickCount;

            if (now - _tickFired >= 1500 &&_arena.getPlayersInRange(_state.positionX, _state.positionY, 15).Count(p => !p.IsDead) >= 1)
            {
                _itemUseID = _weapon.ItemID;
                _weapon.shotFired();
                _bDetonated = true;
                return base.poll();
            }



            if (now - _tickFired >= 11000)
            {
                steering.steerDelegate = null;
                _itemUseID = _weapon.ItemID;
                _weapon.shotFired();
                _bDetonated = true;
                return base.poll();
            }


            if (now - _tickLastWave >= 80)
            {
                Helpers.Player_RouteExplosion(_arena.Players, 1030, _state.positionX, _state.positionY, 0, 0, 0);
                _tickLastWave = now;
            }


            if (_movement.bCollision)
            {
                steering.steerDelegate = null;
                _itemUseID = _weapon.ItemID;
                _weapon.shotFired();
                _bDetonated = true;
                return base.poll();
            }

            if (_target != null)
            {

                if (_target.getInventoryAmount(12) >= 1)
                {
                    _distractedTarget = getTargetPoint();
                    _target = null;
                    return base.poll();
                }


                double distance = (_state.position() - _target._state.position()).Length;
                if (distance > 1.0f)
                    steering.steerDelegate = steerForPersuePlayer;
                else if (distance <= 0.35f)
                {
                    steering.steerDelegate = steerForPersuePlayer;
                    _itemUseID = _weapon.ItemID;
                    _weapon.shotFired();
                    _bDetonated = true;
                    return base.poll();
                }
            }
            else
            {


                double distance = (_state.position() - _distractedTarget).Length;
                if (distance > 1.0f)
                    steering.steerDelegate = steerForSeekTarget;
                else if (distance <= 0.55f)
                {
                    steering.steerDelegate = steerForSeekTarget;
                    _itemUseID = _weapon.ItemID;
                    _weapon.shotFired();
                    _bDetonated = true;
                    return base.poll();
                }
            }
            
            //Handle normal functionality
            return base.poll();
        }

        /// <summary>
        /// Moves the medic on a persuit course towards the player, while keeping seperated from other medics
        /// </summary>
        public Vector3 steerForPersuePlayer(InfantryVehicle vehicle)
        {
            if (_target == null)
                return Vector3.Zero;

            Vector3 pursuitSteer = vehicle.SteerForPursuit(_target.ActiveVehicle.Abstract, 0.3f);

            return pursuitSteer;
        }

        public Vector3 steerForSeekTarget(InfantryVehicle vehicle)
        {
            Vector3 pursuitSteer = vehicle.SteerForSeek(_distractedTarget);
            return pursuitSteer;
        }

        public Vector3 getTargetPoint()
        {
            Helpers.ObjectState target = new Helpers.ObjectState();

            int blockedAttempts = 30;
            short pX;
            short pY;
            while (true)
            {
                pX = _target._state.positionX;
                pY = _target._state.positionY;
                Helpers.randomPositionInArea(_arena, 1000, ref pX, ref pY);
                if (_arena.getPlayersInRange(pX, pY, 25).Count(p => p == _target) >= 1)
                {
                    blockedAttempts--;
                    if (blockedAttempts == 0)
                        break;

                    continue;
                }

                target.positionX = pX;
                target.positionY = pY;
                break;
            }
            return target.position();
        }

    }
}
