#!/usr/bin/env python3
# -*- coding:utf-8 -*-
try:
    import os
    import sys
    import re
    import socket

    sys.path.append(sys.path[0] + "/../../../")

    from gspylib.os.platform import support_platform
except Exception as ie:
    sys.exit("[GAUSS-52200] : Unable to import module: %s." % str(ie))

CMD_CACHE = {}


class CommandNotFoundException(Exception):
    """
    """

    def __init__(self, cmd, paths):
        super().__init__()
        self.cmd = cmd
        self.paths = paths

    def __str__(self):
        return "Could not locate command: '%s' in this set of paths: %s" % (self.cmd, repr(self.paths))


def findCmdInPath(cmd, additionalPaths=None, printError=True):
    """
    """
    global CMD_CACHE
    if not additionalPaths:
        additionalPaths = []
    if cmd not in CMD_CACHE:
        # Search additional paths and don't add to cache.
        for p in additionalPaths:
            f = os.path.join(p, cmd)
            if os.path.exists(f):
                return f

        for p in support_platform.CMD_PATH:
            f = os.path.join(p, cmd)
            if os.path.exists(f):
                CMD_CACHE[cmd] = f
                return f

        if printError:
            print('Command %s not found' % cmd)
        search_path = support_platform.CMD_PATH[:]
        search_path.extend(additionalPaths)
        raise CommandNotFoundException(cmd, search_path)
    else:
        return CMD_CACHE[cmd]


