﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Tap.Tilt
{
    /// <summary>
    /// Spawner creates a pool and spawns from that pool according to randoms with limits specified by properties
    /// </summary>
    public class Spawner : MonoBehaviour
    {
        /// <summary>
        /// What to spawn
        /// </summary>
        public GameObject spawnItem;

        /// <summary>
        /// Locations to spawn
        /// </summary>
        public Transform[] spawnLocations;

        /// <summary>
        /// Random order (0) or increment of array of locations (int)
        /// </summary>
        public int locationIncrement = 0;

        // How many items to spawn in the pool, maximum in scene
        public int spawnCount;

        // How long (minimum) to wait between spawning
        public float minSpawnTime = 1;

        // How long (max) to wait between spawning
        public float maxSpawnTime = 10;

        private GameObject[] pool;

        private int itemIndex = 0;
        private int locationIndex = 0;

        // Start is called before the first frame update
        void Awake()
        {
            pool = new GameObject[spawnCount];
            for (int foi = 0; foi < spawnCount; foi++)
            {
                pool[foi] = Instantiate(spawnItem);
                pool[foi].SetActive(false);
            }
        }

        private void OnEnable()
        {
            StartCoroutine(Spawn());
        }

        private int searchIndex;
        private int searchCount;
        IEnumerator Spawn()
        {
            if (pool != null)
            {
                // Find an inactive object to spawn in the pool
                searchIndex = itemIndex + 1;
                if (searchIndex >= pool.Length)
                    searchIndex = 0;

                // Simple forward-search the pool for objects to spawn
                // Limit the loop count
                searchCount = 0;
                while (pool[searchIndex].activeInHierarchy && searchCount < pool.Length)
                {
                    if (searchIndex >= spawnCount - 1)
                        searchIndex = 0;
                    else
                        searchIndex++;

                    searchCount++;
                }

                // If the searchCount >= pool.Length, then nothing was found to spawn
                if (searchCount >= pool.Length)
                {
                    Debug.Log("Add item to spawn pool " + spawnItem.name);
                    // create a new pool that contains one more item and select the new item
                    GameObject[] tempPool = new GameObject[pool.Length + 1];
                    int foi;
                    for (foi = 0; foi < pool.Length; foi++)
                        tempPool[foi] = pool[foi];

                    // After the for structure, the foi value is pool size + 1
                    tempPool[foi] = Instantiate(spawnItem);
                    searchIndex = foi;
                    
                    // replace the pool with the enlarged pool
                    pool = tempPool;
                }
                // Determine the location to spawn
                if (locationIncrement == 0)
                    locationIndex = Random.Range(0, spawnLocations.Length);
                else
                {
                    locationIndex += locationIncrement;
                    if (locationIndex >= spawnLocations.Length)
                        locationIndex -= spawnLocations.Length;
                }

                // Move the spawned item to the appropriate transform
                pool[searchIndex].transform.position = spawnLocations[locationIndex].position;
                pool[searchIndex].transform.rotation = spawnLocations[locationIndex].rotation;

                // If the item has any rigidbody component, set the velocity and angularVelocity to 0
                Rigidbody rigid = pool[searchIndex].GetComponent<Rigidbody>();
                if (rigid != null)
                {
                    rigid.velocity = Vector3.zero;
                    rigid.angularVelocity = Vector3.zero;
                }

                // Set it as active to add it to the scene
                pool[searchIndex].SetActive(true);

                // Set the current index to the selected value
                itemIndex = searchIndex;

            }

            // Set the time for the next spawn, according to the min/max
            yield return new WaitForSeconds(Random.Range(minSpawnTime, maxSpawnTime));
            StartCoroutine(Spawn());
        }
    }
}
