using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Text.RegularExpressions;

public class Twbot : MonoBehaviour {

    public GameObject dropAsset;
    public GameObject acceptingAsset;
    public GameObject finAsset;
    public TextMesh txtWinning;
    public GameObject playerObject;
    public ParticleSystem explosionSystem;

    private TwitchIRC IRC;
    private bool allowingDropInput = false;
    private Dictionary<String, ViewerMove> playerMoves;

    // Use this for initialization
    void Start () {
        IRC = this.GetComponent<TwitchIRC>();

        //IRC.SendCommand("CAP REQ :twitch.tv/tags"); //register for additional data such as emote-ids, name color etc.
        IRC.messageRecievedEvent.AddListener(OnChatMsgRecieved);

        //dumb.. hack?
        this.finAsset.GetComponent<Animator>().SetTrigger("in");

        //start this madness
        Invoke("allowDropInput", 5f);
    }

    void allowDropInput()
    {

        //animate in the trigger
        this.acceptingAsset.GetComponent<Animator>().SetTrigger("in");
        this.finAsset.GetComponent<Animator>().SetTrigger("out");

        IRC.SendMsg("Accepting input - next 10 seconds");

        //clear out the drops on the page
        GameObject[] drops = GameObject.FindGameObjectsWithTag("ball");
        foreach(GameObject drop in drops)
        {
            Destroy(drop);
        }

        //reset player position
        playerObject.SendMessage("ResetPosition");

        //clear out old dictionary data..
        playerMoves = new Dictionary<string, ViewerMove>();

        //let player
        allowingDropInput = true;

        //wait X seconds and begin the game
        Invoke("placeDrops", 15f);
    }

    void placeDrops()
    {

        //hide the 'gate'
        this.acceptingAsset.GetComponent<Animator>().SetTrigger("out");


        IRC.SendMsg("Received your input NOW BE PATIENT.");
        //don't let players specifiy their drops..
        //Though now that I think about it.. it doesn't really matter!
        //I could just write code so everyone's /last/ input counts, even if they got it in late.
        allowingDropInput = false;

        //reset session drops and hits
        TPHController.sessionDrops = 0;
        TPHController.hp = 0;

        //place the objects
        foreach (KeyValuePair<string, ViewerMove> entry in playerMoves)
        {


            //make that drop
            switch(entry.Value.pattern)
            {
                case "hallway":
                    MakeHallway(entry.Value.position);
                    break;
                case "cone":
                    MakeCone(entry.Value.position);
                    break;
                case "funnel":
                    MakeFilter(entry.Value.position);
                    break;
                default:
                    TPHController.sessionDrops++;
                    Instantiate(dropAsset, entry.Value.position, Quaternion.identity);
                    break;
            }
            //Instantiate(dropAsset, entry.Value.position, Quaternion.identity);
        }

        //up the count..
        TPHController.hp = TPHController.sessionDrops;

        //reset the player and set them moving
        playerObject.SendMessage("BeginPlay");

        //wait X seconds and then end the play second
        Invoke("ArrivedEndOfLevel", 15f);
    }

    void ArrivedEndOfLevel()
    {

        //calculations on if the user has gotten past 80%
        float winningPer = 100f;
        if (TPHController.sessionDrops > 0) //so  we don't divide by zedo. LORD ZEDO.
        {
            winningPer = (TPHController.hp / TPHController.sessionDrops) * 100f;
        }

        txtWinning.text = winningPer.ToString("0\\%");

        //if they have, explode the particle system
        if (winningPer > 80f)
        {
            explosionSystem.Emit(124);
            this.finAsset.GetComponent<AudioSource>().Play();
        }

        this.finAsset.GetComponent<Animator>().SetTrigger("in");

        playerObject.GetComponent<Rigidbody2D>().velocity = new Vector2(0f, 0f);

        //wait a few seconds before moving back.
        Invoke("allowDropInput", 7f);
    }

    void OnChatMsgRecieved(string msg)
    {
        //doesn't 'msg' seem like it should be short for 'massage'?
        Match userName = Regex.Match(msg, "^.*\\!");

        //clean up to the only command I care about - drop
        if (Regex.IsMatch(msg, "!drop") && allowingDropInput)
        {
            // word found
            string[] splitInput = Regex.Split(msg, "!drop");
            string[] options = Regex.Split(splitInput[1], " ");

            //get numeric versions of this input
            if (options.Length >= 4)
            {
                string patternOption = options[1];
                float x;
                float y;
                bool parsedX = float.TryParse(options[2] + ".0", out x); 
                bool parsedY = float.TryParse(options[3] + ".0", out y);

                if (parsedX && parsedY)
                {
                    //sanity check on inputs (for player.. enjoyment?)
                    Vector2 dropPos = new Vector2(x >= 0 ? x % 9 : Mathf.Abs(x) % 9 * -1, (Mathf.Abs(y) % 35) + 5f);

                    //make a position out of it.
                    //Vector2 dropPos = new Vector2(x, y);

                    //make a drop at the location the user specified
                    //Instantiate(dropAsset, dropPos, Quaternion.identity);

                    //Well, you know.
                    if (!playerMoves.ContainsKey(userName.Value))
                    {

                        ViewerMove vm = new ViewerMove();
                        vm.position = dropPos;
                        vm.pattern = patternOption;

                        //add that drop.
                        playerMoves.Add(userName.Value, vm);
                    }
                }
            }
        }
    }
    

    void MakeHallway(Vector2 pos)
    {
        TPHController.sessionDrops += 6;
        Instantiate(dropAsset, pos + new Vector2(-2f, 2f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(2f, 2f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(-2f, 0f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(2f, 0f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(-2f, -2f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(2f, -2f), Quaternion.identity);
    }

    void MakeCone(Vector2 pos)
    {
        TPHController.sessionDrops += 6;
        Instantiate(dropAsset, pos + new Vector2(-3f, 2f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(3f, 2f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(-2f, 0f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(2f, 0f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(-1f, -2f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(1f, -2f), Quaternion.identity);
    }

    void MakeFilter(Vector2 pos)
    {
        TPHController.sessionDrops += 6;
        Instantiate(dropAsset, pos + new Vector2(-1f, 2f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(1f, 2f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(-2f, 0f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(2f, 0f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(-3f, -2f), Quaternion.identity);
        Instantiate(dropAsset, pos + new Vector2(3f, -2f), Quaternion.identity);
    }

}

struct ViewerMove
{
    public Vector2 position;
    public String pattern;
}