using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[RequireComponent(typeof(BoxCollider2D))]
public class playerControllerScript : MonoBehaviour {

	public AudioClip chickenPick;
	public AudioClip pigPick;
	public AudioClip cowPick;
	public AudioClip personPick;
	public AudioClip holyPick;
	public AudioClip purePick;
	public AudioClip babyPick;


	BoxCollider2D _collider;
	RaycastOrigins raycastOrigins;
	const float skinWidth = 0.015f;

	public string pickUpButton;

	public int horizontalRayCount = 3;
	public int verticalRayCount = 3;
	float horizontalRaySpacing;
	float verticalRaySpacing;

	public LayerMask collisionMask;
	public LayerMask pickupMask;

	public float pickUpRange = 1.0f;
	public Transform holdPosition;
	public bool holding = false;

	Collider2D theClosestObject;
	Collider2D theHoldingObject;

	Collider2D[] hitColliders;

	LineRenderer lineRenderer;

	private Animator anim;

	// Use this for initialization
	void Start () {

		anim = gameObject.GetComponent<Animator> ();

		_collider = gameObject.GetComponent<BoxCollider2D> ();

		lineRenderer = gameObject.GetComponent<LineRenderer> ();

		lineRenderer.sortingOrder = 1000;

		CalculateRaySpacing ();

	}

	void Update(){

		// Check pickups in range
		PickUpRange ();

		// Actions from fire input
		if(Input.GetButtonDown(pickUpButton)){

			Debug.Log ("The Closest Object" + theClosestObject.name);

			if (!holding && theClosestObject.tag != "Fire") {

				PickUp (theClosestObject);
				Debug.Log ("Pick up.");

			} else if (holding && theClosestObject.tag == "Fire") {

				Throw (theHoldingObject, theClosestObject);
               	Debug.Log ("Throw.");

			} else if (holding) {

				LetItGo (theHoldingObject);
				Debug.Log ("Let it go.");

			} else {
				Debug.Log ("nothing to see");
				return;

			}

		}

		CheckHolding ();

		//print (holding);

		if (holding) {
			anim.SetBool ("Carrying", true);
		} else {
			anim.SetBool ("Carrying", false);
		}

		//Debug.Log ("The closest object is " + theClosestObject);
		//Debug.Log ("The holding object is " + theHoldingObject);

	}

	public void Move(Vector3 velocity){

		UpdateRaycastOrigins ();

		if(velocity.x != 0){

			horizontalCollisions (ref velocity);

		}

		if(velocity.y != 0){

			verticalCollisions (ref velocity);

		}

		transform.Translate (velocity);

	}

