<reponame>ARgorithm/TemplateLibrary
"""The queue module provides support for queues. The main class in this module
is the Queue class. The QueueState acts as a support class to Queue class. For
this reason the Queue class can directly be imported from the ARgorithmToolkit
library without having to import from the queue module:

    >>> q = ARgorithmToolkit.queue.Queue(name="q",algo=algo)
    >>> q = ARgorithmToolkit.Queue(name="q",algo=algo)
"""

from ARgorithmToolkit.utils import State, StateSet, ARgorithmError, ARgorithmStructure
from ARgorithmToolkit.encoders import serialize

class QueueState():
    """This class is used to generate states for various actions performed on
    the ``ARgorithmToolkit.queue.Queue`` object.

    Attributes:

        name (str) : Name of the variable for whom we are generating states
        _id (str) : id of the variable for whom we are generating states
    """
    def __init__(self,name,_id):
        self.name = name
        self._id = _id

    def queue_declare(self,comments=""):
        """Generates the `queue_declare` state when an instance of queue is
        created.

        Args:
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `queue_declare` state for respective queue
        """
        state_type = "queue_declare"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "body" : []
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def queue_push(self,body,element,comments=""):
        """Generates the `queue_push` state when an element is added to queue.

        Args:
            body (list): Body of queue
            element: Element to be added to back of queue
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `queue_push` state for respective queue
        """
        state_type = "queue_push"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "body" : list(body),
            "element" : element
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def queue_pop(self,body, element, comments=""):
        """Generates the `queue_pop` state when an element is removed from
        queue.

        Args:
            body (list): Body of queue
            comments (str, optional): Comments for descriptive purpose. Defaults to "".
            element : element that was popped from the queue.

        Returns:
            State: Returns the `queue_pop` state for respective queue
        """
        state_type = "queue_pop"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "body" : list(body),
            "element" : element,
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def queue_front(self,body,comments=""):
        """Generates the `queue_front` state when front of queue is accessed.

        Args:
            body (list): Body of queue
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `queue_front` state for respective queue
        """
        state_type = "queue_front"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "body" : list(body),
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def queue_back(self,body,comments=""):
        """Generates the `queue_back` state when back of queue is accessed.

        Args:
            body (list): Body of queue
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `queue_back` state for respective queue
        """
        state_type = "queue_back"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "body" : list(body),
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

