# Path: thingsboard_gateway/storage/event_storage.py
# class EventStorage(ABC):
# 
#     @abstractmethod
#     def put(self, event):
#         pass
# 
#     @abstractmethod
#     def get_event_pack(self):
#         # Returns max "10" events from pack
#         pass
# 
#     @abstractmethod
#     def event_pack_processing_done(self):
#         # Indicates that events from previous "get_event_pack" may be cleared
#         pass
# 
#     @abstractmethod
#     def stop(self):
#         # Stop the storage processing
#         pass
# 
# Path: thingsboard_gateway/storage/sqlite/database.py
# class Database(Thread):
#     """
#         What this component does:
#         - abstracts creating tables for devices.
#         - writes to database
#         - reads from database
#         - delete data older than specified in config
#         ------------- ALL OF THIS IN AN ATOMIC WAY ---------
#     """
# 
#     def __init__(self, config, processing_queue: Queue):
#         super().__init__()
#         self.setDaemon(True)
#         self.settings = StorageSettings(config)
# 
#         if not exists(self.settings.data_folder_path):
#             with open(self.settings.data_folder_path, 'w'):
#                 pass
# 
#         # Pass settings to connector
#         self.db = DatabaseConnector(self.settings)
# 
#         self.db.connect()
# 
#         # process Queue
#         self.processQueue = processing_queue
# 
#         self.__stopped = False
# 
#         self.__last_msg_check = time()
# 
#         self.msg_counter = 0
#         self.start()
# 
#     def init_table(self):
#         try:
#             self.db.execute('''CREATE TABLE IF NOT EXISTS messages (timestamp INTEGER, message TEXT); ''')
#             self.db.commit()
#         except Exception as e:
#             self.db.rollback()
#             log.exception(e)
# 
#     def run(self):
#         while True:
#             self.process()
# 
#             sleep(.2)
# 
#     def process(self):
#         try:
#             if time() - self.__last_msg_check >= self.settings.messages_ttl_check_in_hours:
#                 self.__last_msg_check = time()
#                 self.delete_data_lte(self.settings.messages_ttl_in_days)
# 
#             # Signalization so that we can spam call process()
#             if not self.__stopped and self.processQueue:
#                 while self.processQueue.qsize() > 0:
# 
#                     req = self.processQueue.get()
# 
#                     log.debug("Processing %s" % req.type)
#                     if req.type is DatabaseActionType.WRITE_DATA_STORAGE:
# 
#                         message = req.data
# 
#                         timestamp = time()
# 
#                         self.db.execute('''INSERT INTO messages (timestamp, message) VALUES (?, ?);''',
#                                         [timestamp, message])
# 
#                         self.db.commit()
#             else:
#                 log.error("Storage is closed!")
# 
#         except Exception as e:
#             self.db.rollback()
#             log.exception(e)
# 
#     def read_data(self, ts):
#         try:
#             data = self.db.execute('''SELECT message FROM messages WHERE timestamp >= ? ;''', [ts])
#             return data
#         except Exception as e:
#             self.db.rollback()
#             log.exception(e)
# 
#     def delete_data(self, ts):
#         try:
#             data = self.db.execute('''DELETE FROM messages WHERE timestamp >= ? ;''', [ts])
#             return data
#         except Exception as e:
#             self.db.rollback()
#             log.exception(e)
# 
#     def delete_data_lte(self, days):
#         try:
#             ts = (datetime.datetime.now() - datetime.timedelta(days=days)).timestamp()
#             data = self.db.execute('''DELETE FROM messages WHERE timestamp <= ? ;''', [ts])
#             return data
#         except Exception as e:
#             self.db.rollback()
#             log.exception(e)
# 
#     def setProcessQueue(self, process_queue):
#         self.processQueue = process_queue
# 
#     def closeDB(self):
#         self.db.close()
# 
# Path: thingsboard_gateway/storage/sqlite/database_request.py
# class DatabaseRequest:
#     # Wrap data and write intention to better control
#     # Writes. They need to be atomic so we don't corrupt DB
#     def __init__(self, _type: DatabaseActionType, data):
#         self.type = _type
#         self.data = data
# 
# Path: thingsboard_gateway/storage/sqlite/database_action_type.py
# class DatabaseActionType(Enum):
#     WRITE_DATA_STORAGE = auto()  # Writes do not require a response on the request


from time import time
from thingsboard_gateway.storage.event_storage import EventStorage
from thingsboard_gateway.storage.sqlite.database import Database
from queue import Queue
from thingsboard_gateway.storage.sqlite.database_request import DatabaseRequest
from thingsboard_gateway.storage.sqlite.database_action_type import DatabaseActionType
from logging import getLogger
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.


#
#   No need to import DatabaseResponse, responses come to this component to be deconstructed
#

log = getLogger("storage")


class SQLiteEventStorage(EventStorage):
    """
    HIGH level api for thingsboard_gateway main loop
    """

    def __init__(self, config):
        log.info("Sqlite Storage initializing...")
        log.info("Initializing read and process queues")
        self.processQueue = Queue(-1)

