#########################################################################
#
#   Copyright 2020-2021 VMware, Inc.  All rights reserved. VMware Confidential
#
#########################################################################
from os import environ
from os.path import join
from logging import getLogger
from cis.utils import read_properties, replace_properties_in_file, \
     write_props_to_file, remove_file, readprop
from .patchUtil import TO_PREPARE_SUFFIX, RPM_SAVE_SUFFIX, updateVersion

# TODO: Remove all non-expand stuff once NDU_Limited_downtime is enabled.

VERSION = 3
_CFG_DIR = "/etc/vmware-eam"
_LOGGING_PROPS = "logging.properties"
_LOG4J_2_TOMCAT_PROPS = "log4j2-tomcat.properties"
_TOMCAT_LOGGING_PROPS_FILE_OLD_NON_EXPAND =  join(
   _CFG_DIR,
   _LOGGING_PROPS + RPM_SAVE_SUFFIX
)
_TOMCAT_LOGGING_PROPS_FILE_OLD_EXPAND = join(
   _CFG_DIR,
   _LOGGING_PROPS
)
_TOMCAT_LOGGING_PROPS_FILE_NEW_NON_EXPAND = join(
   _CFG_DIR,
   _LOG4J_2_TOMCAT_PROPS
)
_TOMCAT_LOGGING_PROPS_FILE_NEW_EXPAND = join(
   _CFG_DIR,
   _LOG4J_2_TOMCAT_PROPS + TO_PREPARE_SUFFIX
)

_OLD_LOG_DIR_PROP = "1catalina.org.apache.juli.FileHandler.directory"
_NEW_LOG_DIR_PROP = "property.tomcat.logdir"
_VCHA_DIR_ENV_VAR = "VMWARE_VCHA_SMALLFILES_DIR"
_EAM_DIR = "eam"

EAM_VERSION = "version"
EAM_VERSION_OLD = join(_CFG_DIR, EAM_VERSION)
EAM_VERSION_NEW = join(_CFG_DIR, EAM_VERSION + TO_PREPARE_SUFFIX)

_TOMCAT_LOGGING_PROPS_NEW = {
   "property.loglevel": "info",
   "property.layoutPattern": "%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} | %5p | %t | %F | %L | %m%n",
   "property.fileDatePattern": "%d{yyyy-MM-dd}",
   _NEW_LOG_DIR_PROP: "${catalina.base}/logs",
   "appender.catalina.type": "RollingFile",
   "appender.catalina.name": "catalinaAppender",
   "appender.catalina.fileName": "${tomcat.logdir}/catalina.log",
   "appender.catalina.filePattern": "${tomcat.logdir}/catalina-${fileDatePattern}.log",
   "appender.catalina.layout.type": "PatternLayout",
   "appender.catalina.layout.pattern": "${layoutPattern}",
   "appender.catalina.policies.type": "Policies",
   "appender.catalina.policies.time.type": "TimeBasedTriggeringPolicy",
   "appender.catalina.policies.time.interval": "1",
   "appender.catalina.policies.time.modulate": "true",
   "appender.localhost.type": "RollingFile",
   "appender.localhost.name": "localhostAppender",
   "appender.localhost.fileName": "${tomcat.logdir}/localhost.log",
   "appender.localhost.filePattern": "${tomcat.logdir}/localhost-${fileDatePattern}.log",
   "appender.localhost.layout.type": "PatternLayout",
   "appender.localhost.layout.pattern": "${layoutPattern}",
   "appender.localhost.policies.type": "Policies",
   "appender.localhost.policies.time.type": "TimeBasedTriggeringPolicy",
   "appender.localhost.policies.time.interval": "1",
   "appender.localhost.policies.time.modulate": "true",
   "logger.localhost.name": "org.apache.catalina.core.ContainerBase.[Catalina].[localhost]",
   "logger.localhost.level": "${loglevel}",
   "logger.localhost.additivity": "false",
   "logger.localhost.appenderRef.localhost.ref": "localhostAppender",
   "logger.vmware.name": "com.vmware",
   "logger.vmware.level": "warn",
   "rootLogger.level": "info",
   "rootLogger.appenderRef.catalina.ref": "catalinaAppender"
}

_EAM_LOG4J_PROPS_FILE_OLD = "/etc/vmware-eam/log4j.properties"
_EAM_LOG4J_PROPS_FILE_NEW = "/etc/vmware-eam/log4j.properties" +\
                            TO_PREPARE_SUFFIX
