"""
Created on 27 Sep 2018

@author: Bruno Beloff (bruno.beloff@southcoastscience.com)
"""

import time

from socket import gaierror

from AWSIoTPythonSDK.exception.operationTimeoutException import operationTimeoutException

from scs_analysis.handler.mqtt_reporter import MQTTReporter

from scs_core.aws.client.client_auth import ClientAuth
from scs_core.aws.client.mqtt_client import MQTTClient

from scs_core.comms.mqtt_conf import MQTTConf

from scs_core.data.queue_report import QueueReport, ClientStatus


# --------------------------------------------------------------------------------------------------------------------

class AWSMQTTPublisher(object):
    """
    classdocs
    """

    __CONNECT_TIME =                3.0         # seconds
    __CONNECT_RETRY_TIME =         10.0         # seconds


    # ----------------------------------------------------------------------------------------------------------------

    def __init__(self, conf: MQTTConf, auth: ClientAuth, client: MQTTClient, reporter: MQTTReporter):
        """
        Constructor
        """
        self.__conf = conf
        self.__auth = auth
        self.__client = client
        self.__reporter = reporter

        # report...
        client_state = ClientStatus.INHIBITED if conf.inhibit_publishing else ClientStatus.WAITING
        self.__status = QueueReport(0, client_state, False)
        self.__report()


    # ----------------------------------------------------------------------------------------------------------------

    def connect(self):
        if self.__conf.inhibit_publishing:
            return

        # report...
        self.__status.client_state = ClientStatus.CONNECTING
        self.__report()

        # connect...
        while True:
            try:
                if self.__client.connect(self.__auth, debug=self.__conf.debug):
                    break

                self.__reporter.print("connect: failed")
                time.sleep(self.__CONNECT_RETRY_TIME)
                continue

            except (OSError, gaierror) as ex:
                self.__reporter.print("connect: %s" % ex)
                time.sleep(self.__CONNECT_RETRY_TIME)
                continue

        time.sleep(self.__CONNECT_TIME)

        # report...
        self.__reporter.print("connect: done")
        self.__status.client_state = ClientStatus.CONNECTED
        self.__report()


    def disconnect(self):
        if self.__conf.inhibit_publishing:
            return

        # disconnect...
        self.__client.disconnect()

        # report...
        self.__reporter.print("disconnect: done")
        self.__status.client_state = ClientStatus.WAITING
        self.__report()


    def publish(self, publication):
        if self.__conf.inhibit_publishing:
            return

        # report...
        self.__status.length = 1                # indicate that document(s) have been presented for publication

        # publish...
        while True:
            try:
                start = time.time()
                reached_paho = self.__client.publish(publication)
                elapsed = time.time() - start

                self.__reporter.print("paho: %s: %0.3f" % ("1" if reached_paho else "0", elapsed))
                break

            except operationTimeoutException:
                # report...
                self.__status.publish_success = False
                self.__report()

        # report...
        self.__status.publish_success = True
        self.__report()


    # ----------------------------------------------------------------------------------------------------------------

    def __report(self):
        self.__status.save(self.__conf.report_file)


    # ----------------------------------------------------------------------------------------------------------------

    def __str__(self, *args, **kwargs):
        return "AWSMQTTPublisher:{conf:%s, auth:%s, client:%s, reporter:%s, report:%s}" % \
               (self.__conf, self.__auth, self.__client, self.__reporter, self.__status)
