# Copyright 2015 VMware, Inc.
# All rights reserved. -- VMware Confidential
import logging
import re
import platform
import os_utils
import time

log = logging.getLogger(__name__)

class PatchUtils:

    versionRegName = 'Version'

    # Version should be in the form of 'w.x.y.z'
    def normalize_version(self, version):
        if version == None:
            return[0,0,0,0]

        subversions = [int(v) for v in version.split(".")]
        while len(subversions) > 4:
            subversions.pop()
        while len(subversions) < 4:
            subversions.append(0)
        return subversions

    def versionCompare(self, verA, verB):
        if verA == None:
            if verB == None:
                return 0
            return -1
        if verB == None:
            return 1;

        normVerA = self.normalize_version(verA)
        normVerB = self.normalize_version(verB)

        for a, b in zip(normVerA, normVerB):
            if a != b:
                return a - b
        return 0

    # Registry-based versioning
    def getSourceVersion(self):
        ''' Loads current component version from registry.
        '''
        # Windows not supported
        if platform.system().lower() == "windows":
            return None

        dirKeyPath = '[HKEY_THIS_MACHINE\\Services\\vmca]'

        return self.getRegValue(dirKeyPath, 'Version')


    def setSourceVersion(self,version):
        ''' Persists the latest applied patch version.
        @param version: The latest patch version
        '''
        # Windows not supported
        if platform.system().lower() == "windows":
            return

        keyPath = '[HKEY_THIS_MACHINE\\Services\\vmca]'

        self.setRegValue(keyPath, 'Version', version)

    def getRequiredDiskSpace(self):
        raise NotImplementedError()

class PatchUtilsWin(PatchUtils):

    def __init__(self):
        return

class PatchUtilsLin(PatchUtils):
    __LW_BIN = '/opt/likewise/bin'
    __LW_SBIN = '/opt/likewise/sbin'
    __LW_REG_BIN = __LW_BIN + '/lwregshell'
    __LW_SM_BIN =  __LW_BIN + '/lwsm'
    __LW_SMD_BIN = __LW_SBIN + '/lwsmd'
    __VMCA_COMPONENT_NAME = 'vmca'
    __VMCA_SERVICE_NAME = 'VMWareCertificateService'
    __VMCA_PRODUCT_NAME = 'VMWare Certificate Services'
    __VMCA_COMPANY_NAME = "VMware, Inc."

    def __init__(self):
         return

    #Returns the Destination machine disk space (in GB)
    def getRequiredDiskSpace(self):
        return "0.01"

    # Check if reg exists under given keyroot.
    def _has_reg_val_lin(self, valueName, keyRoot):
        command = [self.__LW_REG_BIN, 'list_values', keyRoot]

        (stdout, stderr, rc) = os_utils.executeCommand(command)

        if rc == 0:
            output = stdout.splitlines()
            for line in output:
                if line.find(valueName) != -1:
                    return True
        return False

    def setRegValue(self, key, valueName, value, regType='REG_SZ'):
        if self._has_reg_val_lin(valueName, key):
            command = [self.__LW_REG_BIN, 'set_value', key, valueName, value]
            (stdout, stderr, rc) = os_utils.executeCommand(command)

            if rc != 0:
                log.info('Error setting key')
                return
        else:
            command = [self.__LW_REG_BIN, 'add_value', key, valueName, regType, value]
            (stdout, stderr, rc) = os_utils.executeCommand(command)

            if rc != 0:
                log.info('Error creating key')
                return

    def getRegValue(self,key,valueName):

        command = [self.__LW_REG_BIN, 'list_values', key]

        (stdout, stderr, rc) = os_utils.executeCommand(command)

        if rc == 0:
            return self._getRegValue(stdout.splitlines(), valueName)
        else:
            return None

    def _getRegValue(self, output, valueName):
        for line in output:
            if line.find(valueName) != -1:
                line = line.replace("+","")
                return re.findall(r'"(.*?)"',line)[1]


    def start_lwsmd(self):
        log.info('Starting service [lwsmd]')

        # See if service is already running...
        command = [self.__LW_SM_BIN, 'status',  'lwreg']
        (stdout, stderr, rc) =  os_utils.executeCommand(command)
        output = stdout.rstrip()
        if 'ERROR_FILE_NOT_FOUND' in output:
            # Service was not running so start it
            command = [self.__LW_SMD_BIN, '--start-as-daemon']
            (stdout, stderr, rc) =  os_utils.executeCommand(command)
            # Make sure it starts
            command = [self.__LW_SM_BIN, 'status', 'lwreg']
            for n in range(1, 60):
                time.sleep(5)
                (stdout, stderr, rc) = os_utils.executeCommand(command)
                output = stdout.rstrip()

                if 'running' in output.lower():
                    log.info('Service lwsmd started succesfully')
                break
            else:
                raise ServiceStartException(serviceName)
            return True
        else:
            log.info('Service lwsmd already running')
            return False

    def stop_lwsmd(self):
        log.info('Stopping service [lwsmd]')

        command = [self.__LW_SM_BIN, 'shutdown']
        os_utils.executeCommand(command)

        command = [self.__LW_SM_BIN, 'list']
        for n in range(1, 60):
            time.sleep(5)
            (stdout, stderr, rc) = os_utils.executeCommand(command)
            output = stdout.rstrip()

            if 'ERROR_FILE_NOT_FOUND' in output.upper():
                break
        else:
            raise ServiceStopException(serviceName)
