<?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 Ticket Model Class
 *
 * @author Varun Shoor
 */
class SWIFT_Ticket extends SWIFT_Model
{
	const TABLE_NAME		=	'tickets';
	const PRIMARY_KEY		=	'ticketid';

	const TABLE_STRUCTURE	=	"ticketid I PRIMARY AUTO NOTNULL,
								ticketmaskid C(20) DEFAULT '' NOTNULL,
								departmentid I DEFAULT '0' NOTNULL,
								departmenttitle C(255) DEFAULT '' NOTNULL,
								ticketstatusid I DEFAULT '0' NOTNULL,
								ticketstatustitle C(255) DEFAULT '' NOTNULL,
								priorityid I DEFAULT '0' NOTNULL,
								prioritytitle C(255) DEFAULT '' NOTNULL,
								emailqueueid I DEFAULT '0' NOTNULL,
								userid I DEFAULT '0' NOTNULL,
								staffid I DEFAULT '0' NOTNULL,
								ownerstaffid I DEFAULT '0' NOTNULL,
								ownerstaffname C(255) DEFAULT '' NOTNULL,
								assignstatus I2 DEFAULT '0' NOTNULL,

								fullname C(225) DEFAULT '' NOTNULL,
								email C(150) DEFAULT '' NOTNULL,
								lastreplier C(255) DEFAULT '' NOTNULL,
								replyto C(150) DEFAULT '' NOTNULL,
								subject C(255) DEFAULT '' NOTNULL,
								dateline I DEFAULT '0' NOTNULL,
								lastactivity I DEFAULT '0' NOTNULL,
								laststaffreplytime I DEFAULT '0' NOTNULL,
								lastuserreplytime I DEFAULT '0' NOTNULL,
								slaplanid I DEFAULT '0' NOTNULL,
								ticketslaplanid I DEFAULT '0' NOTNULL,
								duetime I DEFAULT '0' NOTNULL,
								totalreplies I DEFAULT '0' NOTNULL,
								ipaddress C(50) DEFAULT '0.0.0.0' NOTNULL,
								flagtype I2 DEFAULT '0' NOTNULL,
								hasnotes I2 DEFAULT '0' NOTNULL,
								hasattachments I2 DEFAULT '0' NOTNULL,
								isemailed I2 DEFAULT '0' NOTNULL,
								edited I2 DEFAULT '0' NOTNULL,
								editedbystaffid I DEFAULT '0' NOTNULL,
								editeddateline I DEFAULT '0' NOTNULL,
								creator I2 DEFAULT '0' NOTNULL,
								charset C(100) DEFAULT '' NOTNULL,
								transferencoding C(50) DEFAULT '' NOTNULL,
								timeworked I DEFAULT '0' NOTNULL,
								timebilled I DEFAULT '0' NOTNULL,
								dateicon I DEFAULT '0' NOTNULL,
								lastpostid I DEFAULT '0' NOTNULL,
								firstpostid I DEFAULT '0' NOTNULL,
								tgroupid I DEFAULT '0' NOTNULL,
								messageid C(17) DEFAULT '' NOTNULL,
								escalationruleid I DEFAULT '0' NOTNULL,
								hasdraft I2 DEFAULT '0' NOTNULL,
								hasbilling I2 DEFAULT '0' NOTNULL,
								isphonecall I2 DEFAULT '0' NOTNULL,
								isescalated I2 DEFAULT '0' NOTNULL,
								isescalatedvolatile I2 DEFAULT '0' NOTNULL,
								phoneno C(255) DEFAULT '' NOTNULL,

								isautoclosed I2 DEFAULT '0' NOTNULL,
								autocloseruleid I DEFAULT '0' NOTNULL,
								autoclosestatus I2 DEFAULT '0' NOTNULL,
								autoclosetimeline I DEFAULT '0' NOTNULL,

								escalatedtime I DEFAULT '0' NOTNULL,
								followupcount I DEFAULT '0' NOTNULL,
								hasfollowup I2 DEFAULT '0' NOTNULL,

								hasratings I2 DEFAULT '0' NOTNULL,
								tickethash C(50) DEFAULT '' NOTNULL,
								islinked I2 DEFAULT '0' NOTNULL,
								trasholddepartmentid I DEFAULT '0' NOT NULL,
								tickettype I2 DEFAULT '0' NOTNULL,
								tickettypeid I DEFAULT '0' NOTNULL,
								tickettypetitle C(255) DEFAULT '' NOTNULL,
								creationmode I2 DEFAULT '0' NOTNULL,

								isfirstcontactresolved I2 DEFAULT '0' NOTNULL,
								wasreopened I2 DEFAULT '0' NOTNULL,
								reopendateline I DEFAULT '0' NOTNULL,
								resolutiondateline I DEFAULT '0' NOTNULL,
								escalationlevelcount I DEFAULT '0' NOTNULL,
								resolutionseconds I DEFAULT '0' NOTNULL,
								resolutionlevel I DEFAULT '0' NOTNULL,
								repliestoresolution I DEFAULT '0' NOTNULL,

								averageresponsetime I DEFAULT '0' NOTNULL,
								averageslaresponsetime I DEFAULT '0' NOTNULL,
								averageresponsetimehits I DEFAULT '0' NOTNULL,
								firstresponsetime I DEFAULT '0' NOTNULL,

								resolutionduedateline I DEFAULT '0' NOTNULL,
								isresolved I2 DEFAULT '0' NOTNULL,
								iswatched I2 DEFAULT '0' NOTNULL,

								oldeditemailaddress C(255) DEFAULT '' NOTNULL,

								recurrencefromticketid I DEFAULT '0' NOTNULL,

								linkkbarticleid I DEFAULT '0' NOTNULL,
								linkticketmacroid I DEFAULT '0' NOTNULL,
								bayescategoryid I DEFAULT '0' NOTNULL";

	const INDEX_TICKETCOUNT = 'departmentid, ticketstatusid, ownerstaffid, tickettypeid, lastactivity';
	const INDEX_1           = 'userid, email, replyto, departmentid, isresolved';
	const INDEX_2           = 'slaplanid, duetime, ticketstatusid';
	const INDEX_3           = 'departmentid, ticketstatusid, lastactivity';
	const INDEX_4           = 'email';
	const INDEX_5           = 'departmentid, ticketstatusid, userid';
	const INDEX_6           = 'departmentid, ticketstatusid, duetime';
	const INDEX_7           = 'dateline';
	const INDEX_8           = 'departmentid, ticketstatusid, lastuserreplytime';
	const INDEX_9           = 'duetime, resolutionduedateline, isescalatedvolatile, isresolved';
	const INDEX_10          = 'ticketmaskid, ticketid, departmentid';
	const INDEX_11          = 'departmentid, ticketstatusid, duetime, resolutionduedateline';
	const INDEX_12          = 'isresolved, departmentid';
	const INDEX_13          = 'ticketstatusid, departmentid, priorityid, tickettypeid';
	const INDEX_14          = 'isescalatedvolatile, isresolved';
	const INDEX_15          = 'ticketid, departmentid'; // Used by Staff API Protocol
	const INDEX_16          = 'ticketid, isresolved, autoclosestatus, lastactivity'; // Used by Auto Close
	const INDEX_17          = 'autoclosestatus, autocloseruleid, autoclosetimeline'; // Used by Auto Close
	const INDEX_18          = 'lastactivity'; // Unified Search
	const INDEX_19          = 'recurrencefromticketid'; // Ticket Recurrence


	const COLUMN_RENAME_HASBENCHMARKS = 'hasratings';

	protected $_dataStore = array();

	// Attachments
	static protected $_attachmentsContainer = array();
	static protected $_notificationAttachmentsContainer = array();

	// Notification Stuff
	public $Notification = false;
	public $NotificationManager = false;
	static protected $_notificationExecutionCache = array();

	// Workflow Queue Related Variables
	static protected $_isWorkflowQueueActive = false;
	static protected $_workflowQueue = array();

	// Watcher
	static protected $_watcherPendingCache = array();
	static protected $_watcherExecutedCache = array();
	protected $_watchNotificationMessage = '';
	protected $_lastPostNotificationMessage = '';
	protected $_watcherCustomName = '';

	protected $_noAlerts = false;

	/**
	 * @var bool This property decides whether the SLA calculation has been queued on shutdown
	 */
	protected $_slaOverdueQueued = -1;

	/**
	 * @var bool This property is used to prevent the execution of SLA calculation.
	 */
	protected $_noSLACalculation = false;

	/**
	 * @var SWIFT_User This property is used to cache the user object
	 */
	protected $_UserObject = false;

	/**
	 * @var SWIFT_UserOrganization This property is used to cache the user organization object
	 */
	protected $_UserOrganizationObject = false;

	/**
	 * @var SWIFT_UserGroup This property is used to cache the user group object
	 */
	protected $_UserGroupObject = false;

	/**
	 * @var bool This property is used to determine the cache flag for the user object
	 */
	protected $_isUserObjectCached = false;

	/**
	 * @var bool This property is used to determine the cache flag for the user group object
	 */
	protected $_isUserGroupObjectCached = false;

	/**
	 * @var bool This property is used to determine the cache flag for the user organization object
	 */
	protected $_isUserOrganizationObjectCached = false;

	/**
	 * @var bool Is used to determine if the status was changed in this object
	 */
	protected $_hasStatusChanged = false;

	/**
	 * @var array Is used to keep old Ticket Properties.
	 */
	protected $_oldTicketProperties = array();

	// Core Constants
	const CREATOR_STAFF = 1;
	const CREATOR_USER = 2;
	const CREATOR_CLIENT = 2;

	const CREATIONMODE_SUPPORTCENTER = 1;
	const CREATIONMODE_STAFFCP = 2;
	const CREATIONMODE_EMAIL = 3;
	const CREATIONMODE_API = 4;
	const CREATIONMODE_SITEBADGE = 5;
	const CREATIONMODE_MOBILE = 6;
	const CREATIONMODE_STAFFAPI = 7;

	const TYPE_DEFAULT = 1;
	const TYPE_PHONE = 2;

	const MAIL_NOTIFICATION = 1;
	const MAIL_CLIENT = 2;
	const MAIL_THIRDPARTY = 3;

	const AUTOCLOSESTATUS_NONE = 0;
	const AUTOCLOSESTATUS_PENDING = 1;
	const AUTOCLOSESTATUS_CLOSED = 2;

	const MODE_DUPLICATE = 0;
	const MODE_SPLIT     = 1;

	/**
	 * Constructor
	 *
	 * @author Varun Shoor
	 * @param SWIFT_Data $_SWIFT_DataObject The SWIFT_Data Object
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Record could not be loaded
	 */
	public function __construct(SWIFT_Data $_SWIFT_DataObject)
	{
		parent::__construct();

		if (!$_SWIFT_DataObject instanceof SWIFT_Data || !$_SWIFT_DataObject->GetIsClassLoaded() || !$this->LoadData($_SWIFT_DataObject)) {
			throw new SWIFT_Ticket_Exception('Failed to load Ticket Object');

			$this->SetIsClassLoaded(false);

			return false;
		}

		$this->Load->Library('Ticket:TicketManager');

		$this->Notification = new SWIFT_TicketNotification($this);
		$this->NotificationManager = new SWIFT_NotificationManager($this);

		register_shutdown_function(array($this, 'ProcessNotifications'));

		if ($this->GetProperty('iswatched') == '1') {
			register_shutdown_function(array($this, 'ProcessWatchers'));
		}

		return true;
	}

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

		if ($this->_slaOverdueQueued != -1) {
			$this->ProcessSLAOverdue($this->_slaOverdueQueued);
		}

		if ($this->GetProperty('iswatched') == '1') {
			$this->ProcessWatchers();
		}

		$this->ProcessUpdatePool();

		parent::__destruct();

