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

""" The following platform framework is used to handle any differences between
    the platform's we support.  The GenericPlatform class is the base class
    that a supported platform extends from and overrides any of the methods
    as necessary.
"""

try:
    import os
    import sys
    import subprocess
    import pwd
    import grp

    sys.path.append(sys.path[0] + "/../../")
    from gspylib.common.ErrorCode import ErrorCode
    from gspylib.common.VersionInfo import VersionInfo
    from gspylib.os.gsplatform import g_Platform
    from gspylib.os.gsfile import g_file

    sys.path.append(sys.path[0] + "/../../../lib")
except Exception as ie:
    sys.exit("[GAUSS-52200] : Unable to import module: %s." % str(ie))


class PlatformCommand():
    """
    Command for os
    """

    def __init__(self):
        """
        function : init function
        input  : NA
        output : NA
        """
        return None

    @staticmethod
    def getDate():
        """
        function : Get current system time
        input : NA
        output: String
        """
        dateCmd = g_Platform.getDateCmd() + " -R "
        (status, output) = subprocess.getstatusoutput(dateCmd)
        # if cmd failed, then exit
        if status != 0:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % "date")
        return output

    @staticmethod
    def getAllCrontab():
        """
        function : Get the crontab
        input : NA
        output: status, output
        """
        cmd = g_Platform.getAllCrontabCmd()
        (status, output) = subprocess.getstatusoutput(cmd)
        if output.find("no crontab for") >= 0:
            output = ""
            status = 0
        # if cmd failed, then exit
        if status != 0:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % "crontab list" + " Error:%s." % output)
        return status, output

    @staticmethod
    def execCrontab(path):
        """
        function : Get the crontab
        input : string
        output: True or False
        """
        if not os.path.exists(path):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % path)
        filePath = os.path.dirname(path)
        fileName = os.path.basename(path)
        cmd = g_Platform.getCdCmd(filePath)
        cmd += " && "
        cmd += g_Platform.getCrontabCmd()
        cmd += (" ./%s" % fileName)
        cmd += " && %s" % g_Platform.getCdCmd("-")
        # if cmd failed, then exit
        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0:
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error:\n%s" % output)
        return True

    @staticmethod
    def source(path):
        """
        function : Get the source
        input : string
        output: True or False
        """
        cmd = g_Platform.getSourceCmd()
        cmd += " %s" % path
        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0:
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error:\n%s" % output)
        return True

    @staticmethod
    def getGrepValue(para="", value="", path=""):
        """
        function : grep value
        input : string,value,path
        output: status, output
        """
        if not os.path.exists(path):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % path)
        cmd = g_Platform.getGrepCmd() + " %s '%s' '%s'" % (para, value, path)
        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0:
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error:\n%s" % output)
        return status, output

    @staticmethod
    def getSysConfiguration():
        """
        function : The size range of PAGE_SIZE obtained by getconf
        input : NA
        output: string
        """
        configCmd = g_Platform.getGetConfValueCmd()
        (status, output) = subprocess.getstatusoutput(configCmd)
        # if cmd failed, then exit
        if status != 0:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50219"] % "system config pagesize")
        return output

    @staticmethod
    def getUserLimits(limitType):
        """
        function : Get current user process limits
        input : string
        output: string
        """
        limit = g_Platform.getUlimitCmd()
        limitCmd = "%s -a | %s -F '%s'" % (limit, g_Platform.getGrepCmd(), limitType)
        (status, output) = subprocess.getstatusoutput(limitCmd)
        # if cmd failed, then exit
        if status != 0:
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % limitCmd + " Error:\n%s" % output)
        return output

    @staticmethod
    def scpFile(ip, sourcePath, targetPath, copyTo=True):
        """
        function : if copyTo is True, scp files to remote host else, scp files to local host
        input : destination host ip
                source path
                target path
                copyTo
        output: NA
        """
        scpCmd = ""
        if os.path.isdir(sourcePath):
            scpCmd = g_Platform.getRemoteCopyCmd(sourcePath, targetPath, ip, copyTo, "directory")
        elif os.path.exists(sourcePath):
            scpCmd = g_Platform.getRemoteCopyCmd(sourcePath, targetPath, ip, copyTo)

        (status, output) = subprocess.getstatusoutput(scpCmd)
        # if cmd failed, then exit
        if status != 0:
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % scpCmd + " Error:\n%s" % output)

    @staticmethod
    def getSshCommand(ip, cmd):
        """
        function : Get ssh command
        input  : null
        output : exe_cmd
        """
        exe_cmd = "%s \"%s\"" % (g_Platform.getSshCmd(ip), cmd)
        return exe_cmd

    @staticmethod
    def getProcess(processKeywords):
        """
        function : Get process id by keywords
        input  : processKeywords
        output : processId
        """
        processId = []
        cmd = g_Platform.getProcessIdByKeyWordsCmd(processKeywords)
        (status, output) = subprocess.getstatusoutput(cmd)
        if status == 0 and str(output.strip()) != "":
            # kill process
            processId = output.strip().split("\n")
        return processId

    @staticmethod
    def getProcPidList(procName):
        """
        function : Get process id by procName
        input  : procName
        output : pidList
        """
        import psutil
        pidList = []
        for pid in psutil.pids():
            try:
                p = psutil.Process(pid)
                if procName == p.name():
                    pidList.append(pid)
            except psutil.NoSuchProcess:
                pass
        return pidList

    def killProcessByProcName(self, procName, killType=2):
        """
        function : Kill the process
        input : int
        output : boolean
        """
        try:
            pidList = self.getProcPidList(procName)
            for pid in pidList:
                os.kill(pid, killType)
            return True
        except Exception:
            return False

    @staticmethod
    def killProcessByPid(procPid, killType=2):
        """
        function : Kill the process
        input : int
        output : boolean
        """
        try:
            os.kill(procPid, killType)
            return True
        except Exception:
            return False

    @staticmethod
    def killallProcess(userName, procName, killType='2'):
        """
        function : Kill all processes by userName and procName.
        input : userName, procName
        output : boolean
        """
        cmd = "%s >/dev/null 2>&1" % g_Platform.getKillallProcessCmd(killType, userName, procName)
        status = os.system(cmd)
        if status != 0:
            return False
        return True

    @staticmethod
    def getUserInfo():
        """
        function : Get user information
        input  : null
        output : userInfo
        """
        userInfo = {"uid": os.getuid(), "name": pwd.getpwuid(os.getuid()).pw_name,
                    "gid": pwd.getpwuid(os.getuid()).pw_gid}
        userInfo["g_name"] = grp.getgrgid(userInfo["gid"]).gr_name

        return userInfo

    @staticmethod
    def getDeviceIoctls(devName):
        """
        function : Get device ioctls
        input  : devName   device name
        output : blockSize
        """
        blockSize = 0
        cmd = g_Platform.getBlockdevCmd(devName)
        (status, output) = subprocess.getstatusoutput(cmd)
        if status != 0:
            raise Exception(ErrorCode.GAUSS_504["GAUSS_50408"] % cmd + " Error: \n%s" % str(output))
        if output.isdigit() and str(output.strip()) != "":
            blockSize = int(output)
        return blockSize

    @staticmethod
    def getPathOwner(pathName):
        """
        function : Get the owner user of path.
        input : pathName
        output : user and group
        """
        user = ""
        group = ""
        # check path
        if not os.path.exists(pathName):
            return user, group
        # get use and group information
        try:
            user = pwd.getpwuid(os.stat(pathName).st_uid).pw_name
            group = grp.getgrgid(os.stat(pathName).st_gid).gr_name
            return user, group
        except Exception:
            return "", ""

    @staticmethod
    def getPackageFile(fileType="tarFile", jrePackage=False, check_exists=False):
        """
        function : Get the path of binary file version.
        input : NA
        output : String
        """
        file_name = g_Platform.getPackageFile(VersionInfo.getPackageVersion(),
                                              VersionInfo.PRODUCT_NAME_PACKAGE, fileType, jrePackage)

        if check_exists:
            if not os.path.exists(file_name):
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % file_name)
            if not os.path.isfile(file_name):
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50210"] % file_name)

        return file_name

    def getTarFilePath(self):
        """
        function : Get the path of binary file version.
        input : NA
        output : NA
        """
        return self.getPackageFile("tarFile", False, False)

    def getBinFilePath(self):
        """
        function : Get the path of binary file version..
        input : NA
        output : NA
        """
        return self.getPackageFile("binFile", False, True)

    def getSHA256FilePath(self):
        """
        function : Get the path of sha256 file version..
        input : NA
        output : NA
        """
        return self.getPackageFile("sha256File", False, True)

    def getJreBinFileName(self):
        """
        function : Get the jre bin file name
        input : NA
        output : NA
        """
        return os.path.basename(self.getPackageFile("binFile", True, False))

    def getJreSHA256FileName(self):
        """
        function : Get the jre sha256 file name
        input : NA
        output : NA
        """
        return os.path.basename(self.getPackageFile("sha256File", True, False))

    @staticmethod
    def getSHA256InfoByFilePath(binPath, sha256Path):
        """
        """
        try:
            fileSHA256 = g_file.getFileSHA256(binPath)
            valueList = g_file.readFile(sha256Path)
            if len(valueList) != 1:
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50204"] % sha256Path)
            sha256Value = valueList[0].strip()
            return fileSHA256, sha256Value
        except Exception as e:
            raise Exception(str(e))

    def getFileSHA256Info(self):
        """
        """
        try:
            binPath = self.getBinFilePath()
            sha256Path = self.getSHA256FilePath()
            (fileSHA256, sha256Value) = self.getSHA256InfoByFilePath(binPath, sha256Path)
            return fileSHA256, sha256Value
        except Exception as e:
            raise Exception(str(e))

    @staticmethod
    def getInplaceUpgradeSQLPath():
        """
        function : Get the path of binary file version.
        input : NA
        output : (String, String)
                 The absolute path of inplace_upgrade_sql.tar.gz
                 The absolute path of inplace_upgrade_sql.sha256
        """
        INPLACE_UPGRADE_SQL_GZ = "inplace_upgrade_sql.tar.gz"
        INPLACE_UPGRADE_SQL_SHA256 = "inplace_upgrade_sql.sha256"
        dirName = os.path.dirname(os.path.realpath(__file__))
        gzPath = os.path.join(dirName, "./../../../", INPLACE_UPGRADE_SQL_GZ)
        sha256Path = os.path.join(dirName, "./../../../", INPLACE_UPGRADE_SQL_SHA256)

        gzPath = os.path.normpath(gzPath)
        sha256Path = os.path.normpath(sha256Path)
        return gzPath, sha256Path

    @staticmethod
    def checkLink(filePath):
        """
        function:check if file is a link
        input: filePath
        output:NA
        """
        if os.path.exists(filePath):
            if os.path.islink(filePath):
                raise Exception(ErrorCode.GAUSS_502["GAUSS_50210"] % filePath)

    @staticmethod
    def getGroupByUser(user):
        """
        function : get group by user
        input : user
        output : group
        """
        try:
            group = grp.getgrgid(pwd.getpwnam(user).pw_gid).gr_name
        except Exception as e:
            raise Exception(ErrorCode.GAUSS_503["GAUSS_50300"] % user + "Detail msg: %s" % str(e))
        return group

    @staticmethod
    def getPortProcessInfo(port):
        """
        function : get port occupation process
        input : port
        output : process info
        """
        cmd = ""
        try:
            processInfo = ""
            cmd = "netstat -an | grep -w %s" % port
            (_, output) = subprocess.getstatusoutput(cmd)
            processInfo += "%s\n" % output
            return processInfo
        except Exception as e:
            raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error:\n%s" % str(e))


g_OSlib = PlatformCommand()
