# -*- coding: utf-8 -*-

"""
    Some utilities used by upgrade scripts
    XXX python2 XXX
"""


import glob
import os
import psycopg2
import sys
import traceback

SCODOC_DIR = os.environ.get("SCODOC_DIR", "/opt/scodoc")
SCODOC_VAR_DIR = os.environ.get("SCODOC_VAR_DIR", "/opt/scodoc-data")


def log(msg):
    "write msg on stderr, add newline and flush"
    sys.stdout.flush()
    sys.stderr.write(msg + "\n")
    sys.stderr.flush()


def get_dept_cnx_str(dept):
    "db cnx string for dept"
    f = os.path.join(SCODOC_VAR_DIR, "config", "depts", dept + ".cfg")
    try:
        return open(f).readline().strip()
    except:
        log("Error: can't read connexion string for dept %s" % dept)
        log("(tried to open %s)" % f)
        raise


def get_depts():
    "list of defined depts"
    files = glob.glob(SCODOC_VAR_DIR + "/config/depts/*.cfg")
    return [os.path.splitext(os.path.split(f)[1])[0] for f in files]


def field_exists(cnx, table, field):
    "true if field exists in sql table"
    cursor = cnx.cursor()
    cursor.execute(
        "SELECT column_name FROM information_schema.columns WHERE table_name = '%s'"
        % table
    )
    r = cursor.fetchall()
    fields = [f[0] for f in r]
    return field in fields


def list_constraint(cnx, constraint_name=""):
    "liste la contrainte (utile surtout pour savoir si elle existe)"
    cursor = cnx.cursor()
    cursor.execute(
        "SELECT * FROM information_schema.table_constraints WHERE constraint_name = %(constraint_name)s",
        {"constraint_name": constraint_name},
    )
    return cursor.fetchall()


def list_table_index(cnx, table):
    "liste les index associés à cette table"
    cursor = cnx.cursor()
    cursor.execute(
        """SELECT t.relname as table_name, i.relname as index_name, a.attname as column_name 
    FROM 
        pg_class t, pg_class i, pg_index ix, pg_attribute a 
    WHERE 
        t.oid = ix.indrelid and i.oid = ix.indexrelid and a.attrelid = t.oid 
        and a.attnum = ANY(ix.indkey) and t.relkind = 'r' 
        and t.relname = %(table)s;
    """,
        {"table": table},
    )
    r = cursor.fetchall()
    return [x[1] for x in r]  # ne garde que le nom de l'index


def _run_sql(sql, cnx):
    cursor = cnx.cursor()
    error = False
    try:
        for cmd in sql:
            log("executing SQL: %s" % cmd)
            cursor.execute(cmd)
            cnx.commit()
    except:
        cnx.rollback()
        log("check_field: failure. Aborting transaction.")
        error = True
        traceback.print_exc()
    return error


def check_field(cnx, table, field, sql_create_commands):
    "if field does not exists in table, run sql commands"
    if not field_exists(cnx, table, field):
        log("missing field %s in table %s: trying to create it" % (field, table))
        error = _run_sql(sql_create_commands, cnx)
        if not field_exists(cnx, table, field):
            log("check_field: new field still missing !")
            raise Exception("database configuration problem")
        elif error:
            log("\n\nAN UNEXPECTED ERROR OCCURRED WHILE UPGRADING DATABASE !\n\n")
        else:
            log("field %s added successfully." % field)


def table_exists(cnx, table):
    "true if SQL table exists"
    cursor = cnx.cursor()
    cursor.execute(
        "SELECT table_name FROM information_schema.tables where table_name='%s'" % table
    )
    r = cursor.fetchall()
    return len(r) > 0


def check_table(cnx, table, sql_create_commands):
    "if table does not exists in table, run sql commands"
    if not table_exists(cnx, table):
        log("missing table %s: trying to create it" % (table))
        error = _run_sql(sql_create_commands, cnx)
        if not table_exists(cnx, table):
            log("check_table: new table still missing !")
            raise Exception("database configuration problem")
        elif error:
            log("\n\nAN UNEXPECTED ERROR OCCURRED WHILE UPGRADING DATABASE !\n\n")
        else:
            log("table %s added successfully." % table)


def sequence_exists(cnx, seq_name):
    "true if SQL sequence exists"
    cursor = cnx.cursor()
    cursor.execute(
        """SELECT relname FROM pg_class
     WHERE relkind = 'S' and relname = '%s'
     AND relnamespace IN (
        SELECT oid FROM pg_namespace WHERE nspname NOT LIKE 'pg_%%' AND nspname != 'information_schema'
     );
    """
        % seq_name
    )
    r = cursor.fetchall()
    return len(r) > 0


def function_exists(cnx, func_name):
    "true if SQL function exists"
    cursor = cnx.cursor()
    cursor.execute(
        """SELECT routine_name FROM information_schema.routines
      WHERE specific_schema NOT IN ('pg_catalog', 'information_schema')
      AND type_udt_name != 'trigger' 
      AND routine_name = '%s';"""
        % func_name
    )
    r = cursor.fetchall()
    return len(r) > 0
