using UnityEngine;
using System.Collections;

public class PlayerMovement : MonoBehaviour
{
    public float acceleration;
    public float maxSpeed;
    public float friction;
    public float deceleration;

    public int raycastHorizontalRays = 4;
    public int raycastVerticalRays = 3;

    public float backOnCollision = 0.1f;

    protected Vector2 colliderSize;

    public Vector2 velocity = Vector2.zero;
    protected float fallHeight = 0f;
    public float jumpHeight = 0f;
    protected bool isJumping = false;
    protected bool isOnGround = false;
    protected Vector2 input = Vector2.zero;
    
    protected Animator animator;
    protected BoxCollider2D boxCollider;

	private int idPlayer;
    private KeyCode[] controlsP2 = { KeyCode.A, KeyCode.D, KeyCode.S, KeyCode.W };
    private KeyCode[] controlsP1 = {KeyCode.LeftArrow, KeyCode.RightArrow, KeyCode.DownArrow, KeyCode.UpArrow};
	private SpriteRenderer spriteRenderer;

    protected void Awake()
    {
        boxCollider = GetComponent<BoxCollider2D>();
		animator = GetComponentInChildren<Animator> ();

        colliderSize = new Vector2(boxCollider.size.x, boxCollider.size.y);
		spriteRenderer = GetComponent<PlayerManager>().spriteRenderer;
    }

    protected void Update()
    {
        input = Vector2.zero;

		KeyCode[] controls = controlsP1;
		if(idPlayer == 2)
			controls = controlsP2;

        if (Input.GetKey(controls[0]) || Input.GetKey(controls[1]) ||
            Input.GetKey(controls[2]) || Input.GetKey(controls[3]))
        {
            if (Input.GetKey(controls[0]))
                input.x = -1;
            if (Input.GetKey(controls[1]))
                input.x = 1;
            if (Input.GetKey(controls[2]))
                input.y = -1;
            if (Input.GetKey(controls[3]))
                input.y = 1;
        }
        else
        {
            if (idPlayer == 1)
                input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
            else if (idPlayer == 2)
                input = new Vector2(Input.GetAxis("Horizontal2"), Input.GetAxis("Vertical2"));
        }

        HorizontalMovement();
        VerticalMovement();

		if (velocity.magnitude > 0) {
			animator.SetBool ("Running", true);
		} else {
			animator.SetBool("Running", false);
		}
    }

    protected void HorizontalMovement()
    {
        if (input.x > 0)
        {
			spriteRenderer.flipX = false;
            if (velocity.x >= 0)
            {
                velocity = new Vector2(velocity.x + acceleration /** Time.deltaTime*/, velocity.y);
                if (velocity.x > maxSpeed /** Time.deltaTime*/)
                    velocity = new Vector2(maxSpeed /** Time.deltaTime*/, velocity.y);
            }
            else
                velocity = new Vector2(velocity.x + deceleration /** Time.deltaTime*/, velocity.y);
        }
        else if (input.x < 0)
        {
			spriteRenderer.flipX = true;
            if (velocity.x <= 0)
            {
                velocity = new Vector2(velocity.x - acceleration/* * Time.deltaTime*/, velocity.y);
                if (velocity.x < -maxSpeed /** Time.deltaTime*/)
                    velocity = new Vector2(-maxSpeed /** Time.deltaTime*/, velocity.y);
            }
            else
                velocity = new Vector2(velocity.x - deceleration /** Time.deltaTime*/, velocity.y);
        }
        else
        {
            float sign = Mathf.Sign(velocity.x);
            velocity = new Vector2(
                velocity.x - friction * Mathf.Sign(velocity.x) /** Time.deltaTime*/,
                velocity.y);
            if (Mathf.Sign(velocity.x) != sign)
                velocity = new Vector2(0, velocity.y);
        }

        if (velocity.x != 0)
        {
            Vector2 dir = velocity.x > 0 ? Vector2.right : -Vector2.right;

            //RaycastHit2D hit = Physics2D.Raycast(transform.position + new Vector3(dir.x * colliderSize.x / 2, 0),
            //    dir, Mathf.Abs(velocity.x),
            //    1 << LayerMask.NameToLayer("Solid"));//Physics2D.CircleCast(transform.position, 0.5f, dir, Mathf.Abs(velocity.x));
            //Debug.DrawRay(transform.position + new Vector3(dir.x * colliderSize.x / 2, 0),
            //    dir * Mathf.Abs(velocity.x), Color.red, 0.1f);

            RaycastHit2D hit = new RaycastHit2D();
            for (int i = 0; i < raycastHorizontalRays; i++)
            {
                float perc = (float)i / (raycastHorizontalRays - 1);

                // porcata per bug
                if (perc == 0) perc = 0.001f; else if (perc == 1) perc = 0.999f;

                float localY = boxCollider.offset.y - boxCollider.size.y / 2 + perc * boxCollider.size.y;

                // porcata per bug
                //if (perc == 0) localY += 0.001f;

                Vector2 origin = new Vector2(
                    transform.position.x + Mathf.Sign(velocity.x) * boxCollider.size.x / 2,
                    transform.position.y);//transform.TransformPoint(new Vector2(dir.x * boxCollider.size.x / 2, localY));
                hit = Physics2D.Raycast(origin, dir, Mathf.Abs(velocity.x) * Time.deltaTime,
                    1 << LayerMask.NameToLayer("Solid"));
                Debug.DrawLine(origin, origin + new Vector2(velocity.x * Time.deltaTime, 0));
                if (hit)
                    break;
            }

            if (hit)
            {
                //Debug.Log("Horizontal hit.normal = " + hit.normal);
                transform.position = hit.point;
                transform.position = new Vector2(
                    transform.position.x - Mathf.Sign(velocity.x) * (boxCollider.size.x / 2 + backOnCollision),
                    transform.position.y);
                velocity = new Vector2(0, velocity.y);
            }
        }

        transform.position = new Vector3(transform.position.x + velocity.x * Time.deltaTime, transform.position.y);
    }

