import time
from logging import getLogger

from nperipherals_core.model.custom_exceptions import FailedWritingToDevice
from nperipherals_core.model.device import WriterDevice, ReaderDevice
from typing import Union

logger = getLogger(__name__)


class PrintInteractor(object):
    def __init__(self, writer_device):
        # type: (Union[ReaderDevice, WriterDevice]) -> None

        self.writer_device = writer_device

    def print_data(self, data):
        # type: (str) -> None

        device_name = self.writer_device.get_name()
        write_retries = self.writer_device.get_write_retries()
        write_retry_sleep_in_seconds = self.writer_device.get_write_retry_sleep_in_seconds()

        logger.info("Writing to device [{}]".format(device_name))
        logger.debug("Writing [{}] to device [{}]".format(data, device_name))

        error_messages = []

        for i in range(write_retries):
            connected = False
            try:
                self.writer_device.initialize()
                self.writer_device.connect()
                connected = True
                self.writer_device.write(data)
                return

            except Exception as ex:
                error_messages.append("Exception #[{}]: [{}]".format(i, repr(ex)))
                logger.warning("Error writing to device [{}]".format(device_name), exc_info=True)
                time.sleep(write_retry_sleep_in_seconds)

            finally:
                if connected:
                    self.writer_device.disconnect()

        raise FailedWritingToDevice("|".join(error_messages))