	void verticalCollisions(ref Vector3 velocity){

		float directionY = Mathf.Sign (velocity.y);
		float rayLength = Mathf.Abs (velocity.y) + skinWidth;

		for(int i = 0; i < verticalRayCount; i++){ 

			Vector2 rayOrigin = (directionY == -1)? raycastOrigins.bottomLeft: raycastOrigins.topLeft;
			rayOrigin += Vector2.right * (verticalRaySpacing * i + velocity.x);
			RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.up * directionY, rayLength, collisionMask);

			Debug.DrawRay (rayOrigin, Vector2.up * directionY * rayLength, Color.green);

			if(hit){

				velocity.y = (hit.distance - skinWidth) * directionY;
				rayLength = hit.distance;

			}

		}

	}

	void horizontalCollisions(ref Vector3 velocity){

		float directionX = Mathf.Sign (velocity.x);
		float rayLength = Mathf.Abs (velocity.x) + skinWidth;

		for(int i = 0; i < verticalRayCount; i++){ 

			Vector2 rayOrigin = (directionX == -1)? raycastOrigins.bottomLeft: raycastOrigins.bottomRight;
			rayOrigin += Vector2.up * (horizontalRaySpacing * i);
			RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.right * directionX, rayLength, collisionMask);

			Debug.DrawRay (rayOrigin, Vector2.right * directionX * rayLength, Color.green);

			if(hit){

				velocity.x = (hit.distance - skinWidth) * directionX;
				rayLength = hit.distance;

			}

		}

	}

	void PickUpRange(){

		hitColliders = Physics2D.OverlapCircleAll (transform.position, pickUpRange, pickupMask);

		foreach(Collider2D hitObject in hitColliders){

			//print (hitObject.name + " is in range to pickup.");

			float currentDist = Vector3.Magnitude(gameObject.transform.position - hitObject.transform.position);

			//print (hitObject.name + " is " + currentDist + " away from the player.");

			FindClosestObject (hitObject);

		}

		if(hitColliders.Length == 0){

			theClosestObject = null;
			lineRenderer.enabled = false;
		}

	}

	void FindClosestObject(Collider2D hitObject){

		Collider2D closestObject = null;
		float currentClosestDist = Vector3.Magnitude(gameObject.transform.position - hitObject.transform.position);
		float lastClosestDist = Mathf.Infinity;

		if(currentClosestDist < lastClosestDist){

			closestObject = hitObject;
			lastClosestDist = currentClosestDist;

			//print ("The closest object is " + closestObject.name);

			theClosestObject = closestObject;

		}

		SetLineRenderer (closestObject);

		//Debug.DrawRay (transform.position, hitObject.transform.position - transform.position, Color.red);

	}

	void SetLineRenderer(Collider2D closestObject){

		if (theHoldingObject == null) {

			lineRenderer.enabled = true;
			lineRenderer.SetPosition (0, gameObject.transform.position);
			lineRenderer.SetPosition (1, closestObject.transform.position);

		} 

	}


	void PickUp(Collider2D closestObj){

		if(hitColliders.Length > 0){

			closestObj.transform.position = holdPosition.transform.position;
			closestObj.transform.parent = gameObject.transform;
			theHoldingObject = theClosestObject;
			lineRenderer.enabled = false;
			//holding = true;

		}

	}

	void LetItGo(Collider2D holdingObject){

		holdingObject.transform.parent = null;
		theHoldingObject = null;
		//holding = false;

	}

	void Throw(Collider2D holdingObject, Collider2D target){

		Debug.Log ("Called Throw()");

		holdingObject.transform.position = target.transform.position;
		switch (holdingObject.name) {
		case "Chicken(Clone)":
				target.gameObject.SendMessage ("RecieveObj", 1);
				break;
			case "Pig(Clone)":
				target.gameObject.SendMessage ("RecieveObj", 2);
				break;
			case "Cow(Clone)":
				target.gameObject.SendMessage ("RecieveObj", 3);
				break;
			case "Person(Clone)":
				target.gameObject.SendMessage ("RecieveObj", 4);
				break;
			case "HolyOne(Clone)":
				target.gameObject.SendMessage ("RecieveObj", 5);
				break;
			case "PureOne(Clone)":
				target.gameObject.SendMessage ("RecieveObj", 6);
				break;
			case "Baby(Clone)":
				target.gameObject.SendMessage ("RecieveObj", 7);
				break;
		}

		holdingObject.transform.parent = null;
		Destroy (holdingObject.gameObject);
		theHoldingObject = null;
		//holding = false;

	}

	void CheckHolding(){

		Transform[] holdings;
		holdings = gameObject.GetComponentsInChildren<Transform> ();

		if(holdings.Length > 2){

			holding = true;

			print ("This is holding");

		} else if (holdings.Length <= 2) {

			holding = false;

		}

	//	print(gameObject.name + " is holding " + holdings.Length + " items.");

	}

	void UpdateRaycastOrigins(){

		Bounds bound = _collider.bounds;
		bound.Expand (skinWidth * -2);

		raycastOrigins.bottomLeft = new Vector2 (bound.min.x, bound.min.y);
		raycastOrigins.bottomRight = new Vector2 (bound.max.x, bound.min.y);
		raycastOrigins.topLeft = new Vector2 (bound.min.x, bound.max.y);
		raycastOrigins.topRight = new Vector2 (bound.max.x, bound.max.y);

	}

	void CalculateRaySpacing(){

		Bounds bound = _collider.bounds;
		bound.Expand (skinWidth * -2);

		horizontalRayCount = Mathf.Clamp (horizontalRayCount, 2, int.MaxValue);
		verticalRayCount = Mathf.Clamp (verticalRayCount, 2, int.MaxValue);

		horizontalRaySpacing = bound.size.y / (horizontalRayCount - 1);
		verticalRaySpacing = bound.size.x / (verticalRayCount - 1);

	}

	struct RaycastOrigins{

		public Vector2 topLeft, topRight;
		public Vector2 bottomLeft, bottomRight;

	}

}
