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

public class Spawner : MonoBehaviour {

    public GameObject DemonPrefab;
	public FireSpawn Fire;

    bool SpawnerOpen;

    public delegate void AddedGlyphToSummoningStackHandler(List<DamageType> summoningStack, int listIndex, DamageType glyph);
    public event AddedGlyphToSummoningStackHandler AddedGlyphToSummoningStack;
    public delegate void DestroyedGlyphFromSummoningStackHandler(List<DamageType> summoningStack, int listIndex, DamageType destroyedSummonGlyph, DamageType destroyedStackGlyph);
    public event DestroyedGlyphFromSummoningStackHandler DestroyedGlyphFromSummoningStack;

    List<DamageType> AttackGlyphs = new List<DamageType>();
    List<DamageType> DefenceGlyphs = new List<DamageType>();
    List<DamageType> SpeedGlyphs = new List<DamageType>();

	public AudioSource CastFail;
	public AudioSource CastSuccess;

    Dictionary<DamageType, DamageType> OppositeDamageType = new Dictionary<DamageType, DamageType>();

	// Use this for initialization
	void Start () {
        SpawnerOpen = false;

        OppositeDamageType[DamageType.Fire] = DamageType.Water;
        OppositeDamageType[DamageType.Earth] = DamageType.Wind;
        OppositeDamageType[DamageType.Water] = DamageType.Fire;
        OppositeDamageType[DamageType.Wind] = DamageType.Earth;
        GameStateController.Instance.GameStateChanged += GameStateHandler;
	}

    void GameStateHandler(EGameState oldState, EGameState newState)
    {
        if (newState == EGameState.Summoming)
        {
            Debug.Log("Spawner opened");
            AttackGlyphs.Clear();
            DefenceGlyphs.Clear();
            SpeedGlyphs.Clear();
            SpawnerOpen = true;
            printGlyphStack();
        }
        else if (oldState == EGameState.Summoming)
        {
            Debug.Log("Spawner closed");
            string attack = "Attack: ";
            foreach (DamageType dt in AttackGlyphs) attack += dt.ToString();
            string defence = "Defence: ";
            foreach (DamageType dt in DefenceGlyphs) defence += dt.ToString();
            string speed = "Speed: ";
            foreach (DamageType dt in SpeedGlyphs) speed += dt.ToString();
            Debug.Log(attack);
            Debug.Log(defence);
            Debug.Log(speed);
            SpawnerOpen = false;

            if (AttackGlyphs.Count > 0 || DefenceGlyphs.Count > 0 || SpeedGlyphs.Count > 0)
            {
				Fire.Spawn();
				audio.Play();
				CastSuccess.Play ();
				Invoke("SpawnDemon", .5f);
            }
			else
			{
				CastFail.Play ();
			}
        }
    }