		return true;
	}

	/**
	 * Execute SLA If pending
	 *
	 * @author Varun Shoor
	 * @param bool $_processResolutionDue (OPTIONAL) Whether to process the resolution due dateline
	 * @param bool $_dontQueue (OPTIONAL) Dont queue the SLA execution
	 * @param bool $_processReplyDue (OPTIONAL)
	 *
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function ExecuteSLA($_processResolutionDue = true, $_dontQueue = false, $_processReplyDue = true)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->ProcessUpdatePool();

		if ($this->_slaOverdueQueued != -1 || $_dontQueue == true) {
			$this->ProcessSLAOverdue($_processResolutionDue, $_processReplyDue);

			if ($_dontQueue) {
				$this->ProcessUpdatePool();
			}
		} else {
			$this->QueueSLAOverdue($_processResolutionDue, $_processReplyDue);
		}

		return true;
	}

	/**
	 * Processes the Update Pool Data
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function ProcessUpdatePool()
	{
		if (!$this->GetIsClassLoaded()) {
			return false;
		} else if (!_is_array($this->GetUpdatePool())) {
			return false;
		}

		$this->Database->AutoExecute(TABLE_PREFIX . 'tickets', $this->GetUpdatePool(), 'UPDATE', "ticketid = '" . intval($this->GetTicketID()) .
				"'");

		$this->ClearUpdatePool();

		return true;
	}

	/**
	 * Retrieves the Ticket ID
	 *
	 * @author Varun Shoor
	 * @return mixed "ticketid" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetTicketID()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		return $this->_dataStore['ticketid'];
	}

	/**
	 * Load the Data
	 *
	 * @author Varun Shoor
	 * @param SWIFT_Data $_SWIFT_DataObject The SWIFT_Data Object
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	protected function LoadData($_SWIFT_DataObject)
	{
		$_SWIFT = SWIFT::GetInstance();

		// Is it a ID?
		if ($_SWIFT_DataObject instanceof SWIFT_DataID && $_SWIFT_DataObject->GetIsClassLoaded())
		{
			$_dataStore = $this->Database->QueryFetch("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid = '" .
					intval($_SWIFT_DataObject->GetDataID()) . "'");
			if (isset($_dataStore['ticketid']) && !empty($_dataStore['ticketid']))
			{
				$this->_dataStore = $_dataStore;
				$this->_dataStore['displayticketid'] = IIF($_SWIFT->Settings->Get('t_eticketid') == 'seq', $this->_dataStore['ticketid'], $this->_dataStore['ticketmaskid']);

				return true;
			}

		// Is it a Store?
		} else if ($_SWIFT_DataObject instanceof SWIFT_DataStore && $_SWIFT_DataObject->GetIsClassLoaded()) {
			$this->_dataStore = $_SWIFT_DataObject->GetDataStore();
			$this->_dataStore['displayticketid'] = IIF($_SWIFT->Settings->Get('t_eticketid') == 'seq', $this->_dataStore['ticketid'], $this->_dataStore['ticketmaskid']);

			if (!isset($this->_dataStore['ticketid']) || empty($this->_dataStore['ticketid']))
			{
				throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
			}

			return true;
		}

		throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);

		return false;
	}

	/**
	 * Returns the Data Store Array
	 *
	 * @author Varun Shoor
	 * @return mixed "_dataStore" Array on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetDataStore()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		return $this->_dataStore;
	}

	/**
	 * Retrieves a Property Value from Data Store
	 *
	 * @author Varun Shoor
	 * @param string $_key The Key Identifier
	 * @return mixed Property Data on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetProperty($_key)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (!isset($this->_dataStore[$_key])) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);

			return false;
		}

		return $this->_dataStore[$_key];
	}

	/**
	 * Check to see if its a valid creator type
	 *
	 * @author Varun Shoor
	 * @param constant $_creatorType The Creator Type
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function IsValidCreatorType($_creatorType)
	{
		if ($_creatorType == self::CREATOR_STAFF || $_creatorType == self::CREATOR_USER)
		{
			return true;
		}

		return false;
	}

	/**
	 * Check to see if its a valid creation mode
	 *
	 * @author Varun Shoor
	 * @param constant $_creationMode The Creation Mode
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function IsValidCreationMode($_creationMode)
	{
		if ($_creationMode == self::CREATIONMODE_SUPPORTCENTER || $_creationMode == self::CREATIONMODE_STAFFCP ||
				$_creationMode == self::CREATIONMODE_EMAIL || $_creationMode == self::CREATIONMODE_API ||
				$_creationMode == self::CREATIONMODE_SITEBADGE || $_creationMode == self::CREATIONMODE_MOBILE ||
				$_creationMode == self::CREATIONMODE_STAFFAPI)
		{
			return true;
		}

		return false;
	}

	/**
	 * Check to see if its a valid ticket type
	 *
	 * @author Varun Shoor
	 * @param constant $_ticketType The Ticket Type
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function IsValidTicketType($_ticketType)
	{
		if ($_ticketType == self::TYPE_DEFAULT || $_ticketType == self::TYPE_PHONE)
		{
			return true;
		}

		return false;
	}

	/**
	 * Get or Create a User ID based on given info
	 *
	 * @author Varun Shoor
	 * @param string $_fullName The User Full Name
	 * @param string $_email the User Email
	 * @param int $_userGroupID The User Group ID
	 * @param int $_languageID (OPTIONAL) The Language ID
	 * @param bool $_checkGeoIP (OPTIONAL) Check GeoIP for User
	 * @return int The User ID on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function GetOrCreateUserID($_fullName, $_email, $_userGroupID, $_languageID = false, $_checkGeoIP = false, $_phoneNumber = '') {
		$_SWIFT = SWIFT::GetInstance();

		// User processing.. no user specified?
		$_userIDFromEmail = SWIFT_UserEmail::RetrieveUserIDOnUserEmail($_email);

		$_userID = false;
		if (!empty($_userIDFromEmail)) {
			$_userID = $_userIDFromEmail;
		} else {
			$_SWIFT_UserObject = SWIFT_User::Create($_userGroupID, false, SWIFT_User::SALUTATION_NONE, $_fullName, '', $_phoneNumber, true,
					false, array($_email), false, $_languageID, false, false, false, false, false, true, true, $_checkGeoIP);

			$_userID = $_SWIFT_UserObject->GetUserID();
		}

		return $_userID;
	}

	/**
	 * Create a new Ticket
	 *
	 * @author Varun Shoor
	 * @param string $_subject The Ticket Subject
	 * @param string $_fullName The Full Name of Creator
	 * @param string $_email The Email of Creator
	 * @param string $_contents The Ticket Contents
	 * @param int $_ownerStaffID The Ticket Owner Staff ID
	 * @param int $_departmentID The Department ID
	 * @param int $_ticketStatusID The Ticket Status ID
	 * @param int $_ticketPriorityID The Ticket Priority ID
	 * @param int $_ticketTypeID The Ticket Type ID
	 * @param int $_userID The User ID (If creator is user)
	 * @param int $_staffID The Staff ID (If creator is staff)
	 * @param constant $_ticketType The Ticket Type (Default/Phone)
	 * @param constant $_creatorType The Creator Type
	 * @param constant $_creationMode The Creation Mode
	 * @param string $_phoneNumber (OPTIONAL) The Phone Number of User
	 * @param int $_emailQueueID (OPTIONAL) The Email Queue ID
	 * @param bool $_dispatchAutoResponder (OPTIONAL) Whether to dispatch the autoresponder msg
	 * @param string $_emailTo (OPTIONAL) Only to be used when creating tickets from staff cp and using send mail option. Signifies the destination email address.
	 * @param bool $_isPrivate (OPTIONAL) Whether private ticket post
	 * @return mixed "_SWIFT_TicketObject" (OBJECT) on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided or If the Object could not be created
	 */

	static public function Create($_subject, $_fullName, $_email, $_contents, $_ownerStaffID, $_departmentID, $_ticketStatusID, $_ticketPriorityID, $_ticketTypeID,
			$_userID, $_staffID, $_ticketType, $_creatorType, $_creationMode, $_phoneNumber = '', $_emailQueueID = 0, $_dispatchAutoResponder = true,
			$_emailTo = '', $_isHTML = false, $_date = DATENOW, $_isPrivate = false)
	{
		$_SWIFT = SWIFT::GetInstance();

		$_departmentID = intval($_departmentID);
		$_ticketStatusID = intval($_ticketStatusID);
		$_ticketPriorityID = intval($_ticketPriorityID);
		$_userID = intval($_userID);
		$_ticketTypeID = intval($_ticketTypeID);

		$_ticketTypeCache = $_SWIFT->Cache->Get('tickettypecache');
		if(empty($_ticketTypeID)) {
			// Set default ticket type ID
			foreach ($_ticketTypeCache as $_ticketTypeID => $_ticketTypeContainer) {
				break;
			}

		}

		if ($_subject == '' || empty($_fullName) || empty($_email) || $_contents == '' || empty($_departmentID) || empty($_ticketStatusID) ||	!self::IsValidCreatorType($_creatorType)
				|| !self::IsValidCreationMode($_creationMode) || !self::IsValidTicketType($_ticketType))
		{
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);

			return false;
		}


		// Sanity check.. IMPORTANT
		$_departmentCache = $_SWIFT->Cache->Get('departmentcache');
		$_ticketStatusCache = $_SWIFT->Cache->Get('statuscache');
		$_ticketPriorityCache = $_SWIFT->Cache->Get('prioritycache');

		if (!isset($_departmentCache[$_departmentID]) || !isset($_ticketStatusCache[$_ticketStatusID]) ||
				!isset($_ticketPriorityCache[$_ticketPriorityID]) || !isset($_ticketTypeCache[$_ticketTypeID])) {
			throw new SWIFT_Ticket_Exception('Invalid Core Data: Department, Status, Priority, Type');
		} else if ($_departmentCache[$_departmentID]['departmentapp'] != APP_TICKETS) {
			throw new SWIFT_Ticket_Exception('Invalid Department App');
		}

		$_ticketMaskID = GenerateUniqueMask();

		$_isPhoneCall = false;
		if ($_ticketType == self::TYPE_PHONE)
		{
			$_isPhoneCall = true;
		}

		$_replyToEmail = $_email;
		if (!empty($_emailTo))
		{
			$_replyToEmail = $_emailTo;
		}

		$_isEmailed = false;
		if ($_creationMode == self::CREATIONMODE_EMAIL)
		{
			$_isEmailed = true;
		}

		$_ipAddress = '';
		if ($_SWIFT->Interface->GetInterface() != SWIFT_Interface::INTERFACE_CRON && $_SWIFT->Interface->GetInterface() != SWIFT_Interface::INTERFACE_CONSOLE)
		{
			$_ipAddress = SWIFT::Get('IP');
		}

		$_SWIFT_BayesianObject = new SWIFT_Bayesian();
		$_finalBayesCategoryID = 0;
		$_probabilityContainer = $_SWIFT_BayesianObject->Get($_subject . ' ' . $_contents);
		if (_is_array($_probabilityContainer))
		{
			$_finalBayesBenchmark = 0;
			foreach ($_probabilityContainer[0] as $_bayesCategoryID => $_probability)
			{
				if ($_probability['combined'] >= 0.500 && $_probability['combined'] > $_finalBayesBenchmark)
				{
					$_finalBayesCategoryID = $_bayesCategoryID;
					$_finalBayesBenchmark = $_probability['combined'];
				}
			}
		}

		// Encoding utf-8 hex(emoji characters) to string
		$_emojiObject = new SWIFT_Emoji();

		$_subject  = $_emojiObject->encode($_subject);
		$_contents = $_emojiObject->encode($_contents);

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('ticketmaskid' => $_ticketMaskID, 'departmentid' => intval($_departmentID),
			'ticketstatusid' => intval($_ticketStatusID), 'priorityid' => intval($_ticketPriorityID), 'emailqueueid' => intval($_emailQueueID),
			'userid' => intval($_userID), 'staffid' => intval($_staffID), 'fullname' => $_fullName, 'email' => mb_strtolower($_email), 'lastreplier' => $_fullName,
			'replyto' => $_replyToEmail, 'subject' => $_subject, 'dateline' => $_date, 'lastactivity' => DATENOW, 'ipaddress' => $_ipAddress,
			'isemailed' => intval($_isEmailed), 'isphonecall' => intval($_isPhoneCall), 'creator' => intval($_creatorType),
			'tickettype' => intval($_ticketType), 'phoneno' => $_phoneNumber, 'tickettypeid' => intval($_ticketTypeID), 'tickethash' => substr(BuildHash(), 0, 12),
			'creationmode' => intval($_creationMode), 'bayescategoryid' => intval($_finalBayesCategoryID)), 'INSERT');
		$_ticketID = $_SWIFT->Database->Insert_ID();

		if (!$_ticketID)
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CREATEFAILED);

			return false;
		}

		$_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataID($_ticketID));
		if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CREATEFAILED);

			return false;
		}

		$_departmentTitle = $_departmentCache[$_departmentID]['title'];
		$_statusTitle = $_ticketStatusCache[$_ticketStatusID]['title'];
		$_typeTitle = $_ticketTypeCache[$_ticketTypeID]['title'];
		$_priorityTitle = $_ticketPriorityCache[$_ticketPriorityID]['title'];

		$_SWIFT_TicketObject->UpdatePool('departmenttitle', $_departmentTitle);
		$_SWIFT_TicketObject->UpdatePool('ticketstatustitle', $_statusTitle);
		$_SWIFT_TicketObject->UpdatePool('tickettypetitle', $_typeTitle);
		$_SWIFT_TicketObject->UpdatePool('prioritytitle', $_priorityTitle);

		// Create the ticket post..
		$_creatorID = $_staffID;
		if ($_creatorType == self::CREATOR_CLIENT) {
			$_creatorID = $_userID;
		}

		// Get Email Queue Name
		$_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
		$_emailQueueAddress = '';
		if (isset($_emailQueueCache['list'][$_emailQueueID])) {
			$_emailQueueAddress = $_emailQueueCache['list'][$_emailQueueID]['email'];
		}

		// Create Audit Log

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1657 Audit Log does not show email queue address via which ticket is created
		 *
		 * Comments: None
		 */
		if (!empty($_emailQueueAddress)) {
			SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_NEWTICKET, sprintf($_SWIFT->Language->Get('al_newticket_queue'), $_fullName, $_email, $_subject, $_emailQueueAddress),
				SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
		} else {
			SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_NEWTICKET, sprintf($_SWIFT->Language->Get('al_newticket'), $_fullName, $_email, $_subject),
				SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
		}

		$_ticketPostID = SWIFT_TicketPost::Create($_SWIFT_TicketObject, $_fullName, $_email, $_contents, $_creatorType, $_creatorID, $_creationMode,
			$_subject, $_emailTo, $_isHTML, false, false, $_date, $_isPrivate);

		$_SWIFT_TicketObject->UpdatePool('firstpostid', $_ticketPostID);
		$_SWIFT_TicketObject->UpdatePool('lastpostid', $_ticketPostID);
		$_SWIFT_TicketObject->UpdatePool('totalreplies', '0');


		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-965 When a new ticket is created with status "closed", 'Clear due time' setting does not work
		 *
		 * Comments: None
		 */

		// SLA & Status Properties
		$_ticketStatusContainer = $_ticketStatusCache[$_ticketStatusID];
		if ($_ticketStatusContainer['resetduetime'] == '1') {
			$_SWIFT_TicketObject->UpdatePool('duetime', '0');
			$_SWIFT_TicketObject->_noSLACalculation = true;
		}

		if ($_ticketStatusContainer['markasresolved'] == '1')
		{
			$_SWIFT_TicketObject->UpdatePool('isresolved', '1');
			$_SWIFT_TicketObject->UpdatePool('resolutiondateline', DATENOW);
			$_SWIFT_TicketObject->UpdatePool('repliestoresolution', $_SWIFT_TicketObject->GetProperty('totalreplies'));

			// How much time did it take to resolve this ticket?
			$_SWIFT_TicketObject->UpdatePool('resolutionseconds', DATENOW-$_SWIFT_TicketObject->GetProperty('dateline'));
		}

		// If the status is set to resolved then we reset the resolution due time
		$_processResolutionDue = false;
		if ($_ticketStatusContainer['markasresolved'] == '1') {
			$_SWIFT_TicketObject->UpdatePool('resolutionduedateline', '0');
			$_SWIFT_TicketObject->UpdatePool('duetime', '0');

			$_SWIFT_TicketObject->_noSLACalculation = true;

		// Otherwise if its not, and resolutionduedateline is 0 then we force it to recalculate the resolution due time
		} else if ($_ticketStatusContainer['markasresolved'] == '0' && $_SWIFT_TicketObject->GetProperty('resolutionduedateline') == '0') {
			$_processResolutionDue = true;
		}

		// Set the ticket owner
		if (!empty($_ownerStaffID)) {
			$_SWIFT_TicketObject->SetOwner(intval($_ownerStaffID));
		}

		$_SWIFT_TicketObject->ProcessSLAOverdue($_processResolutionDue);

		// Notification Event
		$_SWIFT_TicketObject->NotificationManager->SetEvent('newticket');

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($_SWIFT_TicketObject);

		// Recount the cache
		SWIFT_TicketManager::Recount(false);

		if ($_dispatchAutoResponder == true)
		{
			register_shutdown_function(array($_SWIFT_TicketObject, 'DispatchAutoresponder'));
		}

		return $_SWIFT_TicketObject;
	}

	/**
	 * Update the Ticket Record
	 *
	 * @author Varun Shoor
	 * @param string $_subject The Ticket Subject
	 * @param string $_fullName The Ticket Fullname
	 * @param string $_email The Ticket Email
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function Update($_subject, $_fullName, $_email)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// Create Audit Log
		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
			sprintf($_SWIFT->Language->Get('al_updateproperties'), StripName($this->GetProperty('subject'), 60), StripName($_subject, 60), StripName($this->GetProperty('fullname'), 30),
			StripName($_fullName, 30), StripName($this->GetProperty('email'), 40), StripName($_email, 40)), SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');

		$this->UpdatePool('subject', $_subject);
		$this->UpdatePool('fullname', $_fullName);

		$_ticketEmailAddress = $this->GetProperty('email');
		if ($this->GetProperty('replyto') != '')
		{
			$_ticketEmailAddress = $this->GetProperty('replyto');
		}

		$this->UpdatePool('oldeditemailaddress', $_ticketEmailAddress);
		$this->UpdatePool('email', $_email);
		$this->UpdatePool('replyto', $_email);

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Delete the Ticket record
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function Delete()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		self::DeleteList(array($this->GetTicketID()));

		$this->SetIsClassLoaded(false);

		return true;
	}

	/**
	 * Delete a list of Tickets
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function DeleteList($_ticketIDList)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_ticketIDList))
		{
			return false;
		}

		$_finalTicketIDList = $_departmentIDList = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord())
		{
			$_finalTicketIDList[] = intval($_SWIFT->Database->Record['ticketid']);

			$_departmentIDList[] = intval($_SWIFT->Database->Record['departmentid']);

			$_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataSTore($_SWIFT->Database->Record));

			// Create Audit Log
			SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_DELETETICKET,
				sprintf($_SWIFT->Language->Get('al_deleteticket'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT->Database->Record['subject'],
						$_SWIFT->Database->Record['fullname'], $_SWIFT->Database->Record['email']),
				SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
		}

		if (!count($_finalTicketIDList))
		{
			return false;
		}

		$_SWIFT->Database->Query("DELETE FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_finalTicketIDList) . ")");

		// Clear Ticket Posts
		SWIFT_TicketPost::DeleteOnTicket($_finalTicketIDList);

		// Clear Attachments
		SWIFT_Attachment::DeleteOnTicket($_finalTicketIDList);

		// Clear Notes
		SWIFT_TicketNote::DeleteOnTicket($_finalTicketIDList);

		// Clear Ticket Drafts
		SWIFT_TicketDraft::DeleteOnTicket($_finalTicketIDList);

		// Release the Locks
		SWIFT_TicketLock::DeleteOnTicket($_finalTicketIDList);
		SWIFT_TicketPostLock::DeleteOnTicket($_finalTicketIDList);

		// Clear the Recipients
		SWIFT_TicketRecipient::DeleteOnTicket($_finalTicketIDList);

		// Clear the Audit Logs
		SWIFT_TicketAuditLog::DeleteOnTicket($_finalTicketIDList);

		// Clear the Time Track entries
		SWIFT_TicketTimeTrack::DeleteOnTicket($_finalTicketIDList);

		// Clear the Message IDs
		SWIFT_TicketMessageID::DeleteOnTicket($_finalTicketIDList);

		// Clear the Linked Table IDs
		SWIFT_TicketLinkedTable::DeleteOnTicket($_finalTicketIDList);

		// Clear the ticket watchers
		SWIFT_TicketWatcher::DeleteOnTicket($_finalTicketIDList);

		// Clear the chains
		SWIFT_TicketLinkChain::DeleteOnTicket($_finalTicketIDList);

		// Delete the merge logs
		SWIFT_TicketMergeLog::DeleteOnTicket($_finalTicketIDList);

		// Delete the Ticket Follow-Up's
		SWIFT_TicketFollowUp::DeleteOnTicket($_finalTicketIDList);

		// Delete the Ticket Escalation Paths
		SWIFT_EscalationPath::DeleteOnTicket($_finalTicketIDList);

		// Delete the Ticket Recurrence
		SWIFT_TicketRecurrence::DeleteOnTicket($_finalTicketIDList);

		// Delete the tags
		SWIFT_TagLink::DeleteOnLinkList(SWIFT_TagLink::TYPE_TICKET, $_finalTicketIDList);

		// Rebuild count cache
		SWIFT_TicketManager::RebuildCache();

		return true;
	}

	/**
	 * Un-Delete a list of Tickets
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function UnDeleteList($_ticketIDList)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_ticketIDList))
		{
			return false;
		}

		$_finalTicketIDList = $_departmentIDList = $_ticketContainer = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord())
		{
			$_ticketContainer[$_SWIFT->Database->Record['ticketid']] = $_SWIFT->Database->Record;

			$_finalTicketIDList[] = intval($_SWIFT->Database->Record['ticketid']);

			$_departmentIDList[] = intval($_SWIFT->Database->Record['departmentid']);

			$_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataSTore($_SWIFT->Database->Record));

			// Create Audit Log
			SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_DELETETICKET,
				sprintf($_SWIFT->Language->Get('al_untrashticket'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT->Database->Record['subject'],
						$_SWIFT->Database->Record['fullname'], $_SWIFT->Database->Record['email']),
				SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
		}

		if (!count($_finalTicketIDList))
		{
			return false;
		}

		foreach ($_finalTicketIDList as $_ticketID)
		{
			$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('departmentid' => intval($_ticketContainer[$_ticketID]['trasholddepartmentid'])), 'UPDATE', "ticketid = '" . intval($_ticketID) . "'");
		}

		// Rebuild count cache
		SWIFT_TicketManager::RebuildCache();

		return true;
	}

	/**
	 * Merge a list of tickets together
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List
	 * @param int $_parentTicketID (OPTIONAL) The Parent Ticket ID
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function Merge($_ticketIDList, $_parentTicketID = false, $_staffID = false) {
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_ticketIDList) || (count($_ticketIDList) < 2 && empty($_parentTicketID))) {
			return false;
		}

		$_departmentIDList = $_ticketMaskIDList = $_mergeTicketIDList = $_mergeEmailList = array();

		if (!$_parentTicketID) {
			$_parentTicketID = $_ticketIDList[0];
		}

		// Load the parent ticket
		$_SWIFT_ParentTicketObject = new SWIFT_Ticket(new SWIFT_DataID($_parentTicketID));
		if (!$_SWIFT_ParentTicketObject instanceof SWIFT_Ticket || !$_SWIFT_ParentTicketObject->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_departmentIDList[] = $_SWIFT_ParentTicketObject->GetProperty('departmentid');

		// Load the other objects
		$_ticketObjectContainer = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord()) {
			if ($_SWIFT->Database->Record['ticketid'] == $_parentTicketID) {
				continue;
			}

			$_ticketObjectContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));

			// Create Audit Log
			$_SWIFT_TicketObject_Merge = $_ticketObjectContainer[$_SWIFT->Database->Record['ticketid']];
			SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject_Merge, null, SWIFT_TicketAuditLog::ACTION_MERGETICKET,
				sprintf($_SWIFT->Language->Get('al_merge'), $_SWIFT_TicketObject_Merge->GetTicketDisplayID(), $_SWIFT->Database->Record['subject'],
						$_SWIFT->Database->Record['fullname'], $_SWIFT->Database->Record['email']),
				SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');

			if (!in_array($_SWIFT->Database->Record['departmentid'], $_departmentIDList)) {
				$_departmentIDList[] = $_SWIFT->Database->Record['departmentid'];
			}

			$_ticketMaskIDList[] = $_SWIFT->Database->Record['ticketmaskid'];

			$_mergeTicketIDList[] = $_SWIFT->Database->Record['ticketid'];

			if (!in_array($_SWIFT->Database->Record['email'], $_mergeEmailList) &&
					$_SWIFT->Database->Record['email'] != $_SWIFT_ParentTicketObject->GetProperty('email')) {
				$_mergeEmailList[] = $_SWIFT->Database->Record['email'];
			}
		}

		/**
		 * @todo Raise Alert Here
		 */

		// By now we have the parent ticket and the child tickets, we need to start the merge process now.

		// Update Notes. !! IMPORTANT: This needs to be called before ticket posts are updated. !!
		SWIFT_TicketNoteManager::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);

		// Update Ticket Posts
		SWIFT_TicketPost::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);

		// Update Attachments
		SWIFT_Attachment::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);

		// Update the Recipients
		SWIFT_TicketRecipient::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);

		// Update the Audit Logs
		SWIFT_TicketAuditLog::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);

		// Update the Time Track entries
		SWIFT_TicketTimeTrack::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);

		// Update the Ticket Follow-Up's
		SWIFT_TicketFollowUp::ReplaceTicket($_mergeTicketIDList, $_SWIFT_ParentTicketObject);

		// Add all the recipients if needed
		if ($_SWIFT->Settings->Get('t_mergrecip') == 1 && count($_mergeEmailList))
		{
			SWIFT_TicketRecipient::Create($_SWIFT_ParentTicketObject, SWIFT_TicketRecipient::TYPE_CC, $_mergeEmailList);
		}

		// Recaclulate all properties
		$_SWIFT_ParentTicketObject->RebuildProperties();

		/**
		 * @todo Add Audit Log Entry
		 */

		// First add the Merge Log List.. this is used to route replies to the right ticket.
		foreach ($_ticketObjectContainer as $_ticketID => $_SWIFT_TicketObject) {
			SWIFT_TicketMergeLog::Create($_SWIFT_ParentTicketObject, $_SWIFT_TicketObject->GetTicketID(),
					$_SWIFT_TicketObject->GetProperty('ticketmaskid'), $_staffID);
		}

		// Delete JUST the ticket entries
		$_SWIFT->Database->Query("DELETE FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_mergeTicketIDList) . ")");

		// Clear Ticket Drafts
		SWIFT_TicketDraft::DeleteOnTicket($_mergeTicketIDList);

		// Release the Locks
		SWIFT_TicketLock::DeleteOnTicket($_mergeTicketIDList);
		SWIFT_TicketPostLock::DeleteOnTicket($_mergeTicketIDList);

		// Clear the Message IDs
		SWIFT_TicketMessageID::DeleteOnTicket($_mergeTicketIDList);

		// Clear the Linked Table IDs
		SWIFT_TicketLinkedTable::DeleteOnTicket($_mergeTicketIDList);

		// Clear the ticket watchers
		SWIFT_TicketWatcher::DeleteOnTicket($_mergeTicketIDList);

		// Clear the chains
		SWIFT_TicketLinkChain::DeleteOnTicket($_mergeTicketIDList);

		// Delete the Ticket Escalation Paths
		SWIFT_EscalationPath::DeleteOnTicket($_mergeTicketIDList);

		// Delete the Ticket Recurrence
		SWIFT_TicketRecurrence::DeleteOnTicket($_mergeTicketIDList);

		// Delete the tags
		SWIFT_TagLink::DeleteOnLinkList(SWIFT_TagLink::TYPE_TICKET, $_mergeTicketIDList);

		// Time for a recount
		SWIFT_TicketManager::RebuildCache();

		return true;
	}

	/**
	 * Move the Ticket record to trash
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function Trash()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		self::TrashList(array($this->GetTicketID()));

		return true;
	}

	/**
	 * Trash a list of Tickets
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function TrashList($_ticketIDList)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_ticketIDList))
		{
			return false;
		}

		$_finalTicketIDList = $_departmentIDList = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord())
		{
			$_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
			$_SWIFT_TicketObject->UpdateTrashDepartment();

			$_finalTicketIDList[] = intval($_SWIFT->Database->Record['ticketid']);

			$_departmentIDList[] = intval($_SWIFT->Database->Record['departmentid']);

			// Create Audit Log
			SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_TRASHTICKET,
				sprintf($_SWIFT->Language->Get('al_trashticket'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT->Database->Record['subject'],
						$_SWIFT->Database->Record['fullname'], $_SWIFT->Database->Record['email']),
				SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
		}

		if (!count($_finalTicketIDList))
		{
			return false;
		}

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('departmentid' => '0'), 'UPDATE', "ticketid IN (" .
				BuildIN($_finalTicketIDList) . ")");

		// Rebuild count cache
		SWIFT_TicketManager::RebuildCache();

		return true;
	}

	/**
	 * Update the trash department
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function UpdateTrashDepartment() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1781 Help desk is not removing the SLA while moving the tickets in Trash folder
		 *
		 */
		$this->ClearOverdue();
		$this->ClearResolutiondue();
		$this->UpdatePool('slaplanid', '0');
		$this->UpdatePool('trasholddepartmentid', $this->GetProperty('departmentid'));
		$this->ProcessUpdatePool();

		return true;
	}

	/**
	 * Ban the creator of this ticket
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @param int $_staffID (OPTIONAL) The Staff ID initiating the Ban
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function Ban($_staffID = 0)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		self::BanList(array($this->GetTicketID()), $_staffID);

		return true;
	}

	/**
	 * Ban a list of ticket ids
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List to ban
	 * @param int $_staffID (OPTIONAL) The Staff ID initiating the Ban
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function BanList($_ticketIDList, $_staffID = 0)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_ticketIDList))
		{
			return false;
		}

		$_staffCache = $_SWIFT->Cache->Get('staffcache');
		$_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
		$_rejectEmailList = array();

		foreach ($_staffCache as $_key => $_val)
		{
			$_rejectEmailList[] = mb_strtolower($_val['email']);
		}

		if (_is_array($_emailQueueCache) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
		{
			foreach ($_emailQueueCache['list'] as $_key => $_val)
			{
				$_rejectEmailList[] = mb_strtolower($_val['email']);
			}
		}

		$_finalEmailBanList = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord())
		{
			$_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));

			// Create Audit Log
			SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_BAN,
				sprintf($_SWIFT->Language->Get('al_ban'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT->Database->Record['email']),
				SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');

			if (!in_array(mb_strtolower($_SWIFT->Database->Record['email']), $_finalEmailBanList) &&
					!in_array(mb_strtolower($_SWIFT->Database->Record['email']), $_rejectEmailList))
			{
				$_finalEmailBanList[] = mb_strtolower($_SWIFT->Database->Record['email']);
			}
		}

		if (!count($_finalEmailBanList))
		{
			return false;
		}

		SWIFT_Loader::LoadModel('Ban:ParserBan', APP_PARSER);

		if (class_exists('SWIFT_ParserBan', false))
		{
			foreach ($_finalEmailBanList as $_key => $_val)
			{
				SWIFT_ParserBan::Create($_val, $_staffID);
			}
		}

		return true;
	}

	/**
	 * Recaculates the 'hasattachment' property of the given tickets
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function RecalculateHasAttachmentProperty($_ticketIDList) {
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_ticketIDList)) {
			return false;
		}

		$_finalTicketIDList = array();
		$_SWIFT->Database->Query("SELECT ticketid FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord()) {
			$_finalTicketIDList[] = $_SWIFT->Database->Record['ticketid'];
		}

		if (!count($_finalTicketIDList)) {
			return false;
		}

		// Now we calculate attachments
		$_attachmentCountContainer = array();
		$_SWIFT->Database->Query("SELECT COUNT(*) AS totalitems, ticketid FROM " . TABLE_PREFIX . "attachments GROUP BY ticketid HAVING ticketid IN (" . BuildIN($_finalTicketIDList) . ")");
		while ($_SWIFT->Database->NextRecord()) {
			$_attachmentCountContainer[$_SWIFT->Database->Record['ticketid']] = intval($_SWIFT->Database->Record['totalitems']);
		}

		$_attachmentTicketIDList = array();
		foreach ($_attachmentCountContainer as $_key => $_val) {
			if ($_val > 0) {
				$_attachmentTicketIDList[] = $_key;
			}
		}

		$_nonAttachmentTicketIDList = array();
		foreach ($_finalTicketIDList as $_ticketID) {
			if (!in_array($_ticketID, $_attachmentTicketIDList)) {
				$_nonAttachmentTicketIDList[] = $_ticketID;
			}
		}

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('hasattachments' => '1'), 'UPDATE', "ticketid IN (" . BuildIN($_attachmentTicketIDList) . ")");

		if (count($_nonAttachmentTicketIDList)) {
			$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('hasattachments' => '0'), 'UPDATE', "ticketid IN (" . BuildIN($_nonAttachmentTicketIDList) . ")");
		}

		return true;
	}

	/**
	 * Retrieve the User Group ID based on User ID
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetUserGroupID() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_userID = intval($this->GetProperty('userid'));
		if (empty($_userID)) {
			return false;
		}

		try {
			$_SWIFT_UserObject = $this->GetUserObject();

			if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded()) {
				return $_SWIFT_UserObject->GetProperty('usergroupid');
			}

		} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
			return false;
		}

		return false;
	}

	/**
	 * Retrieve the SLA properties. This array is used to process the SLA rules and the value should match the criteria specified for SWIFT_SLA
	 *
	 * @author Varun Shoor
	 * @return mixed "_slaProperties" (ARRAY) on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetSLAProperties() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_slaProperties = array();
		$_slaProperties[SWIFT_SLA::SLA_TICKETSTATUS] = $this->GetProperty('ticketstatusid');
		$_slaProperties[SWIFT_SLA::SLA_TICKETPRIORITY] = $this->GetProperty('priorityid');
		$_slaProperties[SWIFT_SLA::SLA_TICKETDEPARTMENT] = $this->GetProperty('departmentid');
		$_slaProperties[SWIFT_SLA::SLA_TICKETOWNER] = $this->GetProperty('ownerstaffid');
		$_slaProperties[SWIFT_SLA::SLA_TICKETEMAILQUEUE] = $this->GetProperty('emailqueueid');
		$_slaProperties[SWIFT_SLA::SLA_TICKETFLAGTYPE] = $this->GetProperty('flagtype');
		$_slaProperties[SWIFT_SLA::SLA_TICKETCREATOR] = $this->GetProperty('creator');
		$_slaProperties[SWIFT_SLA::SLA_TICKETUSERGROUP] = $this->GetUserGroupID();

		$_slaProperties[SWIFT_SLA::SLA_TICKETFULLNAME] = $this->GetProperty('fullname');
		$_slaProperties[SWIFT_SLA::SLA_TICKETEMAIL] = $this->GetProperty('email');
		$_slaProperties[SWIFT_SLA::SLA_TICKETLASTREPLIER] = $this->GetProperty('lastreplier');
		$_slaProperties[SWIFT_SLA::SLA_TICKETSUBJECT] = $this->GetProperty('subject');
		$_slaProperties[SWIFT_SLA::SLA_TICKETCHARSET] = $this->GetProperty('charset');

		$_slaProperties[SWIFT_SLA::SLA_TICKETTEMPLATEGROUP] = $this->GetProperty('tgroupid');
		$_slaProperties[SWIFT_SLA::SLA_TICKETISRESOLVED] = $this->GetProperty('isresolved');
		$_slaProperties[SWIFT_SLA::SLA_TICKETTYPE] = $this->GetProperty('tickettypeid');
		$_slaProperties[SWIFT_SLA::SLA_TICKETWASREOPENED] = $this->GetProperty('wasreopened');
		$_slaProperties[SWIFT_SLA::SLA_TICKETTOTALREPLIES] = $this->GetProperty('totalreplies');
		$_slaProperties[SWIFT_SLA::SLA_TICKETBAYESCATEGORY] = $this->GetProperty('bayescategoryid');

		return $_slaProperties;
	}

	/**
	 * process the SLA Overdue time
	 *
	 * @author Varun Shoor
	 * @param bool $_processResolutionDue (OPTIONAL) Whether to process the resolution due dateline
	 * @param bool $_processReplyDue      (OPTIONAL)
	 *
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function ProcessSLAOverdue($_processResolutionDue = false, $_processReplyDue = true)
	{
		$_SWIFT = SWIFT::GetInstance();
		chdir(SWIFT_BASEPATH);
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if ($this->_noSLACalculation == true || $this->GetProperty('isresolved') == '1') {
			return false;
		}

		$this->Load->Library('SLA:SLAManager');

		$_slaManagerResult = $this->SLAManager->GetDueTime($this);
		if (count($_slaManagerResult) != 2) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_SWIFT_SLAPlanObject = $_slaManagerResult[0];
		$_overDueSeconds = $_slaManagerResult[1];

		if ($_SWIFT_SLAPlanObject instanceof SWIFT_SLA && $_SWIFT_SLAPlanObject->GetIsClassLoaded()) {
			// Notification Rule
			$this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_SLAPLAN, $this->GetProperty('slaplanid'), $_SWIFT_SLAPlanObject->GetSLAPlanID());

			/*
			 * BUG FIX - Varun Shoor
			 *
			 * SWIFT-970 Resolution time is not updated according to SLA plan, while changing the ticket department using Mass Action
			 *
			 * Comments: We now force resolution due time recalculation if SLA plan changes
			 */
			if ($this->GetProperty('slaplanid') != $_SWIFT_SLAPlanObject->GetSLAPlanID()) {
				$_processResolutionDue = true;
				$_processReplyDue      = true;
			}

			$this->UpdatePool('slaplanid', $_SWIFT_SLAPlanObject->GetSLAPlanID());
			$this->UpdatePool('isescalatedvolatile', '0');


			/**
			 * BUG FIX - Parminder Singh
			 *
			 * SWIFT-795: Issue with SLA plan retention
			 *
			 * Comments: If no SLA found then clear the exising one.
			 */
		} else {
			// $this->UpdatePool('slaplanid', '0');
		}

		/**
		 * BUG FIX - Parminder Singh
		 *
		 * SWIFT-1583: "Clear the Due Time" setting under Ticket Statuses settings, does not work properly
		 *
		 * Comments: If the setting 'Clear the Due Time' is disabled and overdue seconds ($_overDueSeconds) are coming blank then no need for SLA/ overdue hours.
		 */
		$_ticketStatusCache = $this->Cache->Get('statuscache');
		if (isset($_ticketStatusCache[$this->GetProperty('ticketstatusid')])) {
			$_ticketStatusContainer = $_ticketStatusCache[$this->GetProperty('ticketstatusid')];

			/**
			 * BUG FIX - Ashish Kataria
			 *
			 * SWIFT-1946: "Clear the Due Time" setting under Ticket Statuses settings, does not work properly
			 *
			 * Comments: If the setting 'Clear the Due Time' is enabled and ticket has been marked as resolved then no need for SLA/ overdue hours when it is updated without changing the status.
			 */
			if (($_ticketStatusContainer['resetduetime'] == '0' && empty($_overDueSeconds) && $this->GetProperty('duetime') != '0')
				|| ($_ticketStatusContainer['resetduetime'] == '1' && $_ticketStatusContainer['markasresolved'] == '1')
			) {
				$this->_noSLACalculation = true;

				return true;
			}
		}

		/*
		 * BUG FIX - Abhishek Mittal
		 *
		 * SWIFT-3835: Incorrect SLA plan gets linked with the ticket when ticket is moved from a resolved status to unresolved status
		 *
		 * Comments: Update reply due time only in case if SLA plan changed
		 */
		/* Bug Fix : Saloni Dhall
		 * SWIFT-3867 : Due time get reset on performing an action on a ticket, which is in status where setting 'Clear ticket reply deadline when set to this status' is enabled.
		 * Comments : if the ticketstatus setting 'Clear ticket reply deadline' already been set to yes, then no need to set the duetime while changing ticket properties in the same status.
		 */
		if ($_processReplyDue === true && (isset($_ticketStatusCache[$this->GetProperty('ticketstatusid')]['resetduetime']) && $_ticketStatusCache[$this->GetProperty('ticketstatusid')]['resetduetime'] != '1')) {

			// Create Audit Log
			$_renderedDate = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_overDueSeconds);
			if (empty($_overDueSeconds)) {
				$_renderedDate = $this->Language->Get('duetimecleared');
			}

			SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET, sprintf($_SWIFT->Language->Get('al_due'), $_renderedDate), SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('duetime'), '', $_overDueSeconds, '');

			$this->UpdatePool('duetime', intval($_overDueSeconds));
		}

		if ($_processResolutionDue == true) {
			if (!$_SWIFT_SLAPlanObject instanceof SWIFT_SLA || !$_SWIFT_SLAPlanObject->GetIsClassLoaded())
			{
				$_SWIFT_SLAPlanObject = null;
			}

			$_slaManagerResult_ResolutionDue = $this->SLAManager->GetResolutionTime($this, $_SWIFT_SLAPlanObject);
			$_resolutionOverDueSeconds = $_slaManagerResult_ResolutionDue[1];

			// Create Audit Log
			$_resolutionRenderedDate = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_resolutionOverDueSeconds);
			if (empty($_resolutionOverDueSeconds)) {
				$_resolutionRenderedDate = $this->Language->Get('duetimecleared');
			}
			SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
				sprintf($_SWIFT->Language->Get('al_resolutiondue'), $_resolutionRenderedDate),
				SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('resolutionduedateline'), '', $_resolutionOverDueSeconds, '');

			$this->UpdatePool('resolutionduedateline', intval($_resolutionOverDueSeconds));
		}

		$this->_noSLACalculation = true;

		return true;
	}

	/**
	 * Queue the SLA Overdue calculation on shutdown
	 *
	 * @author Varun Shoor
	 * @param bool $_processResolutionDue (OPTIONAL) Whether to process the resolution due dateline
	 * @param bool $_processReplyDue      (OPTIONAL)
	 *
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function QueueSLAOverdue($_processResolutionDue = false, $_processReplyDue = true)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if ($this->_slaOverdueQueued != -1) {
			return true;
		}

		$this->_slaOverdueQueued = $_processResolutionDue;

		register_shutdown_function(array($this, 'ProcessSLAOverdue'), $this->_slaOverdueQueued, $_processReplyDue);

		return true;
	}

	/**
	 * Set a fixed SLA Plan for this Ticket
	 *
	 * @author Varun Shoor
	 * @param SWIFT_SLA $_SWIFT_SLAObject The SWIFT_SLA Object Pointer
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function SetSLA(SWIFT_SLA $_SWIFT_SLAObject) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (!$_SWIFT_SLAObject instanceof SWIFT_SLA || !$_SWIFT_SLAObject->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		// If the current sla plan and the one provided matches then bail out
		if ($this->GetProperty('ticketslaplanid') == $_SWIFT_SLAObject->GetSLAPlanID()) {
			return true;
		}

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

		// Create Audit Log
		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATESLA,
			sprintf($_SWIFT->Language->Get('al_sla'), $_SWIFT_SLAObject->GetProperty('title')),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('ticketslaplanid'), '', $_SWIFT_SLAObject->GetSLAPlanID(), '');

		// Notification Rule
		$this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_SLAPLAN, $this->GetProperty('ticketslaplanid'), $_SWIFT_SLAObject->GetSLAPlanID());

		// Notification Update
		$_oldTicketSLAPlanID = $this->GetProperty('ticketslaplanid');
		$_oldSLATitle = $_newSLATitle = '';
		if ($_oldTicketSLAPlanID != '0') {
			if (isset($_slaPlanCache[$_oldTicketSLAPlanID])) {
				$_oldSLATitle = $_slaPlanCache[$_oldTicketSLAPlanID]['title'];
			} else {
				$_oldSLATitle = $this->Language->Get('na');
			}
		}

		$_newSLATitle = $_SWIFT_SLAObject->GetProperty('title');

		$this->Notification->Update($this->Language->Get('notification_sla'), $_oldSLATitle, $_newSLATitle);

		$this->UpdatePool('ticketslaplanid', intval($_SWIFT_SLAObject->GetSLAPlanID()));
		$this->UpdatePool('slaplanid', intval($_SWIFT_SLAObject->GetSLAPlanID()));
		$this->UpdatePool('isescalatedvolatile', '0');

		// We set these to 0 and expect the sla processing engine to set the correct values
//		$this->UpdatePool('duetime', '0');
//		$this->UpdatePool('resolutionduedateline', '0');

		$this->_noSLACalculation = false;
		$this->ProcessSLAOverdue(true);
//		$this->QueueSLAOverdue(true);

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Clear the fixed Ticket SLA Plan
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function ClearSLA() {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if ($this->GetProperty('ticketslaplanid') == '0') {
			return true;
		}

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

		// Create Audit Log
		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATESLA,
			$_SWIFT->Language->Get('al_slaclear'),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('ticketslaplanid'), '', 0, '');

		// Notification Update
		$_oldTicketSLAPlanID = $this->GetProperty('ticketslaplanid');
		$_oldSLATitle = $_newSLATitle = '';
		if ($_oldTicketSLAPlanID != '0') {
			if (isset($_slaPlanCache[$_oldTicketSLAPlanID])) {
				$_oldSLATitle = $_slaPlanCache[$_oldTicketSLAPlanID]['title'];
			} else {
				$_oldSLATitle = $this->Language->Get('na');
			}
		}

		$_newSLATitle = $this->Language->Get('notificationcleared');

		$this->Notification->Update($this->Language->Get('notification_sla'), $_oldSLATitle, $_newSLATitle);

		$this->UpdatePool('ticketslaplanid', 0);

		$this->QueueSLAOverdue();

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Escalate this Ticket
	 *
	 * @author Varun Shoor
	 * @param SWIFT_EscalationRule $_SWIFT_EscalationRuleObject
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function Escalate(SWIFT_EscalationRule $_SWIFT_EscalationRuleObject) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (!$_SWIFT_EscalationRuleObject instanceof SWIFT_EscalationRule || !$_SWIFT_EscalationRuleObject->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_staffCache = $this->Cache->Get('staffcache');

		// We execute this before all arguments so that if a custom SLA plan is set, it can override this value.
		$this->UpdatePool('isescalatedvolatile', '1');

		SWIFT_EscalationPath::Create($this, $this->GetProperty('slaplanid'), $_SWIFT_EscalationRuleObject->GetEscalationRuleID(),
				$this->GetProperty('ownerstaffid'), $this->GetProperty('departmentid'), $this->GetProperty('ticketstatusid'),
				$this->GetProperty('priorityid'), $this->GetProperty('tickettypeid'), $this->GetProperty('flagtype'));

		if ($_SWIFT_EscalationRuleObject->GetProperty('staffid') != '-1' && $_SWIFT_EscalationRuleObject->GetProperty('staffid') != '0' && isset($_staffCache[$_SWIFT_EscalationRuleObject->GetProperty('staffid')]))
		{
			$this->SetOwner($_SWIFT_EscalationRuleObject->GetProperty('staffid'));
		}

		if ($_SWIFT_EscalationRuleObject->GetProperty('departmentid') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('departmentid') != '-1')
		{
			$this->SetDepartment($_SWIFT_EscalationRuleObject->GetProperty('departmentid'));
		}

		if ($_SWIFT_EscalationRuleObject->GetProperty('ticketstatusid') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('ticketstatusid') != '-1')
		{
			$this->SetStatus($_SWIFT_EscalationRuleObject->GetProperty('ticketstatusid'));
		}

		if ($_SWIFT_EscalationRuleObject->GetProperty('priorityid') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('priorityid') != '-1')
		{
			$this->SetPriority($_SWIFT_EscalationRuleObject->GetProperty('priorityid'));
		}

		if ($_SWIFT_EscalationRuleObject->GetProperty('tickettypeid') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('tickettypeid') != '-1')
		{
			$this->SetType($_SWIFT_EscalationRuleObject->GetProperty('tickettypeid'));
		}

		if ($_SWIFT_EscalationRuleObject->GetProperty('flagtype') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('flagtype') != '-1')
		{
			$this->SetFlag($_SWIFT_EscalationRuleObject->GetProperty('flagtype'));
		}

		/**
		 * BUG FIX - Mansi Wason <mansi.wason@kayako.com>
		 *
		 * SWIFT-4444: "Disabled SLA plan gets applied on the ticket if set in the triggered Escalation rule."
		 *
		 * Comments: If the SLA plan is enabled only than it is applied.
		 */
		if ($_SWIFT_EscalationRuleObject->GetProperty('newslaplanid') != '0' && $_SWIFT_EscalationRuleObject->GetProperty('newslaplanid') != '-1') {
			$_slaObject = new SWIFT_SLA(new SWIFT_DataID($_SWIFT_EscalationRuleObject->GetProperty('newslaplanid')));
			if ($_slaObject->GetProperty('isenabled') == '1') {
				$this->SetSLA($_slaObject);
			}
		}

		if ($_SWIFT_EscalationRuleObject->GetProperty('addtags') != '')
		{
			$_tagContainer = json_decode($_SWIFT_EscalationRuleObject->GetProperty('addtags'));
			if (is_array($_tagContainer)) {
				SWIFT_Tag::AddTags(SWIFT_TagLink::TYPE_TICKET, $this->GetTicketID(),
						$_tagContainer, false);
			}
		}

		if ($_SWIFT_EscalationRuleObject->GetProperty('removetags') != '')
		{
			$_tagContainer = json_decode($_SWIFT_EscalationRuleObject->GetProperty('removetags'));
			if (is_array($_tagContainer)) {
				SWIFT_Tag::RemoveTags(SWIFT_TagLink::TYPE_TICKET, array($this->GetTicketID()),
					$_tagContainer, false);
			}

		}

		$this->UpdatePool('escalationruleid', $_SWIFT_EscalationRuleObject->GetEscalationRuleID());
		$this->UpdatePool('isescalated', '1');
		$this->UpdatePool('escalatedtime', DATENOW);
		$this->UpdatePool('escalationlevelcount', ($this->GetProperty('escalationlevelcount')+1));

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Mark the ticket as watched
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function MarkAsWatched() {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('iswatched', '1');

		return true;
	}

	/**
	 * Mark the ticket as overdue
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function MarkAsDue() {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// Create Audit Log
		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
			$_SWIFT->Language->Get('al_duestaffoverdue'),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('duetime'), '', DATENOW, '');

		// Notification Update
		$_newDueDate = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, DATENOW);
		$this->Notification->Update($this->Language->Get('notification_due'), '', $_newDueDate);


		$this->UpdatePool('duetime', DATENOW);

		// Prevent SLA Calculation
		$this->_noSLACalculation = true;

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Clear the overdue time
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function ClearOverdue() {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// Prevent calculation of SLA due time on this ticket
		$this->_noSLACalculation = true;

		if ($this->GetProperty('duetime') == '0') {
			return true;
		}

		// Create Audit Log
		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
			$_SWIFT->Language->Get('al_duestaffclear'),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('duetime'), '', 0, '');

		// Notification Update
		$_oldDueDate = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $this->GetProperty('duetime'));
		$_newDueDate = $this->Language->Get('notificationcleared');

		$this->Notification->Update($this->Language->Get('notification_due'), $_oldDueDate, $_newDueDate);

		$this->UpdatePool('duetime', '0');

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Set the Template Group
	 *
	 * @author Varun Shoor
	 * @param int $_templateGroupID The Template Group ID
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function SetTemplateGroup($_templateGroupID)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('tgroupid', intval($_templateGroupID));

		return true;
	}

	/**
	 * Clear the resolution time
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function ClearResolutionDue() {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if ($this->GetProperty('resolutionduedateline') == '0') {
			return true;
		}

		// Create Audit Log
		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
			$_SWIFT->Language->Get('al_resduestaffclear'),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('resolutionduedateline'), '', 0, '');

		// Notification Update
		$_oldDueDate = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $this->GetProperty('resolutionduedateline'));
		$_newDueDate = $this->Language->Get('notificationcleared');

		$this->Notification->Update($this->Language->Get('notification_resolutiondue'), $_oldDueDate, $_newDueDate);

		$this->UpdatePool('resolutionduedateline', '0');

		// Prevent calculation of SLA due time on this ticket
		$this->_noSLACalculation = true;

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Set a flag on this ticket
	 *
	 * @author Varun Shoor
	 * @param constant $_flagType The Flag Type
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function SetFlag($_flagType) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->Load->Library('Flag:TicketFlag');
		$_flagContainer = $this->TicketFlag->GetFlagContainer();

		if ($_flagType == '0') {
			// Notification Update
			$_oldFlagTitle = '';
			if (isset($_flagContainer[$this->GetProperty('flagtype')])) {
				$_oldFlagTitle = $_flagContainer[$this->GetProperty('flagtype')][0];
			}
			$_newFlagTitle = $this->Language->Get('notificationcleared');

			$this->Notification->Update($this->Language->Get('notification_flag'), $_oldFlagTitle, $_newFlagTitle);

			$this->UpdatePool('flagtype', '0');

			$this->QueueSLAOverdue();

			return true;
		}

		if (!SWIFT_TicketFlag::IsValidFlagType($_flagType)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		// If this ticket already has a flag set which matches the one specified.. then move on
		if ($this->GetProperty('flagtype') == $_flagType) {
			return true;
		}

		// Create Audit Log
		$_flagTitle = $_flagContainer[$_flagType][0];

		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATEFLAG,
			sprintf($_SWIFT->Language->Get('al_flag'), $_flagTitle),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('flagtype'), '', $_flagType, '');

		// Notification Rule
		$this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_FLAGTYPE, $this->GetProperty('flagtype'), $_flagType);

		// Notification Update
		$_oldFlagTitle = '';
		if (isset($_flagContainer[$this->GetProperty('flagtype')])) {
			$_oldFlagTitle = $_flagContainer[$this->GetProperty('flagtype')][0];
		}
		$_newFlagTitle = $_flagTitle;

		$this->Notification->Update($this->Language->Get('notification_flag'), $_oldFlagTitle, $_newFlagTitle);

		$this->UpdatePool('flagtype', intval($_flagType));

		$this->QueueSLAOverdue(false,false);

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Clear a flag on a ticket
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function ClearFlag() {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// If there is no flag set, then ignore.
		if ($this->GetProperty('flagtype') == '0') {
			return true;
		}

		$_SWIFT_TicketFlagObject = new SWIFT_TicketFlag();
		$_flagContainer = $_SWIFT_TicketFlagObject->GetFlagContainer();

		// Create Audit Log
		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATEFLAG,
			$_SWIFT->Language->Get('al_flagclear'),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('flagtype'), '', 0, '');

		// Notification Update
		$_oldFlagTitle = '';
		if (isset($_flagContainer[$this->GetProperty('flagtype')])) {
			$_oldFlagTitle = $_flagContainer[$this->GetProperty('flagtype')][0];
		}
		$_newFlagTitle = $this->Language->Get('notificationcleared');

		$this->Notification->Update($this->Language->Get('notification_flag'), $_oldFlagTitle, $_newFlagTitle);

		$this->UpdatePool('flagtype', 0);

		$this->QueueSLAOverdue();

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Change the department for the ticket
	 *
	 * @author Varun Shoor
	 * @param int $_departmentID The department id
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or if Invalid Data is Provided
	 */
	public function SetDepartment($_departmentID) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (empty($_departmentID)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_departmentCache = $this->Cache->Get('departmentcache');
		if (!isset($_departmentCache[$_departmentID])) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		// If the ticket is already in this department then bail out
		if ($this->GetProperty('departmentid') == $_departmentID) {
			return true;
		}

		// Add old and new department to recount queue
//		SWIFT_TicketManager::Recount($this->GetProperty('departmentid'));
//		SWIFT_TicketManager::Recount($_departmentID);
		SWIFT_TicketManager::Recount(false);

		// Create Audit Log
		$_oldDepartmentTitle = $_newDepartmentTitle = '';
		if (isset($_departmentCache[$this->GetProperty('departmentid')])) {
			$_oldDepartmentTitle = $_departmentCache[$this->GetProperty('departmentid')]['title'];
		}

		if ($this->GetProperty('departmentid') == '0') {
			$_oldDepartmentTitle = $this->Language->Get('trash');
		}

		$_newDepartmentTitle = $_departmentCache[$_departmentID]['title'];

		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATEDEPARTMENT,
			sprintf($_SWIFT->Language->Get('al_department'), $_oldDepartmentTitle, $_newDepartmentTitle),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('departmentid'), '', $_departmentID, '');

		// Notification Rule
		$this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_DEPARTMENT, $this->GetProperty('departmentid'), $_departmentID);

		// Notification Update
		$_oldNotificationDepartmentTitle = $_newNotificationDepartmentTitle = '';
		if ($_oldDepartmentTitle == '') {
			$_oldNotificationDepartmentTitle = $this->Language->Get('na');
		} else {
			$_oldNotificationDepartmentTitle = $_oldDepartmentTitle;
		}

		$_newNotificationDepartmentTitle = $_newDepartmentTitle;

		$_oldUserNotificationDepartmentTitle = $_oldNotificationDepartmentTitle;
		$_newUserNotificationDepartmentTitle = $_newNotificationDepartmentTitle;

		if (isset($_departmentCache[$this->GetProperty('departmentid')]) && $_departmentCache[$this->GetProperty('departmentid')]['departmenttype'] == SWIFT_PRIVATE) {
			$_oldUserNotificationDepartmentTitle = $this->Language->Get('private');
		}

		if (isset($_departmentCache[$_departmentID]) && $_departmentCache[$_departmentID]['departmenttype'] == SWIFT_PRIVATE) {
			$_newUserNotificationDepartmentTitle = $this->Language->Get('private');
		}

		$this->Notification->Update($this->Language->Get('notification_department'), $_oldNotificationDepartmentTitle, $_newNotificationDepartmentTitle, $_oldUserNotificationDepartmentTitle, $_newUserNotificationDepartmentTitle);

		$this->UpdatePool('departmentid', intval($_departmentID));
		$this->UpdatePool('departmenttitle', $_newDepartmentTitle);

		$this->QueueSLAOverdue(false,false);

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Set the Ticket Type
	 *
	 * @author Varun Shoor
	 * @param int $_ticketTypeID The Ticket Type ID
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function SetType($_ticketTypeID) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (empty($_ticketTypeID)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		// Verify value of ticket type
		$_ticketTypeCache = $this->Cache->Get('tickettypecache');
		if (!isset($_ticketTypeCache[$_ticketTypeID])) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_ticketTypeContainer = $_ticketTypeCache[$_ticketTypeID];

		// If current ticket type is same as the new type then bail out
		if ($this->GetProperty('tickettypeid') == $_ticketTypeID) {
			return true;
		}

		// Verify the department id link of ticket type

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1298 Issue with ticket types and ticket statuses, if they are linked with Parent department
		 *
		 * Comments: None
		 */
		$_departmentCache = $this->Cache->Get('departmentcache');
		$_parentDepartmentID = false;
		if (isset($_departmentCache[$this->GetProperty('departmentid')])) {
			$_parentDepartmentID = $_departmentCache[$this->GetProperty('departmentid')]['parentdepartmentid'];
		}

		if ($_ticketTypeContainer['departmentid'] != '0' && $_ticketTypeContainer['departmentid'] != $this->GetProperty('departmentid') && $_ticketTypeContainer['departmentid'] != $_parentDepartmentID) {
			throw new SWIFT_Ticket_Exception('Ticket Type (' . intval($_ticketTypeID) . ') & Department ID (' . intval($this->GetProperty('departmentid')) . ') Mismatch');
		}

		// Create Audit Log
		$_oldTypeTitle = $_newTypeTitle = '';
		if (isset($_ticketTypeCache[$this->GetProperty('tickettypeid')])) {
			$_oldTypeTitle = $_ticketTypeCache[$this->GetProperty('tickettypeid')]['title'];
		}

		$_newTypeTitle = $_ticketTypeCache[$_ticketTypeID]['title'];

		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETYPE,
			sprintf($_SWIFT->Language->Get('al_type'), $_oldTypeTitle, $_newTypeTitle),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('tickettypeid'), '', $_ticketTypeID, '');

		// Notification Rule
		$this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_TICKETTYPE, $this->GetProperty('tickettypeid'), $_ticketTypeID);

		// Notification Update
		$_oldNotificationTypeTitle = $_newNotificationTypeTitle = '';
		if ($_oldTypeTitle == '') {
			$_oldNotificationTypeTitle = $this->Language->Get('na');
		} else {
			$_oldNotificationTypeTitle = $_oldTypeTitle;
		}

		$_newNotificationTypeTitle = $_newTypeTitle;

		$_oldUserNotificationTypeTitle = $_oldNotificationTypeTitle;
		$_newUserNotificationTypeTitle = $_newNotificationTypeTitle;

		/**
		 * BUG FIX - Simaranjit Singh
		 *
		 * SWIFT-2945:  Notice generated when Ticket Type is set from '-NA-' to an available Ticket Type
		 *
		 * Comments: None
		 */
		if (isset($_ticketTypeCache[$this->GetProperty('tickettypeid')]) && $_ticketTypeCache[$this->GetProperty('tickettypeid')]['type'] == SWIFT_PRIVATE) {
			$_oldUserNotificationTypeTitle = $this->Language->Get('private');
		}

		if ($_ticketTypeCache[$_ticketTypeID]['type'] == SWIFT_PRIVATE) {
			$_newUserNotificationTypeTitle = $this->Language->Get('private');
		}

		$this->Notification->Update($this->Language->Get('notification_type'), $_oldNotificationTypeTitle, $_newNotificationTypeTitle, $_oldUserNotificationTypeTitle, $_newUserNotificationTypeTitle);


		$this->UpdatePool('tickettypeid', intval($_ticketTypeID));
		$this->UpdatePool('tickettypetitle', $_newTypeTitle);

