using UnityEngine;
using System.Collections;

public class BodyBlock : MonoBehaviour 
{
	public Vector2 m_size = Vector2.one;
	[HideInInspector] public BodyBlock[] m_siblings = new BodyBlock[(int)eBlockDirection.Count];

	[SerializeField] GameObject m_cornerTopLeft = null;
	[SerializeField] GameObject m_cornerTopRight = null;
	[SerializeField] GameObject m_cornerBottomLeft = null;
	[SerializeField] GameObject m_cornerBottomRight = null;

	[SerializeField] Sprite m_defaultSprite = null;

	[SerializeField] Sprite m_leafSprite = null;
	[SerializeField] Animator m_animator = null;


	bool m_selected = false;
	SpriteRenderer m_sprite = null;

	eBlockDirection m_prev = eBlockDirection.None; 
	eBlockDirection m_next = eBlockDirection.None;

    Carryable m_carrying = null;

	public eBlockDirection GetNextSibling() { return m_next; }
	public eBlockDirection GetPrevSibling() { return m_prev; }

	public BodyBlock GetSibling(eBlockDirection direction){ int dir = (int)direction; return ( dir >= 0 && dir < 4 ) ? m_siblings[dir] : null; }

    public bool IsCarrying()
    {
        return m_carrying != null;
    }

    public Carryable GetCarryable()
    {
        return m_carrying;
    }

    public void StartCarrying(Carryable carryable)
    {
        // Find highest block
        if (m_siblings[(int)eBlockDirection.Up] != null)
        {
            if (m_siblings[(int)eBlockDirection.Up].IsCarrying())
            {
                return;
            }

            m_siblings[(int)eBlockDirection.Up].StartCarrying(carryable);
        }
        else
        {
            carryable.OnPickup();

            m_carrying = carryable;
            m_carrying.transform.SetParent(transform, false);
            m_carrying.transform.localPosition = new Vector2(0.0f, m_size.y * 0.5f + carryable.GetSize().y * 0.5f);          
        }
    }

    public void DropCarrying()
    {
        m_carrying.transform.SetParent(null);
        m_carrying.OnDrop();
        m_carrying = null;
    }

	public void Deselect()
	{
		m_selected = false;
		UpdateSprite();
	}

	public void Select()
	{
		m_selected = true;
		// Todo: highlight
		UpdateSprite();
	}

	public bool GetSelected()
	{
		return m_selected;
	}
	public Vector2 GetBlockSize() { return m_size; }
	public float GetBlockSize(eBlockDirection dir)
	{
		if ( dir == eBlockDirection.Left || dir == eBlockDirection.Right )
		{
			return m_size.x;
		}
		return m_size.y;		
	}

	public int GetSiblingCount()
	{
		int result = 0;
		for ( int i = 0; i < 4; ++i )
		{
			if ( m_siblings[i] != null )
				result++;
		}
		return result;
	}

	// REturns the parent block TODO: CURRENTLY JUST RETURNS FIRST VALID SIBLING
	public BodyBlock GetParentBlock()
	{
		// TODO: Return actual parent
		return GetFirstSibling();
	}

	public BodyBlock GetFirstSibling() 
	{
		// Returns first valid sibling
		for ( int i = 0; i < 4; ++i )
		{
			if ( m_siblings[i] != null )
				return m_siblings[i];
		}
		return null;
	}


	public eBlockDirection GetFirstSiblingDirection() 
	{
		// Returns first valid sibling
		for ( int i = 0; i < 4; ++i )
		{
			if ( m_siblings[i] != null )
				return (eBlockDirection)i;
		}
		return eBlockDirection.Left;
	}

	public void Remove()
	{
        if (m_carrying)
        {
            int checkDirection = (int)eBlockDirection.Down;
            if (m_siblings[checkDirection] != null)
            {
                m_siblings[checkDirection].m_siblings[(int)eBlockDirection.Up] = null;
                m_siblings[checkDirection].StartCarrying(m_carrying);
            }
            else
            {
                DropCarrying();
            }
        }

		GameObject.Destroy(gameObject);
	}

	public void ClearNextSibling()
	{
		m_next = eBlockDirection.None;
	}
	public void ClearPrevSibling()
	{
		m_prev = eBlockDirection.None;
	}


	public void SetNextSibling(eBlockDirection dir, BodyBlock block )
	{
		m_siblings[(int)dir] = block;
        m_next = dir;

        if (dir == eBlockDirection.Up && IsCarrying())
        {
            m_siblings[(int)dir].StartCarrying(m_carrying);
            m_carrying = null;
        }
	}

