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

public class InputManager  
{    
    public enum TouchPhases
    {
        None,
        Began,
        Moved,
        Ended
    }

    public bool IsInputBlocked = false;

    private struct GaiaTouch
    {
        public TouchPhases TouchPhase { get; private set; }
        public int FingerID { get; private set; }
        public Vector3 TouchPos { get; private set; }
        public GaiaTouch(TouchPhases touchPhase, int fingerID, Vector3 touchPos)
        {
            TouchPhase = touchPhase;
            FingerID = fingerID;
            TouchPos = touchPos;
        }
    }

    private class ReceivablePriorityPair
    {
        public IInputReceivable Receivable;
        public int Priority;
        public bool InputShallNotPass;
        public ReceivablePriorityPair(IInputReceivable receivable, int priority, bool inputShallNotPass)
        {
            Receivable = receivable;
            Priority = priority;
            InputShallNotPass = inputShallNotPass;
        }
    }

    private List<ReceivablePriorityPair> mReceivablesList = new List<ReceivablePriorityPair>();

    public void RegisterInputReceivableOnTop(IInputReceivable receivable, bool inputShallNotPass)
    {
        int prioridade = mReceivablesList.Count > 0 ? mReceivablesList[0].Priority + 1 : 0;
        RegisterInputReceivable(receivable, inputShallNotPass, prioridade);
    }

    public void RegisterInputReceivable(IInputReceivable receivable, bool inputShallNotPass, int priority)
    {
        int indexToInsertAt = 0;
        // insere ordenado por prioridade em ordem decrescente
        foreach (ReceivablePriorityPair spawnerPair in mReceivablesList)
        {
            if (priority >= spawnerPair.Priority)
            {
                break;
            }
            ++indexToInsertAt;
        }
        mReceivablesList.Insert(indexToInsertAt, new ReceivablePriorityPair(receivable, priority, inputShallNotPass));
    }

    public void UnregisterInputReceivable(IInputReceivable receivable)
    {        
        mReceivablesList.RepeatUntil
        (
            receivablePair => {}, 
            receivablePair =>
            {
                if (receivablePair.Receivable.Equals(receivable))
                {
                    mReceivablesList.Remove(receivablePair);
                    return true;
                }
                return false;
            }
        );
    }
    
    public void Update(float ellapsed)
    {
        if (!IsInputBlocked)
        {
            List<GaiaTouch> gaiaTouches = new List<GaiaTouch>();
#if UNITY_EDITOR || UNITY_STANDALONE_WIN
            if (Input.GetMouseButtonDown(0)) gaiaTouches.Add(new GaiaTouch(TouchPhases.Began, 0, Input.mousePosition));
            else if (Input.GetMouseButton(0)) gaiaTouches.Add(new GaiaTouch(TouchPhases.Moved, 0, Input.mousePosition));
            else if (Input.GetMouseButtonUp(0)) gaiaTouches.Add(new GaiaTouch(TouchPhases.Ended, 0, Input.mousePosition));
            if (Input.GetMouseButtonDown(1)) gaiaTouches.Add(new GaiaTouch(TouchPhases.Began, 1, Input.mousePosition));
            else if (Input.GetMouseButton(1)) gaiaTouches.Add(new GaiaTouch(TouchPhases.Moved, 1, Input.mousePosition));
            else if (Input.GetMouseButtonUp(1)) gaiaTouches.Add(new GaiaTouch(TouchPhases.Ended, 1, Input.mousePosition));
            if (Input.GetMouseButtonDown(2)) gaiaTouches.Add(new GaiaTouch(TouchPhases.Began, 2, Input.mousePosition));
            else if (Input.GetMouseButton(2)) gaiaTouches.Add(new GaiaTouch(TouchPhases.Moved, 2, Input.mousePosition));
            else if (Input.GetMouseButtonUp(2)) gaiaTouches.Add(new GaiaTouch(TouchPhases.Ended, 2, Input.mousePosition));
#elif UNITY_IPHONE || UNITY_ANDROID
            Input.touches.ForEach(touch =>
            {
                TouchPhases touchPhase = TouchPhases.None;
                if (touch.phase == TouchPhase.Began) touchPhase = TouchPhases.Began;
                else if (touch.phase == TouchPhase.Moved) touchPhase = TouchPhases.Moved;
                else if (touch.phase == TouchPhase.Ended) touchPhase = TouchPhases.Ended;
                if (touchPhase != TouchPhases.None)
                {
                    gaiaTouches.Add(new GaiaTouch(touchPhase, touch.fingerId, touch.position));
                }
            });
#endif
            gaiaTouches.ForEach(gaiaTouch =>
            {
                mReceivablesList.RepeatUntil(receivable => { }, receivable => receivable.Receivable.OnTouch(gaiaTouch.TouchPos, gaiaTouch.TouchPhase, gaiaTouch.FingerID) || receivable.InputShallNotPass);
            });
        }
    }
}