using System;
using System.Collections.Generic;
using SFML.Graphics;
using SFML.Window;
using YourBeatingHeart.Main.Effects;
using YourBeatingHeart.Main.Helper;
using YourBeatingHeart.Main.Entities;
using YourBeatingHeart.Main.Graphics;
using YourBeatingHeart.Main.States.Play.Data;
using YourBeatingHeart.Main.Sound;

namespace YourBeatingHeart.Main.States.Play.Entities
{
    public class Player : PlayStateEntity
    {
        private const string FORCE_FEEDBACK_ANIMATION_HEART_BEAT = "heartbeat";

        private const double DEAD_ZONE = 0.3f;

        private readonly uint joystickId;

        public bool joystickConnected;

        private Joystick.Axis axisLeftRight1;
        private Joystick.Axis axisUpDown1;
        private Joystick.Axis axisLeftRight2;
        private Joystick.Axis axisUpDown2;
        private Joystick.Axis axisLeftRightPad;
        private Joystick.Axis axisUpDownPad;
        private Joystick.Axis axisTriggers;

        private uint buttonGreen;
        private uint buttonRed;
        private uint buttonBlue;
        private uint buttonYellow;
        private uint buttonLeftShoulder;
        private uint buttonRightShoulder;
        private uint buttonLeftStick;
        private uint buttonRightStick;

        protected uint jumpButton;
        protected uint executeButton;
        protected uint throwButton;

        protected Keyboard.Key keyUp;
        protected Keyboard.Key keyDown;
        protected Keyboard.Key keyLeft;
        protected Keyboard.Key keyRight;
        protected Keyboard.Key keyAttack;
        protected Keyboard.Key keyThrow;

        protected bool jumpButtonPressed;
        protected bool pickupButtonPressed;
        protected bool downPressed;

        protected Vector2f velocity;

        private bool stunned;
        private long stunEndTime;

        public Item HoldingItem;

        public bool HoldsItem { get { return HoldingItem != null; } }
        public bool HasHeartInHand { get { return heartInHand != null; } }

        private PlayerHeart heartInHand
        {
            get
            {
                if ((HoldingItem != null) && (HoldingItem.Type == ItemType.Heart))
                    return ((Heart) HoldingItem).PlayerHeart;

                return null;
            }
        }

        private int hatIndex = 0;

        private Vector2f direction;
        private float width;
        private float height;
        private Vector2f targetDirectionJoystick;
        public bool Standing { get; private set; }

        public string Name { get; protected set; }

        public Vector2f Direction { get { return direction; } }
        public FloatRect CollisionRect { get { return new FloatRect(Position.X - width / 2, Position.Y - height, width, height); } }

        private Dictionary<Keyboard.Key, bool> keyMashingEnabled;
        private Dictionary<Keyboard.Key, int> keyMashingProgress;
        private Dictionary<Keyboard.Key, int> keyMashingRequired;
        private List<Keyboard.Key> keyMashingCompleted;

        private Player executedPlayer = null;
        private float timeSinceLastExecuteMash = 0;

        protected AnimatedSprite bodySprite;
        protected AnimatedSprite headSprite;
        protected AnimatedSprite armSprite;
        protected Sprite pickupHintSprite;
        protected Sprite buttonMashingSpriteUp;
        protected Sprite buttonMashingSpriteDown;
        protected AnimatedSprite godsFavorSprite;

        public int IsLockedCount = 0;
        public bool IsLocking = false;

        protected ControllerVibration ControllerVibration;

        public bool Alive { get; protected set; }
        public bool MarkedByGodForDeath { get; protected set; }
        private bool wasKilledByGod;

        public bool CanPickupItemGuiElement;
        public bool CanSacrificeSelf;

        // this might be dirty? can we be sure that joystickId < 4? [TW: Yup, it's fine.]
        public uint Id { get { return joystickId; } }

        public bool GodsFavor { get; set; }

        public int Score { get; set; }

