<?php

// imports
require_once 'util/Logger.php';
require_once 'util/Transaction.php';
require_once 'util/XmlFormatter.php';
require_once 'GenericAdmin/GenericAdmin.php';
require_once 'AlarmManagement/DataTypes/ComCon.php';
require_once 'AlarmManagement/DataTypes/EventSpec.php';
require_once 'AlarmManagement/DataTypes/InstAddr.php';
require_once 'AlarmManagement/DataTypes/HostAddr.php';
require_once 'AlarmManagement/DataTypes/AlarmStatus.php';
require_once 'AlarmManagement/DataTypes/AlarmSevty.php';
require_once 'AlarmManagement/DataTypes/ServInfl.php';
require_once 'AlarmManagement/AlmMgt_Impl/EventRegistration.php';
require_once 'AlarmManagement/AlmMgt_Impl/EventForwarding.php';
require_once 'AlarmManagement/AlmMgt_Impl/AlarmValuation.php';
require_once 'AlarmManagement/AlmMgt_Impl/AlarmRecording.php';
require_once 'AlarmManagement/AlmMgt_Impl/AlarmBalancing.php';
require_once 'AlarmManagement/AlmMgt_Impl/AlarmAdministration.php';
require_once 'AlarmInterface/AlarmingInterface.php';

/**
 * Fassade class for AlarmManagement
 *
 * GENERAL NOTE
 * ------------
 * Purpose:
 * - Logging
 * - Process management
 * - TA management
 * No application logic is implemented here!
 * 
 * Implementation throws exceptions!
 *
 * @author     WagnerTech UG <mail@wagnertech.de>
 * @package    SysAl.AlarmManagement
 */
class AlarmManagement extends GenericAdmin implements AlarmingInterface {

   /**
	* Constructor
	*
	* @param   none
	* @return  see application implementation
	*
	* purpose  initialization of Generic Admin usage
	*/
	function __construct() {
		// load common Configuration
		include 'AlarmManagement/AlmMgt_Impl/ConfigurationData.php';
		Config::setConfiguration($configurationData);

		// Generic Administration configuration data
		include 'AlarmManagement/GenadData.php';
		parent::setDscrData($mocd_tab, $atdc_tab);
		
		date_default_timezone_set("MET");
    }

