from tlib.base.ExceptionHelper import TLibException
import cx_Oracle


class ConnectionError(TLibException):
    def __init__(self, err_code, err_description):
        self.code, self.description = err_code, err_description
    def __str__(self):
        return 'Connection to DB FAILURE with error(/code: description/) /%d: %s/' % (self.code, self.description)


class AutoCommitError(TLibException):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return "Wrong argument '%s' passed in <get_autocommit_status> function. Valid args are str: 'local', 'global' or 'session'." % self.value


class QueryError(TLibException):
    def __init__(self, err_code, err_description):
        self.code, self.description = err_code, err_description
    def __str__(self):
        return 'query function FAILURE with error(/code: description/) /%d: %s/ %d: %s' % (self.code, self.description)


class ExecuteError(TLibException):
    def __init__(self, err_code, err_description):
        self.code, self.description = err_code, err_description
    def __str__(self):
        return 'execute function FAILURE with error (/code: description/) /%d: %s/' % (self.code, self.description)


class OracleConnector(object):
    """
    Connects to MySQL DB, executes queries
    Autocommit is disabled by default, commit is done with commit function
    Warnings are turned into exceptions
    """
    def __init__(self, sid, username=None, password=None, host=None, port=None):
        """
        Initialize DB connection. Turning warning into exceptions
        """
        self.db = None
        try:
            dsn_tns = sid
            if host:
                dsn_tns = cx_Oracle.makedsn(host, port, sid)
            self.db = cx_Oracle.connect(user=username, password=password, dsn=dsn_tns)
            self.cursor = self.db.cursor()
            self.db.autocommit = 0   # in case of autocommit will change by default to ON in future
        except cx_Oracle.Error, err:
            raise ConnectionError(err.args[0], err.args[1])


    def get_autocommit_status(self):
        """
        returns tuple Autocommit status i.e. 1 for True and 0 for False
        """
        return self.db.autocommit


    def query_select(self, query):
        """
        Send/execute SELECT queries, returns data from DB
        :param: str MySQL query
        :return: tuple with arguments dictionaries, each dictionary is a row of DB i.e. ({row_first}, {row_second}, ... ,{row_last})
        """
        try:
            self.cursor.execute(query)
            return self.cursor.fetchall()
        except cx_Oracle.Error, err:
            raise QueryError(err.args[0], err.args[1])

    def query_execute(self, query):
        """
        Sends query to DB. Can be DELETE, UPDATE
        :param: str query
        :return: dict {DictCursor}
        """
        try:
            self.cursor.execute(query)
            return self.cursor
        except cx_Oracle.Error, err:
            raise ExecuteError(err.args[0], err.args[1])

    def commit(self):
        """
        Commits all changes, returns Exception in case of failure
        """
        self.db.commit()

    def rollback(self):
        """
        Rolls back all commits, returns exception in case of failure
        """
        self.db.rollback()

    def close_cursor(self):
        """
        Close cursor. Connection to DB is still open, new cursor can be created
        """
        self.cursor.close()

    def close_db(self):
        """
        Close DB connection. All uncommitted changes are lost
        """
        self.db.close()

    def __del__(self):
        self.cursor.close()
        self.db.close()

