/*
 * +================================================================================+
 *      __  ___  ______________  __  __  ______________   ____
 *     / / / / |/ /  _/_  __/\ \/ / / / / /_  __/  _/ /  / __/
 *    / /_/ /    // /  / /    \  / / /_/ / / / _/ // /___\ \
 *    \____/_/|_/___/ /_/     /_/  \____/ /_/ /___/____/___/
 *
 * +================================================================================+
 *
 *    "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 System.Collections.Generic;
using UnityEngine;

namespace Utils.Data {

	/// <summary>
	/// Message queue class that lets you queue up messages.
	/// Use the OnNextMessage event to get the next message when it becomes next in the queue.
	/// Use the OnNoMoreMessages event to be noticed when no more messages are in the queue.
	/// </summary>
	public class MessageQueue : MonoBehaviour {

		/// <summary>
		/// The message event handler.
		/// </summary>
		public delegate void MessageEventHandler(MessageQueue queue);
		/// <summary>
		/// Occurs when the next message is becomes active.
		/// </summary>
		public event MessageEventHandler OnNextMessage;
		/// <summary>
		/// Occurs when no more messages are available.
		/// </summary>
		public event MessageEventHandler OnNoMoreMessages;

		/// <summary>
		/// The current message.
		/// </summary>
		public MessageQueueMessage Message {
			get; protected set;
		}

		/// <summary>
		/// The messages.
		/// </summary>
		private Queue<MessageQueueMessage> messages;
		/// <summary>
		/// The time.
		/// </summary>
		private float time;

		void Awake() {
			// Init
			messages = new Queue<MessageQueueMessage>();
			time = 0f;
		}

		void Update () {
			if (Message == null && messages.Count > 0) {
				// Get first message
				Message = messages.Dequeue();

				// Don't raise event if no one is subscribed
				MessageEventHandler handler = OnNextMessage;
				if (handler != null) handler(this);
			} else if (Message != null) {
				// Increment current time if message is available
				time += Time.deltaTime;

				// Check if next message is due
				if (time >= Message.Duration) {
					time -= Message.Duration;
					
					// Next message if available
					if (messages.Count > 0) {
						// Get message
						Message = messages.Dequeue();

						// Raise next message event
						MessageEventHandler handler = OnNextMessage;
						if (handler != null) handler(this);
					} else {
						// Empty message
						Message = null;

						// Raise no more messages event
						MessageEventHandler handler = OnNoMoreMessages;
						if (handler != null) handler(this);
						
						time = 0f;
					}
				}
			}
		}

		/// <summary>
		/// Add the specified message to the queue.
		/// </summary>
		/// <param name="message">The message.</param>
		public void Add(MessageQueueMessage message) {
			messages.Enqueue(message);
		}

		/// <summary>
		/// Add a message to the queue.
		/// </summary>
		/// <param name="text">The text of the message.</param>
		/// <param name="time">The time until the next message.</param>
		public void Add(string text, float duration = 3f) {
			Add(new MessageQueueMessage(text, duration));
		}
	}

	/// <summary>
	/// A message with a text and a duration.
	/// </summary>
	public class MessageQueueMessage {
		/// <summary>
		/// The text.
		/// </summary>
		public string Text;
		/// <summary>
		/// The duration.
		/// </summary>
		public float Duration;

		/// <summary>
		/// Initializes a new instance of the <see cref="Utils.Data.MessageQueueMessage"/> struct.
		/// </summary>
		/// <param name="text">The text.</param>
		/// <param name="duration">The duration.</param>
		public MessageQueueMessage(string text, float duration = 3f) {
			Text = text;
			Duration = duration;
		}
	}
}