	public void SetPrevSibling(eBlockDirection dir, BodyBlock block )
	{
		m_siblings[(int)dir] = block;
		m_prev = dir;
	}

	public void ClearSiblings()
	{
		for ( int i = 0; i < 4; ++i )
		{
			m_siblings[i] = null;
		}
		m_next = eBlockDirection.None;
		m_prev = eBlockDirection.None;
	}


	// Sets the sprite and rotates to face that direction. If face is true, it'll play the face animation from faceIdleTime
	public void SetSprite(Sprite sprite, eBlockDirection direction =  eBlockDirection.None, bool isFace = false, float faceIdleTimer = 0 )
	{
		if ( isFace == false && m_animator )
			m_animator.enabled = false;

		if ( m_sprite == null )
			m_sprite = GetComponentInChildren<SpriteRenderer>();
		if ( m_sprite == null )
			return;
		m_sprite.sprite = sprite;
		if ( direction == eBlockDirection.Left )
		{
			m_sprite.transform.localRotation = Quaternion.Euler(0,0,90);
		}
		else if ( direction == eBlockDirection.Right )
		{
			m_sprite.transform.localRotation = Quaternion.Euler(0,0,-90);
		}
		else if ( direction == eBlockDirection.Down )
		{
			m_sprite.transform.localRotation = Quaternion.Euler(0,0,180);
		}
		else 
		{
			m_sprite.transform.localRotation = Quaternion.Euler(0,0,0);
		}


		if ( isFace == true && m_animator )
		{
			m_animator.enabled = true;
			float length = m_animator.GetCurrentAnimatorStateInfo(0).length;
			if ( length > 0 )
			{
				Debug.Log(string.Format("playing with length {0}, timer {1}, normalised {2}",length, faceIdleTimer, (faceIdleTimer%length)/length));
				m_animator.Play("HeadIdle", 0, (faceIdleTimer%length)/length);
			}
			/*
			AnimatorStateInfo info = m_animator.GetCurrentAnimatorStateInfo(0);
			info.normalizedTime
			m_animator.runtimeAnimatorController.animationClips[0].
			m_animator.GetCurrentAnimatorStateInfo(-1).time
			m_animator.animation..time = Time.timeSinceLevelLoad;
			*/
		}
	}
	/*
	public void PlayFaceAnim()
	{
		if ( m_animator != null )
		{
			m_animator.enabled = true;
		}
	}
	public void StopFaceAnim()
	{
		if ( m_animator != null )
		{
			m_animator.enabled = false;
		}
	}*/

	public void SetCorners(eBlockDirection fromDir, eBlockDirection toDir )
	{
		bool topLeft = false;
		bool topRight = false;
		bool bottomLeft = false;
		bool bottomRight = false;


		switch ( fromDir )
		{
		case eBlockDirection.Down: topLeft = true; topRight = true; break;
		case eBlockDirection.Up: bottomLeft = true; bottomRight = true; break;
		case eBlockDirection.Right: topLeft = true; bottomLeft = true; break;
		case eBlockDirection.Left: topRight = true; bottomRight = true; break;
		}

		switch ( toDir )
		{
		case eBlockDirection.Down: bottomLeft = true; bottomRight = true; break;
		case eBlockDirection.Up: topLeft = true; topRight = true; break;
		case eBlockDirection.Right: topRight = true; bottomRight = true; break;
		case eBlockDirection.Left: topLeft = true; bottomLeft = true; break;
		}

		m_cornerBottomLeft.SetActive(bottomLeft);
		m_cornerBottomLeft.SetActive(bottomLeft);
		m_cornerBottomLeft.SetActive(bottomLeft);
		m_cornerBottomLeft.SetActive(bottomLeft);
		m_cornerTopLeft 	 .SetActive(topLeft );
		m_cornerTopRight     .SetActive(topRight   );
		m_cornerBottomLeft   .SetActive(bottomLeft );
		m_cornerBottomRight  .SetActive(bottomRight);

	}


	// Use this for initialization
	void Start () 
	{
		if ( m_sprite == null )
			m_sprite = GetComponentInChildren<SpriteRenderer>();
		UpdateSprite();
	}

	
	// Update is called once per frame
	void Update () 
	{
		
	}
	void UpdateSprite()
	{/*
		if ( m_sprite == null )
			m_sprite = GetComponentInChildren<SpriteRenderer>();
		if ( m_sprite == null )
			return;
		if ( GetSiblingCount() > 1 )
		{
			m_sprite.sprite =  m_defaultSprite;
		}
		else 
		{
			m_sprite.sprite = m_leafSprite;
		}*/
	}
}