	void SpawnDemon()
	{
		GameObject demon = GameObject.Instantiate(DemonPrefab, transform.position, Quaternion.identity) as GameObject;
		Weapon weapon = demon.GetComponentInChildren<Weapon>();
		DemonAI demonAI = demon.GetComponentInChildren<DemonAI>();
		foreach (DamageType dt in AttackGlyphs)
		{
			switch (dt)
			{
			case DamageType.Fire: weapon.FireDamage += 1; break;
			case DamageType.Earth: weapon.EarthDamage += 1; break;
			case DamageType.Water: weapon.WaterDamage += 1; break;
			case DamageType.Wind: weapon.WindDamage += 1; break;
			}
		}
		
		CharacterData charData = demon.GetComponentInChildren<CharacterData>();
		foreach (DamageType dt in DefenceGlyphs)
		{
			switch (dt)
			{
			case DamageType.Fire: charData.FireDefence += 1; break;
			case DamageType.Earth: charData.EarthDefence += 1; break;
			case DamageType.Water: charData.WaterDefence += 1; break;
			case DamageType.Wind: charData.WindDefence += 1; break;
			}
		}
		
		float speedSum = SpeedGlyphs.Count;
		float speedFactor = Mathf.Min(1.0f, speedSum / 10.0f);
		demonAI.MovementSpeed = 1.0f + (demonAI.MaxSpeed-1) * speedFactor;
		weapon.FramesToAttack = (int)( 30.0f - 20.0f * speedFactor );
		weapon.FramesToRecover = (int)( 25.0f - 20.0f * speedFactor );
		
		
		int totalGlyphCount = AttackGlyphs.Count + DefenceGlyphs.Count + SpeedGlyphs.Count;
		
		while (totalGlyphCount > 0)
		{
			switch (Random.Range(1, 5))
			{
			case 1: charData.addGlyphToStack(DamageType.Fire); break;
			case 2: charData.addGlyphToStack(DamageType.Earth); break;
			case 3: charData.addGlyphToStack(DamageType.Water); break;
			case 4: charData.addGlyphToStack(DamageType.Wind); break;
			}
			totalGlyphCount -= 1;
		}
		
		DemonConfigurator demonConf = demon.GetComponentInChildren<DemonConfigurator>();
		float attackFactor = Mathf.Min(1.0f, AttackGlyphs.Count / 6.0f);
		demonConf.SetArms((int)(attackFactor * 3.0f));
		demonConf.SetBody((int)(attackFactor * 3.0f));
		float defenseFactor = Mathf.Min(1.0f, DefenceGlyphs.Count / 6.0f);
		demonConf.SetHead((int)(defenseFactor * 3.0f));
		demonConf.SetLegs((int)(speedFactor * 3.0f));
		
		int fireCount = 0, earthCount = 0, waterCount = 0, windCount = 0;
		foreach (DamageType damage in AttackGlyphs)
		{
			switch (damage)
			{
			case DamageType.Fire: fireCount += 1; break;
			case DamageType.Earth: earthCount += 1; break;
			case DamageType.Water: waterCount += 1; break;
			case DamageType.Wind: windCount += 1; break;
			}
		}
		foreach (DamageType damage in DefenceGlyphs)
		{
			switch (damage)
			{
			case DamageType.Fire: fireCount += 1; break;
			case DamageType.Earth: earthCount += 1; break;
			case DamageType.Water: waterCount += 1; break;
			case DamageType.Wind: windCount += 1; break;
			}
		}
		foreach (DamageType damage in SpeedGlyphs)
		{
			switch (damage)
			{
			case DamageType.Fire: fireCount += 1; break;
			case DamageType.Earth: earthCount += 1; break;
			case DamageType.Water: waterCount += 1; break;
			case DamageType.Wind: windCount += 1; break;
			}
		}
		Color color = Color.white;
		int maxCount = Mathf.Max(fireCount, earthCount, waterCount, windCount);
		if (maxCount == fireCount)
		{
			color = new Color(1.0f, 0.7f, 0.28f);
		}
		else if (maxCount == earthCount)
		{
			color = new Color(0.71f, 0.31f, 0.17f);
		}
		else if (maxCount == waterCount)
		{
			color = new Color(0.23f, 0.47f, 1.0f);
		}
		else if (maxCount == windCount)
		{
			color = new Color(0.6f, 0.88f, 1.0f);
		}
		float lerpFactor = Mathf.Min(1.0f, maxCount / 10.0f);
		color = Color.Lerp(Color.white, color, lerpFactor);
		demonConf.SetColor(color, 0.05f);

        // signal summoned demon to tutorial
        GameStateController.Instance.TutorialDemonSummoned();
	}

    // Update is called once per frame
    void Update()
    {
        if (SpawnerOpen && CharacterManager.instance.PlayerCharacter.GlyphStack.Count > 0)
        {
            if (Input.GetButtonUp("Slot1"))
            {
                popStackToSlot(AttackGlyphs, 1);
            }
            else if (Input.GetButtonUp("Slot2"))
            {
                popStackToSlot(DefenceGlyphs, 2);
            }
            else if (Input.GetButtonUp("Slot3"))
            {
                popStackToSlot(SpeedGlyphs, 3);
            }
        }
	}

    void popStackToSlot(List<DamageType> slot, int listIndex)
    {
        DamageType damagetype = CharacterManager.instance.PlayerCharacter.popGlyphStack();
        if (!slot.Remove(OppositeDamageType[damagetype]))
        {
            slot.Add(damagetype);
            if (AddedGlyphToSummoningStack != null)
            {
                AddedGlyphToSummoningStack(slot, listIndex, damagetype);
            }
        }
        else
        {
            Debug.Log(damagetype.ToString() + " und " + OppositeDamageType[damagetype] + " löschen sich aus!!");
            if (DestroyedGlyphFromSummoningStack != null)
            {
                DestroyedGlyphFromSummoningStack(slot, listIndex, OppositeDamageType[damagetype], damagetype);
            }
        }
                        
        printGlyphStack();
    }

    void printGlyphStack()
    {
        string stack = "Stack: ";
        foreach (DamageType dt in CharacterManager.instance.PlayerCharacter.GlyphStack) stack += dt.ToString();
        Debug.Log(stack);
    }
}