        public Player(PlayState playState, string name, Vector2f position, Vector2f origin, Keyboard.Key keyUp, 
            Keyboard.Key keyDown, Keyboard.Key keyLeft, Keyboard.Key keyRight, Keyboard.Key attack, Keyboard.Key keyThrow,
            uint joystickId)
            : base(playState, position, 0)
        {
            Name = name;

            this.joystickId = joystickId;

            hatIndex = (int)joystickId;
            Standing = true;

            bodySprite = new AnimatedSprite("base.xml", Game);
            bodySprite.Origin = origin;

            armSprite = new AnimatedSprite("arm.xml", Game);
            armSprite.Origin = origin;

            headSprite = new AnimatedSprite("crown.xml", Game);
            headSprite.Origin = origin;

            pickupHintSprite = new Sprite(Game.LoadTexture("Y_button_up.png"));
            pickupHintSprite.Origin = origin - new Vector2f(15,-75);

            buttonMashingSpriteUp = new Sprite(Game.LoadTexture("button_up.png"));
            buttonMashingSpriteUp.Origin = pickupHintSprite.Origin;

            buttonMashingSpriteDown = new Sprite(Game.LoadTexture("button_down.png"));
            buttonMashingSpriteDown.Origin = pickupHintSprite.Origin;

            godsFavorSprite = new AnimatedSprite("Fire.xml", Game, 30);
            godsFavorSprite.Origin = new Vector2f(65,95);
            godsFavorSprite.Scale = new Vector2f(1.5f, 1.5f);
            godsFavorSprite.Color = BodyColor;
            godsFavorSprite.Play("FireAni");

            PlayAnimation("idle");

            bodySprite.Color = BodyColor;
            headSprite.Color = BodyColor;

            this.keyUp = keyUp;
            this.keyDown = keyDown;
            this.keyLeft = keyLeft;
            this.keyRight = keyRight;
            this.keyAttack = attack;
            this.keyThrow = keyThrow;


            ControllerVibration = new ControllerVibration(joystickId);
            ControllerVibration.AddAnimation(FORCE_FEEDBACK_ANIMATION_HEART_BEAT, new ControllerVibration.Animation(playState.HeartBeatEffectValues, true, true, 50));

            joystickConnected = false;

            axisLeftRight1 = Joystick.Axis.X;
            axisUpDown1 = Joystick.Axis.Y;
            axisLeftRight2 = Joystick.Axis.U;
            axisUpDown2 = Joystick.Axis.R;
            axisLeftRightPad = Joystick.Axis.PovX;
            axisUpDownPad = Joystick.Axis.PovY;
            axisTriggers = Joystick.Axis.Z;

            buttonGreen = 0;
            buttonRed = 1;
            buttonBlue = 2;
            buttonYellow = 3;
            buttonLeftShoulder = 4;
            buttonRightShoulder = 5;
            buttonLeftStick = 8;
            buttonRightStick = 9;

            jumpButton = buttonGreen;
            executeButton = buttonBlue;
            throwButton = buttonYellow;

            jumpButtonPressed = false;
            downPressed = false;

            direction = new Vector2f();
            width = 55;
            height = 75;
            targetDirectionJoystick = new Vector2f();

            stunned = false;
            stunEndTime = 0;

            keyMashingEnabled = new Dictionary<Keyboard.Key, bool>();
            keyMashingProgress = new Dictionary<Keyboard.Key, int>();
            keyMashingRequired = new Dictionary<Keyboard.Key, int>();
            keyMashingCompleted = new List<Keyboard.Key>();

            Layer = PlayState.Layers.Players;

            HoldingItem = null;
            Alive = true;
            CanPickupItemGuiElement = false;
            CanSacrificeSelf = false;

            GodsFavor = false;
        }

        public Color BodyColor
        {
            get { return Constants.PLAYER_COLORS[Id]; }
        }

        public override void Added()
        {
            base.Added();

            playState.CollisionManager.Add(this);

            joystickConnected = Game.IsJoystickConnected(joystickId);

            playState.Window.KeyPressed += KeyPressed;
            playState.Window.KeyReleased += KeyReleased;
            playState.Window.JoystickMoved += OnJoystickMoved;
            playState.Window.JoystickButtonPressed += OnJoystickButtonPressed;
            playState.Window.JoystickButtonReleased += OnJoystickButtonReleased;
            playState.Window.JoystickConnected += OnJoystickConnected;
            playState.Window.JoystickDisconnected += OnJoystickDisconnected;
        }

