
## Import python standard libraries
import os
import pathlib
import sqlite3
import sys

## LOGGER imports
import logging
from logging.handlers import RotatingFileHandler
import traceback

## Disable caching
sys.dont_write_bytecode = True

## Set paths
DIRECTORY, FILENAME = os.path.split(os.path.abspath(__file__))
WORKING_DIRECTORY_PATH = str(pathlib.PurePath(DIRECTORY).parents[0])

## LOGGING SECTION
LOGGER = logging.getLogger("IoTClient Log")
LOGGER.setLevel(logging.DEBUG)
HANDLER = RotatingFileHandler(WORKING_DIRECTORY_PATH + os.sep + "    IotClient_Error.log", maxBytes = 1024*100, backupCount = 2)
FORMATTER = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
HANDLER.setFormatter(FORMATTER)
LOGGER.addHandler(HANDLER)

class ThingPushManager():
    """Interface for inteprocesscommunication over database"""
    def __init__(self, db_path):
        """Initialization of the thing push manager class
        **Syntax**
        import ThingPush - use always module name
        *Global*
        THING_PUSH = ThingPush.ThingPushManager("../..")
        *Class instance*
        self._thing_push = ThingPush.ThingPushManager("../..")
        **Parameters**
        *db_path* - String that denotes the path for pushing information to InternetDriver
        **Returns**
        ThingPushManager object"""
        self._db_name = db_path + os.sep + "ThingToInternet.db"
        self._db_connection = sqlite3.connect(self._db_name, check_same_thread=False)
        self._tbl_name = None
        self._query = None
        self._result = None

    def insert_command(self, command, payload, timestamp):
        """Methode for inserting commands into database for the InternetDriver
        **Syntax**
        *Global*
        THING_PUSH.insert_command("ALARM", '{"ID": "DP0",.....}', "2017-01-01 00:00:00.0000")
        *Class instance*
        self._thing_push.insert_command("ALARM", '{"ID": "DP0",.....}', "2017-01-01 00:00:00.0000")
        **Parameters**
        *command* - String that denotes which command should be pushed to the InternetDriver
        *payload* - JSON formatted string with parameters to the corresponding command
        *timestamp* - utc timestamp
        **Returns**
        Result from the insert into database operation"""
        self._result = None
        self._tbl_name = "commands"
        self._query = 'INSERT INTO {} (COMMAND, PAYLOAD, TIMESTAMP) ' \
                      'VALUES (?, ?, ?)'.format(self._tbl_name)
        try:
            with self._db_connection:
                self._result = self._db_connection.execute(self._query, (command, payload, timestamp, ))
        except Exception as ex:
            LOGGER.error(str(ex))
            LOGGER.error(traceback.format_exc())
            print (str(ex))
            print (traceback.format_exc())

        return self._result

    def insert_data(self, payload, timestamp):
        """Methode for inserting data into database for the InternetDriver
        **Syntax**
        *Global*
        THING_PUSH.insert_data('{"ID": "DP0",.....}', "2017-01-01 00:00:00.0000")
        *Class instance*
        self._thing_push.insert_data('{"ID": "DP0",.....}', "2017-01-01 00:00:00.0000")
        **Parameters**
        *payload* - JSON formatted string with parameters to the corresponding data
        *timestamp* - utc timestamp
        **Returns**
        Result from the insert into database operation"""
        self._result = None
        self._tbl_name = "data"
        self._query = 'INSERT INTO {} (PAYLOAD, TIMESTAMP) VALUES (?, ?)'.format(self._tbl_name)
        try:
            with self._db_connection:
                self._result = self._db_connection.execute(self._query, (payload, timestamp, ))
        except Exception as ex:
            LOGGER.error(str(ex))
            LOGGER.error(traceback.format_exc())
            print (str(ex))
            print (traceback.format_exc())

        return self._result

    def insert_undefined_data(self, bootcounter, timeoffset, payload):
        """Methode for inserting undefined data into database for the InternetDriver
        **Syntax**
        *Global*
        THING_PUSH.insert_undefined_data(1, 10, '{"ID": "DP0",.....}')
        *Class instance*
        self._thing_push.insert_undefined_data(1, 10, '{"ID": "DP0",.....}')
        **Parameters**
        *bootcounter* - Integer which denotes the boot start without valid timestamp
        *timeoffset* - Integer which denotes the offset to thing start
        *payload* - JSON formatted string with parameters to the corresponding data
        **Returns**
        Result from the insert into database operation"""
        self._result = None
        self._tbl_name = "undefineddata"
        self._query = 'INSERT INTO {} (BOOTCOUNTER, TIMEOFFSET, PAYLOAD) ' \
                      'VALUES (?, ?, ?)'.format(self._tbl_name)
        try:
            with self._db_connection:
                self._result = self._db_connection.execute(self._query,
                                                           (bootcounter, timeoffset, payload, ))
        except Exception as ex:
            LOGGER.error(str(ex))
            LOGGER.error(traceback.format_exc())
            print (str(ex))
            print (traceback.format_exc())

        return self._result

    def get_max_boot_counter(self):
        """Methode for retrieving the maximal bootcounter
        **Syntax**
        *Global*
        THING_PUSH.get_max_boot_counter()
        *Class instance*
        self._thing_push.get_max_boot_counter()
        **Parameters**
        None
        **Returns**
        Result the maximal value of the bootcounter if no data returns zero"""
        self._result = None
        self._tbl_name = "undefineddata"
        self._query = 'SELECT IFNULL(MAX(BOOTCOUNTER),0) FROM {}'.format(self._tbl_name)
        try:
            with self._db_connection:
                self._result = self._db_connection.execute(self._query).fetchone()
        except Exception as ex:
            LOGGER.error(str(ex))
            LOGGER.error(traceback.format_exc())
            print (str(ex))
            print (traceback.format_exc())

        return self._result[0]

    def __del__(self):
        """Destructor of the thing push manager object
        **Syntax**
        None
        **Parameters**
        None
        **Returns**
        None"""
        try:
            self._db_connection.close()
        except Exception as ex:
            LOGGER.error(str(ex))
            LOGGER.error(traceback.format_exc())
            print (str(ex))
            print (traceback.format_exc())
