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

public class DialogScreen : IInputReceivable
{
    public GameObject CharacterObj, TextObj, CharNameObj, CharRoleObj;

    private enum eDialogScrenPhases { NotStartedYet, Writing, WaitingForNextInput, WaitingForFinishInput, WaitingForTime, Finished, PostFinished }

    private const float CHARACTER_INTERVAL = 0.025f;
    private const float DURATION = 3.0f;
    private float MAX_LINE_LENGTH = 2.0f;
    private const int MAX_LINE_QTT = 3;
    private readonly char BLANK = char.Parse(" ");
    private readonly char NEWLINE = char.Parse("\n");

    private Dialog mDialog;
    private tk2dSpriteAnimator mCharacterAnimator;
    private tk2dTextMesh mText, mCharName, mCharRole;
    private int mCurrentSpeechIndex = -1;
    private int mCurrentTextIndex = -1;
    private eDialogScrenPhases mCurrentPhase = eDialogScrenPhases.NotStartedYet;
    private bool mButtonClicked = false;
    private float mElapsed = 0.0f;
    private Enums.eDialogModes mDialogMode;
    private string mCompleteString = "";

    private static bool sCalculatedCharactersLength = false;
    private static Dictionary<char, float> sCharactersLength = new Dictionary<char, float>();    
    private void CalculateCharactersLength()
    {
        if (!sCalculatedCharactersLength)
        {
            sCalculatedCharactersLength = true;            
            tk2dTextMesh text = TextObj.GetComponent<tk2dTextMesh>();
            sCharactersLength = Util.CreateCharactersLengthDictionary(text);
            text.text = "";
            text.Commit();
        }
    }

    private void Awake()
    {		
        Util.AssertTrue
        (
            CharacterObj != null && TextObj != null && 
            CharNameObj != null && CharRoleObj != null, "All gameobjects must be set"
        );
        mCharacterAnimator = CharacterObj.GetComponent<tk2dSpriteAnimator>();
        Util.AssertTrue(mCharacterAnimator != null, "A gameobject is missing its 'tk2dAnimatedSprite' component");
        mText = TextObj.GetComponent<tk2dTextMesh>();
		mCharName = CharNameObj.GetComponent<tk2dTextMesh>();
        mCharRole = CharRoleObj.GetComponent<tk2dTextMesh>();
        Util.AssertTrue(mText != null && mCharName != null && mCharRole != null, "A gameobject is missing its 'tk2dTextMesh' component");

        RegisterButtonAction("NextButton", () => { }, () => { mButtonClicked = true; });
        RegisterButtonAction("OkButton", () => { }, () => { mButtonClicked = true; });
        RegisterButtonAction("FastForwardBtn", () => { }, () => FastForwardButtonAction());
        RegisterButtonAction("ImageBGBtn", () => { }, () => FastForwardButtonAction());


        InputRedirecter.Instance.InteractionPressed += HandleInteractionPressed;
    }

    private void OnDestroy()
    {
        InputRedirecter.Instance.InteractionPressed -= HandleInteractionPressed;
    }

    private void HandleInteractionPressed(object sender, System.EventArgs e)
    {
        FastForwardButtonAction();
    }

    private void FastForwardButtonAction()
    {
        if (mCurrentPhase == eDialogScrenPhases.Writing)
        {
            mText.text = mCompleteString;
            mText.Commit();
            PlayCurrentCharacterAnim(false);
            mCurrentTextIndex = 0;
            mCurrentSpeechIndex++;
            mElapsed = 0.0f;
            if (mDialogMode == Enums.eDialogModes.Timed)
            {
                mCurrentPhase = eDialogScrenPhases.WaitingForTime;
            }
            else if (mCurrentSpeechIndex == mDialog.Speeches.Length)
            {
                mCurrentPhase = eDialogScrenPhases.WaitingForFinishInput;
            }
            else
            {
                mCurrentPhase = eDialogScrenPhases.WaitingForNextInput;
            }
        }
        else if ((mCurrentPhase == eDialogScrenPhases.WaitingForFinishInput) || (mCurrentPhase == eDialogScrenPhases.WaitingForNextInput))
        {
            mButtonClicked = true;
        }
    }

    public override void OnDataPackReceived(object dataPack)
    {
        Util.AssertTrue(dataPack as DialogDataPack != null, "Datapacks sent to the dialog screen must be dialog datapacks");
        mDialog = DialogManager.Instance.GetDialog((dataPack as DialogDataPack).DialogType);
        mDialogMode = (dataPack as DialogDataPack).DialogMode;
        mCurrentSpeechIndex = 0;
        mCurrentTextIndex = 0;
		CalculateCharactersLength();
        mCurrentPhase = eDialogScrenPhases.Writing;
        PlayCurrentCharacterAnim(true);
        mText.text = "";
        mText.Commit();
        CheckSpeechLines();
    }