        public override void Removed()
        {
            base.Removed();

            playState.CollisionManager.Remove(this);

            playState.Window.KeyPressed -= KeyPressed;
            playState.Window.KeyReleased -= KeyReleased;
            playState.Window.JoystickMoved -= OnJoystickMoved;
            playState.Window.JoystickButtonPressed -= OnJoystickButtonPressed;
            playState.Window.JoystickButtonReleased -= OnJoystickButtonReleased;
            playState.Window.JoystickConnected -= OnJoystickConnected;
            playState.Window.JoystickDisconnected -= OnJoystickDisconnected;
        }

        public void PauseAnimations()
        {
            bodySprite.Pause();
            armSprite.Pause();
            headSprite.Pause();
        }

        public override void Update(float elapsedTime)
        {
            UpdateSprites(elapsedTime);

            if (bodySprite.ActiveAnimation == "die_c")
                Alive = false;

            if (bodySprite.ActiveAnimation == "spawn")
            {
                if (bodySprite.GetFrame() == 16)
                    PlayAnimation("idle");
                else
                    return;
            }

            if (bodySprite.ActiveAnimation == "jump")
            {
                if (bodySprite.GetFrame() == 1)
                    PlayAnimation("idle");
            }

            if (bodySprite.ActiveAnimation == "landing")
            {
                if (bodySprite.GetFrame() == 1)
                    PlayAnimation("idle");
            }

            if (!Alive)
            {
                if (wasKilledByGod)
                {
                    if (bodySprite.ActiveAnimation != "sacrifice")
                        PlayAnimation("sacrifice");
                    else if (bodySprite.GetFrame() == 11)
                        PauseAnimations();
                }
                else
                {
                    if (bodySprite.ActiveAnimation != "die_b" && bodySprite.ActiveAnimation != "die_c")
                        PlayAnimation("die_b");
                    else if (bodySprite.GetFrame() == 16)
                        PauseAnimations();

                    if (bodySprite.ActiveAnimation == "die_c" && bodySprite.GetFrame() == 13)
                    {
                        PlayAnimation("idle");
                        Respawn();
                    }
                }
                return;
            }

            if (IsLockedCount > 0)
            {
                DropItem();
            }

            Vector2f direction = this.direction;

            if (!joystickConnected)
            {
                if (Keyboard.IsKeyPressed(keyLeft))
                    direction.X -= 1;

                if (Keyboard.IsKeyPressed(keyRight))
                    direction.X += 1;
            }

            if (playState.Timer.ElapsedMilliseconds > stunEndTime)
                stunned = false;            


            if (stunned || IsLockedCount > 0 || IsLocking || (bodySprite.ActiveAnimation == "take_heart" && bodySprite.GetFrame() < 15))
            {
                direction.X = 0;
                direction.Y = 0;
            }
            else
            {
                if (jumpButtonPressed)
                {
                    if (Standing)
                    {
                        SoundManager.Instance.PlaySound(SoundEvent.Jump);
                        Standing = false;
                        velocity.Y += Constants.PLAYER_JUMP_IMPULSE;
                    }
                }
            }
            velocity.X = direction.X * Constants.PLAYER_WALK_SPEED;
            velocity.Y += Constants.GRAVITY * elapsedTime;

            float dx = velocity.X * elapsedTime;
            float dy = velocity.Y * elapsedTime;

            // Flip player sprite
            if (((dx > 0) && (bodySprite.Scale.X < 0)) ||
                ((dx < 0) && (bodySprite.Scale.X > 0)))
            {
                SetOrientation(-bodySprite.Scale.X);
            }

            var actualMove = playState.CollisionManager.Restrict(CollisionRect, new Vector2f(dx, dy));

            // Floor?
            if (actualMove.Y < dy)
            {
                if (velocity.Y > 0)
                {
                    if (!Standing)
                    {
                        PlayAnimation("landing");
                        SoundManager.Instance.PlaySound(SoundEvent.JumpLand);
                    }
                    Standing = true;
                    velocity.Y = 0;
                }
            }
            else if (velocity.Y > 0)
                Standing = false;

            var cr = CollisionRect;
            Player collidingPlayer = playState.CollisionManager.PlayerCollision(
                new FloatRect(cr.Left + actualMove.X, cr.Top + cr.Height + actualMove.Y, cr.Width, 1)
            );

            if ((collidingPlayer != null) && (collidingPlayer != this))
            {
                float otherPlayerFeet = collidingPlayer.CollisionRect.Top + collidingPlayer.CollisionRect.Height;

                // jumped on player when we were on top of him before
                if (Position.Y < collidingPlayer.CollisionRect.Top)
                {
                    collidingPlayer.Stun((long)(Constants.STUN_DURATION * Math.Min(velocity.Y, 3000) / 1500));
                    velocity.Y = Constants.PLAYER_JUMP_IMPULSE;
                }
                // jumped from below against player on top of us - we are stunned! oh no!
                else if ((Position.Y > otherPlayerFeet) && (Position.Y + actualMove.Y < otherPlayerFeet))
                {
                    Stun((long)(Constants.STUN_DURATION * Math.Min(collidingPlayer.velocity.Y, 3000) / 1500));
                    collidingPlayer.velocity.Y = Constants.PLAYER_JUMP_IMPULSE;
                }
            }

            if (executedPlayer == null)
            {
                if (armSprite.ActiveAnimation != "take_heart" || actualMove.X != 0)
                {
                    if (IsLockedCount > 0)
                    {
                        if (bodySprite.ActiveAnimation == "die_a" && bodySprite.GetFrame() == 8)
                            PlayAnimation("die_quicktime");
                    }
                    else if (bodySprite.ActiveAnimation != "landing")
                    {
                        if (stunned)
                            PlayAnimation("stunned");
                        else if (!Standing)
                            PlayAnimation("jump");
                        else if (actualMove.X != 0)
                            PlayAnimation("run");
                        else
                            PlayAnimation("idle");
                    }
                }
                else
                {
                    if (bodySprite.GetFrame() == 30)
                        bodySprite.Play("idle");
                }
            }
            else
            {
                if (bodySprite.GetFrame() == 8 && bodySprite.ActiveAnimation == "grab_heart" ) PlayAnimation("heart_quicktime");
                if(bodySprite.ActiveAnimation == "heart_quicktime" && executedPlayer.Alive)
                    executedPlayer.SetAnimFrame(bodySprite.GetFrame());
            }

            if (HasHeartInHand)
            {
                heartInHand.Update(elapsedTime);
                if (!heartInHand.Alive)
                {
                    HeartStoppedBeating();
                }
                else
                {
                    ControllerVibration.CurrentSpeed = heartInHand.CurrentHeartBeatSpeed;
                    ControllerVibration.CurrentMultiplier = heartInHand.CurrentHeartBeatStrength;

                    if (playState.CollisionManager.inTouchDownArea(CollisionRect.GetCenter()))
                    {
                        playState.PlayerScored(this, Constants.SCORE_PER_TOUCHDOWN);
                        heartInHand.Destroy();
                        LoseHeart();
                    }
                }
            }

            Move(actualMove.X, actualMove.Y);
            bodySprite.Position = Position;

            if (joystickConnected)
                ControllerVibration.Update(elapsedTime);

            if (executedPlayer != null)
            {
                if (!executedPlayer.Alive)
                {
                    executedPlayer.IsLockedCount--;
                    StopButtonMashing(keyAttack);
                }
                else
                {
                    timeSinceLastExecuteMash += elapsedTime;
                    if (timeSinceLastExecuteMash >= Constants.EXECUTE_TIMEOUT)
                    {
                        timeSinceLastExecuteMash = Constants.EXECUTE_TIMEOUT;
                        executedPlayer.IsLockedCount--;
                        IsLocking = false;
                        executedPlayer = null;
                        StopButtonMashing(keyAttack);
                    }
                }
            }

            // check button mashing
            foreach (KeyValuePair<Keyboard.Key, bool> pair in keyMashingEnabled)
            {
                if (pair.Value)
                {
                    if (keyMashingProgress[pair.Key] >= keyMashingRequired[pair.Key])
                    {
                        OnMashingComplete(pair.Key);
                        StopButtonMashing(pair.Key);
                    }
                }
            }

            foreach (Keyboard.Key key in keyMashingCompleted)
            {
                keyMashingEnabled[key] = false;
                keyMashingProgress[key] = 0;
            }
            keyMashingCompleted.Clear();

            if (!HoldsItem)
            {
                Item itemToPickUp = GetItemAbleToBePickedUp();
                CanPickupItemGuiElement = itemToPickUp != null;

                if ((itemToPickUp != null) && pickupButtonPressed)
                {
                    PickupItem(itemToPickUp);
                }
            }
            else
            {
                CanPickupItemGuiElement = false;
            }

            jumpButtonPressed = false;
            pickupButtonPressed = false;
        }

