<?php
/**
 * ###############################################
 *
 * SWIFT Framework
 * _______________________________________________
 *
 * @author		Varun Shoor
 *
 * @package		SWIFT
 * @copyright	Copyright (c) 2001-2012, Kayako
 * @license		http://www.kayako.com/license
 * @link		http://www.kayako.com
 *
 * ###############################################
 */

/**
 * The Escalation Rule Manager Class. Handles all the execution, logging and other routines
 *
 * @author Varun Shoor
 */
class SWIFT_EscalationRuleManager extends SWIFT_Library
{
	/**
	 * Constructor
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 */
	public function __construct()
	{
		parent::__construct();

		$this->Language->Load('staff_ticketsmain');
		$this->Language->Load('staff_ticketsmanage');

		SWIFT_Ticket::LoadLanguageTable();

		return true;
	}

	/**
	 * Destructor
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 */
	public function __destruct()
	{
		parent::__destruct();

		return true;
	}

	/**
	 * Run the Escalation Rules
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 */
	public function Run()
	{
		$_SWIFT = SWIFT::GetInstance();

		$_slaPlanCache = $this->Cache->Get('slaplancache');

		$_ticketIDList = $_ticketObjectContainer = array();

		// First retrieve all the tickets that are supposedly due
		$this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ((duetime <= '" . DATENOW . "' AND duetime != '0') OR (resolutionduedateline <= '" . DATENOW . "' AND resolutionduedateline != '0')) AND isescalatedvolatile = '0' AND isresolved = '0' AND departmentid != '0'");
		while ($this->Database->NextRecord())
		{
			$_ticketIDList[] = $this->Database->Record['ticketid'];
			$_ticketObjectContainer[$this->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($this->Database->Record));
		}

		// Now itterate through each ticket and see which escalation rule it belongs to and execute accordingly
		foreach ($_ticketObjectContainer as $_ticketID => $_SWIFT_TicketObject)
		{
			// SLA Plan is invalid? Or Ticket in Trash? move on!
			if (!isset($_slaPlanCache[$_SWIFT_TicketObject->GetProperty('slaplanid')]) || $_SWIFT_TicketObject->GetProperty('departmentid') == '0')
			{
				continue;
			}

			$_escalationRuleObjectContainer = $this->RetrieveEscalationRuleObjects($_SWIFT_TicketObject);

			foreach ($_escalationRuleObjectContainer as $_escalationRuleID => $_SWIFT_EscalationRuleObject)
			{
				// Already escalated under same rule?
				if ($_SWIFT_TicketObject->GetProperty('escalationruleid') == $_escalationRuleID) {
					continue;
				}

				$_SWIFT_TicketObject->Escalate($_SWIFT_EscalationRuleObject);
				$_SWIFT_TicketObject->ProcessUpdatePool();

				/*
				 * BUG FIX - Mahesh Salaria
				 *
				 * SWIFT-773 SLA time ticker starts again, after Escalation is triggered on the ticket, regardless of SLA plan criteria
				 *
				 * Comments: None
				 */
				$_SWIFT_TicketObject->ExecuteSLA();
				/*
				 * BUG FIX - Ravi Sharma
				 *
				 * SWIFT-471 Audit Log does not show the SLA plan and Escalation rule applied on the ticket
				 *
				 * Comments: None
				 */
				SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_SLA, sprintf($_SWIFT->Language->Get('al_escalated'), $_slaPlanCache[$_SWIFT_TicketObject->GetProperty('slaplanid')]['title']), SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');

				$_escalationNotificationContainer = SWIFT_EscalationNotification::RetrieveOnEscalationRule($_escalationRuleID);
				foreach ($_escalationNotificationContainer as $_escalationNotificationID => $_escalationNotificationContainer) {
					$_notificationSubject = $_escalationNotificationContainer['subject'];
					$_notificationContents = $_escalationNotificationContainer['notificationcontents'];

					$_notificationType = false;
					switch ($_escalationNotificationContainer['notificationtype']) {
						case SWIFT_EscalationNotification::TYPE_USER:
							$_notificationType = SWIFT_TicketNotification::TYPE_USER;
							break;

						case SWIFT_EscalationNotification::TYPE_USERORGANIZATION:
							$_notificationType = SWIFT_TicketNotification::TYPE_USERORGANIZATION;
							break;

						case SWIFT_EscalationNotification::TYPE_STAFF:
							$_notificationType = SWIFT_TicketNotification::TYPE_STAFF;
							break;

						case SWIFT_EscalationNotification::TYPE_TEAM:
							$_notificationType = SWIFT_TicketNotification::TYPE_TEAM;
							break;

						case SWIFT_EscalationNotification::TYPE_DEPARTMENT:
							$_notificationType = SWIFT_TicketNotification::TYPE_DEPARTMENT;
							break;

						default:
							break;
					}

					$_SWIFT_TicketObject->Notification->Dispatch($_notificationType, array(), $_notificationSubject, $_notificationContents);
				}
			}
		}

		SWIFT_TicketManager::RebuildCache();

		return true;
	}