//		SWIFT_TicketManager::Recount($this->GetProperty('departmentid'));
		SWIFT_TicketManager::Recount(false);

		$this->QueueSLAOverdue(false,false);

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Set the Has Status Changed Property
	 *
	 * @author Varun Shoor
	 * @param bool $_hasStatusChanged
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function SetHasStatusChanged($_hasStatusChanged)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->_hasStatusChanged = $_hasStatusChanged;

		return true;
	}

	/**
	 * Retrieve the Has Status Changed Property
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetHasStatusChanged()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		return $this->_hasStatusChanged;
	}

	/**
	 * Set the Ticket Status
	 *
	 * @author Varun Shoor
	 * @param int $_ticketStatusID The Ticket Status ID
	 * @param bool $_isViaAutoClose (OPTIONAL) If the status change is via auto close
	 * @param bool $_suppressSurveyEmail (OPTIONAL) Whether to suppress survey email
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function SetStatus($_ticketStatusID, $_isViaAutoClose = false, $_suppressSurveyEmail = false) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

		} else if (empty($_ticketStatusID)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_ticketStatusCache = $this->Cache->Get('statuscache');
		if (!isset($_ticketStatusCache[$_ticketStatusID])) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_ticketStatusContainer = $_ticketStatusCache[$_ticketStatusID];

		$this->SetHasStatusChanged(true);

		// If the current ticket status id matches then bail out
		if ($this->GetProperty('ticketstatusid') == $_ticketStatusID) {
			return true;
		}

		// Verify the department id link of ticket status

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1298 Issue with ticket types and ticket statuses, if they are linked with Parent department
		 *
		 * Comments: None
		 */
		$_departmentCache = $this->Cache->Get('departmentcache');
		$_parentDepartmentID = false;
		if (isset($_departmentCache[$this->GetProperty('departmentid')])) {
			$_parentDepartmentID = $_departmentCache[$this->GetProperty('departmentid')]['parentdepartmentid'];
		}

		if ($_ticketStatusContainer['departmentid'] != '0' && $_ticketStatusContainer['departmentid'] != $this->GetProperty('departmentid') && $_ticketStatusContainer['departmentid'] != $_parentDepartmentID) {
			throw new SWIFT_Ticket_Exception('Ticket Status (' . intval($_ticketStatusID) . ') & Department ID (' . intval($this->GetProperty('departmentid')) . ') Mismatch');
		}

		// Create Audit Log
		$_oldStatusTitle = $_newStatusTitle = '';
		if (isset($_ticketStatusCache[$this->GetProperty('ticketstatusid')])) {
			$_oldStatusTitle = $_ticketStatusCache[$this->GetProperty('ticketstatusid')]['title'];
		}

		$_newStatusTitle = $_ticketStatusCache[$_ticketStatusID]['title'];

		$_statusLanguageKey = 'al_status';
		if ($_isViaAutoClose) {
			$_statusLanguageKey = 'al_statusautoclose';
		}

		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATESTATUS,
			sprintf($_SWIFT->Language->Get($_statusLanguageKey), $_oldStatusTitle, $_newStatusTitle),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('ticketstatusid'), '', $_ticketStatusID, '');

		// Notification Rule
		$this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_TICKETSTATUS, $this->GetProperty('ticketstatusid'), $_ticketStatusID);

		// Notification Update
		$_oldNotificationStatusTitle = $_newNotificationStatusTitle = '';
		if ($_oldStatusTitle == '') {
			$_oldNotificationStatusTitle = $this->Language->Get('na');
		} else {
			$_oldNotificationStatusTitle = $_oldStatusTitle;
		}

		$_newNotificationStatusTitle = $_newStatusTitle;

		$_oldUserNotificationStatusTitle = $_oldNotificationStatusTitle;
		$_newUserNotificationStatusTitle = $_newNotificationStatusTitle;

		/**
		 * BUG FIX - Ravi sharma <ravi.sharma@kayako.com>
		 *
		 * SWIFT-3202 Undefined offset: 0 (D:/xampp/htdocs/kayako/__apps/tickets/models/Ticket/class.SWIFT_Ticket.php:2420)
		 */
		if (isset($_ticketStatusCache[$this->Get('ticketstatusid')]) && isset($_ticketStatusCache[$this->Get('ticketstatusid')]['statustype']) && $_ticketStatusCache[$this->Get('ticketstatusid')]['statustype'] == SWIFT_PRIVATE) {
			$_oldUserNotificationStatusTitle = $this->Language->Get('private');
		}

		if ($_ticketStatusCache[$_ticketStatusID]['statustype'] == SWIFT_PRIVATE) {
			$_newUserNotificationStatusTitle = $this->Language->Get('private');
		}

		$this->Notification->Update($this->Language->Get('notification_status'), $_oldNotificationStatusTitle, $_newNotificationStatusTitle, $_oldUserNotificationStatusTitle, $_newUserNotificationStatusTitle);

		$this->UpdatePool('ticketstatusid', intval($_ticketStatusID));
		$this->UpdatePool('ticketstatustitle', $_newStatusTitle);