@serialize
class Queue(ARgorithmStructure):
    """The Queue class is a container interface for the queue, a linear
    container implementation of FIFO.

    Attributes:
        name (str): name given to the rendered block in augmented reality. Essential. Should not be altered after initialisation
        algo (ARgorithmToolkit.utils.StateSet): The stateset that will store the states generated by the instance of Queue Class
        comments (str, optional): Comments for descriptive purpose. Defaults to "".

    Raises:
        ARgorithmError: raised if name is not given or Stateset if not provided

    Example:
        >>> algo = ARgorithmToolkit.StateSet()
        >>> q = ARgorithmToolkit.queue.Queue(name="q",algo=algo)
    """

    def __init__(self, name:str, algo:StateSet, comments:str = ""):
        try:
            assert isinstance(name,str)
            self._id = str(id(self))
            self.state_generator = QueueState(name, self._id)
        except AssertionError as e:
            raise ARgorithmError('Give valid name to data structure') from e
        try:
            assert isinstance(algo,StateSet)
            self.algo = algo
        except AssertionError as e:
            raise ARgorithmError("Queue structure needs a reference of template to store states") from e
        self.body = []
        state = self.state_generator.queue_declare(comments)
        self.algo.add_state(state)

    def __len__(self):
        """The operator overload for len() function that returns size of queue.

        Returns:
            int: Size of queue

        Example:
            >>> len(q)
            0
        """
        return len(self.body)

    def empty(self):
        """Checks whether queue is empty or not.

        Returns:
            bool: If true , it means queue is empty

        Example:
            >>> q.empty()
            True
            >>> q.push(3)
            >>> q.empty()
            False
        """
        return len(self)==0

    def push(self,element,comments=""):
        """Adds element to back of queue.

        Args:
            element : Element to be added to queue
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Example:
            >>> q
            Queue([3])
            >>> q.push(5)
            >>> q.push(4)
            >>> q
            Queue([3, 5, 4])
        """
        self.body.append(element)
        state = self.state_generator.queue_push(self.body,element,comments)
        self.algo.add_state(state)

    def pop(self,comments=""):
        """Removes element from front of queue and returns it.

        Args:
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Raises:
            ARgorithmError: Raised if queue is empty

        Returns:
            element: The element popped from queue

        Example:
            >>> q
            Queue([3, 5, 4])
            >>> q.pop()
            3
            >>> q.pop()
            5
            >>> q
            Queue([4])
        """
        if self.empty():
            raise ARgorithmError('queue is empty')
        item = self.body[0]
        self.body = self.body[1:]
        state = self.state_generator.queue_pop(body=self.body,element=item, comments=comments)
        self.algo.add_state(state)
        return item

    def front(self,comments=""):
        """Returns front element of queue.

        Args:
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Raises:
            ARgorithmError: Raised if queue is empty

        Returns:
            element: The element at front of queue

        Examples:
            >>> q
            Queue([4, 2, 1])
            >>> q.front()
            4
        """
        if self.empty():
            raise ARgorithmError('queue is empty')
        item = self.body[0]
        state = self.state_generator.queue_front(self.body,comments)
        self.algo.add_state(state)
        return item

    def back(self,comments=""):
        """Returns back element of queue.

        Args:
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Raises:
            ARgorithmError: Raised if queue is empty

        Returns:
            element: The element at back of queue

        Examples:
            >>> q
            Queue([4, 2, 1])
            >>> q.back()
            1
        """
        if self.empty():
            raise ARgorithmError('queue is empty')
        item = self.body[-1]
        state = self.state_generator.queue_back(self.body,comments)
        self.algo.add_state(state)
        return item

    def __str__(self):
        """String conversion for Queue.

        Returns:
            str: String describing Queue
        """
        return f"Queue({self.body.__str__()})"

    def __repr__(self):
        """Return representation for shell outputs.

        Returns:
            str: shell representation for queue
        """
        return f"Queue({self.body.__repr__()})"

"""The queue module provides support for queues. The main class in this module
is the Queue class. The QueueState acts as a support class to Queue class. For
this reason the Queue class can directly be imported from the ARgorithmToolkit
library without having to import from the queue module:

    >>> q = ARgorithmToolkit.queue.Queue(name="q",algo=algo)
    >>> q = ARgorithmToolkit.Queue(name="q",algo=algo)
"""

from ARgorithmToolkit.utils import State, StateSet, ARgorithmError, ARgorithmStructure
from ARgorithmToolkit.encoders import serialize

class QueueState():
    """This class is used to generate states for various actions performed on
    the ``ARgorithmToolkit.queue.Queue`` object.

    Attributes:

        name (str) : Name of the variable for whom we are generating states
        _id (str) : id of the variable for whom we are generating states
    """
    def __init__(self,name,_id):
        self.name = name
        self._id = _id

    def queue_declare(self,comments=""):
        """Generates the `queue_declare` state when an instance of queue is
        created.

        Args:
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `queue_declare` state for respective queue
        """
        state_type = "queue_declare"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "body" : []
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def queue_push(self,body,element,comments=""):
        """Generates the `queue_push` state when an element is added to queue.

        Args:
            body (list): Body of queue
            element: Element to be added to back of queue
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `queue_push` state for respective queue
        """
        state_type = "queue_push"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "body" : list(body),
            "element" : element
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def queue_pop(self,body, element, comments=""):
        """Generates the `queue_pop` state when an element is removed from
        queue.

        Args:
            body (list): Body of queue
            comments (str, optional): Comments for descriptive purpose. Defaults to "".
            element : element that was popped from the queue.

        Returns:
            State: Returns the `queue_pop` state for respective queue
        """
        state_type = "queue_pop"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "body" : list(body),
            "element" : element,
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def queue_front(self,body,comments=""):
        """Generates the `queue_front` state when front of queue is accessed.

        Args:
            body (list): Body of queue
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `queue_front` state for respective queue
        """
        state_type = "queue_front"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "body" : list(body),
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

    def queue_back(self,body,comments=""):
        """Generates the `queue_back` state when back of queue is accessed.

        Args:
            body (list): Body of queue
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Returns:
            State: Returns the `queue_back` state for respective queue
        """
        state_type = "queue_back"
        state_def = {
            "id" : self._id,
            "variable_name" : self.name,
            "body" : list(body),
        }
        return State(
            state_type=state_type,
            state_def=state_def,
            comments=comments
        )

