# A cyclic implementation of a queue

# This file serves mainly as a demonstration of
# queue idea, implementation and management.

# Python provides a queue module which
# should be used in most standard "real life" applications.
# For more details on queue module see
# https://docs.python.org/3/library/queue.html

class Queue:
    def __init__(self, maxCapacity):
        self.queueSize = maxCapacity
        self.items = [None] * self.queueSize
        self.front = 0
        self. tail = 0


    def isEmpty(self):
        return (self.tail == self.front)

    def isFull(self):
        return self.tail + 1 == self.front or \
         (self.front == 0 and self.tail == len(self.items)-1)

    def size(self):
        if self.front < self.tail:         # [.... front X X X X tail ...]
            return self.tail - self.front
        else:                              # [X X X tail .... front X X X]
            return self.tail + (self.queueSize - self.front)

    def enqueue(self, item):
        print( ">> Enqueue", item)
        # check overflow
        if self.isFull():
            print( "   queue is full. Cannot insert", item )
            return
        self.items[self.tail] = item
        self.tail = (self.tail + 1) % self.queueSize
        self.display()


    def dequeue(self):
        print( ">> Dequeue")
        if self.isEmpty():
            print( "   queue is empty. Cannot dequeue" )
            return
        node = self.items[self.front]
        self.front = (self.front + 1) % self.queueSize
        self.display()
        return node

    # logical print
    def print1(self):
        if self.isEmpty():
            print("Queue is empty.")
            return

        print( ("+---" * self.size())+ "+" )
        print( "|", end = "")
        i = self.front
        while True:
            if i == self.tail: break
            item = self.items[i]
            itemstr = str(item)
            if 0 <= item <= 10:
                itemstr = " " + str(item) + " "
            if -9 <= item <= -1 or 10 <= item <= 99:
                itemstr =  " "+ str(item)
            print(itemstr + "|", end = "")
            i = (i + 1) % self.queueSize
        print()
        print( ("+---" * self.size())+ "+" )

    def isValidIndex(self, i):
        if self.front < self.tail:         # [.... front xxx i xxx tail ...]
            return self.front <= i < self.tail
        else:                              # [ xx i xx tail .... front xx i xx]
            return i < self.tail or self.front <= i

    # physical print
    def display(self):
        if self.isEmpty():
            print("Queue is empty.")
            return

        top = ["    "] * (self.queueSize + 1)
        if self.front == self.tail:
            top[self.front] = "Fr/Ta"
        else:
            top[self.front] = "Frnt"
            top[self.tail] = "Tail"
        print( "".join(top))

        print(("+---" * self.queueSize) + "+")
        print( "|", end = "")
        i = self.front
        for i in range(self.queueSize):
            itemstr = "   "
            if self.isValidIndex(i):
                item = self.items[i]
                itemstr = str(item)
                if 0 <= item <= 10:
                    itemstr = " " + str(item) + " "
                if -9 <= item <= -1 or 10 <= item <= 99:
                    itemstr =  " "+ str(item)
            print(itemstr + "|", end = "")
            i = (i + 1) % self.queueSize
        print()
        print(("+---" * self.queueSize) + "+")


    # more aliases

    def push(self, item):
        self.enqueue(item)

    def insert(self, item):
        self.enqueue(item)

    def pop(self):
        return self.dequeue()

    def delete(self):
        return self.dequeue()

    # ---- end of class Queue -----------------------


q = Queue( 6 )
q.print1()
q.display()
q.insert(10)
q.insert(20)
q.insert(30)
q.insert(40)
q.delete()
q.delete()
q.delete()
q.insert(50)
q.insert(60)
q.insert(70)
q.insert(80)
q.insert(90)
q.insert(100)
q.delete()




