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


public enum MenuAction
{
    Stay,
    Attack,
    Magic,
    Item,
    Cancel,
    Confirm,
}


public class PlayerObject : MonoBehaviour
{
    static public Dictionary<string, MenuAction> ACTION_MENU = new Dictionary<string, MenuAction >()
    {
        { "Stay", MenuAction.Stay },
        { "Attack", MenuAction.Attack },
        { "Magic", MenuAction.Magic },
        { "Item", MenuAction.Item },
        { "Cancel", MenuAction.Cancel }
    };

    static public Dictionary<string, MenuAction> CONFIRM_MENU = new Dictionary<string, MenuAction>()
    {
        { "Confirm", MenuAction.Confirm },
        { "Cancel", MenuAction.Cancel }
    };
    
    Dictionary<string, MenuAction > m_currentMenu;
    string m_currentMenuName;
    GridCoord m_showMenuAt;
    MenuAction m_chosenMenuItem;

    private InputStateType m_inputState;
    static private PlayerObject ms_instance = null;
    private GridCoord m_targetPosChosen;
    private bool m_moveLogic;
    private bool m_playerWasSelected;
    private bool m_inputAllowed;
    private bool m_mouseHit;
    private int m_chosenScrollMenuItem;

    private GuiScrollChoice m_scrollMenu = new GuiScrollChoice();

    public static PlayerObject Instance
    {
        get { return ms_instance; }
    }

    public CharacterInfo Info
    {
        get { return GetComponent<CharacterObject>().Info; }
    }

	// Use this for initialization
	void Start ()
    {
        if (ms_instance != null)
        {
            Debug.LogError("Only one player allowed");
        }
        ms_instance = this;
        m_inputState = InputStateType.NotInBattle;
    }
	
	// Update is called once per frame
	void Update () 
    {
        if ( MenuSystem.InBattle == false )
        {
            m_inputState = InputStateType.NotInBattle;
        }
    }

    public enum InputStateType
    {
        NotInBattle,
        Idle,
        WaitForGridClick,
        WaitForGridClickMouseUp,
        WaitForGridClickChosen,
        WaitForMenuClick,
        WaitForMenuClickChosen,
        WaitForScrollMenuClick,
        WaitForScrollMenuClickChosen,
    }

    public InputStateType InputState
    {
        get { return m_inputState;  }
    }
    
    public void WaitForGridClick( bool moveLogic )
    {
        m_inputState = InputStateType.WaitForGridClick;
        m_moveLogic = moveLogic;
        m_inputAllowed = true;
    }

    public void AllowInput()
    {
        m_inputAllowed = true;
    }
    public void DisallowInput()
    {
        m_inputAllowed = false;
    }

    public void MouseDown(Transform hitObj)
    {
        m_mouseHit = false;

        if (m_inputAllowed == false )
        {
            return;
        }
        if (m_inputState == InputStateType.WaitForGridClick)
        {
            GridObject gridObj = hitObj.GetComponent<GridObject>();
            if (gridObj != null)
            {
                m_targetPosChosen = gridObj.GridPosition;
                m_mouseHit = true;

                if (m_moveLogic)
                {
                    if (PlayerObject.Instance.GetComponent<GridObject>().GridPosition == gridObj.GridPosition)
                    {
                        m_inputState = InputStateType.WaitForGridClickMouseUp;
                        m_playerWasSelected = true;
                    }
                    else
                    {
                        m_playerWasSelected = false;

                        // Moveable highlight tile chosen
                        m_inputState = InputStateType.WaitForGridClickMouseUp;
                    }
                }
                else
                {
                    // Action logic
                    if ( gridObj.m_canBeSelectedByAction )
                    {
                        m_inputState = InputStateType.WaitForGridClickMouseUp;
                        m_playerWasSelected = false;
                    }
                    else
                    {                        
                        // TODO - fail noise?
                    }
                }
            }
        }
    }

    public void MouseDownNoHits()
    {
        if (m_inputState == InputStateType.WaitForGridClick)
        {
            m_mouseHit = false;
            m_playerWasSelected = false;
            m_inputState = InputStateType.WaitForGridClickMouseUp;
            m_targetPosChosen = GetComponent<GridObject>().GridPosition;
        }
    }

    public void MouseUp()
    {
        if (m_inputAllowed == false)
        {
            return;
        }

        if (m_inputState == InputStateType.WaitForGridClickMouseUp)
        {
            m_inputState = InputStateType.WaitForGridClickChosen;

            if ( m_mouseHit )
            {
                m_inputAllowed = false;
            }
        }
    }

    public bool CheckMousePick( out GridCoord destPos, out bool cancel )
    {
        if (m_inputState == InputStateType.WaitForGridClickChosen)
        {
            if ( m_playerWasSelected == false )
            {
                cancel = ( m_mouseHit == false );
                destPos = m_targetPosChosen;
                return true;
            }
        }

        {
            cancel = false;
            destPos = new GridCoord(0, 0);
            return false;
        }
    }

