#!/usr/bin/env python3
# -*- coding:utf-8 -*-

try:
    import sys
    import importlib

    importlib.reload(sys)
    import os
    import subprocess
    from gspylib.inspection.common import SharedFuncs
    from gspylib.inspection.common.CheckItem import BaseItem
    from gspylib.inspection.common.CheckResult import ResultStatus
    from gspylib.os.gsfile import g_file
except ImportError as e:
    raise Exception("[GAUSS-52200] : Unable to import module: %s." % str(e))

SHELLPATH = os.path.realpath(os.path.join(os.path.split(os.path.realpath(__file__))[0], "../../lib/checkblacklist/"))

# file permission
FILE_MODE = 755

# the special string
specailStr = "Blacklist Check for DataBase"
# the constant string
itemStr = "checkitem                           | result | expected | status  |         failed_process_script"
sepStr = "---------------------------------------------------------------+--------+----------+---------+---------" \
         "-------------------------------"


class CheckBlackList(BaseItem):
    def __init__(self):
        super(CheckBlackList, self).__init__(self.__class__.__name__)

    def checkFilePermission(self, filename):
        """
        Function : check file: 1.exist 2. isfile 3. permission
        Note     : 1.You must check that the file exist and is a file.
                   2.You can choose whether to check the file's permission:executable.
        """
        if (not os.path.exists(filename)):
            raise Exception("The file %s does not exist." % filename)
        if (not os.path.isfile(filename)):
            raise Exception("%s is not file." % filename)
        if (not os.access(filename, os.X_OK)):
            g_file.changeMode(FILE_MODE, filename)

    def analyzeStr(self, tempstr):
        """
        Function : Parse the string
        Note     : Find "FAILED" from the specified string
        """
        tempLine = []
        tempBuf = ""
        sqlList = []
        result = True
        lastdatabase = ""
        for line in tempstr.split("\n"):
            line = line.strip()
            if line.find("Blacklist Check for DataBase") >= 0:
                tempLine.append(line)
                lastdatabase = line.split(':')[1].replace('*', '').strip()
            if line.find("FAILED") >= 0:
                tempLine.append(line)
                sqlname = line.split('|')[4].strip()
                sqlList.append((lastdatabase, sqlname))
                result = False

        if len(tempLine) != 0:
            for content in tempLine:
                content = "%s\n" % content
                tempBuf = "%s%s" % (tempBuf, content)
        return result, tempBuf, sqlList

    def execSqlFile(self, sqlFile, database='postgres'):
        cmd = "gsql -p %s -d %s -f %s" % (self.port, database, sqlFile)
        return SharedFuncs.runShellCmd(cmd, self.user, self.mpprcFile)

    def doCheck(self):
        # check database connection
        sqlcmd = "select pg_catalog.pg_sleep(1);"
        cmd = "gsql -m -d postgres -p %s -c '%s'" % (self.port, sqlcmd)
        if not self.mpprcFile:
            cmd = "source '%s' && %s" % (self.mpprcFile, cmd)
        if os.getuid() == 0:
            cmd = "su - %s -c \"%s\" " % (self.user, cmd)
        self.result.raw = cmd
        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0 or output.find("connect to server failed") > 0:
            self.result.rst = ResultStatus.NG
            self.result.val = "The database can not be connected."
            self.result.raw += "\nError: %s" % output
            return
        # shell name
        prepareShell = "DBCheck.sh"
        queryShell = "ExecuteSQLOnAllDB.sh"
        sqlFile = "blacklist_check.sql"
        # the path of script
        prepareShellName = os.path.join(SHELLPATH, prepareShell)
        # judge permission
        self.checkFilePermission(prepareShellName)
        queryShellName = os.path.join(SHELLPATH, queryShell)
        sqlFileName = os.path.join(SHELLPATH, sqlFile)
        # judge permission
        self.checkFilePermission(queryShellName)

        # Change mpprc info
        if not self.mpprcFile:
            raise Exception("No environment variables were set.")
        mpprcPath = self.mpprcFile.replace('/', '\/')
        g_file.replaceFileLineContent("source.*", "source\ %s" % mpprcPath, prepareShellName)
        # 1. prepare something
        exectueCmd1 = "cd %s && sh %s -p %d" % (SHELLPATH, prepareShellName, self.port)
        # Call the shell script
        output1 = SharedFuncs.runShellCmd(exectueCmd1, self.user, self.mpprcFile)

        # 2. query shell command
        exectueCmd2 = "cd %s && sh %s -f %s -p %d" % (SHELLPATH, queryShellName, sqlFileName, self.port)
        # Call the shell script
        output2 = SharedFuncs.runShellCmd(exectueCmd2, self.user, self.mpprcFile)
        # save the execution result
        self.result.raw = "Output of the first shell command:\n'%s'\n Output of the second shell command:\n'%s'" % (
            output1, output2)

        (results, content, sql_list) = self.analyzeStr(self.result.raw)
        if results:
            # The two scripts were executed successfully and there was no "FAILED" in the result---OK
            self.result.rst = ResultStatus.OK
            self.result.val = "Check the results successfully!"
        else:
            # The two scripts were executed successfully and there have "FAILED" in the result---NG
            self.result.rst = ResultStatus.NG
            tempContent = itemStr + "\n" + sepStr + "\n"

            sql_output_list = []
            if sql_list:
                for database, sql in sql_list:
                    if not sql:
                        continue
                    if not database:
                        database = ""
                    sql_out = self.execSqlFile(os.path.join(SHELLPATH, sql.strip()), database)
                    sql_output_list.append("\nrun sql %s on %s for more detail:\n%s" % (sql, database, sql_out))
            sql_out_put = "".join(sql_output_list)
            self.result.val = tempContent + content + sql_out_put
