"""
TODO (swapnil) - This class is deprecated. Do NOT use in future code
"""
from __future__ import annotations # Required for Synchronized to be subscriptable

from typing import Any
from multiprocessing import Value, Queue
from multiprocessing.sharedctypes import Synchronized
from ctypes import c_bool

""" Function success/failure """
CRITICAL = "CRITICAL"
FAILURE = "FAILURE"
SUCCESS = "SUCCESS"
WARNING = "WARNING"
UNSUPPORTED = "UNSUPPORTED"
EXCEPTION = "EXCEPTION"
DEBUG = "DEBUG"
INFO = "INFO"

CRITICAL_CLR = "#fc5c65"
FAILURE_CLR = "#eb3b5a"
EXCEPTION_CLR = "#fed330"
WARNING_CLR = "#f7b731"
UNSUPPORTED_CLR = "#a5b1c2"
SUCCESS_CLR = "#26de81"
INFO_CLR = "#0fb9b1"
DEBUG_CLR = "#d1d8e0"

""" Return packet index """
MSG_STAT = 0
MSG_DATA = 1
MSG_CLR = 2


# Default maximum queue size use -1 to set to "infinite"
DEFAULT_MAX_Q_SIZE = 100000


# Class Name: CustomQueue
# Description: A customized queue object for MacOS and Windows with Multiprocessing support
class CustomQueue(object):
    def __init__(self, maxQsize=DEFAULT_MAX_Q_SIZE):
        # Define the queue object
        self.__q = Queue()
        # Define the queue access flag
        self.__flag = Value(c_bool, False)
        # Define the queue size
        self.__size = Value('i', 0)
        # Define the maximum size of the queue
        self.__maxSize = Value('i', 0)
        # Initialize the queue max size
        self.setMaxSize(maxQsize)

    """**************************************** Static thread-safe functions ****************************************"""

    # Function Name: __set
    # Arguments: parameter (The parameter to change), value (The value to change the parameter to)
    # Returns: None
    # Description: Thread safe parameter setter
    @staticmethod
    def __set(parameter: Synchronized[Any], value):
        with parameter.get_lock():
            parameter.value = value

    # Function Name: __inc
    # Arguments: parameter (The parameter to change), amount (The amount to increment by)
    # Returns: None
    # Description: Thread safe parameter incrementer
    @staticmethod
    def __inc(parameter: Synchronized[Any], amount: int = 1):
        with parameter.get_lock():
            parameter.value += amount

    # Function Name: __dec
    # Arguments: parameter (The parameter to change), amount (The amount to decrement by)
    # Returns: None
    # Description: Thread safe parameter decrementer
    @staticmethod
    def __dec(parameter: Synchronized[Any], amount: int = 1):
        with parameter.get_lock():
            parameter.value -= amount

    """****************************************** Max Size set/get functions ****************************************"""

    # Function Name: getMaxSize
    # Arguments: None
    # Returns: Returns the current max size value
    # Description: Returns the configured max size of the queue
    def getMaxSize(self):
        # Get a snapshot of the maxsize value
        value = self.__maxSize.value
        # Return the value based on range
        return value if value > 0 else DEFAULT_MAX_Q_SIZE

    # Function Name: setMaxSize
    # Arguments: maxQsize (The new max size value)
    # Returns: SUCCESS (if value is valid)
    # Description: Re-configures max size of the queue
    def setMaxSize(self, maxQsize: int=DEFAULT_MAX_Q_SIZE):
        # Check the input range
        if maxQsize <= 0:
            self.__set(self.__maxSize, DEFAULT_MAX_Q_SIZE)
            return WARNING, "Expected a value greater than zero received <{}>".format(str(maxQsize))

        self.__set(self.__maxSize, maxQsize)
        return SUCCESS, "Max queue size updated to <{}> successfully".format(str(self.__maxSize.value))

    """**************************************** Queue flag set/get functions ****************************************"""

    # Function Name: setFlag
    # Arguments: None
    # Returns: None
    # Description: Sets the flag to true
    def setFlag(self):
        self.__set(self.__flag, True)

    # Function Name: releaseFlag
    # Arguments: None
    # Returns: None
    # Description: Sets the flag to false
    def releaseFlag(self):
        self.__set(self.__flag, False)

    # Function Name: getFlag
    # Arguments: None
    # Returns: Flag status
    # Description: Returns the current flag value
    def getFlag(self):
        return self.__flag.value

    """******************************************* Queue operation functions ****************************************"""

    # Function Name: put
    # Arguments: data (The data to be added)
    # Returns: SUCCESS if data is added
    # Description: Adds data to queue if enabled
    def put(self, data):
        # Check queue flag
        if self.__flag.value:
            # Add new data to queue
            self.__inc(self.__size, 1)
            self.__q.put(data)
            # Maintain the queue size if specified
            while self.__size.value > self.__maxSize.value > 0:
                self.__dec(self.__size, 1)
                self.__q.get()
            return SUCCESS, "CustomQueue: Data added to queue"
        return FAILURE, "CustomQueue: Queue access denied! Can't write to queue"

    # Function Name: get
    # Arguments: None
    # Returns: Data in queue FIFO based
    # Description: Returns data from queue if enabled and is not empty
    def get(self):
        if self.__flag.value:
            if not self.empty():
                self.__dec(self.__size, 1)
                return self.__q.get()
            return []
        return FAILURE, "CustomQueue: Queue access denied! Can't read from queue"

    # Function Name: getAll
    # Arguments: None
    # Returns: Data in queue FIFO based
    # Description: Returns all data from queue if enabled
    def getAll(self):
        if self.__flag.value:
            queueData = list()
            while not self.empty():
                self.__dec(self.__size, 1)
                queueData.append(self.__q.get())
            return queueData
        return FAILURE, "CustomQueue: Queue access denied! Can't read from queue"

    """********************************************* Queue status functions *****************************************"""

    # Function Name: clear
    # Arguments: None
    # Returns: None
    # Description: Clears all the data in the queue
    def clear(self):
        while not self.empty():
            self.__dec(self.__size, 1)
            self.__q.get()

    # Function Name: empty
    # Arguments: None
    # Returns: Bool indicating if queue is empty (True) or not (False)
    # Description: Checks if the queue is empty
    def empty(self):
        return True if self.__size.value <= 0 else False

    # Function Name: qsize
    # Arguments: None
    # Returns: Integer indicating the size of the queue
    # Description: Returns the current size of the queue
    def qsize(self):
        return self.__size.value

    """*********************************************** End of Queue Class *******************************************"""
