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

public class EnemyManager : MonoBehaviour
{
    public Transform m_enemyPrefab;
    
    public static EnemyManager ms_instance;
    public static EnemyManager Instance
    {
        get { return ms_instance; }
    }

    public HashSet<Transform> m_enemies;

	// Use this for initialization
	void Start ()
    {
        if (ms_instance != null)
        {
            Debug.LogError("Only one enemyman allowed");
        }
        ms_instance = this;

        m_enemies = new HashSet<Transform>();
	}
	
	// Update is called once per frame
	void Update () 
    {
	
	}

    public void AddEnemy( GridCoord placeAt, EnemyID id, int level )
    {
        CharacterInfo info = EnemyDatabase.GetItem(id);
        if ( info == null )
        {
            Debug.LogError("No info for " + (int)id);
        }

        Object newObj = Instantiate(m_enemyPrefab, placeAt.GetUnityPos(), Quaternion.identity);

        Transform objTrans = newObj as Transform;
        objTrans.localScale = new Vector3(GridManager.UNITY_GRID_SIZE, GridManager.UNITY_CHARACTER_DEPTH, GridManager.UNITY_GRID_SIZE);

        if (level > 1)
        {
            info.m_maxHp *= level;
            info.m_currentHp *= level;
            info.m_currentMp *= level;
            info.m_maxHp *= level;

            info.m_attack *= level;
            info.m_defense *= level;
        }

        objTrans.GetComponent<GridObject>().UpdatePosition(placeAt, true);
        objTrans.GetComponent<CharacterObject>().Info = info;

        CharacterIcons.Instance.ApplyEnemyIcon(objTrans, info.m_enemyIconIndex);

        m_enemies.Add(objTrans);
        GridManager.Instance.AddObject(objTrans.GetComponent<GridObject>());

        m_enemiesToPlace--;
    }

    public void KillEnemy(EnemyObject enemy)
    {
        if ( enemy == null )
        {
            return;
        }
        GridManager.Instance.RemoveObject(enemy.GetComponent<GridObject>());
        m_enemies.Remove(enemy.transform);

        GameObject obj = enemy.gameObject;
        Destroy(obj);
    }

    public void KillAllEnemies()
    {
        while ( m_enemies.Count > 0 )
        {
            foreach( Transform t in m_enemies )
            {
                KillEnemy(t.GetComponent<EnemyObject>());

                // I don't trust removal during iteration
                break;
            }
        }
        CharacterStatsGui.ClearEnemy();
    }

    public bool IsEmpty( GridCoord pos )
    {
        GridObject dummyObj;
        if (GridManager.Instance.TestCollision(pos, out dummyObj, false) == false)
        {
            return true;
        }
        return false;
    }

    public GridCoord RandGridPos( int border, int minProxim )
    {
        int range = GridManager.MAP_SIZE_X - (border * 2);

        GridCoord newPos = new GridCoord(0, 0);

        while (NewIteration() )
        {
            newPos.x = Random.Range(border, border + range);
            newPos.y = Random.Range(border, border + range);
            
            if (IsEmpty(newPos))
            {
                return newPos;
            }
        }
        return newPos;
    }

    public GridCoord RandomSafeWalk( GridCoord from )
    {
        // Move progressively out if it fails
        for ( int moveBy = 1;moveBy<5;moveBy++)
        {
            // Random start dir
            int dir = Random.Range(0, 4);

            // try all four though
            for ( int i=0;i<4;i++ )
            {                
                GridCoord newPos = from;

                switch ( dir )
                {
                    case 0: newPos.x += moveBy; break;
                    case 1: newPos.y += moveBy; break;
                    case 2: newPos.x -= moveBy; break;
                    case 3: newPos.y -= moveBy; break;
                }

                if (IsEmpty(newPos))
                {
                    return newPos;
                }

                dir++;
                dir = dir % 4;
            }
        }
        return from;
    }

    public int m_iterations;
    private int m_enemiesToPlace;

    public bool NewIteration()
    {
        m_iterations++;
        if ( m_iterations > 1000 )
        {
            return false;
        }
        return true;
    }

            
    public void AddRandomEnemies()
    {
        int batNum = ( PlayerObject.Instance.Info.m_battleNumber);

        Random.seed = (PlayerObject.Instance.Info.m_battleNumber * 221247);
        
        // Enemy types to encounter
        int minEnemyIndex = batNum - 3;
        int maxEnemyIndex = batNum + 2;

        List<int> enemyLevels = new List<int>();
        
        {
            int numEnemies = 4 + (batNum * 3);
            numEnemies = (int)((float)numEnemies * Random.Range(0.9f, 1.1f));

            numEnemies = Mathf.Min(64, numEnemies);
            numEnemies = Mathf.Max(6, numEnemies);

            m_enemiesToPlace = numEnemies;
            m_iterations = 0;

            Debug.Log("Placing " + m_enemiesToPlace + " enemies");
        }

        int chanceToNextLevel = 1;
        for ( int i=maxEnemyIndex;i>= minEnemyIndex; )
        {            
            enemyLevels.Add( i );

            if ( Random.Range( 0, chanceToNextLevel) == 0 )
            {
                // Drop to lower level enemy
                i--;
                if (( i % 2 ) == 0 )
                {
                    chanceToNextLevel += 1;
                }
            }

            if ( NewIteration() == false )
            {
                break;
            }

            if ( enemyLevels.Count >= m_enemiesToPlace )
            {
                break;
            }
        }

        while ((m_enemiesToPlace > 0) && (NewIteration()))
        {
            int numInGroup = 1;

            // Do clustered enemies
            if ( Random.Range( 0,3) == 0 )
            {
                int maxInGroup = batNum / 2;
                maxInGroup = Mathf.Min(6, maxInGroup);
                maxInGroup = Mathf.Max(4, maxInGroup);

                // Group
                numInGroup = Random.Range(2, maxInGroup);
            }

            GridCoord emptyPos = RandGridPos(16, 0);

            while ( numInGroup > 0 )
            {
                if ( m_enemiesToPlace == 0 )
                {
                    break;
                }
                int indexIntoLevelsList = m_enemiesToPlace - 1;

//                 Debug.Log("In List1: " + indexIntoLevelsList + " ");
//                 Debug.Log("In List2: " + enemyLevels.Count + " ");
                EnemyID id = EnemyDatabase.GetID(enemyLevels[indexIntoLevelsList]);

                AddEnemy(emptyPos, id, 1);
                numInGroup--;

                if (numInGroup > 0)
                {               
                 emptyPos = RandomSafeWalk(emptyPos);
                }
            }

        }
    }


}