_EAM_LOG4J_TO_APPEDN = {"appender.rolling.strategy.fileIndex": "min"}
_EAM_LOG4J_TO_UPDATE = {"appender.rolling.policies.size.size": "50MB",
                        "appender.rolling.strategy.max": "20"}
_log = getLogger(__name__)

def run(ctx, isExpand):
   """
   Configures tomcat's log directory in log4j2-tomcat.properties and updates
   eam log files config.

   :param: ctx : B2B context
   :type: ctx : PatchContext, B2B specific structure, please refer to B2B
               documentation.
   :param: isExpand: boolean flag, True if this patch is invoked from expand
                    phase, False otherwise.
   :type: bool
   :raises Exception: if the patch fail.
   """
   versionFile = EAM_VERSION_NEW if isExpand else EAM_VERSION_OLD
   try:
      _configureTomcatLogging(isExpand)
      _removeLoggingPropertiesSymlink(isExpand)
      _updateEamLogsConfig(isExpand)
      updateVersion(VERSION, versionFile)
   except Exception as e:
      _log.error("EAM version three patch failed.", e)
      raise e

def updateReplicationConfig(replicationConfig):
   """
   Updates given replication config with patch specific config
   file replication configuration.

   Each item in the dictionary have following semantic:
      Key -> path of a file from source machine
      Value -> path of a file from target machine
   The file from source machine is replicated on the location pointed
   in the value over the target machine. If the Value is None, the file
   is not replicated.

   :param: replicationConfig: dictionary where to place patch specific
           config replication.
   :type: dict(str, str)
   """
   replicationConfig[EAM_VERSION_OLD] = None
   replicationConfig[EAM_VERSION_NEW] = EAM_VERSION_OLD
   replicationConfig[_TOMCAT_LOGGING_PROPS_FILE_OLD_EXPAND] = None
   replicationConfig[_TOMCAT_LOGGING_PROPS_FILE_NEW_EXPAND] = _TOMCAT_LOGGING_PROPS_FILE_OLD_EXPAND
   replicationConfig[_EAM_LOG4J_PROPS_FILE_OLD] = None
   replicationConfig[_EAM_LOG4J_PROPS_FILE_NEW] = _EAM_LOG4J_PROPS_FILE_OLD

def _configureTomcatLogging(isExpand):
   oldFile = _TOMCAT_LOGGING_PROPS_FILE_OLD_EXPAND if isExpand else\
       _TOMCAT_LOGGING_PROPS_FILE_OLD_NON_EXPAND
   newFile = _TOMCAT_LOGGING_PROPS_FILE_NEW_EXPAND if isExpand else\
       _TOMCAT_LOGGING_PROPS_FILE_NEW_NON_EXPAND

   _log.info("Configuring tomcat's log directory in " + newFile)

   oldProps = read_properties(oldFile, _OLD_LOG_DIR_PROP)

   logDir = oldProps[_OLD_LOG_DIR_PROP]

   if not logDir.strip().startswith("/"):
      raise Exception("Illegal log directory " + logDir)

   configToUpdate = {_NEW_LOG_DIR_PROP: logDir}

   write_props_to_file(newFile,_TOMCAT_LOGGING_PROPS_NEW.items())

   replace_properties_in_file(newFile,configToUpdate)

   _log.info("The logging directory was configured successfully.")

def _removeLoggingPropertiesSymlink(isExpand):
   if not isExpand:
      _log.info("Removing logging.properties VCHA symlink")

      vchaDir = environ[_VCHA_DIR_ENV_VAR]
      if vchaDir:
         remove_file(join(vchaDir, _EAM_DIR, _LOGGING_PROPS))

      _log.info("Logging.properties symlink removed successfully")

def _updateEamLogsConfig(isExpand):
   _log.info("Updating EAM log files configuration.")

   file = _EAM_LOG4J_PROPS_FILE_NEW if isExpand else _EAM_LOG4J_PROPS_FILE_OLD

   for key, value in _EAM_LOG4J_TO_APPEDN.items():
      prop = readprop(file, key)
      if not prop:
         write_props_to_file(file, [(key, value)], mode='a+')

   replace_properties_in_file(file, _EAM_LOG4J_TO_UPDATE)

   _log.info("EAM log files configuration was updated successfully.")
