import os
import sys
import psycopg2
import unittest
import logging
from pprint import pprint

from ConfigParser import RawConfigParser

LOG = logging.getLogger()
LOG_handler = logging.StreamHandler()
LOG_formatter = logging.Formatter(fmt='%(asctime)s [%(funcName)s:%(lineno)03d] %(levelname)-5s: %(message)s',
                                  datefmt='%m-%d-%Y %H:%M:%S')
LOG_handler.setFormatter(LOG_formatter)
LOG.addHandler(LOG_handler)
LOG.setLevel(logging.INFO)

DB_ORACLE = "oracle"
DB_TARGET = "target"


class BaseTest(unittest.TestCase):
    """Base test case code that will connect to the oracle and target database"""

    def __init__(self, test_name, config_path, base_name):
        unittest.TestCase.__init__(self, test_name)
        self.tableCtr = 0
        self.initConnections = False

        # Basename for all tables in this test
        self.baseName = base_name.lower()

        # Load in configuration file
        LOG.info("Loading config file '%s'" % config_path)
        self.config = RawConfigParser()
        self.config.read(config_path)

    ## DEF

    def nextTableName(self):
        name = "%s_%02d" % (self.baseName, self.tableCtr)
        self.tableCtr += 1
        return name

    ## DEF

    def createConnections(self):
        # Initialize database connections
        for db in [DB_ORACLE, DB_TARGET]:
            try:
                self.__dict__[db] = psycopg2.connect(
                    host=self.config.get(db, 'db_host'),
                    port=self.config.get(db, 'db_port'),
                    database=self.config.get(db, 'db_name'),
                    user=self.config.get(db, 'db_user'),
                    password=self.config.get(db, 'db_pass'),
                )
            except:
                LOG.error("Unable to connect to %s database" % db.upper())
                raise
            assert (not self.__dict__[db] is None)
            LOG.debug("Connected to %s database" % db.upper())
            ## FOR

    ## DEF

    def closeConnections(self):
        for db in [DB_ORACLE, DB_TARGET]:
            if self.__dict__[db] is not None:
                self.__dict__[db].close()
                ## FOR

    ## DEF

    def getConnections(self):
        return self.__dict__[DB_ORACLE], self.__dict__[DB_TARGET]

    def getTargetConn(self):
        return self.__dict__[DB_TARGET]

    def getOracleConn(self):
        return self.__dict__[DB_ORACLE]

    def getTestTables(self, conn):
        with conn.cursor() as cursor:
            cursor.execute("""
                SELECT table_name FROM information_schema.tables
                 WHERE table_name LIKE %s
                   AND table_catalog !~ '^(pg_|sql_)'
                """, (self.baseName + '_%',))
            result = [x[0] for x in cursor.fetchall()]
        return result

    ## DEF

    def dropTables(self):
        for db in [DB_ORACLE, DB_TARGET]:
            conn = self.__dict__[db]
            LOG.debug("Dropping %s.%s tables" % (db, self.baseName))
            for tableName in self.getTestTables(conn):
                # Use a separate cursor per table in case one of tests creates a lot of tables
                # Otherwise we may run out of locks in the DBMS
                with conn.cursor() as cursor:
                    sql = "DROP TABLE IF EXISTS %s" % tableName
                    LOG.debug("EXEC[%s]: %s" % (db, sql))
                    cursor.execute(sql)
                LOG.debug("Flushing drop tables for %s" % db)
                conn.commit()
                ## WITH

    ## DEF

    def setUp(self):
        # First initialization the connections before we do anything
        self.createConnections()

        # Then clear out any tables that may lingering from the last time we ran this
        self.dropTables()
        pass

    ## DEF

    def tearDown(self):
        self.closeConnections()
        pass
        ## DEF

        ## CLASS