//		SWIFT_TicketManager::Recount($this->GetProperty('departmentid'));
		SWIFT_TicketManager::Recount(false);

		// Was reopened?
		if ($_ticketStatusContainer['markasresolved'] == '0' && $this->GetProperty('isresolved') == '1') {
			$this->UpdatePool('wasreopened', '1');
			$this->UpdatePool('reopendateline', DATENOW);
		}

		if ($_ticketStatusContainer['resetduetime'] == '1') {
			$this->ClearOverdue();
		}

		if ($_ticketStatusContainer['markasresolved'] == '1')
		{
			$this->UpdatePool('isresolved', '1');
			$this->UpdatePool('resolutiondateline', DATENOW);
			$this->UpdatePool('repliestoresolution', $this->GetProperty('totalreplies'));

			// How much time did it take to resolve this ticket?
			$this->UpdatePool('resolutionseconds', DATENOW-$this->GetProperty('dateline'));
		} else {
			$this->UpdatePool('isresolved', '0');

			// Are we changing to an unresolved status and ticket is marked as auto closed or pending closure?
			if ($this->GetProperty('autoclosestatus') != self::AUTOCLOSESTATUS_NONE) {
				$this->UpdatePool('autoclosestatus', self::AUTOCLOSESTATUS_NONE);
				$this->UpdatePool('isautoclosed', '0');
				$this->UpdatePool('autoclosetimeline', '0');
			}
		}

		// If the status is set to resolved then we reset the resolution due time
		$_processResolutionDue = false;
		if ($_ticketStatusContainer['markasresolved'] == '1') {
			$this->UpdatePool('resolutionduedateline', '0');
			$this->UpdatePool('duetime', '0');
			$this->UpdatePool('slaplanid', '0');

			$this->_noSLACalculation = true;

		// Otherwise if its not, and resolutionduedateline is 0 then we force it to recalculate the resolution due time
		} else if ($_ticketStatusContainer['markasresolved'] == '0' && $this->GetProperty('resolutionduedateline') == '0') {
			$_processResolutionDue = true;
		}

		$this->QueueSLAOverdue($_processResolutionDue, false);

		// Is First Contact Resolved?
		if ($this->GetProperty('totalreplies') == '0' && $_ticketStatusContainer['markasresolved'] == '1' && $this->GetProperty('isfirstcontactresolved') == '0') {
			$this->UpdatePool('isfirstcontactresolved', '1');
		}

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);
		/**
		 * BUG FIX : Nidhi Gupta <nidhi.gupta@kayako.com>
		 *
		 * SWIFT-3020 Survey Email arrives first followed by ticket reply.
		 *
		 * Comments: Code placement changes.
		 */
		// Do we have to trigger a survey?
		if ($_ticketStatusContainer['triggersurvey'] == '1' && !$_suppressSurveyEmail)
		{
			$this->Load->Library('Ticket:TicketEmailDispatch', array($this));
			$this->TicketEmailDispatch->DispatchSurvey();
		}

		return true;
	}

	/**
	 * Set the Ticket Priority
	 *
	 * @author Varun Shoor
	 * @param int $_ticketPriorityID The Ticket Priority ID
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function SetPriority($_ticketPriorityID) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (empty($_ticketPriorityID)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_ticketPriorityCache = $this->Cache->Get('prioritycache');
		if (!isset($_ticketPriorityCache[$_ticketPriorityID])) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_ticketPriorityContainer = $_ticketPriorityCache[$_ticketPriorityID];

		// If the current ticket priority id matches then bail out
		if ($this->GetProperty('priorityid') == $_ticketPriorityID) {
			return true;
		}

		// Create Audit Log
		$_oldPriorityTitle = $_newPriorityTitle = '';
		if (isset($_ticketPriorityCache[$this->GetProperty('priorityid')])) {
			$_oldPriorityTitle = $_ticketPriorityCache[$this->GetProperty('priorityid')]['title'];
		}

		$_newPriorityTitle = $_ticketPriorityCache[$_ticketPriorityID]['title'];

		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATEPRIORITY,
			sprintf($_SWIFT->Language->Get('al_priority'), $_oldPriorityTitle, $_newPriorityTitle),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('priorityid'), '', $_ticketPriorityID, '');

		// Notification Rule
		$this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_TICKETPRIORITY, $this->GetProperty('priorityid'), $_ticketPriorityID);

		// Notification Update
		$_oldNotificationPriorityTitle = $_newNotificationPriorityTitle = '';
		if ($_oldPriorityTitle == '') {
			$_oldNotificationPriorityTitle = $this->Language->Get('na');
		} else {
			$_oldNotificationPriorityTitle = $_oldPriorityTitle;
		}

		$_newNotificationPriorityTitle = $_newPriorityTitle;

		$_oldUserNotificationPriorityTitle = $_oldNotificationPriorityTitle;
		$_newUserNotificationPriorityTitle = $_newNotificationPriorityTitle;

		/*
		 * BUG FIX - Gurpreet Singh
		 *
		 * SWIFT-3416 Undefined offset error when using mass action in ticket view
		 */
		if (isset($_ticketPriorityCache[$this->GetProperty('priorityid')]['type']) && $_ticketPriorityCache[$this->GetProperty('priorityid')]['type'] == SWIFT_PRIVATE) {
			$_oldUserNotificationPriorityTitle = $this->Language->Get('private');
		}

		if ($_ticketPriorityCache[$_ticketPriorityID]['type'] == SWIFT_PRIVATE) {
			$_newUserNotificationPriorityTitle = $this->Language->Get('private');
		}

		$this->Notification->Update($this->Language->Get('notification_priority'), $_oldNotificationPriorityTitle, $_newNotificationPriorityTitle, $_oldUserNotificationPriorityTitle, $_newUserNotificationPriorityTitle);

		$this->UpdatePool('priorityid', intval($_ticketPriorityID));
		$this->UpdatePool('prioritytitle', $_newPriorityTitle);

//		SWIFT_TicketManager::Recount($this->GetProperty('departmentid'));
		SWIFT_TicketManager::Recount(false);

		$this->QueueSLAOverdue(false, false);

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Set the Ticket Owner
	 *
	 * @author Varun Shoor
	 * @param int $_staffID The Owner Staff ID
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function SetOwner($_staffID) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_staffCache = $this->Cache->Get('staffcache');
		if ($_staffID != 0 && !isset($_staffCache[$_staffID])) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		// If the current owner matches the one provided then bail out
		if ($this->GetProperty('ownerstaffid') == $_staffID) {
			return true;
		}

		// Create Audit Log
		$_oldOwnerTitle = $_newOwnerTitle = '';
		if (isset($_staffCache[$this->GetProperty('ownerstaffid')])) {
			$_oldOwnerTitle = $_staffCache[$this->GetProperty('ownerstaffid')]['fullname'];
		}

		if ($this->GetProperty('ownerstaffid') == '0') {
			$_oldOwnerTitle = $this->Language->Get('unassigned');
		}

		if ($_staffID == '0') {
			$_newOwnerTitle = $this->Language->Get('unassigned');
		} else {
			$_newOwnerTitle = $_staffCache[$_staffID]['fullname'];
		}

		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATEOWNER,
			sprintf($_SWIFT->Language->Get('al_owner'), $_oldOwnerTitle, $_newOwnerTitle),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('ownerstaffid'), '', $_staffID, '');

		// Notification Event
		$this->NotificationManager->SetEvent('ticketassigned');

		// Notification Rule
		$this->NotificationManager->Changed(SWIFT_NotificationRule::CRITERIA_OWNER, $this->GetProperty('ownerstaffid'), $_staffID);

		// Notification Update
		$_oldNotificationOwnerTitle = $_newNotificationOwnerTitle = '';
		if ($_oldOwnerTitle == '') {
			$_oldNotificationOwnerTitle = $this->Language->Get('na');
		} else {
			$_oldNotificationOwnerTitle = $_oldOwnerTitle;
		}

		$_newNotificationOwnerTitle = $_newOwnerTitle;

		$this->Notification->Update($this->Language->Get('notification_staff'), $_oldNotificationOwnerTitle, $_newNotificationOwnerTitle);


		$this->UpdatePool('ownerstaffid', intval($_staffID));

		$_staffName = '';
		if (isset($_staffCache[$_staffID])) {
			$_staffName = $_staffCache[$_staffID]['fullname'];
		}

		$this->UpdatePool('ownerstaffname', $_staffName);

		// How many owners did it take to resolve this ticket?
		$this->UpdatePool('resolutionlevel', intval($this->GetProperty('resolutionlevel'))+1);