    public bool PlayerWasSelected()
    {
        if (m_inputState == InputStateType.WaitForGridClickChosen)
        {
            return m_playerWasSelected;
        }
        return false;
    }

    public void ShowMenu( GridCoord atPos, string caption, Dictionary<string,MenuAction> menuItems )
    {
        m_currentMenu = menuItems;
        m_currentMenuName = caption;
        m_showMenuAt = atPos;
        m_inputState = InputStateType.WaitForMenuClick;
    }
    
    void OnGUI()
    {
        if ( m_inputState != InputStateType.NotInBattle )
        {
            const int HEADING_WIDTH = 200;
            string headingText = MenuSystem.GAME_NAME + string.Format("\nBattle #{0} - Turn #{1}", Info.m_battleNumber, BattleManager.Instance.m_turnNumber);
            GUI.Box(new Rect((Screen.width - HEADING_WIDTH) / 2, 0, HEADING_WIDTH, 40), headingText);
        }

        if (m_inputState == InputStateType.WaitForMenuClick)
        {
            // TODO - Check for cancelling by clicking outside the menu? Cancel is in all menus though, so can cut this one I think.

            Vector3 screenPos = Camera.main.WorldToScreenPoint(m_showMenuAt.GetUnityPos() + new Vector3(GridManager.UNITY_GRID_SIZE, 0, 0));
            
            int totalHeight = ((int)m_currentMenu.Count * 30) + 30;

            int yPos = ( Screen.height - (int)screenPos.y ) - (totalHeight / 2);

            GUI.Box(new Rect(screenPos.x, yPos, 100, totalHeight), m_currentMenuName);
            yPos += 20;

            foreach (KeyValuePair<string, MenuAction> entry in m_currentMenu)
            {
                if (GUI.Button(new Rect(screenPos.x + 10, yPos, 80, 20), entry.Key))
                {
                    m_chosenMenuItem = entry.Value;
                    m_inputState = InputStateType.WaitForMenuClickChosen;
                }

                yPos += 30;
            }
        }
        else if (m_inputState == InputStateType.WaitForScrollMenuClick)
        {
            m_scrollMenu.OnGUI();

            if (m_scrollMenu.HasChosen(out m_chosenScrollMenuItem))
            {
                m_inputState = InputStateType.WaitForScrollMenuClickChosen;
            }
        }
    }

    public void ShowScrollMenu()
    {
        m_inputState = InputStateType.WaitForScrollMenuClick;
    }

    public bool CheckScrollMenuResult(out int action)
    {
        if (m_inputState == InputStateType.WaitForScrollMenuClickChosen)
        {
            SFXManager.Play(SFXManager.Instance.m_menuSelect);
            m_inputState = InputStateType.Idle;
            action = m_chosenScrollMenuItem;
            return true;
        }
        else
        {
            action = -1;
            return false;
        }
    }

    public GuiScrollChoice ScrollMenu
    {
        get { return m_scrollMenu;  }
    }

    public bool CheckMenuResult(out MenuAction chosenAction)
    {
        if (m_inputState == InputStateType.WaitForMenuClickChosen)
        {
            SFXManager.Play(SFXManager.Instance.m_menuSelect);
            m_inputState = InputStateType.Idle;
            chosenAction = m_chosenMenuItem;
            return true;
        }
        else
        {
            chosenAction = MenuAction.Cancel;
            return false;
        }
    }

    public float LevelUp()
    {
        const float AWARD_TIME = 3.5f;

        string text;
        CharacterLevelling.LevelUp( GetComponent<CharacterObject>().Info, out text );

        VoiceManager.Instance.Play(3);

        SFXManager.Play(SFXManager.Instance.m_levelUp);
        GuiStatusText.DisplayText(text, AWARD_TIME);

        return AWARD_TIME;
    }

    public bool LoadFromPlayerPrefs()
    {
        string tmp = PlayerPrefs.GetString("Player", string.Empty);
        if (tmp == string.Empty)
            return false;

        LoadFromString(tmp);
        return true;
    }

    public void SaveToPlayerPrefs()
    {
        PlayerPrefs.SetString("Player",GetComponent<CharacterObject>().Info.ConvertToString() );
        PlayerPrefs.Save();
    }

    public void LoadFromString(string str)
    {
        GetComponent<CharacterObject>().Info = GetComponent<CharacterObject>().Info.SetFromString(str);
    }

    public void SetupPlayerDefaults()
    {
        GetComponent<CharacterObject>().Info = new CharacterInfo("Milo", 17, 7, 8, 8, 6, false);
        GetComponent<CharacterObject>().Info.AddMagic(MagicID.Heal1);
        GetComponent<CharacterObject>().Info.AddItem(ItemID.Sword1);
        GetComponent<CharacterObject>().Info.AddItem(ItemID.Heal1);
        GetComponent<CharacterObject>().Info.AddItem(ItemID.Heal1);
    }

}