@serialize
class Queue(ARgorithmStructure):
    """The Queue class is a container interface for the queue, a linear
    container implementation of FIFO.

    Attributes:
        name (str): name given to the rendered block in augmented reality. Essential. Should not be altered after initialisation
        algo (ARgorithmToolkit.utils.StateSet): The stateset that will store the states generated by the instance of Queue Class
        comments (str, optional): Comments for descriptive purpose. Defaults to "".

    Raises:
        ARgorithmError: raised if name is not given or Stateset if not provided

    Example:
        >>> algo = ARgorithmToolkit.StateSet()
        >>> q = ARgorithmToolkit.queue.Queue(name="q",algo=algo)
    """

    def __init__(self, name:str, algo:StateSet, comments:str = ""):
        try:
            assert isinstance(name,str)
            self._id = str(id(self))
            self.state_generator = QueueState(name, self._id)
        except AssertionError as e:
            raise ARgorithmError('Give valid name to data structure') from e
        try:
            assert isinstance(algo,StateSet)
            self.algo = algo
        except AssertionError as e:
            raise ARgorithmError("Queue structure needs a reference of template to store states") from e
        self.body = []
        state = self.state_generator.queue_declare(comments)
        self.algo.add_state(state)

    def __len__(self):
        """The operator overload for len() function that returns size of queue.

        Returns:
            int: Size of queue

        Example:
            >>> len(q)
            0
        """
        return len(self.body)

    def empty(self):
        """Checks whether queue is empty or not.

        Returns:
            bool: If true , it means queue is empty

        Example:
            >>> q.empty()
            True
            >>> q.push(3)
            >>> q.empty()
            False
        """
        return len(self)==0

    def push(self,element,comments=""):
        """Adds element to back of queue.

        Args:
            element : Element to be added to queue
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Example:
            >>> q
            Queue([3])
            >>> q.push(5)
            >>> q.push(4)
            >>> q
            Queue([3, 5, 4])
        """
        self.body.append(element)
        state = self.state_generator.queue_push(self.body,element,comments)
        self.algo.add_state(state)

    def pop(self,comments=""):
        """Removes element from front of queue and returns it.

        Args:
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Raises:
            ARgorithmError: Raised if queue is empty

        Returns:
            element: The element popped from queue

        Example:
            >>> q
            Queue([3, 5, 4])
            >>> q.pop()
            3
            >>> q.pop()
            5
            >>> q
            Queue([4])
        """
        if self.empty():
            raise ARgorithmError('queue is empty')
        item = self.body[0]
        self.body = self.body[1:]
        state = self.state_generator.queue_pop(body=self.body,element=item, comments=comments)
        self.algo.add_state(state)
        return item

    def front(self,comments=""):
        """Returns front element of queue.

        Args:
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Raises:
            ARgorithmError: Raised if queue is empty

        Returns:
            element: The element at front of queue

        Examples:
            >>> q
            Queue([4, 2, 1])
            >>> q.front()
            4
        """
        if self.empty():
            raise ARgorithmError('queue is empty')
        item = self.body[0]
        state = self.state_generator.queue_front(self.body,comments)
        self.algo.add_state(state)
        return item

    def back(self,comments=""):
        """Returns back element of queue.

        Args:
            comments (str, optional): Comments for descriptive purpose. Defaults to "".

        Raises:
            ARgorithmError: Raised if queue is empty

        Returns:
            element: The element at back of queue

        Examples:
            >>> q
            Queue([4, 2, 1])
            >>> q.back()
            1
        """
        if self.empty():
            raise ARgorithmError('queue is empty')
        item = self.body[-1]
        state = self.state_generator.queue_back(self.body,comments)
        self.algo.add_state(state)
        return item

    def __str__(self):
        """String conversion for Queue.

        Returns:
            str: String describing Queue
        """
        return f"Queue({self.body.__str__()})"

    def __repr__(self):
        """Return representation for shell outputs.

        Returns:
            str: shell representation for queue
        """
        return f"Queue({self.body.__repr__()})"