    protected void VerticalMovement()
    {
        if (input.y > 0)
        {
            if (velocity.y >= 0)
            {
                velocity = new Vector2(velocity.x, velocity.y + acceleration);
                if (velocity.y > maxSpeed)
                    velocity = new Vector2(velocity.x, maxSpeed);
            }
            else
                velocity = new Vector2(velocity.x, velocity.y + deceleration);
        }
        else if (input.y < 0)
        {
            if (velocity.y <= 0)
            {
                velocity = new Vector2(velocity.x, velocity.y - acceleration);
                if (velocity.y < -maxSpeed)
                    velocity = new Vector2(velocity.x, -maxSpeed);
            }
            else
                velocity = new Vector2(velocity.x, velocity.y - deceleration);
        }
        else
        {
            float sign = Mathf.Sign(velocity.y);
            velocity = new Vector2(
                velocity.x,
                velocity.y - friction * Mathf.Sign(velocity.y));
            if (Mathf.Sign(velocity.y) != sign)
                velocity = new Vector2(velocity.x, 0);
        }

        if (velocity.y != 0)
        {
            Vector2 dir = velocity.y > 0 ? Vector2.up : -Vector2.up;

            RaycastHit2D hit = new RaycastHit2D();
            for (int i = 0; i < raycastVerticalRays; i++)
            {
                float perc = (float)i / (raycastVerticalRays - 1);

                // porcata per bug
                if (perc == 0) perc = 0.001f; else if (perc == 1) perc = 0.999f;

                float localX = boxCollider.offset.x - boxCollider.size.x / 2 + perc * boxCollider.size.x;

                // porcata per bug
                //if (perc == 0) localY += 0.001f;

                Vector2 origin = new Vector2(
                    transform.position.x,
                    transform.position.y + Mathf.Sign(velocity.y) * boxCollider.size.y / 2);//transform.TransformPoint(new Vector2(localX, dir.y * boxCollider.size.y / 2));
                hit = Physics2D.Raycast(origin, dir, Mathf.Abs(velocity.y) * Time.deltaTime,
                    1 << LayerMask.NameToLayer("Solid"));
                Debug.DrawLine(origin, origin + new Vector2(0, velocity.y * Time.deltaTime));
                if (hit)
                    break;
            }

            if (hit)
            {
                Debug.Log("Horizontal hit.normal = " + hit.normal);
                transform.position = hit.point; //new Vector3(transform.position.x, hit.point.y - dir.y * colliderSize.y / 2);
                transform.position = new Vector2(transform.position.x,
                    transform.position.y - Mathf.Sign(velocity.y) * (boxCollider.size.y / 2 + backOnCollision));
                velocity = new Vector2(velocity.x, 0);
            }
        }

        transform.position = new Vector3(transform.position.x, transform.position.y + velocity.y * Time.deltaTime);
    }

	public void SetIdPlayer(int id){
		idPlayer = id;
	}
}