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

    sys.path.append(sys.path[0] + "/../../")
    from gspylib.common.ErrorCode import ErrorCode
    from gspylib.common.Common import DefaultValue
    from gspylib.os.gsfile import g_file
    from gspylib.os.gsOSlib import g_OSlib
    from gspylib.os.gsnetwork import g_network
except ImportError as ie:
    sys.exit("[GAUSS-52200] : Unable to import module: %s." % str(ie))

TIME_OUT = 2
RETRY_TIMES = 100


class BaseComponent(object):
    '''
    The class is used to define base component.
    '''

    def __init__(self):
        '''
        function: initialize the parameters
        input : NA
        output: NA
        '''
        self.logger = None
        self.instInfo = None
        self.version = ""
        self.pkgName = ""
        self.initParas = {}
        self.binPath = ""
        self.dwsMode = False
        self.level = 1
        self.clusterType = DefaultValue.CLUSTER_TYPE_MASTER_STANDBY

    def install(self):
        pass

    def setGucConfig(self, setMode='set', paraDict=None):
        pass

    def setPghbaConfig(self, clusterAllIpList):
        pass

    def start(self):
        pass

    def stop(self):
        pass

    def uninstall(self):
        pass

    def killProcess(self, signaltype, pidList):
        """
        function: kill process
        input:  process flag
        output: NA
        """

    def fixPermission(self):
        pass

    def upgrade(self):
        pass

    def createPath(self):
        pass

    def perCheck(self):
        """
        function: 1.Check instance port
                  2.Check instance IP
        input : NA
        output: NA
        """
        ipList = self.instInfo.listenIps
        ipList.extend(self.instInfo.haIps)
        portList = [self.instInfo.port, self.instInfo.haPort]

        ipList = DefaultValue.Deduplication(ipList)
        portList = DefaultValue.Deduplication(portList)
        self.logger.debug("[%s]ipList:%s,portList:%s." %
                          (self.instInfo.instanceId, ipList, portList))
        # check port
        for port in portList:
            self.__checkport(port, ipList)
        # check ip
        failIps = g_network.checkIpAddressList(ipList)
        if len(failIps) > 0:
            raise Exception(ErrorCode.GAUSS_506["GAUSS_50600"] + " The IP is %s." % ",".join(failIps))

    def __checkport(self, port, ipList):
        """
        function: check Port
        input : NA
        output: NA
        """
        tmpDir = DefaultValue.getTmpDirFromEnv()
        if not os.path.exists(tmpDir):
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50201"] % tmpDir + " Please create it first.")
        pgsqlFiles = os.listdir(tmpDir)

        self.__checkRandomPortRange(port)

        pgsql = ".s.PGSQL.%d" % port
        pgsql_lock = ".s.PGSQL.%d.lock" % port
        if pgsql in pgsqlFiles:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50200"] % "socket file" + " Port:%s." % port)

        if pgsql_lock in pgsqlFiles:
            raise Exception(ErrorCode.GAUSS_502["GAUSS_50200"] % "socket lock file" + " Port:%s." % port)

        # Verify that the port is occupied
        for ip in ipList:
            # Address family detection.
            if 6 == g_network.getIPType(ip):
                sk = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
            else:
                sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sk.settimeout(TIME_OUT)

            # retry  port 4 times
            retryFlag = True
            retryTime = 0
            while retryFlag:
                try:
                    sk.bind((ip, port))
                    sk.close()
                    break
                except socket.error as sex:
                    retryTime += 1
                    time.sleep(1)
                    if retryTime > RETRY_TIMES:
                        try:
                            portProcessInfo = g_OSlib.getPortProcessInfo(port)
                            self.logger.debug("The ip [%s] port [%s] is occupied. "
                                              "\nBind error msg:\n%s\nDetail msg:\n%s" %
                                              (ip, port, str(sex), portProcessInfo))
                        except Exception as pex:
                            self.logger.debug("Failed to get the process information of the port [%s], output:%s." %
                                              (port, str(pex)))
                        raise Exception(ErrorCode.GAUSS_506["GAUSS_50601"] % port)

    def __checkRandomPortRange(self, port):
        """
        function: Check if port is in the range of random port
        input : port
        output: NA
        """
        try:
            rangeFile = "/proc/sys/net/ipv4/ip_local_port_range"
            output = g_file.readFile(rangeFile)
            res = output[0].split()
        except Exception as e:
            self.logger.debug("Warning: Failed to get the range of random port. Detail: \n%s" % str(e))
            return
        if len(res) != 2:
            self.logger.debug("Warning: The range of random port is invalid. Detail: \n%s" % str(output))
            return
        minPort = int(res[0])
        maxPort = int(res[1])
        if minPort <= port <= maxPort:
            self.logger.debug("Warning: Current instance port %s is in the range of random port(%d - %d)." %
                              (port, minPort, maxPort))

    def postCheck(self):
        pass