//		SWIFT_TicketManager::Recount($this->GetProperty('departmentid'));
		SWIFT_TicketManager::Recount(false);

		$this->QueueSLAOverdue(false,false);

		// Load the last notification message for ticket assigned alert
		$this->LoadLastPostNotificationMessage();

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Set the Due Time
	 *
	 * @author Varun Shoor
	 * @param string $_dueDateline The Due Dateline
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function SetDue($_dueDateline) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (empty($_dueDateline)) {
			return false;
		}

		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
			sprintf($_SWIFT->Language->Get('al_due'), SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_dueDateline)),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('duetime'), '', $_dueDateline, '');

		// Notification Update
		$_oldNotificationDueTitle = $_newNotificationDueTitle = '';
		if ($this->GetProperty('duetime') == '0') {
			$_oldNotificationDueTitle = $this->Language->Get('na');
		} else {
			$_oldNotificationDueTitle = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $this->GetProperty('duetime'));
		}

		$_newNotificationDueTitle = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_dueDateline);

		$this->Notification->Update($this->Language->Get('notification_due'), $_oldNotificationDueTitle, $_newNotificationDueTitle);

		// Prevent calculation of SLA due time on this ticket
		$this->_noSLACalculation = true;

		$this->UpdatePool('duetime', intval($_dueDateline));

		return true;
	}

	/**
	 * Set the Resolution Due Time
	 *
	 * @author Varun Shoor
	 * @param string $_dueDateline The Due Dateline
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function SetResolutionDue($_dueDateline) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (empty($_dueDateline)) {
			return false;
		}

		SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_UPDATETICKET,
			sprintf($_SWIFT->Language->Get('al_resolutiondue'), SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_dueDateline)),
			SWIFT_TicketAuditLog::VALUE_NONE, $this->GetProperty('duetime'), '', $_dueDateline, '');

		// Notification Update
		$_oldNotificationDueTitle = $_newNotificationDueTitle = '';
		if ($this->GetProperty('resolutionduedateline') == '0') {
			$_oldNotificationDueTitle = $this->Language->Get('na');
		} else {
			$_oldNotificationDueTitle = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $this->GetProperty('resolutionduedateline'));
		}

		$_newNotificationDueTitle = SWIFT_Date::Get(SWIFT_Date::TYPE_DATETIME, $_dueDateline);

		$this->Notification->Update($this->Language->Get('notification_resolutiondue'), $_oldNotificationDueTitle, $_newNotificationDueTitle);

		// Prevent calculation of SLA due time on this ticket
		$this->_noSLACalculation = true;

		$this->UpdatePool('resolutionduedateline', intval($_dueDateline));

		return true;
	}

	/**
	 * Retrieve the linked tickets in the active chain
	 *
	 * @author Varun Shoor
	 * @return array The Linked Ticket Container
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetLinks() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if ($this->GetProperty('islinked') == '0') {
			return array();
		}

		// First get all the chain hashes where this ticket is part of
		$_chainHashList = array();
		$this->Database->Query("SELECT chainhash FROM " . TABLE_PREFIX . "ticketlinkchains WHERE ticketid = '" . intval($this->GetTicketID()) .
				"'");
		while ($this->Database->NextRecord()) {
			$_chainHashList[] = $this->Database->Record['chainhash'];
		}

		if (!count($_chainHashList)) {
			return array();
		}

		// Now get all the tickets that are part of the chain hashes
		$_ticketLinkContainer = array();
		$this->Database->Query("SELECT tickets.*, ticketlinkchains.ticketlinktypeid FROM " . TABLE_PREFIX . "ticketlinkchains AS ticketlinkchains
			LEFT JOIN " . TABLE_PREFIX . "tickets AS tickets ON (ticketlinkchains.ticketid = tickets.ticketid) WHERE
			chainhash IN (" . BuildIN($_chainHashList) . ")");
		while ($this->Database->NextRecord()) {
			if ($this->Database->Record['ticketid'] == $this->GetTicketID()) {
				continue;
			}

			$_ticketLinkContainer[$this->Database->Record['ticketlinktypeid']][$this->Database->Record['ticketid']] =
					new SWIFT_Ticket(new SWIFT_DataStore($this->Database->Record));
		}

		return $_ticketLinkContainer;
	}

	/**
	 * Mark ticket as linked
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function MarkAsLinked() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('islinked', '1');

		return true;
	}

	/**
	 * Mark ticket as unlinked
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function MarkAsUnlinked() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('islinked', '0');

		return true;
	}

	/**
	 * Lock a Ticket
	 *
	 * @author Varun Shoor
	 * @param SWIFT_Staff $_SWIFT_StaffObject The SWIFT_Staff Object Pointer
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function Lock(SWIFT_Staff $_SWIFT_StaffObject) {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (!$_SWIFT_StaffObject instanceof SWIFT_Staff || !$_SWIFT_StaffObject->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		SWIFT_TicketLock::Create($this, $_SWIFT_StaffObject);

		return true;
	}

	/**
	 * Unlock the ticket completely
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function Unlock() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		SWIFT_TicketLock::DeleteOnTicket(array($this->GetTicketID()));

		return true;
	}

	/**
	 * Rebuild the Ticket Properties (hasnotes, hasattachments etc.)
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function RebuildProperties() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_ticketStatusCache = $this->Cache->Get('statuscache');

		/**
		 * BUG FIX - Parminder Singh
		 *
		 * SWIFT-1894: 'Trash' count does not clear the ticket count in case a department is deleted
		 *
		 */

		$_departmentCache = $this->Cache->Get('departmentcache');

		if ($this->GetProperty('trasholddepartmentid') != '0' && !isset($_departmentCache[$this->GetProperty('trasholddepartmentid')])) {
			$this->UpdatePool('trasholddepartmentid', '0');
		}

		// First Post, Last Post & Total Replies
		$_ticketPostIDContainer = $this->Database->QueryFetch("SELECT MIN(ticketpostid) AS firstpostid, MAX(ticketpostid) AS lastpostid,
			COUNT(*) AS totalreplies FROM " . TABLE_PREFIX . "ticketposts WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
		if (isset($_ticketPostIDContainer['firstpostid']) && !empty($_ticketPostIDContainer['firstpostid']))
		{
			$this->UpdatePool('firstpostid', intval($_ticketPostIDContainer['firstpostid']));
		}

		if (isset($_ticketPostIDContainer['lastpostid']) && !empty($_ticketPostIDContainer['lastpostid']))
		{
			$this->UpdatePool('lastpostid', intval($_ticketPostIDContainer['lastpostid']));

			$_lastTicketPostContainer = $this->Database->QueryFetch("SELECT fullname, dateline FROM " . TABLE_PREFIX . "ticketposts WHERE
				ticketpostid = '" . intval($_ticketPostIDContainer['lastpostid']) . "'");

			if (isset($_lastTicketPostContainer['fullname']) && !empty($_lastTicketPostContainer['fullname']))
			{
				$this->UpdatePool('lastreplier', $_lastTicketPostContainer['fullname']);
			}

			if (isset($_lastTicketPostContainer['dateline']) && $_lastTicketPostContainer['dateline'] > $this->GetProperty('lastactivity'))
			{
				$this->UpdatePool('lastactivity', intval($_lastTicketPostContainer['dateline']));
			}
		}

		if (isset($_ticketPostIDContainer['totalreplies']))
		{
			// We deduct by 1 to ignore the original ticket post as a reply
			if ($_ticketPostIDContainer['totalreplies'] > 0)
			{
				$_ticketPostIDContainer['totalreplies']--;
			}

			$this->UpdatePool('totalreplies', intval($_ticketPostIDContainer['totalreplies']));
		}

		// Has Notes?
		$_hasNotesContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalnotes FROM " . TABLE_PREFIX . "ticketnotes WHERE
			linktypeid = '" . intval($this->GetTicketID()) . "' AND linktype = '" . SWIFT_TicketNoteManager::LINKTYPE_TICKET . "'");

		$this->UpdatePool('hasnotes', IIF($_hasNotesContainer['totalnotes'] > 0, '1', '0'));


		/**
		 * BUG FIX - Simaranjit Singh
		 *
		 * SWIFT-2576: 'hasattachments' field is not getting saved if ticket is having attachments
		 *
		 * Comments: Update hasattachments for ticket posts also
		 */

		$_ticketPostIDList = array();

		// Has Attachments?
		$this->Database->Query("SELECT linktypeid AS ticketpostid FROM " . TABLE_PREFIX . "attachments WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
		while ($this->Database->NextRecord()) {
			$_ticketPostIDList[] = $this->Database->Record['ticketpostid'];
		}

		$this->UpdatePool('hasattachments', IIF(count($_ticketPostIDList) > 0, '1', '0'));

		if (_is_array($_ticketPostIDList)) {

			// First, set hasattachment to '0' for this ticket ID
			$this->Database->AutoExecute(TABLE_PREFIX . 'ticketposts', array('hasattachments' => '0'), 'UPDATE', "ticketid = '" . intval($this->GetTicketID()) . "'");
			// Now, set hasattachment to '1' based on ticket post ID list
			$this->Database->AutoExecute(TABLE_PREFIX . 'ticketposts', array('hasattachments' => '1'), 'UPDATE', "ticketpostid IN (" . BuildIN($_ticketPostIDList) . ")");
		}

		// Has Draft?
		$_hasDraftContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "ticketdrafts WHERE
			ticketid = '" . intval($this->GetTicketID()) . "'");

		$this->UpdatePool('hasdraft', IIF($_hasDraftContainer['totalitems'] > 0, '1', '0'));

		// Has Billing Entries?
		$_hasBillingContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "tickettimetracks WHERE
			ticketid = '" . intval($this->GetTicketID()) . "'");

		$this->UpdatePool('hasbilling', IIF($_hasBillingContainer['totalitems'] > 0, '1', '0'));

		// Has Follow-Up's?
		$_hasFollowUpContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "ticketfollowups WHERE
			ticketid = '" . intval($this->GetTicketID()) . "'");

		$this->UpdatePool('hasfollowup', IIF($_hasFollowUpContainer['totalitems'] > 0, '1', '0'));
		$this->UpdatePool('followupcount', intval($_hasFollowUpContainer['totalitems']));

		// Update time worked + time billed
		$_ticketTimeWorked = $_ticketTimeBillable = 0;
		$this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickettimetracks WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
		while ($this->Database->NextRecord())
		{
			$_ticketTimeWorked += intval($this->Database->Record['timespent']);
			$_ticketTimeBillable += intval($this->Database->Record['timebillable']);
		}

		$this->UpdateTimeTrack($_ticketTimeWorked, $_ticketTimeBillable);

		// Is Resolved
		if (isset($_ticketStatusCache[$this->GetProperty('ticketstatusid')])) {
			if ($_ticketStatusCache[$this->GetProperty('ticketstatusid')]['markasresolved'] == '1')
			{
				$this->UpdatePool('isresolved', '1');
				$this->UpdatePool('repliestoresolution', $this->GetProperty('totalreplies'));
			} else {
				$this->UpdatePool('isresolved', '0');
			}
		}

		// Rebuild the titles & names
		$this->RebuildTitles();

		// Calculate the additional properties
		$this->CalculateProperties();

		// Load and Process Workflow Rules
		self::AddToWorkflowQueue($this);

		return true;
	}

	/**
	 * Rebuilds the titles associated with the ticket
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function RebuildTitles()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_departmentCache = $this->Cache->Get('departmentcache');
		$_staffCache = $this->Cache->Get('staffcache');
		$_ticketStatusCache = $this->Cache->Get('statuscache');
		$_ticketPriorityCache = $this->Cache->Get('prioritycache');
		$_ticketTypeCache = $this->Cache->Get('tickettypecache');
		$_slaPlanCache = $this->Cache->Get('slaplancache');
		$_escalationRuleCache = $this->Cache->Get('escalationrulecache');

		// Build local properties
		if (isset($_departmentCache[$this->GetProperty('departmentid')])) {
			$this->UpdatePool('departmenttitle', $_departmentCache[$this->GetProperty('departmentid')]['title']);
		}

		if (isset($_staffCache[$this->GetProperty('ownerstaffid')])) {
			$this->UpdatePool('ownerstaffname', $_staffCache[$this->GetProperty('ownerstaffid')]['fullname']);
		}

		if (isset($_ticketStatusCache[$this->GetProperty('ticketstatusid')])) {
			$this->UpdatePool('ticketstatustitle', $_ticketStatusCache[$this->GetProperty('ticketstatusid')]['title']);
		}

		if (isset($_ticketPriorityCache[$this->GetProperty('priorityid')])) {
			$this->UpdatePool('prioritytitle', $_ticketPriorityCache[$this->GetProperty('priorityid')]['title']);
		}

		if (isset($_ticketTypeCache[$this->GetProperty('tickettypeid')])) {
			$this->UpdatePool('tickettypetitle', $_ticketTypeCache[$this->GetProperty('tickettypeid')]['title']);
		}

		// Ticket Drafts
		$_ticketDraftUpdateContainer = array();
		$this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "ticketdrafts WHERE ticketid = '" . $this->GetTicketID() . "'");
		while ($this->Database->NextRecord()) {
			$_ticketDraftUpdateContainer[$this->Database->Record['ticketdraftid']] = $this->Database->Record;

			/*
			 * BUG FIX - Abhishek Mittal
			 *
			 * SWIFT-3833: Illegal string offset 'staffname'
			 */
			if (isset($_staffCache[$this->Database->Record['staffid']])) {
				$_ticketDraftUpdateContainer[$this->Database->Record['ticketdraftid']]['staffname'] = $_staffCache[$this->Database->Record['staffid']]['fullname'];
			}

			if (isset($_staffCache[$this->Database->Record['editedbystaffid']])) {
				$_ticketDraftUpdateContainer[$this->Database->Record['ticketdraftid']]['editedstaffname'] = $_staffCache[$this->Database->Record['editedbystaffid']]['fullname'];
			}
		}

		foreach ($_ticketDraftUpdateContainer as $_ticketDraftID => $_ticketDraft) {
			SWIFT_TicketDraft::UpdateStaffName($_ticketDraftID, $_ticketDraft['staffname'], $_ticketDraft['editedstaffname']);
		}
		unset($_ticketDraftUpdateContainer);

		// Ticket Audit Logs
		$_ticketAuditLogUpdateContainer = array();
		$this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "ticketauditlogs WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
		while ($this->Database->NextRecord()) {
			$_ticketAuditLogUpdateContainer[$this->Database->Record['ticketauditlogid']] = $this->Database->Record;

			if (isset($_departmentCache[$this->Database->Record['departmentid']])) {
				$_ticketAuditLogUpdateContainer[$this->Database->Record['ticketauditlogid']]['departmenttitle'] = $_departmentCache[$this->Database->Record['departmentid']]['title'];
			}

			if ($this->Database->Record['creatortype'] == SWIFT_TicketAuditLog::CREATOR_STAFF && isset($_staffCache[$this->Database->Record['creatorid']])) {
				$_ticketAuditLogUpdateContainer[$this->Database->Record['ticketauditlogid']]['creatorfullname'] = $_staffCache[$this->Database->Record['creatorid']]['fullname'];
			}
		}

		foreach ($_ticketAuditLogUpdateContainer as $_ticketAuditLogID => $_ticketAuditLog) {
			SWIFT_TicketAuditLog::UpdateProperties($_ticketAuditLogID, $_ticketAuditLog['departmenttitle'], $_ticketAuditLog['creatorfullname']);
		}
		unset($_ticketAuditLogUpdateContainer);

		// Ticket Notes
		$_ticketNoteUpdateContainer = array();
		$this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "ticketnotes
			WHERE linktype = '" . SWIFT_TicketNote::LINKTYPE_TICKET . "' AND linktypeid = '" . intval($this->GetTicketID()) . "'");
		while ($this->Database->NextRecord()) {
			$_ticketNoteUpdateContainer[$this->Database->Record['ticketnoteid']] = $this->Database->Record;

			if (isset($_staffCache[$this->Database->Record['staffid']])) {
				$_ticketNoteUpdateContainer[$this->Database->Record['ticketnoteid']]['staffname'] = $_staffCache[$this->Database->Record['staffid']]['fullname'];
			}

			if (isset($_staffCache[$this->Database->Record['editedstaffid']])) {
				$_ticketNoteUpdateContainer[$this->Database->Record['ticketnoteid']]['editedstaffname'] = $_staffCache[$this->Database->Record['editedstaffid']]['fullname'];
			}
		}

		foreach ($_ticketNoteUpdateContainer as $_ticketNoteID => $_ticketNote) {
			SWIFT_TicketNoteManager::UpdateProperties($_ticketNoteID, $_ticketNote['staffname'], $_ticketNote['editedstaffname']);
		}

		unset($_ticketNoteUpdateContainer);

		// Ticket Time Tracks
		$_ticketTimeTrackUpdateContainer = array();
		$this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickettimetracks WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
		while ($this->Database->NextRecord()) {
			$_ticketTimeTrackUpdateContainer[$this->Database->Record['tickettimetrackid']] = $this->Database->Record;

			if (isset($_staffCache[$this->Database->Record['creatorstaffid']])) {
				$_ticketTimeTrackUpdateContainer[$this->Database->Record['tickettimetrackid']]['creatorstaffname'] = $_staffCache[$this->Database->Record['creatorstaffid']]['fullname'];
			}

			if (isset($_staffCache[$this->Database->Record['editedstaffid']])) {
				$_ticketTimeTrackUpdateContainer[$this->Database->Record['tickettimetrackid']]['editedstaffname'] = $_staffCache[$this->Database->Record['editedstaffid']]['fullname'];
			}

			if (isset($_staffCache[$this->Database->Record['workerstaffid']])) {
				$_ticketTimeTrackUpdateContainer[$this->Database->Record['tickettimetrackid']]['workerstaffname'] = $_staffCache[$this->Database->Record['workerstaffid']]['fullname'];
			}
		}

		foreach ($_ticketTimeTrackUpdateContainer as $_ticketTimeTrackID => $_ticketTimeTrack) {
			SWIFT_TicketTimeTrack::UpdateProperties($_ticketTimeTrackID, $_ticketTimeTrack['creatorstaffname'], $_ticketTimeTrack['editedstaffname'], $_ticketTimeTrack['workerstaffname']);
		}
		unset($_ticketTimeTrackUpdateContainer);

		// Escalation Paths
		$_escalationPathUpdateContainer = array();
		$this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "escalationpaths WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
		while ($this->Database->NextRecord()) {
			$_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']] = $this->Database->Record;

			if (isset($_slaPlanCache[$this->Database->Record['slaplanid']])) {
				$_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['slaplantitle'] = $_slaPlanCache[$this->Database->Record['slaplanid']]['title'];
			}

			if (isset($_escalationRuleCache[$this->Database->Record['escalationruleid']])) {
				$_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['escalationruletitle'] = $_escalationRuleCache[$this->Database->Record['escalationruleid']]['title'];
			}

			if (isset($_staffCache[$this->Database->Record['ownerstaffid']])) {
				$_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['ownerstaffname'] = $_staffCache[$this->Database->Record['ownerstaffid']]['fullname'];
			}

			if (isset($_departmentCache[$this->Database->Record['departmentid']])) {
				$_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['departmenttitle'] = $_departmentCache[$this->Database->Record['departmentid']]['title'];
			}

			if (isset($_ticketStatusCache[$this->Database->Record['ticketstatusid']])) {
				$_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['ticketstatustitle'] = $_ticketStatusCache[$this->Database->Record['ticketstatusid']]['title'];
			}

			if (isset($_ticketPriorityCache[$this->Database->Record['priorityid']])) {
				$_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['prioritytitle'] = $_ticketPriorityCache[$this->Database->Record['priorityid']]['title'];
			}

			if (isset($_ticketTypeCache[$this->Database->Record['tickettypeid']])) {
				$_escalationPathUpdateContainer[$this->Database->Record['escalationpathid']]['tickettypetitle'] = $_ticketTypeCache[$this->Database->Record['tickettypeid']]['title'];
			}
		}

		foreach ($_escalationPathUpdateContainer as $_escalationPathID => $_escalationPath) {
			SWIFT_EscalationPath::UpdateProperties($_escalationPathID, $_escalationPath['slaplantitle'], $_escalationPath['escalationruletitle'], $_escalationPath['ownerstaffname'],
					$_escalationPath['departmenttitle'], $_escalationPath['ticketstatustitle'], $_escalationPath['prioritytitle'], $_escalationPath['tickettypetitle']);
		}
		unset($_escalationPathUpdateContainer);

		return true;
	}

	/**
	 * Calculate the Ticket Properties like is firstcontactresolved etc.
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function CalculateProperties() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_SWIFT_TicketPostObject_Last = false;
		try {
			$_SWIFT_TicketPostObject_Last = new SWIFT_TicketPost(new SWIFT_DataID($this->GetProperty('lastpostid')));
		} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
		}

		// Is First Contact Resolved?
		if ($this->GetProperty('totalreplies') == '1' && $_SWIFT_TicketPostObject_Last instanceof SWIFT_TicketPost && $_SWIFT_TicketPostObject_Last->GetIsClassLoaded() && $_SWIFT_TicketPostObject_Last->GetProperty('creator') == SWIFT_TicketPost::CREATOR_STAFF
				&& $this->GetProperty('isresolved') == '1' && $this->GetProperty('isfirstcontactresolved') == '0') {
			$this->UpdatePool('isfirstcontactresolved', '1');
		}

		$_lastActivity = $this->GetProperty('lastactivity');
		$_lastPostActivity = $_lastActivity;
		if ($_SWIFT_TicketPostObject_Last instanceof SWIFT_TicketPost && $_SWIFT_TicketPostObject_Last->GetIsClassLoaded()) {
			$_lastPostActivity = $_SWIFT_TicketPostObject_Last->GetProperty('dateline');
		}

		$_finalLastActivity = $_lastActivity;
		if ($_lastPostActivity > $_finalLastActivity) {
			$_finalLastActivity = $_lastPostActivity;
		}

		if ($this->GetProperty('isresolved') == '1') {
			$this->UpdatePool('resolutiondateline', $_finalLastActivity);

			// How much time did it take to resolve this ticket?
			$this->UpdatePool('resolutionseconds', $_finalLastActivity-$this->GetProperty('dateline'));
		} else {
			$this->UpdatePool('resolutiondateline', '0');
			$this->UpdatePool('resolutionseconds', '0');
		}

		// Is watched?
		$_ticketWatcherCountContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "ticketwatchers WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
		if (isset($_ticketWatcherCountContainer['totalitems']) && $_ticketWatcherCountContainer['totalitems'] > 0) {
			$this->UpdatePool('iswatched', '1');
		} else {
			$this->UpdatePool('iswatched', '0');
		}

		// Calculate the average response time
		$this->UpdatePool('averageresponsetime', '0');
		$this->UpdatePool('averageresponsetimehits', '0');

		$_ticketPostContainer = array();
		$_oldPostDateline = $_lastPostDateline = 0;
		$this->Database->Query("SELECT ticketpostid, dateline, creator FROM " . TABLE_PREFIX . "ticketposts WHERE ticketid = '" . intval($this->GetTicketID()) . "' ORDER BY ticketpostid ASC");
		while ($this->Database->NextRecord()) {
			$_ticketPostContainer[$this->Database->Record['ticketpostid']] = $this->Database->Record;
		}

		$_firstResponseTime = 0;

		foreach ($_ticketPostContainer as $_ticketPostID => $_ticketPost) {
			if (!empty($_lastPostDateline)) {
				$_responseTime = $_ticketPost['dateline'] - $_lastPostDateline;

				$_postFirstResponseTime = 0;

				if (empty($_firstResponseTime) && $_ticketPost['creator'] == SWIFT_TicketPost::CREATOR_STAFF) {
					/**
					 * BUG FIX - Ravi Sharma <ravi.sharma@kayako.com>
					 *
					 * SWIFT-3929 First Response Time returns negative value for merged tickets
					 *
					 * Comments: Calculating response time from ticket posts, irrespective of ticket creation time.
					 */
					$_firstResponseTime = (int) $_ticketPost['dateline'] - reset($_ticketPostContainer)['dateline'];
					$_postFirstResponseTime = $_firstResponseTime;
				}

				$_updateContainer = array();
				$_updateContainer['responsetime'] = $_responseTime;

				if (!empty($_postFirstResponseTime)) {
					$_updateContainer['firstresponsetime'] = $_postFirstResponseTime;
				}

				$this->Database->AutoExecute(TABLE_PREFIX . 'ticketposts', $_updateContainer, 'UPDATE', "ticketpostid = '" . intval($_ticketPostID) . "'");
			}

			if ($_ticketPost['creator'] != SWIFT_TicketPost::CREATOR_STAFF) {
				$_oldPostDateline = $_ticketPost['dateline'];
			} else if (!empty($_oldPostDateline) && $_ticketPost['creator'] == SWIFT_TicketPost::CREATOR_STAFF) {
				$_responseTime = $_ticketPost['dateline']-$_oldPostDateline;
				$this->UpdateAverageResponseTime($_responseTime);

				$_oldPostDateline = 0;
			}

			$_lastPostDateline = $_ticketPost['dateline'];
		}

		if (!empty($_firstResponseTime)) {
			$this->UpdatePool('firstresponsetime', intval($_firstResponseTime));
		}

		return true;
	}

	/**
	 * Change the ticket's hasattachments property to true
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function MarkHasAttachments() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('hasattachments', '1');

		return true;
	}

	/**
	 * Change the ticket's hasratings property to true
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function MarkHasRatings() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('hasratings', '1');

		return true;
	}

	/**
	 * Change the ticket's hasfollowup property to true
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function MarkHasFollowUp() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('hasfollowup', '1');

		return true;
	}

	/**
	 * Change the ticket's hasdraft property to true
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function MarkHasDraft() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('hasdraft', '1');

		return true;
	}

	/**
	 * Change the ticket's hasdraft property to false
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function ClearHasDraft() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('hasdraft', '0');

		return true;
	}

	/**
	 * Change the ticket's hasnotes property to true
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function MarkHasNotes() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('hasnotes', '1');

		return true;
	}

	/**
	 * Change the ticket's hasbilling property to true
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function MarkHasBilling() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('hasbilling', '1');

		return true;
	}

	/**
	 * Update the time tracking information
	 *
	 * @author Varun Shoor
	 * @param int $_timeSpent The Time Spent
	 * @param int $_timeBilled The Time Billed
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function UpdateTimeTrack($_timeSpent, $_timeBilled)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('timeworked', intval($_timeSpent));
		$this->UpdatePool('timebilled', intval($_timeBilled));

		return true;
	}

	/**
	 * Set the Message ID for this Ticket
	 *
	 * @author Varun Shoor
	 * @param string $_messageID The Message ID
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function SetMessageID($_messageID) {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (empty($_messageID)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$this->UpdatePool('messageid', $_messageID);

		return true;
	}

	/**
	 * Check to see if the given staff/user can access the ticket
	 *
	 * @author Varun Shoor
	 * @param SWIFT_Base $_SWIFT_BaseObject The SWIFT_Base Object Pointer
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function CanAccess($_SWIFT_BaseObject) {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if ((!$_SWIFT_BaseObject instanceof SWIFT_Staff || !$_SWIFT_BaseObject->GetIsClassLoaded()) &&
				(!$_SWIFT_BaseObject instanceof SWIFT_User || !$_SWIFT_BaseObject->GetIsClassLoaded())) {
			return false;
		}

		// Staff Check
		if ($_SWIFT_BaseObject instanceof SWIFT_Staff)
		{
			$_assignedDepartmentIDList = $_SWIFT_BaseObject->GetAssignedDepartments(APP_TICKETS);

			if (in_array($this->GetProperty('departmentid'), $_assignedDepartmentIDList)) {
				return true;
			} else if ($this->GetProperty('departmentid') == '0'
					&& ($this->GetProperty('trasholddepartmentid') == '0' || in_array($this->GetProperty('trasholddepartmentid'), $_assignedDepartmentIDList))) {
				return true;
			}

		// User Check
		} else if ($_SWIFT_BaseObject instanceof SWIFT_User) {
			$_userEmailList = array();
			$_userID = $_SWIFT_BaseObject->GetUserID();
			$_userEmailList = array_merge($_userEmailList, $_SWIFT_BaseObject->GetEmailList());

			$_userIDList = array($_SWIFT_BaseObject->GetUserID());

			// Does this user have a shared organization or he is a manager in an organization?
			$_SWIFT_UserOrganizationObject = $_SWIFT_BaseObject->GetOrganization();

			if (($_SWIFT_BaseObject->GetProperty('userrole') == SWIFT_User::ROLE_MANAGER && $_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded()) ||
					($_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded() && $_SWIFT_UserOrganizationObject->GetProperty('organizationtype') == SWIFT_UserOrganization::TYPE_SHARED))
			{
				$_userIDList_Organization = array();
				$this->Database->Query("SELECT userid FROM " . TABLE_PREFIX . "users
					WHERE userorganizationid = '" . intval($_SWIFT_UserOrganizationObject->GetUserOrganizationID()) . "'");
				while ($this->Database->NextRecord())
				{
					$_userIDList_Organization[] = $this->Database->Record['userid'];

					$_userIDList[] = $this->Database->Record['userid'];
				}

				$_userEmailList = array_merge($_userEmailList, SWIFT_UserEmail::RetrieveListOnUserIDList($_userIDList_Organization));
			}

			if ($this->GetProperty('userid') != '0' && in_array($this->GetProperty('userid'), $_userIDList))
			{
				return true;
			} else if (in_array(mb_strtolower($this->GetProperty('email')), $_userEmailList)) {
				return true;
			} else if ($this->GetProperty('creator') == SWIFT_Ticket::CREATOR_STAFF && in_array(mb_strtolower($this->GetProperty('replyto')), $_userEmailList)) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Return the Ticket ID to be displayed according to relevant setting
	 *
	 * @author Varun Shoor
	 * @return mixed Ticket Mask ID or Ticket ID
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetTicketDisplayID() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		return IIF($this->Settings->Get('t_eticketid') == 'seq', $this->GetProperty('ticketid'), $this->GetProperty('ticketmaskid'));
	}

	/**
	 * Recalculate the Ticket Link Property
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function RecalculateTicketLinkProperty($_ticketIDList) {
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_ticketIDList)) {
			return false;
		}

		$_ticketContainer = $_ticketLinkStatus = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord()) {
			$_ticketContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
		}

		// Calculate the link chains
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "ticketlinkchains WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord()) {
			$_ticketLinkStatus[] = $_SWIFT->Database->Record['ticketid'];
		}

		foreach ($_ticketContainer as $_ticketID => $_SWIFT_TicketObject) {
			if (in_array($_ticketID, $_ticketLinkStatus)) {
				$_SWIFT_TicketObject->MarkAsLinked();
			} else {
				$_SWIFT_TicketObject->MarkAsUnlinked();
			}
		}

		return true;
	}

	/**
	 * Get the ticket post count
	 *
	 * @author Varun Shoor
	 * @return int The Ticket Post Count
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetTicketPostCount() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_totalCount = 0;

		$_totalItemContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "ticketposts WHERE ticketid = '" .
				intval($this->GetTicketID()) . "'");
		if (isset($_totalItemContainer['totalitems'])) {
			$_totalCount = intval($_totalItemContainer['totalitems']);
		}

		return $_totalCount;
	}

	/**
	 * Retrieve the ticket posts associated with this ticket
	 *
	 * @author Varun Shoor
	 * @param int $_offset (OPTIONAL) The Starting Offset
	 * @param int $_limit (OPTIONAL) The Number of Results to Return
	 * @param string $_sortOrder (OPTIONAL) ASC/DESC The Sort Order
	 * @param constant $_creator (OPTIONAL) Filter by the Creator
	 * @return array The Ticket Post Object Container
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetTicketPosts($_offset = 0, $_limit = false, $_sortOrder = 'ASC', $_creator = false) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_ticketPostObjectContainer = array();

		$_sqlQuery = "SELECT * FROM " . TABLE_PREFIX . "ticketposts WHERE ticketid = '" . intval($this->GetTicketID()) . "' ORDER BY ticketpostid " .
				$_sortOrder;
		if (!empty($_limit)) {
			$this->Database->QueryLimit($_sqlQuery, $_limit, $_offset);
		} else {
			$this->Database->Query($_sqlQuery);
		}

		while ($this->Database->NextRecord()) {
			if (!empty($_creator) && $_creator != $this->Database->Record['creator']) {
				continue;
			}

			$_ticketPostObjectContainer[$this->Database->Record['ticketpostid']] = new SWIFT_TicketPost(new SWIFT_DataStore($this->Database->Record));
		}

		return $_ticketPostObjectContainer;
	}

	/**
	 * Train the given tickets
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function TrainBayesList($_ticketIDList, $_bayesCategoryID) {
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_ticketIDList)) {
			return false;
		} else if (empty($_bayesCategoryID)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_bayesianCategoryCache = $_SWIFT->Cache->Get('bayesiancategorycache');

		$_SWIFT_BayesianObject = new SWIFT_Bayesian();
		if (!$_SWIFT_BayesianObject instanceof SWIFT_Bayesian || !$_SWIFT_BayesianObject->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		if (!isset($_bayesianCategoryCache[$_bayesCategoryID]))
		{
			throw new SWIFT_Ticket_Exception('Bayesian Category does not exist');
		}

		$_ticketObjectContainer = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord()) {
			$_ticketObjectContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
		}

		foreach ($_ticketObjectContainer as $_ticketID => $_SWIFT_TicketObject) {
			$_ticketPostContainer = $_SWIFT_TicketObject->GetTicketPosts(0, false, 'ASC', SWIFT_Ticket::CREATOR_CLIENT);
			if (!_is_array($_ticketPostContainer)) {
				continue;
			}

			$_finalTicketPostText = $_SWIFT_TicketObject->GetProperty('subject');
			foreach ($_ticketPostContainer as $_ticketPostID => $_SWIFT_TicketPostObject) {
				$_finalTicketPostText .= $_SWIFT_TicketPostObject->GetProperty('contents') . SWIFT_CRLF;
			}

			$_SWIFT_BayesianObject->Train($_ticketID, $_bayesCategoryID, $_finalTicketPostText);
		}

		return true;
	}

	/**
	 * Train the Bayesian
	 *
	 * @author Varun Shoor
	 * @param int $_bayesCategoryID The Bayesian Category ID
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function TrainBayes($_bayesCategoryID)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (empty($_bayesCategoryID)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		self::TrainBayesList(array($this->GetTicketID()), $_bayesCategoryID);

		return true;
	}

	/**
	 * Mark the given ticket ids as spam
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function MarkAsSpamList($_ticketIDList) {
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_ticketIDList)) {
			return false;
		}

		$_bayesianCategoryCache = $_SWIFT->Cache->Get('bayesiancategorycache');

		$_SWIFT_BayesianObject = new SWIFT_Bayesian();
		if (!$_SWIFT_BayesianObject instanceof SWIFT_Bayesian || !$_SWIFT_BayesianObject->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_bayesCategoryID = false;
		foreach ($_bayesianCategoryCache as $_bayesianCategoryID => $_bayesianCategoryContainer) {
			if ($_bayesianCategoryContainer['categorytype'] == SWIFT_BayesianCategory::CATEGORY_SPAM) {
				$_bayesCategoryID = $_bayesianCategoryContainer['bayescategoryid'];

				break;
			}
		}

		if (!$_bayesCategoryID) {
			throw new SWIFT_Ticket_Exception('Spam Bayesian Category not found');
		}

		$_ticketObjectContainer = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord()) {
			$_ticketObjectContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
		}

		foreach ($_ticketObjectContainer as $_ticketID => $_SWIFT_TicketObject) {
			$_ticketPostContainer = $_SWIFT_TicketObject->GetTicketPosts(0, false, 'ASC', SWIFT_Ticket::CREATOR_CLIENT);
			if (!_is_array($_ticketPostContainer)) {
				continue;
			}

			$_finalTicketPostText = $_SWIFT_TicketObject->GetProperty('subject');
			foreach ($_ticketPostContainer as $_ticketPostID => $_SWIFT_TicketPostObject) {
				$_finalTicketPostText .= $_SWIFT_TicketPostObject->GetProperty('contents') . SWIFT_CRLF;
			}

			$_SWIFT_BayesianObject->Train($_ticketID, $_bayesCategoryID, $_finalTicketPostText);
		}

		if ($_SWIFT->Settings->Get('t_spammovetotrash') == '1') {
			self::TrashList($_ticketIDList);
		}

		if ($_SWIFT->Settings->Get('t_spamban') == '1') {
			self::BanList($_ticketIDList, $_SWIFT->Staff->GetStaffID());
		}

		return true;
	}

	/**
	 * Watch a ticket list
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function Watch($_ticketIDList, SWIFT_Staff $_SWIFT_StaffObject) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$_SWIFT_StaffObject instanceof SWIFT_Staff || !$_SWIFT_StaffObject->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		} else if (!_is_array($_ticketIDList)) {
			return false;
		}

		$_ticketObjectContainer = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord()) {
			$_ticketObjectContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
		}

		if (!count($_ticketObjectContainer)) {
			return false;
		}

		foreach ($_ticketObjectContainer as $_ticketID => $_SWIFT_TicketObject) {
			// Create Audit Log
			SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, null, SWIFT_TicketAuditLog::ACTION_WATCH,
				sprintf($_SWIFT->Language->Get('al_watch'), $_SWIFT_TicketObject->GetTicketDisplayID(), $_SWIFT_StaffObject->GetProperty('fullname')),
				SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');

			SWIFT_TicketWatcher::Create($_SWIFT_TicketObject, $_SWIFT_StaffObject);
		}

		return true;
	}

	/**
	 * Unwatch a ticket list
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Ticket ID List
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function UnWatch($_ticketIDList, SWIFT_Staff $_SWIFT_StaffObject) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$_SWIFT_StaffObject instanceof SWIFT_Staff || !$_SWIFT_StaffObject->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		} else if (!_is_array($_ticketIDList)) {
			return false;
		}

		SWIFT_TicketWatcher::DeleteOnTicket($_ticketIDList, array($_SWIFT_StaffObject->GetStaffID()));

		return true;
	}

	/**
	 * Add the object to the active workflow queue
	 *
	 * @author Varun Shoor
	 * @param SWIFT_Ticket $_SWIFT_TicketObject The SWIFT_Ticket Object Pointer
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function AddToWorkflowQueue(SWIFT_Ticket $_SWIFT_TicketObject) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		} else if (isset(self::$_workflowQueue[$_SWIFT_TicketObject->GetTicketID()])) {
			return true;
		}

		self::$_workflowQueue[$_SWIFT_TicketObject->GetTicketID()] = $_SWIFT_TicketObject;

		if (self::$_isWorkflowQueueActive) {
			return true;
		}

		self::$_isWorkflowQueueActive = true;

		SWIFT::Shutdown('SWIFT_Ticket', 'ProcessWorkflowQueue', 9, false);

		return true;
	}

	/**
	 * Process the workflow queue for each active ticket
	 *
	 * @author Varun Shoor <varun.shoor@kayako.com>
	 * @author Nidhi Gupta <nidhi.gupta@kayako.com>
	 *
	 * @return bool
	 *
	 * @throws SWIFT_Ticket_Exception
	 */
	static public function ProcessWorkflowQueue()
	{
		//$_SWIFT = SWIFT::GetInstance();

		if (!count(self::$_workflowQueue)) {
			return true;
		}

		$_ticketWorkflowIDContainer = $_ticketIDList = array();

		foreach (self::$_workflowQueue as $_ticketID => $_SWIFT_TicketObject) {
			$_ticketWorkflowIDContainer[$_ticketID] = SWIFT_TicketWorkflow::ExecuteAll($_SWIFT_TicketObject);

			$_ticketIDList[] = $_ticketID;
		}

		if (!count($_ticketWorkflowIDContainer)) {
			self::$_workflowQueue         = array();
			self::$_isWorkflowQueueActive = false;

			return false;
		}

		SWIFT_TicketLinkedTable::DeleteOnTicket($_ticketIDList, SWIFT_TicketLinkedTable::LINKTYPE_WORKFLOW);

		foreach ($_ticketWorkflowIDContainer as $_ticketID => $_ticketWorkflowIDList) {
			if (!isset(self::$_workflowQueue[$_ticketID])) {
				throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
			}

			// Add the workflows to the ticket
			if (_is_array($_ticketWorkflowIDList)) {
				SWIFT_TicketLinkedTable::CreateIfNotExists(self::$_workflowQueue[$_ticketID], array(SWIFT_TicketLinkedTable::LINKTYPE_WORKFLOW => $_ticketWorkflowIDList));
			}

			unset(self::$_workflowQueue[$_ticketID]);
		}

		self::$_workflowQueue         = array();
		self::$_isWorkflowQueueActive = false;

		return true;
	}

	/**
	 * Processes the POST attachment field (ticketattachments) and adds the attachments to the ticket
	 *
	 * @author Varun Shoor
	 * @param SWIFT_TicketPost $_SWIFT_TicketPostObject (OPTIONAL) The Ticket Post Object
	 * @param string $_fieldName (OPTIONAL) The Custom Field Name
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function ProcessPostAttachments(SWIFT_TicketPost $_SWIFT_TicketPostObject = null, $_fieldName = '') {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_finalFieldName = 'ticketattachments';
		if (!empty($_fieldName))
		{
			$_finalFieldName = $_fieldName;
		}

		$_listFieldName = $_finalFieldName . 'list';

		// Link with first post if none specified
		if ($_SWIFT_TicketPostObject == null) {
			$_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($this->GetProperty('firstpostid')));
		}

		if (!$_SWIFT_TicketPostObject instanceof SWIFT_TicketPost || !$_SWIFT_TicketPostObject->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		$_attachmentCount = 0;

		if (isset($_POST[$_listFieldName]) && _is_array($_POST[$_listFieldName]))
		{
			foreach ($_POST[$_listFieldName] as $_attachmentID)
			{
				$_SWIFT_AttachmentObject = new SWIFT_Attachment($_attachmentID);

				SWIFT_Attachment::CloneOnTicket($this, $_SWIFT_TicketPostObject, $_SWIFT_AttachmentObject);

				$this->AddToNotificationAttachments($_SWIFT_AttachmentObject->GetProperty('filename'), $_SWIFT_AttachmentObject->GetProperty('filetype'),
						$_SWIFT_AttachmentObject->Get());

				$_attachmentCount++;

			}

			if ($_attachmentCount > 0) {

				$this->UpdatePool('hasattachments', '1');

				/**
				 * BUG FIX - Simaranjit Singh
				 *
				 * SWIFT-2576: 'hasattachments' field is not getting saved if ticket is having attachments
				 *
				 * Comments: Update hasattachments for ticket posts also
				 */
				$_SWIFT_TicketPostObject->UpdatePool('hasattachments', '1');
			}

			unset($_POST[$_listFieldName]);
		}

		if (!isset($_FILES[$_finalFieldName]) || !_is_array($_FILES[$_finalFieldName]) || !_is_array($_FILES[$_finalFieldName]['name'])) {
			return false;
		}

		// Create the attachments
		foreach ($_FILES[$_finalFieldName]['name'] as $_fileIndex => $_fileName) {
			if (empty($_fileName) || empty($_FILES[$_finalFieldName]['type'][$_fileIndex]) || empty($_FILES[$_finalFieldName]['size'][$_fileIndex]) ||
					!is_uploaded_file($_FILES[$_finalFieldName]['tmp_name'][$_fileIndex]))
			{
				continue;
			}

			$_SWIFT_AttachmentStoreObject = new SWIFT_AttachmentStoreFile($_FILES[$_finalFieldName]['tmp_name'][$_fileIndex],
					$_FILES[$_finalFieldName]['type'][$_fileIndex], $_fileName);

			$_SWIFT_AttachmentObject = SWIFT_Attachment::CreateOnTicket($this, $_SWIFT_TicketPostObject, $_SWIFT_AttachmentStoreObject);

			$this->AddToNotificationAttachments($_fileName, $_FILES[$_finalFieldName]['type'][$_fileIndex], file_get_contents($_FILES[$_finalFieldName]['tmp_name'][$_fileIndex]));

			$_attachmentCount++;
		}

		if ($_attachmentCount > 0) {

			$this->UpdatePool('hasattachments', '1');

			/**
			 * BUG FIX - Simaranjit Singh
			 *
			 * SWIFT-2576: 'hasattachments' field is not getting saved if ticket is having attachments
			 *
			 * Comments: Update hasattachments for ticket posts also
			 */
			$_SWIFT_TicketPostObject->UpdatePool('hasattachments', '1');
		}

		return true;
	}

	/**
	 * Retrieve the ticket attachment container
	 *
	 * @author Varun Shoor
	 * @return array $_ticketAttachmentContainer
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetAttachmentContainer() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_ticketAttachmentContainer = array();

		$this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "attachments WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
		while ($this->Database->NextRecord()) {
			$_ticketAttachmentContainer[$this->Database->Record['linktypeid']][$this->Database->Record['attachmentid']] = $this->Database->Record;
		}

		return $_ticketAttachmentContainer;
	}

	/**
	 * Retrieve the history count for this user based on his userid & email address
	 *
	 * @author Varun Shoor
	 * @return int The History Count
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetHistoryCount() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_userID = '-1';
		if ($this->GetProperty('userid') != '0')
		{
			$_userID = intval($this->GetProperty('userid'));
		}

		/** BUG FIX : Parminder Singh <parminder.singh@kayako.com>
		 *
		 * SWIFT-2041 : Wrong count under History tab, when ticket is created from Staff CP using 'Send Mail' option
		 */
		$_extendedSQL = "email = '" . $this->Database->Escape($this->GetProperty('email')) . "'";
		if ($this->GetProperty('replyto') != '') {
			$_extendedSQL = "replyto = '" . $this->Database->Escape($this->GetProperty('replyto')) . "'";
		}

		$_countContainer = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "tickets
														 WHERE userid = '" . intval($_userID) . "' OR " . $_extendedSQL);
		if (isset($_countContainer['totalitems']) && intval($_countContainer['totalitems']) > 0) {
			return $_countContainer['totalitems'] - 1;
		}

		return 0;
	}

	/**
	 * Retrieve the history for this ticket
	 *
	 * @author Varun Shoor
	 * @return array The History Container
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function RetrieveHistory() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_historyContainer = array();

		/** BUG FIX : Parminder Singh <parminder.singh@kayako.com>
		 *
		 * SWIFT-2041 : Wrong count under History tab, when ticket is created from Staff CP using 'Send Mail' option
		 */
		$_extendedSQL = "email = '" . $this->Database->Escape($this->GetProperty('email')) . "'";
		if ($this->GetProperty('replyto') != '') {
			$_extendedSQL = "replyto = '" . $this->Database->Escape($this->GetProperty('replyto')) . "'";
		}

		if ($this->GetProperty('userid') != '0')
		{
			$_extendedSQL .= " OR userid = '" . intval($this->GetProperty('userid')) . "'";
		}

		$this->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets
								 WHERE " . $_extendedSQL . "
								 ORDER BY dateline DESC");
		while ($this->Database->NextRecord()) {
			$_historyContainer[$this->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($this->Database->Record));
		}

		return $_historyContainer;
	}

	/**
	 * Retrieve the relevant user object
	 *
	 * @author Varun Shoor
	 * @return mixed "SWIFT_User" (OBJECT) on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetUserObject() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// Have we already cached the user object?
		if ($this->_isUserObjectCached == true) {
			return $this->_UserObject;
		}

		$_SWIFT_UserObject = false;
		if ($this->GetProperty('userid') != '0') {
			try {
				$_SWIFT_UserObject = new SWIFT_User(new SWIFT_DataID($this->GetProperty('userid')));
			} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {

				return false;
			}
		}

		$this->_UserObject = $_SWIFT_UserObject;
		$this->_isUserObjectCached = true;

		return $_SWIFT_UserObject;
	}

	/**
	 * Retrieve the relevant user group object
	 *
	 * @author Varun Shoor
	 * @return mixed "SWIFT_UserGroup" (OBJECT) on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetUserGroupObject() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// Have we already cached the user object?
		if ($this->_isUserGroupObjectCached == true) {
			return $this->_UserGroupObject;
		}

		$_SWIFT_UserObject = $this->GetUserObject();
		$_SWIFT_UserGroupObject = false;

		if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
		{
			try {
				$_SWIFT_UserGroupObject = new SWIFT_UserGroup($_SWIFT_UserObject->GetProperty('usergroupid'));
			} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {

				return false;
			}
		}

		$this->_UserGroupObject = $_SWIFT_UserGroupObject;
		$this->_isUserGroupObjectCached = true;

		return $_SWIFT_UserGroupObject;
	}

	/**
	 * Retrieve the user organization object associated with this ticket
	 *
	 * @author Varun Shoor
	 * @return mixed "SWIFT_UserOrganization" (OBJECT) on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetUserOrganizationObject() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// Have we already cached the user organization object?
		if ($this->_isUserOrganizationObjectCached == true) {
			return $this->_UserOrganizationObject;
		}

		$_SWIFT_UserOrganizationObject = false;

		$_SWIFT_UserObject = $this->GetUserobject();

		if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded() &&
				$_SWIFT_UserObject->GetProperty('userorganizationid') != '0')
		{
			try
			{
				$_SWIFT_UserOrganizationObject = new SWIFT_UserOrganization($_SWIFT_UserObject->GetProperty('userorganizationid'));
			} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {

			}
		}

		$this->_UserOrganizationObject = $_SWIFT_UserOrganizationObject;
		$this->_isUserOrganizationObjectCached = true;

		return $_SWIFT_UserOrganizationObject;
	}

	/**
	 * Get the relevant mail subject based on mail type
	 *
	 * @author Varun Shoor
	 * @param constant $_mailType The Mail Type
	 * @param string $_customSubject (OPTIONAL) The Custom Subject
	 * @return mixed "Mail Subject" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetMailSubject($_mailType, $_customSubject = '') {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
		$_emailQueueID = $this->GetProperty('emailqueueid');
		$_templateGroupID = $this->GetProperty('tgroupid');

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1327 From name and From email address improvements in autoresponder email, if visitor sends an offline message and help desk create the ticket
		 * SWIFT-1651 From Email Address (in autoresponder email) should set according to the template group under email queue, if ticket is created from client support center in case of multi-domain installation
		 *
		 * Comments: None
		 */

		// First try to load up the email queue based on template group & department match
		if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
		{
			foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
			{
				if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid') && $_emailQueueContainer['tgroupid'] == $_templateGroupID)
				{
					$_emailQueueID = $_emailQueueContainer['emailqueueid'];

					break;
				}
			}
		}

		// No Queue Prefix set, itterate through queues looking for one for ONLY this department
		if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
		{
			foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
			{
				if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid'))
				{
					$_emailQueueID = $_emailQueueContainer['emailqueueid'];

					break;
				}
			}
		}

		$_subjectPrefix = $_finalSubjectPrefix = '';
		if (isset($_emailQueueCache['list'][$_emailQueueID]))
		{
			$_emailQueueContainer = $_emailQueueCache['list'][$_emailQueueID];

			$_subjectPrefix = $_emailQueueContainer['prefix'];
		}

		if (!empty($_subjectPrefix))
		{
			$_finalSubjectPrefix = $_subjectPrefix . ' ';
		}

		$_finalSubject = $this->GetProperty('subject');
		if (!empty($_customSubject)) {
			$_finalSubject = $_customSubject;
		}

		if ($this->Settings->Get('t_cleanmailsubjects') == '1') {
			return $_finalSubject;
		}

		switch ($_mailType) {
			case self::MAIL_NOTIFICATION:
				return '[' . $_finalSubjectPrefix . '!' . $this->GetTicketDisplayID() . ']: ' . $_finalSubject;
				break;

			case self::MAIL_CLIENT:
				return '[' . $_finalSubjectPrefix . '#' . $this->GetTicketDisplayID() . ']: ' . $_finalSubject;
				break;

			case self::MAIL_THIRDPARTY:
				return '[' . $_finalSubjectPrefix . '~' . $this->GetTicketDisplayID() . ']: ' . $_finalSubject;
				break;

			default:
				break;
		}

		return false;
	}

	/**
	 * Retrieve the default from name for the email
	 *
	 * @author Varun Shoor
	 * @param SWIFT_Staff $_SWIFT_StaffObject (OPTIONAL) The SWIFT_Staff Object Pointer
	 * @return string The Default From Name
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetMailFromName(SWIFT_Staff $_SWIFT_StaffObject = null)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
		$_emailQueueID = $this->GetProperty('emailqueueid');
		$_templateGroupID = $this->GetProperty('tgroupid');
		if (empty($_templateGroupID) && isset($_SWIFT->TemplateGroup) && $_SWIFT->TemplateGroup instanceof SWIFT_TemplateGroup) {
            $_templateGroupID = $_SWIFT->TemplateGroup->GetTemplateGroupID();
        }


		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1327 From name and From email address improvements in autoresponder email, if visitor sends an offline message and help desk create the ticket
		 * SWIFT-1651 From Email Address (in autoresponder email) should set according to the template group under email queue, if ticket is created from client support center in case of multi-domain installation
		 *
		 * Comments: None
		 */

		// First try to lookup based on department and template group
		if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
		{
			foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
			{
				if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid') && $_emailQueueContainer['tgroupid'] == $_templateGroupID)
				{
					$_emailQueueID = $_emailQueueContainer['emailqueueid'];

					break;
				}
			}
		}

		// No Queue Prefix set, itterate through queues looking for one for ONLY this department
		if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
		{
			foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
			{
				if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid'))
				{
					$_emailQueueID = $_emailQueueContainer['emailqueueid'];

					break;
				}
			}
		}

		// Name Priority: Template Group > Settings > Staff > Email Queue

		$_defaultFromName = SWIFT::Get('companyname');
		if (empty($_defaultFromName))
		{
			$_defaultFromName = $this->Settings->Get('general_companyname');
		}

		if ($_SWIFT_StaffObject instanceof SWIFT_Staff && $_SWIFT_StaffObject->GetIsClassLoaded())
		{
			$_defaultFromName = $_SWIFT_StaffObject->GetProperty('fullname');
		}

		if (isset($_emailQueueCache['list'][$_emailQueueID]))
		{
			$_emailQueueContainer = $_emailQueueCache['list'][$_emailQueueID];

			if (!empty($_emailQueueContainer['customfromname']))
			{
				$_defaultFromName = $_emailQueueContainer['customfromname'];
			}
		}

		return $_defaultFromName;
	}

	/**
	 * Retrieve the default from email
	 *
	 * @author Varun Shoor
	 * @return string The Default Return Email
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetMailFromEmail()
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_emailQueueCache = $_SWIFT->Cache->Get('queuecache');
		$_emailQueueID = $this->GetProperty('emailqueueid');
		$_templateGroupID = $this->GetProperty('tgroupid');
		if (empty($_templateGroupID) && isset($_SWIFT->TemplateGroup) && $_SWIFT->TemplateGroup instanceof SWIFT_TemplateGroup) {
            $_templateGroupID = $_SWIFT->TemplateGroup->GetTemplateGroupID();
        }

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1327 From name and From email address improvements in autoresponder email, if visitor sends an offline message and help desk create the ticket
		 * SWIFT-1651 From Email Address (in autoresponder email) should set according to the template group under email queue, if ticket is created from client support center in case of multi-domain installation
		 *
		 * Comments: None
		 */

		// First check against the template group id and department id
		if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
		{
			foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
			{
				if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid') && $_templateGroupID == $_emailQueueContainer['tgroupid'])
				{
					$_emailQueueID = $_emailQueueContainer['emailqueueid'];

					break;
				}
			}
		}

		// No Queue Prefix set, itterate through queues looking for one for ONLY this department
		if (empty($_emailQueueID) && isset($_emailQueueCache['list']) && _is_array($_emailQueueCache['list']))
		{
			foreach ($_emailQueueCache['list'] as $_emailQueueContainer)
			{
				if ($_emailQueueContainer['departmentid'] == $this->GetProperty('departmentid'))
				{
					$_emailQueueID = $_emailQueueContainer['emailqueueid'];

					break;
				}
			}
		}

		// Email Priority: Settings > Email Queue
		$_defaultFromEmail = $this->Settings->Get('general_returnemail');

		if (isset($_emailQueueCache['list'][$_emailQueueID]))
		{
			$_emailQueueContainer = $_emailQueueCache['list'][$_emailQueueID];
			if (!empty($_emailQueueContainer['customfromemail']))
			{
				$_defaultFromEmail = $_emailQueueContainer['customfromemail'];
			} else {
				$_defaultFromEmail = $_emailQueueContainer['email'];
			}
		}

		return $_defaultFromEmail;
	}

	/**
	 * Load the Core Language Table
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function LoadLanguageTable() {
		$_SWIFT = SWIFT::GetInstance();

		$_SWIFT->Language->Load('tickets_notifications', SWIFT_LanguageEngine::TYPE_FILE);
		$_SWIFT->Language->Load('tickets_auditlogs', SWIFT_LanguageEngine::TYPE_FILE);

		return true;
	}

	/**
	 * Retrieve the signature for this based on associated queue or given staff/user
	 *
	 * @author Varun Shoor
	 * @param bool $_isHTML Whether the reply is HTML
	 * @param object $_SWIFT_StaffObject (OPTIONAL) The SWIFT_Staff Object
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function GetSignature($_isHTML, $_SWIFT_StaffObject = null)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_emailQueueCache = $_SWIFT->Cache->Get('queuecache');

		$_emailQueueID = $this->GetProperty('emailqueueid');

		$_signatureContents = '';

		if ($_isHTML == true)
		{
			$_signatureContents = '<br />';
		} else {
			$_signatureContents = SWIFT_CRLF;
		}

		// First priority is given to Staff signature
		if ($_SWIFT_StaffObject instanceof SWIFT_Staff && $_SWIFT_StaffObject->GetIsClassLoaded())
		{
			$_staffSignatureContents = '';
			try {
				$_staffSignatureContents = $_SWIFT_StaffObject->GetProperty('signature');
			} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
			}

			if ($_isHTML == true)
			{
				$_signatureContents .= nl2br($_staffSignatureContents);
			} else {
				$_signatureContents .= preg_replace("#(\r\n|\r|\n)#s", SWIFT_CRLF, $_staffSignatureContents);
			}
		}

		if (_is_array($_emailQueueCache) && isset($_emailQueueCache['list'][$_emailQueueID])) {
			$_emailQueueContainer = $_emailQueueCache['list'][$_emailQueueID];
			if ($_isHTML == true)
			{
				$_signatureContents .= nl2br($_emailQueueContainer['contents']);
			} else {
				$_signatureContents .= preg_replace("#(\r\n|\r|\n)#s", SWIFT_CRLF, $_emailQueueContainer['contents']);
			}
		}

		return $_signatureContents;
	}

	/**
	 * Dispatch the auto responder msg
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function DispatchAutoresponder()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// We dispatch the auto responder to ALL registered emails of the user
		$_ccEmailList = $this->GetCCUserEmails();

		$this->Load->Library('Ticket:TicketEmailDispatch', array($this));
		$this->TicketEmailDispatch->DispatchAutoresponder('', $_ccEmailList);

		return true;
	}

	/**
	 * Retrieves all other emails of the user excluding the one that was used to create the ticket
	 *
	 * @author Varun Shoor
	 * @return array The Email List
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetCCUserEmails()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_SWIFT_UserObject = $this->GetUserObject();

		$_ccEmailList = array();
		if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
		{
			$_userEmailList = $_SWIFT_UserObject->GetEmailList();
			if (_is_array($_userEmailList))
			{
				foreach ($_userEmailList as $_emailAddress)
				{
					if (mb_strtolower($_emailAddress) != mb_strtolower($this->GetProperty('email')))
					{
						$_ccEmailList[] = $_emailAddress;
					}
				}
			}
		}

		return $_ccEmailList;
	}

	/**
	 * Retrieve the first ticket post object
	 *
	 * @author Varun Shoor
	 * @return SWIFT_TicketPost The SWIFT_TicketPost Object
	 * @throws SWIFT_Exception If the Class is not Loaded or If Invalid Data is Provided
	 */
	public function GetFirstPostObject()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($this->GetProperty('firstpostid')));
		if (!$_SWIFT_TicketPostObject instanceof SWIFT_TicketPost || !$_SWIFT_TicketPostObject->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_INVALIDDATA);
		}

		return $_SWIFT_TicketPostObject;
	}

	/**
	 * Retrieve the time tracking count for the ticket
	 *
	 * @author Varun Shoor
	 * @return int The Count
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetTimeTrackCount()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_timeTrackCount = $this->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "tickettimetracks WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
		if (isset($_timeTrackCount['totalitems']))
		{
			return intval($_timeTrackCount['totalitems']);
		}

		return 0;
	}

	/**
	 * Retrieve the list of all possible ticket ids created by a given user
	 *
	 * @author Varun Shoor
	 * @param SWIFT_User $_SWIFT_UserObject The SWIFT_User Object Pointer
	 * @return array The Ticket ID List
	 * @throws SWIFT_Exception If Invalid Data is Provided
	 */
	static public function GetTicketIDListOnUser(SWIFT_User $_SWIFT_UserObject)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$_SWIFT_UserObject instanceof SWIFT_User || !$_SWIFT_UserObject->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_INVALIDDATA);
		}

		$_ticketIDList = array();

		$_SWIFT->Database->Query("SELECT ticketid FROM " . TABLE_PREFIX . "tickets WHERE userid = '" . intval($_SWIFT_UserObject->GetUserID()) . "' OR email IN (" . BuildIN($_SWIFT_UserObject->GetEmailList()) . ")");
		while ($_SWIFT->Database->NextRecord())
		{
			$_ticketIDList[] = intval($_SWIFT->Database->Record['ticketid']);
		}

		return $_ticketIDList;
	}

	/**
	 * Create a Note
	 *
	 * @author Varun Shoor
	 * @param SWIFT_User $_SWIFT_UserObject (OPTIONAL) The User Object
	 * @param string $_noteContents The Note Contents
	 * @param int $_noteColor The Note Color
	 * @param string $_noteType The Note Type
	 * @param int $_forStaffID (OPTIONAL) Restrict view to a given staff
	 * @param SWIFT_Staff $_SWIFT_StaffObject (OPTIONAL) The Staff Object to create note as
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function CreateNote($_SWIFT_UserObject, $_noteContents, $_noteColor, $_noteType, $_forStaffID = false, $_SWIFT_StaffObject = false) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_isOrganizationNote = false;
		$_SWIFT_UserOrganizationObject = $this->GetUserOrganizationObject();

		if ($_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded() &&
				isset($_noteType) && $_noteType == 'userorganization')
		{
			$_isOrganizationNote = true;
		}

		// Add notes
		if (!empty($_noteContents))
		{
			if ($_isOrganizationNote)
			{
				SWIFT_UserOrganizationNote::Create($_SWIFT_UserOrganizationObject, $_noteContents, intval($_noteColor));

				SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_NEWNOTE,
					$_SWIFT->Language->Get('al_usernote'),
					SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
			} else if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded() && isset($_noteType) && $_noteType == 'user') {
				SWIFT_UserNote::Create($_SWIFT_UserObject, $_noteContents, intval($_noteColor));

				SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_NEWNOTE,
					$_SWIFT->Language->Get('al_usernote'),
					SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
			} else {

				$_staffID = 0;
				$_staffName = $this->Language->Get('system');
				if ($_SWIFT_StaffObject instanceof SWIFT_Staff && $_SWIFT_StaffObject->GetIsClassLoaded()) {
					$_staffID = $_SWIFT_StaffObject->GetStaffID();
					$_staffName = $_SWIFT_StaffObject->GetProperty('fullname');
				} else if ($_SWIFT->Staff instanceof SWIFT_Staff && $_SWIFT->Staff->GetIsClassLoaded()) {
					$_staffID = $_SWIFT->Staff->GetStaffID();
					$_staffName = $_SWIFT->Staff->GetProperty('fullname');
				}

				SWIFT_TicketNote::Create($this, intval($_forStaffID), $_staffID, $_staffName, $_noteContents, intval($_noteColor));

				SWIFT_TicketAuditLog::AddToLog($this, null, SWIFT_TicketAuditLog::ACTION_NEWNOTE, $_SWIFT->Language->Get('al_ticketnote'), SWIFT_TicketAuditLog::VALUE_NONE, 0, '', 0, '');
			}

			if ( $this->Settings->Get('t_ticketnoteresetsupdatetime') == 1 ) {
				$this->UpdatePool('lastactivity', DATENOW);

				/*
				 * BUG FIX - Ravi Sharma
				 *
				 * SWIFT-2672: Resetting due time doesn't reset overdue color on tickets
				 *
				 * Comments: None
				 */
				$this->QueueSLAOverdue();
			}

		}

		return true;
	}

	/**
	 * Retrieve the Ticket ID from a Ticket Mask ID
	 *
	 * @author Varun Shoor
	 * @param string $_ticketMaskID The Ticket Mask ID
	 * @return int The Ticket ID
	 * @throws SWIFT_Exception If Invalid Data is Provided
	 */
	static public function GetTicketIDFromMask($_ticketMaskID)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (empty($_ticketMaskID))
		{
			throw new SWIFT_Exception(SWIFT_INVALIDDATA);
		}

		$_ticketIDContainer = $_SWIFT->Database->QueryFetch("SELECT ticketid FROM " . TABLE_PREFIX . "tickets WHERE ticketmaskid = '" . $_SWIFT->Database->Escape($_ticketMaskID) . "'");
		if (isset($_ticketIDContainer['ticketid']) &&  !empty($_ticketIDContainer['ticketid']))
		{
			return $_ticketIDContainer['ticketid'];
		}

		return false;
	}

	/**
	 * Retrieve the history count for this user based on his userid & email addresses
	 *
	 * @author Varun Shoor
	 * @param SWIFT_User $_SWIFT_UserObject
	 * @param array $_userEmailList
	 * @return int The History Count
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function GetHistoryCountOnUser($_SWIFT_UserObject, $_userEmailList = array()) {
		$_SWIFT = SWIFT::GetInstance();

		$_userID = '-1';
		if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
		{
			$_userID = $_SWIFT_UserObject->GetUserID();
		}

		if (!_is_array($_userEmailList))
		{
			$_userEmailList = $_SWIFT_UserObject->GetEmailList();
		}

		/**
		 * BUG FIX - Saloni Dhall
		 *
		 * SWIFT-3069: Wrong ticket count and the tickets coming after clicking on 'Tickets Tab' under 'Users Tab' in staff CP shows incorrect count and tickets.
		 */
		$_SWIFT->Database->Query("SELECT creator, replyto FROM " . TABLE_PREFIX . "tickets WHERE userid = '" .
			intval($_userID) . "' OR email IN (" . BuildIN($_userEmailList) . ") OR replyto IN (" . BuildIN($_userEmailList) . ")");
		$_totalTicketCount = 0;
		while ($_SWIFT->Database->NextRecord()) {
			if ($_SWIFT->Database->Record['creator'] == SWIFT_Ticket::CREATOR_STAFF && !in_array(mb_strtolower($_SWIFT->Database->Record['replyto']), $_userEmailList)) {
				continue;
			}
			$_totalTicketCount++;
		}
		return $_totalTicketCount;
	}

	/**
	 * Retrieve the history for this user
	 *
	 * @author Varun Shoor
	 * @param SWIFT_User $_SWIFT_UserObject
	 * @param array $_emailList The Email List
	 * @param string $_sortBy (OPTIONAL) The Custom Sort By
	 * @param string $_sortOrder (OPTIONAL) The Custom Sort Order
	 * @return array The History Container
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	static public function RetrieveHistoryOnUser($_SWIFT_UserObject, $_emailList = array(), $_sortBy = false, $_sortOrder = false) {
		$_SWIFT = SWIFT::GetInstance();

		$_userID = '-1';
		$_userEmailList = $_emailList;
		if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
		{
			$_userID = $_SWIFT_UserObject->GetUserID();
			$_userEmailList = array_merge($_userEmailList, $_SWIFT_UserObject->GetEmailList());
		}

		$_historyContainer = array();

		$_ticketSortBy = 'dateline';
		$_ticketSortOrder = 'DESC';
		if (!empty($_sortBy) && !empty($_sortOrder))
		{
			$_ticketSortBy = $_sortBy;
			$_ticketSortOrder = $_sortOrder;
		}
		/**
		 * BUG FIX - Saloni Dhall
		 *
		 * SWIFT-3069: Wrong ticket count and the tickets coming after clicking on 'Tickets Tab' under 'Users Tab' in staff CP shows incorrect count and tickets.
		 */
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets WHERE userid = '" . intval($_userID) .
			"' OR email IN (" . BuildIN($_userEmailList) . ") OR replyto IN (" . BuildIN($_userEmailList) . ") ORDER BY " . $_ticketSortBy . " " . $_ticketSortOrder);
		while ($_SWIFT->Database->NextRecord()) {
			if ($_SWIFT->Database->Record['creator'] == SWIFT_Ticket::CREATOR_STAFF && !in_array(mb_strtolower($_SWIFT->Database->Record['replyto']), $_userEmailList)) {
				continue;
			}
			$_historyContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
		}
		return $_historyContainer;

	}

	/**
	 * Retrieve the Support Center Tickets for this user
	 *
	 * @author Varun Shoor
	 *
	 * @param SWIFT_User $_User
	 * @param bool       $_sortBy    (OPTIONAL) The Custom Sort By
	 * @param bool       $_sortOrder (OPTIONAL) The Custom Sort Order
	 * @param int        $_offset    (OPTIONAL) The Starting Offset
	 * @param bool       $_limit     (OPTIONAL) The Number of Results to Return
	 * @param bool       $_excludeResolved
	 * @param int        $_lastTicketID
	 *
	 * @return array The History Container
	 */
	static public function RetrieveSCTicketsOnUser(SWIFT_User $_User, $_sortBy = false, $_sortOrder = false, $_offset = 0, $_limit = false, $_excludeResolved = false, $_lastTicketID = 0) {
		$_SWIFT = SWIFT::GetInstance();

		$_userID        = '-1';
		$_userEmailList = array();
		if ($_User instanceof SWIFT_User && $_User->GetIsClassLoaded())
		{
			$_userID        = $_User->GetID();
			$_userEmailList = array_merge($_userEmailList, $_User->GetEmailList());
		}

		$_historyContainer = array();

		$_ticketSortBy    = 'dateline';
		$_ticketSortOrder = 'DESC';
		if (!empty($_sortBy) && !empty($_sortOrder))
		{
			$_ticketSortBy    = $_sortBy;
			$_ticketSortOrder = $_sortOrder;
		}

		$_userIDList = array($_User->GetID());

		// Does this user have a shared organization or he is a manager in an organization?
		$_UserOrganization = $_User->GetOrganization();

		if (($_User->Get('userrole') == SWIFT_User::ROLE_MANAGER && $_UserOrganization instanceof SWIFT_UserOrganization && $_UserOrganization->GetIsClassLoaded()) ||
				($_UserOrganization instanceof SWIFT_UserOrganization && $_UserOrganization->GetIsClassLoaded() && $_UserOrganization->Get('organizationtype') == SWIFT_UserOrganization::TYPE_SHARED))
		{
			$_userIDList_Organization = array();
			$_SWIFT->Database->Query("SELECT userid FROM " . TABLE_PREFIX . "users
									  WHERE userorganizationid = '" . intval($_UserOrganization->GetUserOrganizationID()) . "'");
			while ($_SWIFT->Database->NextRecord())
			{
				$_userIDList_Organization[] = $_SWIFT->Database->Record['userid'];
				$_userIDList[]              = $_SWIFT->Database->Record['userid'];
			}

			$_userEmailList = array_unique(array_merge($_userEmailList, SWIFT_UserEmail::RetrieveListOnUserIDList($_userIDList_Organization)));
		}

		$_whereExtended  = '';
		$_whereExtended .=  IIF(!empty($_excludeResolved), " AND isresolved = 0" . $_lastTicketID);
		$_whereExtended .=  IIF(!empty($_lastTicketID),     " AND ticketid < "    . $_lastTicketID);

		$_SWIFT->Database->QueryLimit("SELECT * FROM " . TABLE_PREFIX . "tickets as tickets
			                           WHERE tickets.userid IN (" . BuildIN(array_unique($_userIDList), true) . ")
			                             AND tickets.departmentid <> 0 " . $_whereExtended . "
			                           ORDER BY " . $_ticketSortBy . " " . $_ticketSortOrder, $_limit, $_offset);

		while ($_SWIFT->Database->NextRecord()) {
            $_historyContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
        }

        $_SWIFT->Database->QueryLimit("SELECT * FROM " . TABLE_PREFIX . "tickets as tickets
			                           WHERE (tickets.email IN (" . BuildIN($_userEmailList) . ") OR tickets.replyto IN (" . BuildIN($_userEmailList) . "))
			                             AND tickets.departmentid <> 0" . $_whereExtended . "
			                           ORDER BY " . $_ticketSortBy . " " . $_ticketSortOrder, $_limit, $_offset);

        while ($_SWIFT->Database->NextRecord()) {
            if (isset($_historyContainer[$_SWIFT->Database->Record['ticketid']]) || ($_SWIFT->Database->Record['creator'] == SWIFT_Ticket::CREATOR_STAFF && !in_array(mb_strtolower($_SWIFT->Database->Record['replyto']), $_userEmailList))) {
                continue;
            }

            $_historyContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
        }

        return $_historyContainer;
	}

	/**
	 * Retrieve the Support Center Tickets count for this user
	 *
	 * @author Varun Shoor
	 * @param SWIFT_User $_SWIFT_UserObject
	 * @param bool $_excludeResolved
	 * @param bool $_resolvedOnly
	 * @return int The History Count
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function RetrieveSCTicketsCountOnUser($_SWIFT_UserObject, $_excludeResolved = false, $_resolvedOnly = false) {
		$_SWIFT = SWIFT::GetInstance();

		$_userID = '-1';
		$_userEmailList = array();
		if ($_SWIFT_UserObject instanceof SWIFT_User && $_SWIFT_UserObject->GetIsClassLoaded())
		{
			$_userID = $_SWIFT_UserObject->GetUserID();
			$_userEmailList = array_merge($_userEmailList, $_SWIFT_UserObject->GetEmailList());
		}

		$_userIDList = array($_SWIFT_UserObject->GetUserID());

		// Does this user have a shared organization or he is a manager in an organization?
		$_SWIFT_UserOrganizationObject = $_SWIFT_UserObject->GetOrganization();

		if (($_SWIFT_UserObject->GetProperty('userrole') == SWIFT_User::ROLE_MANAGER && $_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded()) ||
				($_SWIFT_UserOrganizationObject instanceof SWIFT_UserOrganization && $_SWIFT_UserOrganizationObject->GetIsClassLoaded() && $_SWIFT_UserOrganizationObject->GetProperty('organizationtype') == SWIFT_UserOrganization::TYPE_SHARED))
		{
			$_userIDList_Organization = array();
			$_SWIFT->Database->Query("SELECT userid FROM " . TABLE_PREFIX . "users WHERE userorganizationid = '" . intval($_SWIFT_UserOrganizationObject->GetUserOrganizationID()) . "'");
			while ($_SWIFT->Database->NextRecord())
			{
				$_userIDList_Organization[] = $_SWIFT->Database->Record['userid'];

				$_userIDList[] = $_SWIFT->Database->Record['userid'];
			}

			$_userEmailList = array_merge($_userEmailList, SWIFT_UserEmail::RetrieveListOnUserIDList($_userIDList_Organization));
		}

		$_whereExtended = '';
		if ($_excludeResolved) {
			$_whereExtended = ' AND isresolved = "0"';
		}

		if ($_resolvedOnly) {
			$_whereExtended = ' AND isresolved = "1"';
		}

		/**
		 * BUG FIX - Ravi Sharma <ravi.sharma@kayako.com>
		 *
		 * SWIFT-4462 Wrong ticket count at client support center.
		 *
		 * Comments: Ticket those created by staff was conflicting in counter (in case of shared organization).
		 */
		$_totalTickets = 0;
		$_SWIFT->Database->Query("SELECT creator, replyto FROM " . TABLE_PREFIX . "tickets
								   WHERE (userid = '" . intval($_userID) . "'
									  OR email IN (" . BuildIN($_userEmailList) . ")
									  OR replyto IN (" . BuildIN($_userEmailList) . "))
									  AND departmentid <> '0' " . $_whereExtended);
		while ($_SWIFT->Database->NextRecord()) {
			if ($_SWIFT->Database->Record['creator'] == SWIFT_Ticket::CREATOR_STAFF && !in_array(mb_strtolower($_SWIFT->Database->Record['replyto']), $_userEmailList)) {
				continue;
			}

			$_totalTickets++;
		}

		return $_totalTickets;
	}

	/**
	 * Set the Watcher Notification Message
	 *
	 * @author Varun Shoor
	 * @param string $_watcherName The Watcher Name
	 * @param string $_watcherMessage The Watcher Message
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function SetWatcherProperties($_watcherName, $_watcherMessage)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->_watcherCustomName = $_watcherName;
		$this->_watchNotificationMessage = $_watcherMessage;

		return true;
	}

	/**
	 * Process the Notification for Ticket Watchers
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function ProcessWatchers()
	{
		chdir(SWIFT_BASEPATH);
		$_ticketID = $this->GetTicketID();

		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (isset(self::$_watcherExecutedCache[$_ticketID]) && self::$_watcherExecutedCache[$_ticketID] == 1) {
			return true;
		}

		$_staffCache = $this->Cache->Get('staffcache');

		$_emailList = array();
		$_ticketWatchContainer = SWIFT_TicketWatcher::RetrieveOnTicket($this);
		if (_is_array($_ticketWatchContainer))
		{
			foreach ($_ticketWatchContainer as $_ticketWatch)
			{
				$_staffID = $_ticketWatch['staffid'];

				if (!isset($_staffCache[$_staffID]))
				{
					continue;
				}

				$_emailList[] = $_staffCache[$_staffID]['email'];
			}
		}

		if (!count($_emailList))
		{
			return false;
		}

		$this->Notification->Dispatch(SWIFT_TicketNotification::TYPE_CUSTOM, $_emailList, $this->GetProperty('subject'), $this->_watchNotificationMessage, $this->_watcherCustomName, '', true);

		self::$_watcherExecutedCache[$_ticketID] = 1;

		return true;
	}

	/**
	 * Queue the Watcher Execution
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function QueueWatcherExecution()
	{
		$_ticketID = $this->GetTicketID();

		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (isset(self::$_watcherPendingCache[$_ticketID]) && self::$_watcherPendingCache[$_ticketID] == '1') {
			return true;
		}

//		SWIFT::Shutdown($this, 'ProcessWatchers', -1, false);

		self::$_watcherPendingCache[$_ticketID] = 1;

		return true;
	}

	/**
	 * Process the Notification Rules
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function ProcessNotifications()
	{
		chdir(SWIFT_BASEPATH);
		$_ticketID = $this->GetTicketID();
		/**
		 * BUG FIX - Saloni Dhall
		 *
		 * SWIFT-3412: New Client Reply rule for notifications works for the first reply only
		 *
		 */
		$_ticketPostID = $this->GetProperty('lastpostid');

		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (isset(self::$_notificationExecutionCache[$_ticketID][$_ticketPostID]) && self::$_notificationExecutionCache[$_ticketID][$_ticketPostID] == '1') {
			return true;
		}

		$this->NotificationManager->Trigger();

		self::$_notificationExecutionCache[$_ticketID][$_ticketPostID] = 1;

		return true;
	}

	/**
	 * Dispatch a Notification via Email on this Ticket
	 *
	 * @author Varun Shoor
	 * @param constant $_notificationType The Notification Type
	 * @param array $_customEmailList The Custom Email List
	 * @param string $_emailPrefix (OPTIONAL) The Custom Email Prefix
	 * @param string $_notificationEvent (OPTIONAL) The Notification Event
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function DispatchNotification($_notificationType, $_customEmailList, $_emailPrefix = '', $_notificationEvent = '')
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_finalEmailPrefix = '';
		if (!empty($_emailPrefix))
		{
			$_finalEmailPrefix = $_emailPrefix . ' - ';
		}

		$_notificationMessage = $this->_watchNotificationMessage;
		if (empty($_notificationMessage)) {
			$_notificationMessage = $this->_lastPostNotificationMessage;
		}

		$this->Notification->Dispatch($_notificationType, $_customEmailList, $_finalEmailPrefix . $this->GetProperty('subject'), $_notificationMessage, $this->_watcherCustomName, '', false, $_notificationEvent);

		return true;
	}

	/**
	 * Dispatch a Notification via Pool (DESKTOP APP) on this Ticket
	 *
	 * @author Varun Shoor
	 * @param constant $_notificationType The Notification Type
	 * @param array $_customStaffIDList The Custom Staff ID List
	 * @param string $_notificationEvent (OPTIONAL) The Notification Event
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function DispatchNotificationPool($_notificationType, $_customStaffIDList, $_notificationEvent = '')
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

//		$this->Notification->DispatchPool($_notificationType, $_customStaffIDList, $this->GetProperty('subject'), $this->_watchNotificationMessage, $this->_watcherCustomName);

		return true;
	}

	/**
	 * Add to Attachments
	 *
	 * @author Varun Shoor
	 * @param string $_fileName The File Name
	 * @param string $_fileType The File Type
	 * @param string $_fileContents The File Contents
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function AddToAttachments($_fileName, $_fileType, $_fileContents)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if (!isset(self::$_attachmentsContainer[$this->GetTicketID()]))
		{
			self::$_attachmentsContainer[$this->GetTicketID()] = array();
		}

		self::$_attachmentsContainer[$this->GetTicketID()][] = array('name' => $_fileName, 'type' => $_fileType, 'contents' => $_fileContents);

		return true;
	}

	/**
	 * Retrieve the Attachments Container
	 *
	 * @author Varun Shoor
	 * @return array The Attachments Container
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetAttachments()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if (!isset(self::$_attachmentsContainer[$this->GetTicketID()]))
		{
			return false;
		}

		return self::$_attachmentsContainer[$this->GetTicketID()];
	}

	/**
	 * Add to Active Attachments (for notifications)
	 *
	 * @author Varun Shoor
	 * @param string $_fileName The File Name
	 * @param string $_fileType The File Type
	 * @param string $_fileContents The File Contents
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function AddToNotificationAttachments($_fileName, $_fileType, $_fileContents)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if (!isset(self::$_notificationAttachmentsContainer[$this->GetTicketID()]))
		{
			self::$_notificationAttachmentsContainer[$this->GetTicketID()] = array();
		}

		self::$_notificationAttachmentsContainer[$this->GetTicketID()][] = array('name' => $_fileName, 'type' => $_fileType, 'contents' => $_fileContents);

		return true;
	}

	/**
	 * Retrieve the Attachments Container
	 *
	 * @author Varun Shoor
	 * @return array The Attachments Container
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetNotificationAttachments()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if (!isset(self::$_notificationAttachmentsContainer[$this->GetTicketID()]))
		{
			return false;
		}

		return self::$_notificationAttachmentsContainer[$this->GetTicketID()];
	}

	/**
	 * Move the tickets to trash
	 *
	 * @author Varun Shoor
	 * @param array $_departmentIDList The Department ID List
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function MoveToTrashBulk($_departmentIDList) {
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_departmentIDList)) {
			return false;
		}

		/**
		 * BUG FIX - Parminder Singh
		 *
		 * SWIFT-1894: 'Trash' count does not clear the ticket count in case a department is deleted
		 *
		 */

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('departmentid' => '0', 'trasholddepartmentid' => '0'), 'UPDATE', "departmentid IN (" . BuildIN($_departmentIDList) . ") OR trasholddepartmentid IN (" . BuildIN($_departmentIDList) . ")");

		return true;
	}

	/**
	 * Move the tickets status to trash
	 *
	 * @author Varun Shoor
	 * @param array $_ticketStatusIDList The Ticket Status ID List
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function ChangeStatusToTrash($_ticketStatusIDList) {
		$_SWIFT = SWIFT::GetInstance();

		if (!_is_array($_ticketStatusIDList)) {
			return false;
		}

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('ticketstatusid' => '0'), 'UPDATE', "ticketstatusid IN (" . BuildIN($_ticketStatusIDList) . ")");

		return true;
	}

	/**
	 * Update the User record
	 *
	 * @author Varun Shoor
	 * @param int $_userID The User ID
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function UpdateUser($_userID)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->UpdatePool('userid', $_userID);
		$this->ProcessUpdatePool();

		return true;
	}

	/**
	 * Retrieve the last post contents
	 *
	 * @author Varun Shoor
	 * @return string The last post contents
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetLastPostContents()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		try {
			$_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($this->GetProperty('lastpostid')));

			if ($_SWIFT_TicketPostObject->GetProperty('ticketid') == $this->GetTicketID())
			{
				return $_SWIFT_TicketPostObject->GetDisplayContents();
			}

		} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {


			return '';
		}



		return '';
	}

	/**
	 * Retrieve the Ticket Post IDs linked with this ticket
	 *
	 * @author Varun Shoor
	 * @param bool $_ignoreForwardedPosts (OPTIONAL) Whether to ignore forwarded posts
	 * @return array The Ticket Post ID List
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetTicketPostIDList($_ignoreForwardedPosts = false)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_ticketPostIDList = array();

		/*
		 * BUG FIX - Parminder Singh
		 *
		 * SWIFT-2286 Staff creates a ticket with attachment. When forward, attachment does not go with the ticket.
		 *
		 */
		$this->Database->Query("SELECT ticketpostid, creator, emailto, isthirdparty FROM " . TABLE_PREFIX . "ticketposts WHERE ticketid = '" . intval($this->GetTicketID()) . "'");
		while ($this->Database->NextRecord()) {
			if ($_ignoreForwardedPosts == true && $this->Database->Record['creator'] == SWIFT_TicketPost::CREATOR_STAFF && $this->Database->Record['emailto'] != '' && $this->Database->Record['isthirdparty'] == '1')
			{
				continue;
			}

			$_ticketPostIDList[] = $this->Database->Record['ticketpostid'];
		}

		return $_ticketPostIDList;
	}

	/**
	 * Update the Average Response Time
	 *
	 * @author Varun Shoor
	 *
	 * @param int $_responseTime
	 *
	 * @throws SWIFT_Exception
	 *
	 * @return bool
	 */
	public function UpdateAverageResponseTime($_responseTime)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}

		$_oldHitCount            = intval($this->GetProperty('averageresponsetimehits'));
		$_oldAverageResponseTime = intval($this->GetProperty('averageresponsetime'));

		$_newHitCount = $_oldHitCount + 1;

		$_newAverageResponseTime = (($_oldAverageResponseTime * $_oldHitCount) + $_responseTime) / $_newHitCount;

		$this->UpdatePool('averageresponsetime', intval($_newAverageResponseTime));
		$this->UpdatePool('averageresponsetimehits', intval($_newHitCount));
		return true;
	}

	/**
	 * @author Nidhi Gupta <nidhi.gupta@kayako.com>
	 *
	 * @param int $_slaResponseTime
	 *
	 * @param int $_ticketID
	 *
	 * @return SWIFT_Ticket
	 *
	 * @throws SWIFT_Exception
	 */
	public function UpdateAverageSLAResponseTime($_slaResponseTime, $_ticketID)
	{
		if (!is_numeric($_slaResponseTime)) {
			throw new SWIFT_Exception(__CLASS__ . ': ' . SWIFT_INVALIDDATA);
		}

		$_averageSLAResponseTime = 0;

		if (intval($this->Get('averageresponsetimehits')) > 0 && intval($this->Get('averageslaresponsetime')) == 0) {
			// slaresponsetime / averageresponsetimehits (as hit counts are already updated with UpdateAverageResponseTime method.
			$_averageSLAResponseTime = (intval($_slaResponseTime)) / intval($this->Get('averageresponsetimehits'));
		} else {
			$_avgSLAResponseTime = $this->Database->QueryFetch('SELECT AVG(slaresponsetime) AS avgslaresponsetime FROM ' . TABLE_PREFIX . 'ticketposts WHERE  ticketid = ' . $_ticketID . ' AND slaresponsetime > 0 GROUP BY ticketid');
			if (_is_array($_avgSLAResponseTime) && array_key_exists('avgslaresponsetime', $_avgSLAResponseTime)) {
				$_averageSLAResponseTime = intval($_avgSLAResponseTime['avgslaresponsetime']);
			}
		}

		$this->UpdatePool('averageslaresponsetime', $_averageSLAResponseTime);

		return $this;
	}

	/**
	 * Update the Email Queue
	 *
	 * @author Varun Shoor
	 * @param int $_emailQueueID The Email Queue ID
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function UpdateQueue($_emailQueueIDIncoming) {
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if ($this->GetProperty('emailqueueid') == $_emailQueueIDIncoming) {
			return true;
		}

		$_emailQueueCache = $this->Cache->Get('queuecache');
		$_templateGroupCache = $this->Cache->Get('templategroupcache');
		$_emailQueueID = 0;
		if (isset($_emailQueueCache['list'][$_emailQueueIDIncoming]))
		{
			$_emailQueueID = $_emailQueueIDIncoming;
		}

		$_emailQueueContainer = false;
		if (isset($_emailQueueCache['list'][$_emailQueueID]))
		{
			$_emailQueueContainer = $_emailQueueCache['list'][$_emailQueueID];
		}

		$_templateGroupID = SWIFT_TemplateGroup::GetDefaultGroupID();

		if (_is_array($_emailQueueContainer) && isset($_templateGroupCache[$_emailQueueContainer['tgroupid']]))
		{
			$_templateGroupID = $_emailQueueContainer['tgroupid'];
		}

		$this->UpdatePool('emailqueueid', intval($_emailQueueID));
		$this->UpdatePool('tgroupid', intval($_templateGroupID));

		return true;
	}

	/**
	 * Load the Last Post Notification Message
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function LoadLastPostNotificationMessage() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		try {
			$_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($this->GetProperty('lastpostid')));

			// Decoding emoji characters
			$_emojiObject = new SWIFT_Emoji();

			$this->_lastPostNotificationMessage = $_emojiObject->decode($_SWIFT_TicketPostObject->GetProperty('contents'));
		} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {

			return false;
		}

		return true;
	}

	/**
	 * Retrieve the Ticket ID Object on the provided Ticket ID
	 *
	 * @author Varun Shoor
	 * @param mixed $_ticketID The Numeric or Mask Ticket ID
	 * @return SWIFT_Ticket
	 */
	static public function GetObjectOnID($_ticketID)
	{
		$_SWIFT = SWIFT::GetInstance();

		$_SWIFT_TicketObject = false;

		if (is_numeric($_ticketID)) {
			try {
				$_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataID($_ticketID));
			} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
			}
		} else {
			$_ticketID = SWIFT_Ticket::GetTicketIDFromMask($_ticketID);
			if (empty($_ticketID)) {
				return false;
			}

			try {
				$_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataID($_ticketID));
			} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
			}
		}

		if ($_SWIFT_TicketObject instanceof SWIFT_Ticket && $_SWIFT_TicketObject->GetIsClassLoaded()) {
			return $_SWIFT_TicketObject;
		}

		// By now we couldnt get the ticket object, we have to lookup the merge logs
		$_mergeTicketID = false;
		if (is_numeric($_ticketID)) {
			$_mergeTicketID = SWIFT_TicketMergeLog::GetTicketIDFromMergedTicketID($_ticketID);
		} else {
			$_mergeTicketID = SWIFT_TicketMergeLog::GetTicketIDFromMergedTicketMaskID($_ticketID);
		}

		if (!empty($_mergeTicketID)) {
			try
			{
				$_SWIFT_TicketObject = new SWIFT_Ticket(new SWIFT_DataID($_mergeTicketID));
			} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
			}

			if ($_SWIFT_TicketObject instanceof SWIFT_Ticket && $_SWIFT_TicketObject->GetIsClassLoaded())
			{
				return $_SWIFT_TicketObject;
			}
		}

		return false;
	}

	/**
	 * Mark the Tickets as Pending Auto Closure
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList
	 * @param SWIFT_AutoCloseRule $_SWIFT_AutoCloseRuleObject
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If Invalid Data is Provided
	 */
	static public function MarkAsAutoClosePending($_ticketIDList, SWIFT_AutoCloseRule $_SWIFT_AutoCloseRuleObject)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$_SWIFT_AutoCloseRuleObject instanceof SWIFT_AutoCloseRule || !$_SWIFT_AutoCloseRuleObject->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_INVALIDDATA);
		}

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('isautoclosed' => '0', 'autocloseruleid' => intval($_SWIFT_AutoCloseRuleObject->GetAutoCloseRuleID()),
			'autoclosestatus' => self::AUTOCLOSESTATUS_PENDING, 'autoclosetimeline' => DATENOW), 'UPDATE', "ticketid IN (" . BuildIN($_ticketIDList) . ")");

		// Do we need to send the pending notification?
		if ($_SWIFT_AutoCloseRuleObject->GetProperty('sendpendingnotification') == '0') {
			return true;
		}

		$_ticketsContainer = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets
			WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord()) {
			$_ticketsContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
		}

		foreach ($_ticketsContainer as $_SWIFT_TicketObject) {
			if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded()) {
				continue;
			}

			$_SWIFT_TicketEmailDispatch = new SWIFT_TicketEmailDispatch($_SWIFT_TicketObject);
			$_SWIFT_TicketEmailDispatch->DispatchPendingAutoClose($_SWIFT_AutoCloseRuleObject);
		}

		return true;
	}

	/**
	 * Mark the Tickets as Closed via Auto Closed
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList
	 * @param SWIFT_AutoCloseRule $_SWIFT_AutoCloseRuleObject
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If Invalid Data is Provided
	 */
	static public function MarkAsAutoClosed($_ticketIDList, SWIFT_AutoCloseRule $_SWIFT_AutoCloseRuleObject)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$_SWIFT_AutoCloseRuleObject instanceof SWIFT_AutoCloseRule || !$_SWIFT_AutoCloseRuleObject->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_INVALIDDATA);
		}

		$_ticketsContainer = array();
		$_SWIFT->Database->Query("SELECT * FROM " . TABLE_PREFIX . "tickets
			WHERE ticketid IN (" . BuildIN($_ticketIDList) . ")");
		while ($_SWIFT->Database->NextRecord()) {
			$_ticketsContainer[$_SWIFT->Database->Record['ticketid']] = new SWIFT_Ticket(new SWIFT_DataStore($_SWIFT->Database->Record));
		}

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array('isautoclosed' => '1', 'autocloseruleid' => intval($_SWIFT_AutoCloseRuleObject->GetAutoCloseRuleID()),
			'autoclosestatus' => self::AUTOCLOSESTATUS_CLOSED, 'autoclosetimeline' => DATENOW), 'UPDATE', "ticketid IN (" . BuildIN($_ticketIDList) . ")");

		foreach ($_ticketsContainer as $_SWIFT_TicketObject) {
			if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded()) {
				continue;
			}

			$_SWIFT_TicketObject->SetStatus($_SWIFT_AutoCloseRuleObject->GetProperty('targetticketstatusid'), true, $_SWIFT_AutoCloseRuleObject->GetProperty('suppresssurveyemail'));

			// Do we need to send the final notification?
			if ($_SWIFT_AutoCloseRuleObject->GetProperty('sendfinalnotification') == '1') {
				$_SWIFT_TicketEmailDispatch = new SWIFT_TicketEmailDispatch($_SWIFT_TicketObject);
				$_SWIFT_TicketEmailDispatch->DispatchFinalAutoClose($_SWIFT_AutoCloseRuleObject);
			}

			$_SWIFT_TicketObject->RebuildProperties();
		}

		return true;
	}

	/**
	 * Retrieve the from email with proper suffix
	 *
	 * @author Varun Shoor
	 * @param string $_fromEmailAddress
	 * @param constant $_mailType
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function RetrieveFromEmailWithSuffix($_fromEmailAddress, $_mailType)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// Have we enabled clean subjects?
		if ($this->Settings->Get('t_cleanmailsubjects') != '1') {
			return $_fromEmailAddress;
		}

		$_finalReturnEmailAddress = '';

		$_matches = array();
		if (preg_match('/^(.*?)@(.*?)$/i', $_fromEmailAddress, $_matches)) {
			$_dispatchType = 'r';
			if ($_mailType == self::MAIL_NOTIFICATION) {
				$_dispatchType = 'a';
			} else if ($_mailType == self::MAIL_THIRDPARTY) {
				$_dispatchType = 't';
			}

			$_hashChunk = substr($this->GetProperty('tickethash'), 0, 5);

			$_finalReturnEmailAddress = $_matches[1] . '+' . $_dispatchType . '.' . $_hashChunk . '.' . $this->GetTicketID() . '@' . $_matches[2];

		} else {
			return $_fromEmailAddress;
		}


		return $_finalReturnEmailAddress;
	}

	/**
	 * Reset SLA Calculations
	 *
	 * @author Mahesh Salaria
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function ResetSLA()
	{
		if (!$this->GetIsClassLoaded()) 	{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->_noSLACalculation = false;

		return true;
	}

	/**
	 * Retrieve the tickets which are generated from this ticket
	 *
	 * @author Parminder Singh
	 *
	 * @param int $_ticketID
	 *
	 * @return bool|array
	 */
	static public function RetrieveRecurrenceHistory($_ticketID)
	{
		if (empty($_ticketID)) {
			return false;
		}

		$_SWIFT = SWIFT::GetInstance();

		$_ticketIDList = $_recurrenceHistoryContainer = array();

		$_SWIFT->Database->Query("SELECT ticketid FROM " . TABLE_PREFIX . self::TABLE_NAME . "
								  WHERE recurrencefromticketid = '" . intval($_ticketID) . "'
								  ORDER BY dateline DESC");

		while ($_SWIFT->Database->NextRecord()) {
			$_ticketIDList[] = $_SWIFT->Database->Record['ticketid'];
		}

		if (!count($_ticketIDList)) {
			return array();
		}

		foreach ($_ticketIDList as $_ticketID) {
			$_recurrenceHistoryContainer[$_ticketID] = new SWIFT_Ticket(new SWIFT_DataID($_ticketID));
		}

		return $_recurrenceHistoryContainer;
	}

	/**
	 * Return the total ticket count
	 *
	 * @author Varun Shoor
	 * @return int The Total Ticket Count
	 */
	static public function GetTicketCount()
	{
		$_SWIFT = SWIFT::GetInstance();

		$_ticketCountContainer = $_SWIFT->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "tickets");
		if (isset($_ticketCountContainer['totalitems']) && !empty($_ticketCountContainer['totalitems'])) {
			return intval($_ticketCountContainer['totalitems']);
		}

		return 0;
	}

	/**
	 * Update the global property on all tickets, used to update stuff like departmentname etc.
	 *
	 * @author Varun Shoor
	 * @param string $_updateFieldName
	 * @param string $_updateFieldValue
	 * @param string $_whereFieldName
	 * @param string $_whereFieldValue
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function UpdateGlobalProperty($_updateFieldName, $_updateFieldValue, $_whereFieldName, $_whereFieldValue)
	{
		$_SWIFT = SWIFT::GetInstance();

		$_updateFieldName = $_SWIFT->Database->Escape($_updateFieldName);
		$_whereFieldName = $_SWIFT->Database->Escape($_whereFieldName);
		$_whereFieldValue = intval($_whereFieldValue); // Expected to be always int

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'tickets', array($_updateFieldName => $_updateFieldValue), 'UPDATE', $_whereFieldName . " = '" . $_SWIFT->Database->Escape($_whereFieldValue) . "'");

		return true;
	}

    /**
	* Set alert rules for ticket
	*
	* @author Ruchi Kothari
	* @param bool $_noAlerts Alert rules
	* @return bool "true" on Success, "false" otherwise
	* @throws SWIFT_Exception If the Class is not Loaded
	*/
	public function SetNoAlerts($_noAlerts)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->_noAlerts = $_noAlerts;
	}

	/**
	* Get alert rules for ticket
	*
	* @author Ruchi Kothari
	* @return bool Alert rules status
	* @throws SWIFT_Exception If the Class is not Loaded
	*/
	public function GetNoAlerts()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		return $this->_noAlerts;
	}

	/**
	 * Set Old Ticket properties. This array is used to Keep previous ticket properties after execution.
	 *
	 * @author Mahesh Salaria
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Ticket_Exception If the Class is not Loaded
	 */
	public function SetOldTicketProperties()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETSTATUS] = $this->GetProperty('ticketstatusid');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETPRIORITY] = $this->GetProperty('priorityid');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETDEPARTMENT] = $this->GetProperty('departmentid');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETOWNER] = intval($this->GetProperty('ownerstaffid'));
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETEMAILQUEUE] = $this->GetProperty('emailqueueid');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETFLAGTYPE] = $this->GetProperty('flagtype');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETCREATOR] = $this->GetProperty('creator');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETUSERGROUP] = $this->GetUserGroupID();

		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETFULLNAME] = $this->GetProperty('fullname');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETEMAIL] = $this->GetProperty('email');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETLASTREPLIER] = $this->GetProperty('lastreplier');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETSUBJECT] = $this->GetProperty('subject');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETCHARSET] = $this->GetProperty('charset');

		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETTEMPLATEGROUP] = $this->GetProperty('tgroupid');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETISRESOLVED] = $this->GetProperty('isresolved');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETTYPE] = intval($this->GetProperty('tickettypeid'));
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETWASREOPENED] = $this->GetProperty('wasreopened');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETTOTALREPLIES] = $this->GetProperty('totalreplies');
		$this->_oldTicketProperties[SWIFT_SLA::SLA_TICKETBAYESCATEGORY] = $this->GetProperty('bayescategoryid');

		return true;
	}

	/**
	 * Get Old ticket properties
	 *
	 * @author Mahesh Salaria
	 * @return array of old ticket properties
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetOldTicketProperties()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		return $this->_oldTicketProperties;
	}

	/**
	 * Retrieve ticket Notes
	 *
	 * @author Simaranjit Singh
	 *
	 * @return array
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function RetrieveNotes()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}

		$_ticketNoteContainer = array();

		$this->Database->Query("SELECT * FROM " . TABLE_PREFIX . SWIFT_TicketNote::TABLE_NAME . "
								WHERE linktype = " . intval(SWIFT_TicketNoteManager::LINKTYPE_TICKET) . "
								  AND linktypeid = " . intval($this->GetTicketID()));

		while ($this->Database->NextRecord()) {
			$_ticketNoteContainer[$this->Database->Record['ticketnoteid']] = $this->Database->Record;
		}

		return $_ticketNoteContainer;
	}
}
