import serial

from abc import ABCMeta
from logging import Logger
from typing import Dict

from nperipherals_core.model.custom_exceptions import DeviceNotConnected
from nperipherals_core.model.device import Device


class SerialDevice(Device):
    __metaclass__ = ABCMeta

    def __init__(
            self,
            logger,                 # type: Logger
            device_configurations   # type: Dict[unicode, unicode]
    ):
        # type: (...) -> None

        self.logger = logger
        self.names = device_configurations["Name"]
        self.port = str(device_configurations["Port"])
        self.bud_rate = int(device_configurations["BaudRate"])
        self.data_bits = int(device_configurations["DataBits"])
        self.serial = None

    def get_name(
            self
    ):
        # type: (...) -> unicode

        if isinstance(self.names, list):
            return ','.join(self.names)

        return self.names

    def initialize(
            self
    ):
        # type: (...) -> None

        try:
            if self.serial is None:
                stop_bits = serial.STOPBITS_ONE
                self.serial = serial.Serial(
                        port=self.port,
                        baudrate=self.bud_rate,
                        bytesize=self.data_bits,
                        timeout=2,
                        stopbits=stop_bits
                )
        except Exception as e:
            self.logger.exception("Error getting serial connection: [{}]".format(repr(e)))
            raise DeviceNotConnected()

    def connect(
            self
    ):
        # type: (...) -> None

        try:
            if self.serial is not None and self.serial.is_open is False:
                self.serial.open()
        except Exception as e:
            self.logger.exception("Error open serial port: [{}]".format(repr(e)))
            raise DeviceNotConnected()

    def disconnect(
            self
    ):
        # type: (...) -> None

        try:
            self.serial.close()
        except Exception as _:
            self.logger.exception("Error closing socket connection")