# Path: thingsboard_gateway/storage/event_storage.py
# class EventStorage(ABC):
# 
#     @abstractmethod
#     def put(self, event):
#         pass
# 
#     @abstractmethod
#     def get_event_pack(self):
#         # Returns max "10" events from pack
#         pass
# 
#     @abstractmethod
#     def event_pack_processing_done(self):
#         # Indicates that events from previous "get_event_pack" may be cleared
#         pass
# 
#     @abstractmethod
#     def stop(self):
#         # Stop the storage processing
#         pass
# 
# Path: thingsboard_gateway/storage/sqlite/database.py
# class Database(Thread):
#     """
#         What this component does:
#         - abstracts creating tables for devices.
#         - writes to database
#         - reads from database
#         - delete data older than specified in config
#         ------------- ALL OF THIS IN AN ATOMIC WAY ---------
#     """
# 
#     def __init__(self, config, processing_queue: Queue):
#         super().__init__()
#         self.setDaemon(True)
#         self.settings = StorageSettings(config)
# 
#         if not exists(self.settings.data_folder_path):
#             with open(self.settings.data_folder_path, 'w'):
#                 pass
# 
#         # Pass settings to connector
#         self.db = DatabaseConnector(self.settings)
# 
#         self.db.connect()
# 
#         # process Queue
#         self.processQueue = processing_queue
# 
#         self.__stopped = False
# 
#         self.__last_msg_check = time()
# 
#         self.msg_counter = 0
#         self.start()
# 
#     def init_table(self):
#         try:
#             self.db.execute('''CREATE TABLE IF NOT EXISTS messages (timestamp INTEGER, message TEXT); ''')
#             self.db.commit()
#         except Exception as e:
#             self.db.rollback()
#             log.exception(e)
# 
#     def run(self):
#         while True:
#             self.process()
# 
#             sleep(.2)
# 
#     def process(self):
#         try:
#             if time() - self.__last_msg_check >= self.settings.messages_ttl_check_in_hours:
#                 self.__last_msg_check = time()
#                 self.delete_data_lte(self.settings.messages_ttl_in_days)
# 
#             # Signalization so that we can spam call process()
#             if not self.__stopped and self.processQueue:
#                 while self.processQueue.qsize() > 0:
# 
#                     req = self.processQueue.get()
# 
#                     log.debug("Processing %s" % req.type)
#                     if req.type is DatabaseActionType.WRITE_DATA_STORAGE:
# 
#                         message = req.data
# 
#                         timestamp = time()
# 
#                         self.db.execute('''INSERT INTO messages (timestamp, message) VALUES (?, ?);''',
#                                         [timestamp, message])
# 
#                         self.db.commit()
#             else:
#                 log.error("Storage is closed!")
# 
#         except Exception as e:
#             self.db.rollback()
#             log.exception(e)
# 
#     def read_data(self, ts):
#         try:
#             data = self.db.execute('''SELECT message FROM messages WHERE timestamp >= ? ;''', [ts])
#             return data
#         except Exception as e:
#             self.db.rollback()
#             log.exception(e)
# 
#     def delete_data(self, ts):
#         try:
#             data = self.db.execute('''DELETE FROM messages WHERE timestamp >= ? ;''', [ts])
#             return data
#         except Exception as e:
#             self.db.rollback()
#             log.exception(e)
# 
#     def delete_data_lte(self, days):
#         try:
#             ts = (datetime.datetime.now() - datetime.timedelta(days=days)).timestamp()
#             data = self.db.execute('''DELETE FROM messages WHERE timestamp <= ? ;''', [ts])
#             return data
#         except Exception as e:
#             self.db.rollback()
#             log.exception(e)
# 
#     def setProcessQueue(self, process_queue):
#         self.processQueue = process_queue
# 
#     def closeDB(self):
#         self.db.close()
# 
# Path: thingsboard_gateway/storage/sqlite/database_request.py
# class DatabaseRequest:
#     # Wrap data and write intention to better control
#     # Writes. They need to be atomic so we don't corrupt DB
#     def __init__(self, _type: DatabaseActionType, data):
#         self.type = _type
#         self.data = data
# 
# Path: thingsboard_gateway/storage/sqlite/database_action_type.py
# class DatabaseActionType(Enum):
#     WRITE_DATA_STORAGE = auto()  # Writes do not require a response on the request


# Path: thingsboard_gateway/storage/sqlite/sqlite_event_storage.py
from time import time
from thingsboard_gateway.storage.event_storage import EventStorage
from thingsboard_gateway.storage.sqlite.database import Database
from queue import Queue
from thingsboard_gateway.storage.sqlite.database_request import DatabaseRequest
from thingsboard_gateway.storage.sqlite.database_action_type import DatabaseActionType
from logging import getLogger

#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.


#
#   No need to import DatabaseResponse, responses come to this component to be deconstructed
#

log = getLogger("storage")


class SQLiteEventStorage(EventStorage):
    """
    HIGH level api for thingsboard_gateway main loop
    """

    def __init__(self, config):
        log.info("Sqlite Storage initializing...")
        log.info("Initializing read and process queues")
        self.processQueue = Queue(-1)

        self.db = Database(config, self.processQueue)