        public void SetOrientation(float _x)
        {
            bodySprite.Scale = new Vector2f(_x, bodySprite.Scale.Y);
            headSprite.Scale = new Vector2f(_x, headSprite.Scale.Y);
            armSprite.Scale = new Vector2f(_x, armSprite.Scale.Y);
        }

        public void SetAnimFrame(int _frame)
        {
            bodySprite.SetFrame(_frame);
            armSprite.SetFrame(_frame);
            headSprite.SetFrame(_frame);
        }

        public override void Draw(RenderTarget renderTarget)
        {
            if (CanSacrificeSelf)
            {
                if (playState.CollisionManager.inTouchDownArea(Position))
                {
                    buttonMashingSpriteUp.Position = Position;
                    renderTarget.Draw(buttonMashingSpriteUp);
                }
            }

            if (GodsFavor)
            {
                godsFavorSprite.Position = Position;
                renderTarget.Draw(godsFavorSprite);
            }

            bodySprite.Position = Position;
            headSprite.Position = Position;
            armSprite.Position = Position;
            renderTarget.Draw(bodySprite);
            renderTarget.Draw(headSprite);

            if (Alive && bodySprite.ActiveAnimation != "spawn")
            {
                renderTarget.Draw(armSprite);
            }

            if (CanPickupItemGuiElement)
            {
                pickupHintSprite.Position = Position;
                renderTarget.Draw(pickupHintSprite);
            }

            if (keyMashingEnabled.ContainsKey(keyAttack) && keyMashingEnabled[keyAttack] && Alive)
            {
                buttonMashingSpriteUp.Position = Position;
                buttonMashingSpriteDown.Position = Position;

                if (timeSinceLastExecuteMash < 0.1)
                    renderTarget.Draw(buttonMashingSpriteDown);
                else
                    renderTarget.Draw(buttonMashingSpriteUp);
            }
        }