class GenericPlatform(object):
    """
    manage OS command,config or service for muti-platform
    """

    def __init__(self):
        pass

    def echoCmdWithNoReturn(self, line, filePath):
        cmd = "echo %s >> '%s' 2>/dev/null" % (line, filePath)
        return cmd

    def getCreateFileCmd(self, path):
        cmd = "touch '%s'" % path
        return cmd

    def getMoveFileCmd(self, src, dest):
        cmd = "mv '%s' '%s'" % (src, dest)
        return cmd

    def get_machine_arch_cmd(self):
        return findCmdInPath('uname') + " -i"

    def getDefaultLocale(self):
        return 'en_US.utf-8'

    def getRemoveCmd(self, pathType):
        opts = " "
        if pathType == "file":
            opts = " -f "
        elif pathType == "directory":
            opts = " -rf "
        return findCmdInPath('rm') + opts

    def getChmodCmd(self, Permission, src, recursive=False):
        return findCmdInPath('chmod') + (" -R " if recursive else support_platform.BLANK_SPACE) + \
               Permission + support_platform.BLANK_SPACE + src

    def getChownCmd(self, owner, group, src, recursive=False):
        return findCmdInPath('chown') + (" -R " if recursive else support_platform.BLANK_SPACE) + \
               owner + support_platform.COLON + group + support_platform.BLANK_SPACE + src

    def getCopyCmd(self, src, dest, pathType=""):
        opts = " "
        if pathType == "directory":
            opts = " -r "
        return findCmdInPath('cp') + " -p  -f " + opts + support_platform.BLANK_SPACE + \
               "'" + src + "'" + support_platform.BLANK_SPACE + "'" + dest + "'"

    def isIpV6(self, ipAddress):
        Valid = re.match("^(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|"
                         "[1-9][0-9]|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|"
                         "[1-9][0-9]|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|"
                         "[1-9][0-9]|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|"
                         "[1-9][0-9]|[0-9])$", ipAddress)
        if Valid:
            if Valid.group() == ipAddress:
                return False
        if (str(ipAddress).find(':')) <= 0:
            return False
        rl = socket.getaddrinfo(ipAddress, None)
        if len(rl) == 0:
            return False
        elif socket.AF_INET6 == rl[0][0]:
            return True
        else:
            return False

    def getRemoteCopyCmd(self, src, dest, remoteHost, copyTo=True, pathType=""):
        opts = " "
        if pathType == "directory":
            opts = " -r "
        remoteHost = '[%s]' % remoteHost if self.isIpV6(remoteHost) else remoteHost
        if copyTo:
            return "export LD_LIBRARY_PATH=/lib64:$LD_LIBRARY_PATH; " + \
                findCmdInPath('scp') + opts + support_platform.BLANK_SPACE + src + \
                support_platform.BLANK_SPACE + remoteHost + support_platform.COLON + dest
        else:
            return "export LD_LIBRARY_PATH=/lib64:$LD_LIBRARY_PATH; " + \
                findCmdInPath('scp') + opts + support_platform.BLANK_SPACE + remoteHost + \
                support_platform.COLON + src + support_platform.BLANK_SPACE + dest

    def getScpCmd(self):
        """
        Get scp cmd for special remotely copy, just like remote to remote or remote to local.
        :return: str
        """
        return findCmdInPath('scp')

    def getUseraddCmd(self, user, group):
        return findCmdInPath('useradd') + " -m " + user + " -g " + group

    def getUserdelCmd(self, user):
        return findCmdInPath('userdel') + " -r " + user

    def getGroupaddCmd(self, group):
        return findCmdInPath('groupadd') + " " + group

    def getGroupdelCmd(self, group):
        return findCmdInPath('groupdel') + " " + group

    def getMoveCmd(self, src, dest):
        return findCmdInPath('mv') + " -f " + "'" + src + "'" + support_platform.BLANK_SPACE + "'" + dest + "'"

    def getMakeDirCmd(self, src, recursive=False):
        return findCmdInPath('mkdir') + (" -p " if recursive else support_platform.BLANK_SPACE) + "'" + src + "'"

    def getPingCmd(self, host, count, interval, packetSize=56):
        opts = " "
        if int(packetSize) != int(56):
            opts = " -s " + str(packetSize)

        from gspylib.os.gsnetwork import g_network
        if g_network.getHostProtoVersion(host) == 6:
            return findCmdInPath('ping6') + support_platform.BLANK_SPACE + host + " -c " + \
                   str(count) + " -i " + str(interval) + opts
        else:
            return findCmdInPath('ping') + support_platform.BLANK_SPACE + host + " -c " + \
                   str(count) + " -i " + str(interval) + opts

    def getWcCmd(self):
        return findCmdInPath('wc')

    def getTarCmd(self):
        return findCmdInPath('tar')

    def getZipCmd(self):
        return findCmdInPath('zip')

    def getUnzipCmd(self):
        return findCmdInPath('unzip')

    def getEchoCmd(self, echoString):
        cmdStr = '%s "%s"' % (findCmdInPath('echo'), echoString)
        return cmdStr

    def getSedCmd(self):
        return findCmdInPath('sed')

    def getGrepCmd(self):
        return findCmdInPath('grep')

    def getLsofCmd(self):
        return findCmdInPath('lsof') + " -i:"

    def getIfconfigCmd(self):
        return findCmdInPath('ifconfig')

    def get_route_cmd(self):
        return findCmdInPath("route")

    def getIpCmd(self):
        return findCmdInPath('ip')

    def getDateCmd(self):
        return findCmdInPath('date')

    def getAwkCmd(self):
        return findCmdInPath('awk')

    def getFindCmd(self):
        return findCmdInPath('find')

    def getTouchCmd(self, filename):
        return findCmdInPath('touch') + support_platform.BLANK_SPACE + filename

    def getListCmd(self):
        return findCmdInPath('ls')

    def getSHA256Cmd(self):
        return findCmdInPath('sha256sum')

    def getProcessCmd(self):
        return findCmdInPath('ps')

    def getCatCmd(self):
        return findCmdInPath('cat')

    def getDdCmd(self):
        return findCmdInPath('dd')

    def getCdCmd(self, path):
        return 'cd' + support_platform.BLANK_SPACE + "'" + path + "'"

    def getAllCrontabCmd(self):
        cmd = findCmdInPath('crontab') + support_platform.BLANK_SPACE + " -l"
        return cmd

    def getCrontabCmd(self):
        return findCmdInPath('crontab')

    def getKillProcessCmd(self, signal, pid):
        return findCmdInPath('kill') + " -" + signal + support_platform.BLANK_SPACE + pid

    def getKillallCmd(self):
        return findCmdInPath('killall')

    def getKillallProcessCmd(self, signal, username, procName=""):
        if procName != "":
            return findCmdInPath('killall') + " -s " + signal + " -u " + username + \
                   support_platform.BLANK_SPACE + procName
        else:
            return findCmdInPath('killall') + " -s " + signal + " -u " + username

    def getXargsCmd(self):
        return findCmdInPath('xargs')

    def getDeleteSemaphoreCmd(self, user):
        ipcs = findCmdInPath('ipcs')
        ipcrm = findCmdInPath('ipcrm')
        xargs = findCmdInPath('xargs')
        awk = findCmdInPath('awk')
        return "%s -s | %s '/ %s /{print $2}' | %s -n1 %s -s" % (ipcs, awk, user, xargs, ipcrm)

    def getProcessIdByKeyWordsCmd(self, keywords):
        ps = findCmdInPath('ps')
        grep = findCmdInPath('grep')
        awk = findCmdInPath('awk')
        return "%s -ef| %s -F -w '%s' | %s -F -v 'grep'| %s '{print $2}'" % (ps, grep, keywords, grep, awk)

    def getSysctlCmd(self):
        return findCmdInPath('sysctl')

    def getServiceCmd(self, serviceName, action):
        return findCmdInPath('service') + support_platform.BLANK_SPACE + serviceName + \
               support_platform.BLANK_SPACE + action

    def getSystemctlCmd(self, serviceName, action):
        return findCmdInPath('systemctl') + support_platform.BLANK_SPACE + action + \
               support_platform.BLANK_SPACE + serviceName

    def getUlimitCmd(self):
        return 'ulimit'

    def getGetConfValueCmd(self):
        return findCmdInPath('getconf') + " PAGESIZE "

    def getBlockdevCmd(self, device, value="", isSet=False):
        if (isSet and value != ""):
            return findCmdInPath('blockdev') + " --setra " + value + support_platform.BLANK_SPACE + device
        else:
            return findCmdInPath('blockdev') + " --getra " + device

    def getHostnameCmd(self):
        return findCmdInPath('hostname')

    def getSysModManagementCmd(self, OperType, module):
        """
        OperType: list     --list system module
              load     --load system module
              insert   --insert system module by force
              remove   --remove system module
              dep      --generate modules.dep and map files
        """
        if OperType == "list":
            return findCmdInPath('lsmod') + support_platform.BLANK_SPACE + module
        elif OperType == "load":
            return findCmdInPath('modprobe') + support_platform.BLANK_SPACE + module
        elif OperType == "insert":
            return findCmdInPath('insmod') + support_platform.BLANK_SPACE + module
        elif OperType == "remove":
            return findCmdInPath('rmmod') + support_platform.BLANK_SPACE + module
        elif OperType == "dep":
            return findCmdInPath('depmod') + support_platform.BLANK_SPACE + module
        else:
            return ""

    def getMountCmd(self):
        return findCmdInPath('mount')

    def getLocaleCmd(self):
        return findCmdInPath('locale')

    def getPasswordExpiresCmd(self, user):
        return findCmdInPath('chage') + " -l " + user

    def getIOStatCmd(self):
        return findCmdInPath('iostat') + " -xm 2 3 "

    def getEthtoolCmd(self):
        return findCmdInPath('ethtool')

    def getTailCmd(self):
        return findCmdInPath('tail')

    def getSshCmd(self, address):
        return "export LD_LIBRARY_PATH=/lib64:$LD_LIBRARY_PATH; " + \
            findCmdInPath('ssh') + support_platform.BLANK_SPACE + address + \
            " -n -o BatchMode=yes -o TCPKeepAlive=yes -o ServerAliveInterval=30 " \
            "-o ServerAliveCountMax=10 -o ConnectTimeout=30 -o ConnectionAttempts=10 "

    def getChkconfigCmd(self, OperType, service=""):
        if OperType == "list":
            return findCmdInPath('chkconfig') + " --list "
        elif OperType == "delete" and service:
            return findCmdInPath('chkconfig') + " --del " + service
        else:
            return ""

    def getNtpqCmd(self):
        return "/usr/sbin/ntpq -p "

    def getManageKerberosCmd(self, OperType):
        """
        OperType: init      --init kerberos
              destory   --destory kerberos
        """
        if OperType == "init":
            return "kinit -k -t "
        elif OperType == "destory":
            return 'kdestroy'
        else:
            return ""

    def getManageSSDCmd(self):
        pass

    def getPythonCmd(self):
        return findCmdInPath('python')

    def getShellCmd(self):
        return findCmdInPath('sh')

    def getSourceCmd(self):
        return 'source'

    def getTestCmd(self):
        """
        Linux test cmd
        example: test -f /etc/profile && echo 1 || echo 2
        """
        return findCmdInPath("test")

    def getPgrepCmd(self):
        """
        Linux pgrep cmd
        """
        return findCmdInPath("pgrep")

    def getExportCmd(self, key="", value=""):
        """
        Linux export cmd
        """
        cmd = findCmdInPath("export")
        if key:
            cmd += " %s=%s" % (key, value)
        return cmd
