#########################################################################
#
#   Copyright 2021 VMware, Inc.  All rights reserved. VMware Confidential
#
#########################################################################
from logging import getLogger
from os import listdir, remove
from os.path import dirname, exists, join, normpath
import re

EAM_CONFIG_DIR = "/etc/vmware-eam/"
EAM_VERSION_FILE_NAME = "version"
EAM_OLD_VERSION_FILE_NAME = "oldVersion"
LIB = "lib"

RUNTIME_MODIFICATION = "runtime.modification"
TO_PREPARE_SUFFIX = ".to.prepare"
RPM_SAVE_SUFFIX = ".rpmsave"

_log = getLogger(__name__)

def getSourceVersion(isExpand):
   """
   Provides source version of the machine.
   :param: isExpand: boolean flag, True if this patch is invoked from expand
                    phase, False otherwise.
   :type: bool
   """
   res = None
   if isExpand:
      res = _readPositiveIntegerFromFile(_getCfgVersionFile())
   else:
      res = _readPositiveIntegerFromFile(
         _composeCurrentVersionFilePath()
      )
   return res

def getTargetVersion():
   """
   Provides target version of the machine.
   """
   patchFiles = listdir(dirname(__file__))
   return max(map(int, map(_getVersion, patchFiles)))

def persistCurrentVersionFile():
   """
   Persists current version file.
   """
   _writeToFile(
      str(_readPositiveIntegerFromFile(_getCfgVersionFile())),
      _composeCurrentVersionFilePath()
   )
   _log.debug("Successfully copied version file.")

def updateVersion(newVersion, versionFile):
   """
   Updates EAM config version.
   :param: newVersion: The target version to persisted in versionFile.
   :type: newVersion: str
   :param: versionFile: The file where the target version to persisted.
   :type: versionFile: str
   """
   #TODO: hardcode version file here
   targetVersion = str(newVersion)
   _writeToFile(targetVersion, versionFile)
   _log.debug("Successfully updated version in conf file: " + targetVersion)

def updateRuntimeModification(modificationKeys):
   '''
   Updates locally stored runtime modification with given keys.
   :param: modificationKeys: keys of the runtime modification to store
   :type: modificationKeys: list(str)
   '''
   runtimeModificationFile = getLocalRuntimeModification()
   if exists(runtimeModificationFile):
      remove(runtimeModificationFile)

   for modificationKey in modificationKeys:
      _writeToFile(
         modificationKey,
         runtimeModificationFile,
         mod='a'
      )

def getLocalRuntimeModification():
   '''
   Provides local file location where to store required runtime modifications.
   '''
   return join(
      EAM_CONFIG_DIR,
      RUNTIME_MODIFICATION + TO_PREPARE_SUFFIX
   )

def getTargetRuntimeModification():
   '''
   Provides target machine file location where are stored required runtime
   modifications.
   '''
   return join(EAM_CONFIG_DIR, RUNTIME_MODIFICATION)

def _getVersion(file):
   res = re.findall(r'patch(\d+).py', file)
   return int(res[0]) if len(res) == 1 else 0

def _composeCurrentVersionFilePath():
   return _getFileFromLib(EAM_OLD_VERSION_FILE_NAME)

def _getCfgVersionFile():
   return join(EAM_CONFIG_DIR, EAM_VERSION_FILE_NAME)

def _getFileFromLib(fileName):
   return normpath(join(dirname(__file__), '..', LIB, fileName))

def _readPositiveIntegerFromFile(file):
   if exists(file):
      with open(file) as f:
         res = int(f.readline().strip())
      if res == None or res < 0:
         _raiseExc("Negative integer for version or empty file.")
   else:
      _log.debug("Version file : " + file + " does not exists. ver = 0")
      res = 0
   return res

def _raiseExc(message, attachment=None):
   _log.error(message)
   raise Exception(message, attachment)

def _writeToFile(text, fileName, mod='w'):
   with open(fileName, mod) as f:
      f.write(text + '\n')