    private void CheckSpeechLines()
    {
        mDialog.Speeches[mCurrentSpeechIndex].UnlockedBadFacts.ForEach(badFact => PersistenceManager.Instance.SetInt("FactUnlocked_" + badFact.ToString(), 1));
        mDialog.Speeches[mCurrentSpeechIndex].UnlockedGoodFacts.ForEach(goodFact => PersistenceManager.Instance.SetInt("FactUnlocked_" + goodFact.ToString(), 1));

        mCompleteString = Util.FormatTk2dText(mText, MAX_LINE_LENGTH, mDialog.Speeches[mCurrentSpeechIndex].Text, sCharactersLength);
    }

    private void PlayCurrentCharacterAnim(bool loop)
    {
        string animName = mDialog.Speeches[mCurrentSpeechIndex].Character.ToString();
		mCharName.text = Strings.CHARACTERS_NAMES[mDialog.Speeches[mCurrentSpeechIndex].Character];
		mCharName.Commit();
        mCharRole.text = Strings.CHARACTERS_ROLES[mDialog.Speeches[mCurrentSpeechIndex].Character];
        mCharRole.Commit();
        mCharacterAnimator.Play(animName);
        if (!loop)
        {
            mCharacterAnimator.Stop();
        }
    }

    private void Update()
    {
        switch (mCurrentPhase)
        {
            case eDialogScrenPhases.NotStartedYet:
                break;
            case eDialogScrenPhases.Writing:
                mElapsed += Time.deltaTime;
                if (mElapsed >= CHARACTER_INTERVAL)
                {
                    mElapsed -= CHARACTER_INTERVAL;
                    mText.text += mCompleteString[mCurrentTextIndex];
                    mText.Commit();
                    mCurrentTextIndex++;
                    if (mCurrentTextIndex == mCompleteString.Length)
                    {
                        PlayCurrentCharacterAnim(false);
                        mCurrentTextIndex = 0;
                        mCurrentSpeechIndex++;
                        mElapsed = 0.0f;
                        if (mDialogMode == Enums.eDialogModes.Timed)
                        {
                            mCurrentPhase = eDialogScrenPhases.WaitingForTime;
                        }
                        else if (mCurrentSpeechIndex == mDialog.Speeches.Length)
                        {
                            mCurrentPhase = eDialogScrenPhases.WaitingForFinishInput;
                        }
                        else
                        {
                            mCurrentPhase = eDialogScrenPhases.WaitingForNextInput;
                        }
                    }
                }
                break;
            case eDialogScrenPhases.WaitingForNextInput:
                if (mButtonClicked)
                {
                    mButtonClicked = false;
                    mText.text = "";
                    mText.Commit();
                    PlayCurrentCharacterAnim(true);
                    mCurrentPhase = eDialogScrenPhases.Writing;
                    CheckSpeechLines();
                }
                break;
            case eDialogScrenPhases.WaitingForFinishInput:
                if (mButtonClicked)
                {
                    mButtonClicked = false;
                    mCurrentPhase = eDialogScrenPhases.Finished;
                }
                break;
            case eDialogScrenPhases.WaitingForTime:
                mElapsed += Time.deltaTime;
                if (mElapsed >= DURATION)
                {
                    mElapsed = 0.0f;
                    if (mCurrentSpeechIndex == mDialog.Speeches.Length)
                    {
                        mCurrentPhase = eDialogScrenPhases.Finished;
                    }
                    else
                    {
                        mText.text = "";
                        mText.Commit();
                        PlayCurrentCharacterAnim(true);
                        mCurrentPhase = eDialogScrenPhases.Writing;
                        CheckSpeechLines();
                    }
                }
                break;
            case eDialogScrenPhases.Finished:
                if(mDialog.GetType() == typeof(EndingDialog))
                {
                    Application.LoadLevel(Application.loadedLevel);
                }
                DialogCaller.Instance.Dismiss(false);
                if (mDialog.mFollowingChoice != null)
                {
                    ChoiceScreenCaller.Instance.Call(mDialog.mFollowingChoice);
                }
                mCurrentPhase = eDialogScrenPhases.PostFinished;
                break;
            case eDialogScrenPhases.PostFinished:
                break;
        }
    }
}
