/*
 * +================================================================================+
 *      __  ___  ______________  __  __  ______________   ____
 *     / / / / |/ /  _/_  __/\ \/ / / / / /_  __/  _/ /  / __/
 *    / /_/ /    // /  / /    \  / / /_/ / / / _/ // /___\ \
 *    \____/_/|_/___/ /_/     /_/  \____/ /_/ /___/____/___/
 *
 * +================================================================================+
 *
 *    "THE BEER-WARE LICENSE"
 *    -----------------------
 *
 *    As long as you retain this notice you can do whatever you want with this
 *    stuff. However it is expressly forbidden to sell or commercially distribute
 *    Unity Utils or parts of it apart from your games.
 *    If you meet any of the authors some day, and you think this stuff is
 *    worth it, you can buy them a beer in return.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *    THE SOFTWARE.
 *
 * +================================================================================+
 *
 *    Authors:
 *    David Krummenacher (dave@timbookedtwo.com)
 *
 */

using UnityEngine;
using Utils.Helpers;

namespace Utils.Behaviours {

	/// <summary>
	/// Simple spawner that instatiates a given amount of a certain game object.
	/// Positioning is relative to the game object with the simple spawner script.
	/// </summary>
	public class SimpleSpawner : MonoBehaviour {

		[Tooltip("The game object to spawn.")]
		/// <summary>
		/// The game object to spawn.
		/// </summary>
		public GameObject Prefab;
		[Tooltip("The lowest amount of game objects to spawn.")]
		/// <summary>
		/// The lowest amount of game objects to spawn.
		/// </summary>
		public int LowAmount;
		[Tooltip("The highest amount of game objects to spawn.")]
		/// <summary>
		/// The highest amount of game objects to spawn.
		/// </summary>
		public int HighAmount;
		[Tooltip("The lowest delay of spawning.\nThe lowest interval time if Intervaled is enabled.")]
		/// <summary>
		/// The lowest delay of spawning.
		/// The lowest interval time if Intervaled is enabled.
		/// </summary>
		public float LowDelay;
		[Tooltip("The highest delay of spawning. This value will never be reached.\nThe highest interval time if Intervaled is enabled.")]
		/// <summary>
		/// The highest delay of spawning. This value will never be reached.
		/// The highest interval time if Intervaled is enabled.
		/// </summary>
		public float HighDelay;
		[Tooltip("If the spawning happens in intervals.")]
		/// <summary>
		/// If the spawning happens in intervals.
		/// </summary>
		public bool Intervaled;
		[Tooltip("Indicates wheter to spawn on startup or not.\nIs only regarded if intervaled is enabled.")]
		/// <summary>
		/// Indicates wheter to spawn on startup or not.
		/// Is only regarded if intervaled is enabled.
		/// </summary>
		public bool Prewarm;
		[Tooltip("The spawning area relative to the game object with the simple spawner script.")]
		/// <summary>
		/// The spawning area relative to the game object with the simple spawner script.
		/// </summary>
		public Bounds Area;
		[Tooltip("The rotation range randomly added to the original rotation of the spawned object.")]
		/// <summary>
		/// The rotation range randomly added to the original rotation of the spawned object.
		/// </summary>
		public Vector3 Rotation;

		/// <summary>
		/// The target time to spawn.
		/// </summary>
		private float targetTime;
		/// <summary>
		/// The current time.
		/// </summary>
		private float currentTime;

		void Start () {
			// Allow for one shot spawning
			if (LowDelay <= 0f || HighDelay <= 0f) {
				Spawn();
				enabled = false;
				return;
			}

			// Setup for intervaled spawning
			if (Prewarm) Spawn();
			targetTime = Random.Range(LowDelay, HighDelay);
			currentTime = Time.deltaTime;
		}

		void Update () {
			// Don't update in one shot spawning
			if (LowDelay <= 0f || HighDelay <= 0f) return;

			// Intervaled spawning
			currentTime += Time.deltaTime;
			if (currentTime >= targetTime) {
				Spawn();
				currentTime -= targetTime;
				targetTime = Random.Range(LowDelay, HighDelay);
			}
		}

		/// <summary>
		/// Spawns the objects.
		/// </summary>
		void Spawn () {
			int targetAmount = Random.Range(LowAmount, HighAmount);

			for (int i = 0; i < targetAmount; i++) {
				GameObject obj = (GameObject) Instantiate(Prefab);
				obj.transform.position = gameObject.transform.position + VectorHelper.RandomRangeVector3(Area);
				obj.transform.Rotate(VectorHelper.RandomRangeVector3(Vector3.zero, Rotation));
			}
		}
	}
}
