# -- Imports ------------------------------------------------------------------
import fwlib  # namespace
from types import TracebackType
from typing import Optional, Type
from time import sleep


class FocasException(Exception):
    pass


class UnableToReadMacro(FocasException):
    """Raised when a macro could not be read"""


class UnableToReadAxis(FocasException):
    """Raised when an axis could not be read"""


class FocasController:
    def __init__(self, ip: str, port: int = 8193, sample_rate: int = 10):
        self.ip = ip
        self.port = port
        self.sample_rate = sample_rate
        self.library_handle = None

    def __enter__(self):        #  -> Focas: gives an Error, so leave it!
        """Initialize the connector class"""

        self.connect()
        return self

    def __exit__(
        self,
        exception_type: Optional[Type[BaseException]],
        exception_value: Optional[BaseException],
        traceback: Optional[TracebackType],
    ) -> None:
        """Clean up the resources used by the storage class

        Parameters
        ----------

        exception_type:
            The type of the exception in case of an exception

        exception_value:
            The value of the exception in case of an exception

        traceback:
            The traceback in case of an exception

        """

        self.disconnect()

    def connect(self):
        ret=1
        n=0
        while ret != 0 and n<4:
            n=n+1
            ret, self.libh = fwlib.cnc_allclibhndl3(self.ip, self.port, self.sample_rate)
            if ret != 0:
                sleep(1/1000)
        if ret != 0:
            raise ConnectionError(
                f"Unable to connect to Focas (IP: {self.ip}, Port:"
                f" {self.port})"
            )

        self.library_handle = self.libh
        assert self.library_handle is not None, "Library handle not initialized"

    def disconnect(self):
        fwlib.cnc_freelibhndl(self.library_handle)

    def read_macro(self, register: int) -> int:
        
        ret, (_, dataFeature) = fwlib.cnc_rdmacror2(self.library_handle, [register])
        if ret != 0:
            raise UnableToReadMacro(f"Unable to read macro “{register}”")
        return dataFeature

    def read_axis(self, category: int, index: int) -> int:
        """
        example
        >>> url="192.168.1.10" 
        >>> with FocasController(url) as controller:
        ...     # 1...position, 0...absolute
        ...     axisdata = controller.read_axis(1,0)
        >>> len(axisdata)
        5
        >>> type(axisdata[0])
        <class 'axdata'>
        
        """
        ret, axisdata = fwlib.cnc_rdaxisdata(self.library_handle, category, [index])
        if ret != 0:
            raise UnableToReadAxis(f"Unable to read axis data “{category}”, “{index}”")
        return axisdata


if __name__ == "__main__":
    # nc_data = []
    tuple = [[1,2,3,5], [0,1]]
    focas_controller = FocasController("192.168.1.10")
    with focas_controller:
        try:
            # axis_tuples = [[1, 0], [2, 0], [3, 0], [5, 0], [5, 1]]
            # for tuple in axis_tuples:
            axisdata = focas_controller.read_axis(tuple[0], tuple[1])
            # for axis in axisdata:
            #     nc_data.append(axis[1])
            # print(nc_data)
        except (ConnectionError, UnableToReadMacro, UnableToReadAxis) as error:
            print(error)
            focas_controller.disconnect()
    print(axisdata)