        private void PlayAnimation(string _name)
        {
            bodySprite.Play(_name);
            string armPrefix = "normal_";
            if(HoldingItem != null)
            {
                if (HasHeartInHand)
                    armPrefix = "heart_";
                else if ((HoldingItem as Remains).RemainType == RemainType.Arm)
                    armPrefix = "arm_";
                else
                    armPrefix = "skull_";
            }

            armSprite.Play(armPrefix + _name);
            headSprite.Play("0" + (hatIndex + 1).ToString() + "_" + _name);
        }

        public void Stun(long duration)
        {
            stunEndTime = playState.Timer.ElapsedMilliseconds + duration;
            stunned = true;

            if (HoldingItem != null)
            {
                DropItem(new Vector2f(-50,-50));
            }
        }

        private void StartButtonMashing(Keyboard.Key key, int numPressesNeeded)
        {
            Console.Out.WriteLine("mashing started");
            keyMashingProgress[key] = 0;
            keyMashingRequired[key] = numPressesNeeded;
            keyMashingEnabled[key] = true;
        }

        private void OnMashingComplete(Keyboard.Key key)
        {
            if (key == keyAttack)
                Execute();
        }

        private void Execute()
        {
            IsLocking = false;
            if (executedPlayer == null)
                return;

            int index = Game.Random(4) - 1;
            if(index == 0)
                SoundManager.Instance.PlaySound(SoundEvent.Execute);
            else if(index == 2)
                SoundManager.Instance.PlaySound(SoundEvent.Execute2);
            else if (index == 3)
                SoundManager.Instance.PlaySound(SoundEvent.Execute3);

            SoundManager.Instance.PlaySound(SoundEvent.Scream);
            
            executedPlayer.Kill();
            PickupItem(new Heart(playState, new Vector2f(), new PlayerHeart(executedPlayer)));
            PlayAnimation("take_heart");
            executedPlayer = null;
        }

