using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DataStructures
{
    public class Queue<T>
    {
        public Queue(int length)
        {
            Nodes = new Node<T>[length];
        }

        public int Count { get; set; }

        public int Head { get; set; }
        public int Tail { get; set; }

        public Node<T>[] Nodes { get; set; }

        public bool Append(params T[] newData)
        {
            if (newData.Length + Count > Nodes.Length)
                return false;

            int i = 0;
            while (i < newData.Length)
            {
                Nodes[Tail] = new Node<T>(Count, newData[i]);
                Count++;

                Tail = Get(Tail);
                i++;
            }

            return true;
        }

        public T Retrieve()
        {
            T returnData;

            if (Count == 0)
                return default(T);
            else
                returnData = Nodes[Head].Data;

            Nodes[Head] = null;
            Count--;

            Head = Get(Head);

            return returnData;
        }

        private int Get(int i)
        {
            return Get(i, 1);
        }

        private int Get(int i, int offset)
        {
            if (i + offset >= Nodes.Length)
                return (i + offset) - Nodes.Length;
            else if (i + offset < 0)
                return Nodes.Length + (i + offset);
            else
                return i + offset;
        }

        public override string ToString()
        {
            String outputStr = String.Empty;

            int i = Head;
            for (; ; )
            {
                outputStr += Nodes[i].ToString();

                i++;
                if (i > Nodes.Length - 1)
                    i = 0;

                if (i == Head || Nodes[i] == null)
                    break;
            }

            outputStr += String.Format("\n\n\tCapacity = {0}/{1},  Head = {2}, Tail = {3}",
                Count, Nodes.Length, Head, Tail);

            return outputStr;
        }
    }
}