The queue module provides support for queues. The main class in this module is the Queue class. The QueueState acts as a support class to Queue class. For this reason the Queue class can directly be imported from the ARgorithmToolkit library without having to import from the queue module:      >>> q = ARgorithmToolkit.queue.Queue(name="q",algo=algo)     >>> q = ARgorithmToolkit.Queue(name="q",algo=algo) This class is used to generate states for various actions performed on     the ``ARgorithmToolkit.queue.Queue`` object.      Attributes:          name (str) : Name of the variable for whom we are generating states         _id (str) : id of the variable for whom we are generating states Generates the `queue_declare` state when an instance of queue is         created.          Args:             comments (str, optional): Comments for descriptive purpose. Defaults to "".          Returns:             State: Returns the `queue_declare` state for respective queue Generates the `queue_push` state when an element is added to queue.          Args:             body (list): Body of queue             element: Element to be added to back of queue             comments (str, optional): Comments for descriptive purpose. Defaults to "".          Returns:             State: Returns the `queue_push` state for respective queue Generates the `queue_pop` state when an element is removed from         queue.          Args:             body (list): Body of queue             comments (str, optional): Comments for descriptive purpose. Defaults to "".             element : element that was popped from the queue.          Returns:             State: Returns the `queue_pop` state for respective queue Generates the `queue_front` state when front of queue is accessed.          Args:             body (list): Body of queue             comments (str, optional): Comments for descriptive purpose. Defaults to "".          Returns:             State: Returns the `queue_front` state for respective queue Generates the `queue_back` state when back of queue is accessed.          Args:             body (list): Body of queue             comments (str, optional): Comments for descriptive purpose. Defaults to "".          Returns:             State: Returns the `queue_back` state for respective queue The Queue class is a container interface for the queue, a linear     container implementation of FIFO.      Attributes:         name (str): name given to the rendered block in augmented reality. Essential. Should not be altered after initialisation         algo (ARgorithmToolkit.utils.StateSet): The stateset that will store the states generated by the instance of Queue Class         comments (str, optional): Comments for descriptive purpose. Defaults to "".      Raises:         ARgorithmError: raised if name is not given or Stateset if not provided      Example:         >>> algo = ARgorithmToolkit.StateSet()         >>> q = ARgorithmToolkit.queue.Queue(name="q",algo=algo) The operator overload for len() function that returns size of queue.          Returns:             int: Size of queue          Example:             >>> len(q)             0 Checks whether queue is empty or not.          Returns:             bool: If true , it means queue is empty          Example:             >>> q.empty()             True             >>> q.push(3)             >>> q.empty()             False Adds element to back of queue.          Args:             element : Element to be added to queue             comments (str, optional): Comments for descriptive purpose. Defaults to "".          Example:             >>> q             Queue([3])             >>> q.push(5)             >>> q.push(4)             >>> q             Queue([3, 5, 4]) Removes element from front of queue and returns it.          Args:             comments (str, optional): Comments for descriptive purpose. Defaults to "".          Raises:             ARgorithmError: Raised if queue is empty          Returns:             element: The element popped from queue          Example:             >>> q             Queue([3, 5, 4])             >>> q.pop()             3             >>> q.pop()             5             >>> q             Queue([4]) Returns front element of queue.          Args:             comments (str, optional): Comments for descriptive purpose. Defaults to "".          Raises:             ARgorithmError: Raised if queue is empty          Returns:             element: The element at front of queue          Examples:             >>> q             Queue([4, 2, 1])             >>> q.front()             4 Returns back element of queue.          Args:             comments (str, optional): Comments for descriptive purpose. Defaults to "".          Raises:             ARgorithmError: Raised if queue is empty          Returns:             element: The element at back of queue          Examples:             >>> q             Queue([4, 2, 1])             >>> q.back()             1 String conversion for Queue.          Returns:             str: String describing Queue Return representation for shell outputs.          Returns:             str: shell representation for queue