        private void StartExecute()
        {
            foreach (Player p in playState.Players)
            {
                if (p == this || !p.Alive)
                    continue;

                Vector2f dist = p.Position - Position;

                if (p.Position.Y - height <= Position.Y && p.Position.Y >= Position.Y - height)
                {
                    if (Math.Sign(dist.X) == bodySprite.Scale.X && Math.Abs(dist.X) < Constants.EXECUTE_RANGE_X)
                    {
                        PlayAnimation("grab_heart");
                        timeSinceLastExecuteMash = 0;
                        Set(p.Position - new Vector2f(32 * Math.Sign(dist.X), 0));
                        executedPlayer = p;
                        executedPlayer.SetOrientation(-Math.Sign(dist.X));
                        executedPlayer.PlayAnimation("die_a");
                        IsLocking = true;
                        executedPlayer.IsLockedCount++;

                        StartButtonMashing(keyAttack, Constants.EXECUTE_BUTTON_PRESSES);
                        break;
                    }
                }
            }
        }

        private void StopButtonMashing(Keyboard.Key key)
        {
            keyMashingCompleted.Add(key);
        }

        private void UpdateSprites(float _elapsedTime)
        {
            bodySprite.Update(_elapsedTime);
            armSprite.Update(_elapsedTime);
            headSprite.Update(_elapsedTime);
            godsFavorSprite.Update(_elapsedTime);
        }
        private void EndJump()
        {
            if (velocity.Y < 0)
                velocity.Y /= 2;
        }

        private void PickupItem(Item itemToPickUp)
        {
            if (HoldsItem)
                throw new Exception("Can't pick up an item while holding something.");

            playState.RemoveEntity(itemToPickUp);

            if (itemToPickUp.Type == ItemType.Heart)
            {
                ControllerVibration.PlayAnimation(FORCE_FEEDBACK_ANIMATION_HEART_BEAT);
            }

            HoldingItem = itemToPickUp;
        }

        public void LoseHeart()
        {
            HoldingItem = null;
            ControllerVibration.StopAnimation();
        }

        public void HeartStoppedBeating()
        {
            LoseHeart();
        }

        private void ThrowOrPickupPressed()
        {
            if (!HoldsItem)
            {
                pickupButtonPressed = true;
                return;
            }

            Vector2f offset = bodySprite.Scale.X > 0 ? new Vector2f(width, -height) : new Vector2f(-width, -height);
            SoundManager.Instance.PlaySound(SoundEvent.Throw);
            HoldingItem.Throw(offset);
            HoldingItem.owner = this;
            DropItem(offset);
        }

        private void DropItem(Vector2f offset = new Vector2f())
        {
            if (!HoldsItem)
                return;

            HoldingItem.Set(Position.X + offset.X, Position.Y + offset.Y);
            playState.AddEntity(HoldingItem);

            if (HoldingItem.Type == ItemType.Heart)
            {
                LoseHeart();
            }
            else
            {
                HoldingItem = null;
            }
        }

        private void AttackPressed()
        {
            if (CanSacrificeSelf)
            {
                if (playState.CollisionManager.inTouchDownArea(Position))
                {
                    KilledByGod();
                    playState.RestartDelayed(Constants.RESTART_DELAY_AFTER_SACRIFICE);
                    playState.HeartEater.Play();
                }
            }

            if (downPressed)
            {
                Console.Out.WriteLine("stomping");
                velocity.X = 0;
                velocity.Y = Constants.PLAYER_STOMP_IMPULSE;
            }

            if (HoldsItem)
                return;

            if (keyMashingEnabled.ContainsKey(keyAttack) && keyMashingEnabled[keyAttack])
                timeSinceLastExecuteMash = 0;
            else
                StartExecute();

            if(keyMashingProgress.ContainsKey(keyAttack))
                keyMashingProgress[keyAttack]++;
        }

        private void KeyPressed(object sender, KeyEventArgs e)
        {
            if (e.Code == keyUp)
            {
                jumpButtonPressed = true;
            }
            else if (e.Code == keyDown && Position.Y < 1023) //HACK! (lowest line at 1024)
            {
                Move(0, 1);
                downPressed = true;
            }
            else if (e.Code == keyAttack)
            {
                AttackPressed();
            }
            else if (e.Code == keyThrow)
            {
                ThrowOrPickupPressed();
            }
        }

        private void KeyReleased(object sender, KeyEventArgs e)
        {
            if (e.Code == keyUp)
                EndJump();
            else if (e.Code == keyDown)
                downPressed = false;
        }