   /**
	* Processes a new alarm condition
	*
	* @param   EventSpec $evt_spec 
	* @param   ReturnType $returnType Defines ReturnType and synchronization behaviour
	* @return  see application implementation
	*/
	static public function processAlarm(
			InstAddr   $inst_addr,				// instance address
			$evt_time,							// event time
			EventSpec  $evt_spec,				// event specification
			ServInfl   $serv_infl = null,		// service influence
			AlarmSevty $perc_sev  = null,		// perceived severity
			$src_host_name = null,				// source host name (local if null)
			HostAddr   $src_host_addr = null,	// source host address (local if null)
			HostAddr   $tgt_host_addr = null)	// target host address (local if null)
	{
		// load common Configuration
		include 'AlarmManagement/AlmMgt_Impl/ConfigurationData.php';
		Config::setConfiguration($configurationData);

		// Supply defaults
		if ($serv_infl == null)
			$serv_infl = new ServInfl();
		if ($perc_sev == null)
			$perc_sev = new AlarmSevty();

		// Logging
		$logger = Logger::getInstance();
		$logger->log(__CLASS__, "START processAlarm");
		$logger->log(__CLASS__, "InstanceAddress " . $inst_addr);
		$logger->log(__CLASS__, "EventTime " . $evt_time);
		$logger->log(__CLASS__, "EventSpec " . $evt_spec);
		$logger->log(__CLASS__, "ServiceInfluence " . $serv_infl);
		$logger->log(__CLASS__, "PerceivedSeverity " . $perc_sev);
		$logger->log(__CLASS__, "SourceHostName " . $src_host_name);
		$logger->log(__CLASS__, "SourceHostAddr " . $src_host_addr);
		$logger->log(__CLASS__, "TargetHostAddr " . $tgt_host_addr);
				
		// call implementation via try/catch
		try {
		    
		    $ec = GenericAdmin::EC_OK;

			Transaction::getInstance()->startTA();
			
			EventRegistration::registerEvent(
				$evt_spec,
				$aed_id);	
			
			EventForwarding::registerHost(
				$src_host_name,
				$src_host_addr,
				$amh_id);
			
			EventForwarding::getHostAddrList(
				$aed_id,
				$local_proc,
				$host_lst);
			
			// comments on hosts: if a source host (name/addr) is specified by the caller,
			// it will be taken (after possible creation) as AMH (amh_id);
			// else the (first) local AMH will be assigned; if no local AMH exists at all,
			// no local processing is possible as result of AFI analysis;
			// forwardAlarm(...) only works either as propagation (src-host was specified originally)
			// or else a local AMH exists (no anonymous forwarding in case of none of both);
			// forwarding of ABM alarms ("balance escalation") requires an existing local AMH as source
			 
			if ($local_proc) {
				// Local Alarm Processing
				$thr_alm_clr = false;
				if ($perc_sev->getValue() != AlarmSevty::AS_CLEAR) {
					// Alarm Begin Processing 
					if ($perc_sev->getValue() == AlarmSevty::AS_INDET) {
						$alm_sev = AlarmValuation::valuateAlarm(
										$aed_id,
										$serv_infl);
					} else { 
						$alm_sev = $perc_sev;
					}
					
					$alm_stat = new AlarmStatus($alm_sev->getValue());

					$ec =  AlarmRecording::recordAlarm(
						$inst_addr,
						$amh_id,
						$evt_time,
						$aed_id,
						$alm_stat,
						$serv_infl,
						$thr_alm_clr);
					
					if ($ec == GenericAdmin::EC_DUPL_INST) {
					    // alarming was already performed
					    Transaction::getInstance()->commitTA();
					    $logger->log(__CLASS__, "END processAlarm with EC_DUPL_INST");
					    return 0;
					}
					$logger->log(__CLASS__, "Alarm. Prio: $alm_stat (", LOG_INFO);
					$logger->log(__CLASS__, "  InstAddr      $inst_addr,
  evt_time      $evt_time,
  EventSpec     $evt_spec,
  ServInfl      $serv_infl,
  AlarmSevty    $perc_sev,
  src_host_name $src_host_name,
  src_host_addr $src_host_addr,
  tgt_host_addr $tgt_host_addr )", LOG_INFO);
				} else {
					// Alarm End Processing
					$ec = AlarmRecording::cancelAlarm(
						$inst_addr,
						$amh_id,
						$aed_id);
					if ($ec == GenericAdmin::EC_OK) {
					   $logger->log(__CLASS__, "Alarm clearance (", LOG_INFO);
					   $logger->log(__CLASS__, "  InstAddr      $inst_addr,
  evt_time      $evt_time,
  EventSpec     $evt_spec,
  src_host_name $src_host_name,
  src_host_addr $src_host_addr,
  tgt_host_addr $tgt_host_addr )", LOG_INFO);
					} 
					else $logger->log(__CLASS__, "AlarmRecording::cancelAlarm returned: ".$ec);
					$alm_stat = new AlarmStatus(AlarmStatus::AS_CLEAR);
				}
                
				AlarmBalancing::strikeBalance(
					$aed_id,
					$alm_stat,
					$thr_alm_clr,
					$esc_inf_lst);

				if (count($esc_inf_lst) > 0) {
					$evt_forw = new EventForwarding();
			
					foreach ($esc_inf_lst as $esc_inf) {
					    $forw_insts = "";
					    foreach ($esc_inf['tgt_hosts'] as $host) $forw_insts .= $host->getHostAddr().":";
					    $logger->log(__CLASS__, "escalate balance to $forw_insts", LOG_INFO);
						$evt_forw->forwardAlarm(
										$esc_inf['tgt_hosts'],
						                $esc_inf['inst'],
										date('y.m.d h:i:s'),
										$esc_inf['event'],
										new ServInfl(ServInfl::SI_INDEP),
										$esc_inf['sevty']);
					}
				}
			}
			
			if (count($host_lst) > 0) {
				if (!isset($evt_forw)) $evt_forw = new EventForwarding();
				$forw_insts = "";
				foreach ($host_lst as $host) $forw_insts .= $host->host_addr.":";
				$logger->log(__CLASS__, "forward alarm to $forw_insts");
				
				$evt_forw->forwardAlarm(
								$host_lst,
								$inst_addr,
					  			$evt_time,
								$evt_spec,
								$serv_infl,
								$perc_sev,
								$amh_id);
			}
			
			Transaction::getInstance()->commitTA();
			
		} catch (Exception $e) {
			$logger->logException(__CLASS__, $e);
			Transaction::getInstance()->rollbackTA();
			throw $e;
		}
		$logger->log(__CLASS__, "END processAlarm");
		return 0;		
	}
	
