import sys
import os
import os_utils
import logging
import shutil

from os_utils import executeCommand
from extensions import extend, Hook
import vcsa_utils
logger = logging.getLogger(__name__)

# TODO: Extract all the common code between this file and __init__.py of external upgrade to a common utility script.
def getPropertyDict(filePath):
   """
   Read the .properties file and return a dictionary of key/value pairs.
   Implemented and tested to work with sms/pbm/sps/features/version.properties only.
   """
   propertyDict = {}
   with open(filePath, 'U') as f:
      for line in f:
         line = line.strip()
         # Skip comments and blank lines
         if not (line.startswith("#") or len(line)==0):
            key, value = line.split("=", 1)
            propertyDict[key.strip()] = value.strip()
   return propertyDict

def getVersion(versionFile):
   if not os.path.isfile(versionFile):
      logger.info("No version file")
      return 0
   propertyDict = getPropertyDict(versionFile)
   if propertyDict is None:
      logger.info("No version available as per version file")
      return 0
   return int(propertyDict['SPS_PATCH_VERSION'])

SPS_HOME = '/usr/lib/vmware-vpx/sps/'
SPS_CONF_PATH = os.path.join(SPS_HOME, 'conf')
SPS_SERVER_CONFIG_PATH = os.path.join(SPS_HOME, 'server', 'config')
SRC_VERSION_FILE_PATH = os.path.join(SPS_SERVER_CONFIG_PATH, 'version.properties')
SRC_VERSION = getVersion(SRC_VERSION_FILE_PATH)
TARGET_VERSION_FILE_PATH = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'version.properties')
TARGET_VERSION = getVersion(TARGET_VERSION_FILE_PATH)
SPS_LIB_PATH = os.path.join(SPS_HOME, 'lib')
COMMON_JAR_PATH = os.environ['VMWARE_COMMON_JARS']
CM_LIB_PATH = '/usr/lib/vmware-cm/lib'
VMWARE_JAVA_SEC_PROP_PATH = os.path.normpath(os.path.join(os.environ['VMWARE_CFG_DIR'], 'java', 'vmware-override-java.security'))
LOG4J_PROP_PATH = os.path.join(SPS_CONF_PATH,'log4j-upgrade.properties')
COMMON_JARS=['bcprov-jdk16-145.jar','commons-beanutils-1.9.4.jar',
             'commons-codec-1.6.jar','commons-collections-3.2.2.jar',
             'commons-configuration-1.6.jar','commons-io-1.4.jar',
             'commons-lang-2.6.jar','commons-logging-1.1.3.jar',
             'custom-rolling-file-appender-1.0.jar','httpclient-4.3.3.jar',
             'httpcore-4.3.2.jar','jna.jar','joda-time-1.6.2.jar','log4j-1.2.16.jar',
             'platform.jar','slf4j-api-1.7.28.jar','slf4j-log4j12-1.7.28.jar',
             'spring-aop-4.3.25.RELEASE.jar','spring-beans-4.3.25.RELEASE.jar',
             'spring-context-4.3.25.RELEASE.jar','spring-core-4.3.25.RELEASE.jar',
             'spring-expression-4.3.25.RELEASE.jar',
             'spring-oxm-4.3.25.RELEASE.jar','spring-web-4.3.25.RELEASE.jar',
             'spring-webmvc-4.3.25.RELEASE.jar']

@extend(Hook.Discovery)
def discover(ctx):
   if (SRC_VERSION == TARGET_VERSION):
      logger.info("SPS source and target version are same : %s. Hence, nothing to patch!" % (SRC_VERSION))
      return None
   elif (TARGET_VERSION < SRC_VERSION):
      errorMsg = "SPS downgrade detected. Source version : %s, Target version : %s" %(SRC_VERSION, TARGET_VERSION)
      logger.error(errorMsg)
      raise Exception(errorMsg)
   logger.info("SPS needs patching from %s to %s" %(SRC_VERSION, TARGET_VERSION))
   return vcsa_utils.getComponentDiscoveryResult("sps")

@extend(Hook.Patch)
def patch(ctx):
   logger.info("Starting SPS patch from %s to %s" %(SRC_VERSION, TARGET_VERSION))

   # Pickup the Java path
   javaCommand = os.environ['VMWARE_JAVA_HOME'] + os.sep + "bin" + os.sep + "java"
   logger.info("Picked up Java command as per VMWARE_JAVA_HOME as %s", javaCommand)

   # Main patch program
   spsPatch = "com.vmware.sps.PatchUpgradeMain"

   # Start constructing command classpath from conf directories
   patchClassPath = SPS_CONF_PATH + os.pathsep + SPS_SERVER_CONFIG_PATH

   # Add server libraries from lib directory
   patchClassPath = patchClassPath + os.pathsep + SPS_LIB_PATH + os.sep + "*"

   # Add required common libraries from common jars directory
   for jarFile in COMMON_JARS:
      patchClassPath = patchClassPath + os.pathsep + COMMON_JAR_PATH + os.sep + jarFile

   # Add cm lib to classpath
   cmVmodlPath = CM_LIB_PATH + os.sep + "vmodl-cm.jar"
   patchClassPath = patchClassPath + os.pathsep + cmVmodlPath

   # Run the command
   logger.info("Patch command to be run with classpath : %s",(patchClassPath))
   spsPatchCommand = [javaCommand, '-Xms256m', '-Xmx512m',
                       '-Dlog4j.configuration=file:%s' % LOG4J_PROP_PATH,
                       '-Djava.security.properties=%s' % VMWARE_JAVA_SEC_PROP_PATH,
                       '-classpath', patchClassPath, spsPatch, '-source_version', (str)(SRC_VERSION), '-target_version', (str)(TARGET_VERSION)]
   stdout, stderr, returnCode,  = executeCommand(spsPatchCommand)
   logger.info("Return code : %s" %(returnCode))
   logger.info("Stdout : %s" %(stdout))
   logger.info("Stderr : %s" %(stderr))
   if (returnCode != 0):
      raise Exception("SPS patch failed")

   # Update the version by replacing the source version file with the target
   shutil.copyfile(TARGET_VERSION_FILE_PATH, SRC_VERSION_FILE_PATH)
   logger.info("SPS is successfully patched")