        private void OnJoystickMoved(object sender, JoystickMoveEventArgs args)
        {
            if (args.JoystickId != joystickId)
                return;

            //Console.WriteLine(args);

            if (args.Axis == axisLeftRight1)
            {
                direction.X = args.Position / 100;
                if (Math.Abs(direction.X) < DEAD_ZONE)
                {
                    direction.X = 0;
                }
                else
                {
                    if(direction.X > 0)
                        direction.X = MathHelper.Clamp(direction.X, 0.7f, 1);
                    else
                        direction.X = MathHelper.Clamp(direction.X, -1, -0.7f);
                }
            }
            else if (args.Axis == axisUpDown1)
            {
                direction.Y = args.Position / 100;
                if (Math.Abs(direction.Y) < DEAD_ZONE)
                {
                    direction.Y = 0;
                }

                if (direction.Y > 0)
                    downPressed = true;
                else
                    downPressed = false;
            }
        }

        private void OnJoystickButtonPressed(object sender, JoystickButtonEventArgs args)
        {
            if (args.JoystickId != joystickId)
                return;

            if (args.Button == jumpButton)
            {
                if (direction.Y > .7f)
                {
                    if (Position.Y < 1023)  //HACK! (lowest line at 1024)
                        Move(0, 1);
                }
                else
                {
                    jumpButtonPressed = true;
                }
            }
            else if (args.Button == executeButton)
            {
                AttackPressed();
            }
            else if (args.Button == throwButton)
            {
                ThrowOrPickupPressed();
            }
        }

        private void OnJoystickButtonReleased(object sender, JoystickButtonEventArgs args)
        {
            if (args.JoystickId != joystickId)
                return;

            if (args.Button == jumpButton)
                EndJump();
        }

        private void OnJoystickConnected(object sender, JoystickConnectEventArgs args)
        {
            if (args.JoystickId != joystickId)
                return;

            joystickConnected = true;
        }

        private void OnJoystickDisconnected(object sender, JoystickConnectEventArgs args)
        {
            if (args.JoystickId != joystickId)
                return;

            joystickConnected = false;
        }

        public void PromotedByGod()
        {
            ControllerVibration.StopAnimation();
            Respawn();
        }

        public void KilledByGod()
        {
            ControllerVibration.StopAnimation();

            if (Alive)
            {
                Kill();
                wasKilledByGod = true;
            }
            else
            {
                MarkedByGodForDeath = true;
            }
        }

        public void Kill()
        {
            wasKilledByGod = false;
            if (!Alive)
                throw new Exception("Can't be killed when not alive");

            DropItem();
            if (executedPlayer != null)
            {
                executedPlayer.IsLockedCount--;
                StopButtonMashing(keyAttack);
            }

            executedPlayer = null;
            IsLocking = false;
            IsLockedCount = 0;
            //playState.RemoveEntity(this);
            Alive = false;
            velocity.Y = 0;
            CanPickupItemGuiElement = false;
        }

        public void Respawn(bool _immidiate = true)
        {
            if (Alive)
                return;
                //throw new Exception("Can't respawn when not dead");

            if (_immidiate)
            {
                SoundManager.Instance.PlaySound(SoundEvent.Spawn);
                var newPosition = playState.GetSpawnPosition(this);
                Set(newPosition.X, newPosition.Y);

                Alive = true;
                PlayAnimation("spawn");

                //playState.AddEntity(this);

                if (MarkedByGodForDeath)
                {
                    KilledByGod();
                }
            }
            else
                PlayAnimation("die_c");
        }

        public Item GetItemAbleToBePickedUp()
        {
            var itemsAbleToBePickedUp = GetItemsAbleToBePickedUp();

            if (itemsAbleToBePickedUp == null)
                return null;

            // Favor hearts
            foreach (var item in itemsAbleToBePickedUp)
            {
                if (item.Type == ItemType.Heart)
                    return item;
            }

            // Else just give the first one
            return itemsAbleToBePickedUp[0];
        }

        private List<Item> GetItemsAbleToBePickedUp()
        {
            List<Item> result = null;

            var playerCollisionRect = CollisionRect;
            playState.ItemList.ForEach(delegate(Item item)
                                           {
                                               if (item.CollisionRect.Intersects(playerCollisionRect))
                                               {
                                                   if (result == null)
                                                       result = new List<Item>();

                                                   result.Add(item);
                                               }
                                           });
            

            return result;
        }
    }
}