	public static function getMonitors() {
		// load common Configuration
		include 'AlarmManagement/AlmMgt_Impl/ConfigurationData.php';
		Config::setConfiguration($configurationData);

		// logging
		$logger = Logger::getInstance();
		$logger->log(__CLASS__, "getMonitors()");
		
		// call implementation via try/catch
		try {

			$ta = Transaction::getInstance();
			$ta->startTA();
		
			// create output formatter
			$xmlFormatter = new XmlFormatter();
			
			AlarmAdministration::getMonitors($xmlFormatter, $ret_val);

			$ta->commitTA();
			
			return $xmlFormatter->printIt();
			
		} catch (Exception $e) {
			$logger->logException(__CLASS__, $e);
			Transaction::getInstance()->rollbackTA();
			throw $e;
		}
	}

	public static function getMonitorAlarms($abm_id) {
		// load common Configuration
		include 'AlarmManagement/AlmMgt_Impl/ConfigurationData.php';
		Config::setConfiguration($configurationData);

		// logging
		$logger = Logger::getInstance();
		$logger->log(__CLASS__, "getMonitorAlarms()");
		$logger->log(__CLASS__, "abm_id=$abm_id");
		
		// call implementation via try/catch
		try {
			$ta = Transaction::getInstance();
			$ta->startTA();
		
			// create output formatter
			$xmlFormatter = new XmlFormatter();
			
			AlarmAdministration::getMonitorAlarms($xmlFormatter, $abm_id, $ret_val);

			$ta->commitTA();
			
			return $xmlFormatter->printIt();
			
		} catch (Exception $e) {
			$logger->logException(__CLASS__, $e);
			Transaction::getInstance()->rollbackTA();
			throw $e;
		}
	}
	
	public static function confirmAlarmBalance($abm_id) {
		// load common Configuration
		include 'AlarmManagement/AlmMgt_Impl/ConfigurationData.php';
		Config::setConfiguration($configurationData);

		// logging
		$logger = Logger::getInstance();
		$logger->log(__CLASS__, "confirmAlarmBalance()");
		$logger->log(__CLASS__, "abm_id=$abm_id");
		
		// call implementation via try/catch
		try {
			$ta = Transaction::getInstance();
			$ta->startTA();
		
			AlarmAdministration::confirmMonitor($abm_id, $esc_inf, $ret_val);

			if ($ret_val == ComCon::RC_OK && count($esc_inf['tgt_hosts']) > 0) {
				$evt_forw = new EventForwarding();
				$evt_forw->forwardAlarm(
								$esc_inf['tgt_hosts'],
								$esc_inf['inst'],
								date('y.m.d h:i:s'),
								$esc_inf['event'],
								new ServInfl(ServInfl::SI_INDEP),
								$esc_inf['sevty']);
			}
			
			$ta->commitTA();

		} catch (Exception $e) {
			$logger->logException(__CLASS__, $e);
			Transaction::getInstance()->rollbackTA();
			throw $e;
		}
	}
	
	public function deleteCacs()
	// this function is for testing only!!
	{
		// load common Configuration
		include 'AlarmManagement/AlmMgt_Impl/ConfigurationData.php';
		Config::setConfiguration($configurationData);

		// Logging
		$logger = Logger::getInstance();
		$logger->log(__CLASS__, "function: deleteCacs");
		$logger->log(__CLASS__, "This function is for testing only!!");
				
		// call implementation via try/catch
		try {

			Transaction::getInstance()->startTA();
			
			$cac_lst = CurrentAlarmConditionQuery::create()->find();
	
			foreach ($cac_lst as $cac) {
				$cac->delete();
			}

			// clear all ABMs
			
			$abm_lst = AlarmBalanceMonitorQuery::create()->find();
			
			foreach ($abm_lst as $abm) {
				$abm->setCfdAstaBal(new AlarmBalance());
				$abm->setUncfdAstaBal(new AlarmBalance());
				$abm->save();
			}
			
			Transaction::getInstance()->commitTA();
			
		} catch (Exception $e) {
			$logger->logException(__CLASS__, $e);
			Transaction::getInstance()->rollbackTA();
			throw $e;
		}
		return 0;		
	}
	
}