	/**
	 * Retrieve the associated escalation rule object with a ticket
	 *
	 * @author Varun Shoor
	 * @param SWIFT $_SWIFT_TicketObject
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	protected function RetrieveEscalationRuleObjects(SWIFT_Ticket $_SWIFT_TicketObject)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_INVALIDDATA);
		}

		$_slaPlanCache = $this->Cache->Get('slaplancache');
		$_escalationRuleCache = $this->Cache->Get('escalationrulecache');

		$_escalationRuleIDList = $_escalationRuleObjectContainer = array();

		$_ticketSLAPlanID = $_SWIFT_TicketObject->GetProperty('slaplanid');
		foreach ($_escalationRuleCache as $_escalationRuleID => $_escalationRuleContainer)
		{
			/*
			 * BUG FIX - Mahesh Salaria
			 *
			 * SWIFT-676 Escalation rule also works on completion of resolution time even if we set the Escalation Type as 'Due'
			 *
			 * Comments: None
			 */

			// We found a escalation rule?
			if ($_escalationRuleContainer['slaplanid'] == $_ticketSLAPlanID)
			{
				if ($_escalationRuleContainer['ruletype'] == SWIFT_EscalationRule::TYPE_BOTH
						&& (($_SWIFT_TicketObject->GetProperty('duetime') <= DATENOW && $_SWIFT_TicketObject->GetProperty('duetime') != '0')
								|| ($_SWIFT_TicketObject->GetProperty('resolutionduedateline') <= DATENOW && $_SWIFT_TicketObject->GetProperty('resolutionduedateline') != '0'))) {
					$_escalationRuleIDList[] = $_escalationRuleID;
				} else if ($_escalationRuleContainer['ruletype'] == SWIFT_EscalationRule::TYPE_DUE
						&& ($_SWIFT_TicketObject->GetProperty('duetime') <= DATENOW && $_SWIFT_TicketObject->GetProperty('duetime') != '0')) {
					$_escalationRuleIDList[] = $_escalationRuleID;

				} else if ($_escalationRuleContainer['ruletype'] == SWIFT_EscalationRule::TYPE_RESOLUTIONDUE
						&& ($_SWIFT_TicketObject->GetProperty('resolutionduedateline') <= DATENOW && $_SWIFT_TicketObject->GetProperty('resolutionduedateline') != '0')) {
					$_escalationRuleIDList[] = $_escalationRuleID;

				}
			}
		}

		if (count($_escalationRuleIDList))
		{
			foreach ($_escalationRuleIDList as $_escalationRuleID)
			{
				if (!isset($_escalationRuleCache[$_escalationRuleID]))
				{
					continue;
				}

				$_escalationRuleObjectContainer[$_escalationRuleID] = new SWIFT_EscalationRule(new SWIFT_DataStore($_escalationRuleCache[$_escalationRuleID]));
			}
		}

		return $_escalationRuleObjectContainer;
	}
}
?>