# datatasks\destinations\DatabaseDestination.py
import os
from datatasks.db.SQLBuilderMixin import SQLBuilderMixin
from datatasks.db.DatabaseFactory import DatabaseFactory
from datatasks import settings

from .FileDestination import FileDestination



class DatabaseDestination(FileDestination, SQLBuilderMixin):
    """Capable of writing records to a database table.  Inherits from FileDestination."""

    def __init__(self, name, db_name, tablename_str, **kwargs):
        self.filepath_str = '{}{}.csv'.format(settings.SHARE_PATH, name)
        super().__init__(name, self.filepath_str, write_headers=False, **kwargs)
        self._db = DatabaseFactory().get_db(db_name)
        self.tablename_str = tablename_str
        self.sql_table_exists = False
        self.set_columns()

    def set_columns(self):
        """
        Querys the database table for the column names and sets the key_list of the instance.
        If table does not exist key list nothing is set.
        """
        super(DatabaseDestination, self).set_keys(self._db.get_column_list(self.tablename_str))
        if self._key_list != []:
            self.sql_table_exists = True
        else:
            self.set_keys(self.source.keys)

    def write_out(self):
        """
        Writes records to the database table.  Records are first printed to a file
        (preferrably a share on the machine where the database is running).  Then a bulk
        insert command is used based on the db_platform attribute set during instantiation.
        """
        if self.sql_table_exists:
            sql_str = 'delete from {};'.format(self.tablename_str)
        else:
            sql_str = self.build_create_table_sql()
        self._db.execute_command(sql_str)
        self.truncate_fields()
        self._db.insert_into(self.tablename_str, self.source)

    def truncate_fields(self):
        """
        Truncates fields to prepare for an auto-assigned varchar(x) datatype that may
        cause database loads to fail.
        """
        if self.sql_table_exists:
            return
        if hasattr(self, 'sql_datatype_map') is False:
            raise Exception('attribute sql_datatype_map is required to be set on this instance')
        for col, datatype in self.sql_datatype_map.items():
            if datatype[:7] == 'varchar':
                max_length = int(datatype.split('(')[1].replace(')', ''))
                for record in self.source:
                    if isinstance(record[col], str):
                        record[col] = record[col][:max_length]
