/*
 * +================================================================================+
 *      __  ___  ______________  __  __  ______________   ____
 *     / / / / |/ /  _/_  __/\ \/ / / / / /_  __/  _/ /  / __/
 *    / /_/ /    // /  / /    \  / / /_/ / / / _/ // /___\ \
 *    \____/_/|_/___/ /_/     /_/  \____/ /_/ /___/____/___/
 *
 * +================================================================================+
 *
 *    "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;

namespace Utils.Effects {

	/// <summary>
	/// Effects base class.
	/// </summary>
	public abstract class Effect : MonoBehaviour {

		[Header("Timing")]
		[Tooltip("Determines wheter to automatically start the effect on creation.")]
		/// <summary>
		/// Determines wheter to automatically start the effect on creation.
		/// </summary>
		public bool AutoStart = true;
		[Tooltip("A delay to start after (in seconds).")]
		/// <summary>
		/// A delay to start after (in seconds).
		/// </summary>
		public float Delay = 0f;
		[Tooltip("The duration of the effect.")]
		/// <summary>
		/// The duration of the effect.
		/// </summary>
		public float Duration = 1f;

		[HideInInspector]
		/// <summary>
		/// Determines whether to remove the effect script after execution.
		/// Won't destroy the game object.
		/// </summary>
		public bool DeleteSelfAfterExecution = false;

		/// <summary>
		/// Indicates whether the effect is infinite. Override this in your own effects.
		/// </summary>
		protected bool infinite = false;
		/// <summary>
		/// The current time (in seconds).
		/// </summary>
		protected float currentTime;
		/// <summary>
		/// The current delay (in seconds).
		/// </summary>
		private float currentDelay;

		/// <summary>
		/// Gets a value indicating whether the effect has started.
		/// </summary>
		/// <value><c>true</c> if the effect has started; otherwise, <c>false</c>.</value>
		public bool HasStarted { get; protected set; }
		/// <summary>
		/// Gets a value indicating whether the effect is playing.
		/// </summary>
		/// <value><c>true</c> if the effect is playing; otherwise, <c>false</c>.</value>
		public bool IsPlaying { get; protected set; }

		void Start() {
			// Start the effect automatically if necessairy
			if (AutoStart) StartEffect();
		}

		void Update() {
			// I the effect has started
			if (HasStarted) {
				// Handle delay
				if (currentDelay > 0f) currentDelay -= Time.deltaTime;
				else {
					// Update the effect
					IsPlaying = true;
					UpdateEffect();
					currentTime += Time.deltaTime;
				}
			}

			// Handle effect ending
			if (!infinite && currentTime >= Duration) EndEffect();
		}

		/// <summary>
		/// Starts the effect.
		/// </summary>
		public void StartEffect() {
			// Handle restart
			if (HasStarted) {
				if (infinite || DeleteSelfAfterExecution) return;
				else EndEffect();
			}

			// Start effect
			HasStarted = true;
			currentDelay = Delay;
			InitEffect();
		}

		/// <summary>
		/// Ends the effect.
		/// </summary>
		public void EndEffect() {
			// End effect
			CleanUpEffect();
			if (DeleteSelfAfterExecution) Destroy(this);
		}

		/// <summary>
		/// Method to initialise the effect. Override this in your own effects.
		/// </summary>
		protected virtual void InitEffect() { }

		/// <summary>
		/// Method to update the effect. Override this in your own effects.
		/// </summary>
		protected virtual void UpdateEffect() { }

		/// <summary>
		/// Method to clean up the effect. Override this in your own effects.
		/// </summary>
		protected virtual void CleanUpEffect() { }
	}
}
