<?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 Post Management Class
 *
 * @author Varun Shoor
 */
class SWIFT_TicketPost extends SWIFT_Model
{
	const TABLE_NAME		=	'ticketposts';
	const PRIMARY_KEY		=	'ticketpostid';

	const TABLE_STRUCTURE	=	"ticketpostid I PRIMARY AUTO NOTNULL,
								ticketid I DEFAULT '0' NOTNULL,
								dateline I DEFAULT '0' NOTNULL,
								userid I DEFAULT '0' NOTNULL,
								fullname C(255) DEFAULT '' NOTNULL,
								email C(255) DEFAULT '' NOTNULL,
								emailto C(255) DEFAULT '' NOTNULL,
								subject C(255) DEFAULT '' NOTNULL,
								ipaddress C(50) DEFAULT '0.0.0.0' NOTNULL,
								hasattachments I2 DEFAULT '0' NOTNULL,
								edited I2 DEFAULT '0' NOTNULL,
								editedbystaffid I DEFAULT '0' NOTNULL,
								editeddateline I DEFAULT '0' NOTNULL,
								creator I2 DEFAULT '0' NOTNULL,
								isthirdparty I2 DEFAULT '0' NOTNULL,
								ishtml I2 DEFAULT '0' NOTNULL,
								isemailed I2 DEFAULT '0' NOTNULL,
								isprivate I2 DEFAULT '0' NOTNULL,
								staffid I DEFAULT '0' NOTNULL,
								contents X2,
								contenthash C(50) DEFAULT '' NOTNULL,
								subjecthash C(50) DEFAULT '' NOTNULL,
								issurveycomment I2 DEFAULT '0' NOTNULL,

								creationmode I2 DEFAULT '0' NOTNULL,
								responsetime I DEFAULT '0' NOTNULL,
								firstresponsetime I DEFAULT '0' NOTNULL,
								slaresponsetime I DEFAULT '0' NOTNULL";

	const INDEX_1			=	'ticketid, staffid';
	const INDEX_2			=	'email, subjecthash';
	const INDEX_3			=	'creator, staffid, dateline';
	const INDEX_4			=	'responsetime';
	const INDEX_5			=	'firstresponsetime';



	protected $_dataStore = array();

	const CREATOR_STAFF = 1;
	const CREATOR_USER = 2;
	const CREATOR_CLIENT = 2;
	const CREATOR_CC = 3;
	const CREATOR_BCC = 4;
	const CREATOR_THIRDPARTY = 5;

	/**
	 * 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 Post Object');

			$this->SetIsClassLoaded(false);

			return false;
		}

		return true;
	}

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

		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 . 'ticketposts', $this->GetUpdatePool(), 'UPDATE', "ticketpostid = '" .
				intval($this->GetTicketPostID()) . "'");

		$this->ClearUpdatePool();

		return true;
	}

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

			return false;
		}

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

	/**
	 * 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)
	{
		// Is it a ID?
		if ($_SWIFT_DataObject instanceof SWIFT_DataID && $_SWIFT_DataObject->GetIsClassLoaded())
		{
			$_dataStore = $this->Database->QueryFetch("SELECT * FROM " . TABLE_PREFIX . "ticketposts WHERE ticketpostid = '" .
					intval($_SWIFT_DataObject->GetDataID()) . "'");
			if (isset($_dataStore['ticketpostid']) && !empty($_dataStore['ticketpostid']))
			{
				$this->_dataStore = $_dataStore;

				return true;
			}

		// Is it a Store?
		} else if ($_SWIFT_DataObject instanceof SWIFT_DataStore && $_SWIFT_DataObject->GetIsClassLoaded()) {
			$this->_dataStore = $_SWIFT_DataObject->GetDataStore();

			if (!isset($this->_dataStore['ticketpostid']) || empty($this->_dataStore['ticketpostid']))
			{
				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 || $_creatorType == self::CREATOR_THIRDPARTY ||
				$_creatorType == self::CREATOR_CC || $_creatorType == self::CREATOR_BCC)
		{
			return true;
		}

		return false;
	}

	/**
	 * Create a Staff Reply
	 *
	 * @author Varun Shoor
	 * @param SWIFT_Ticket $_SWIFT_TicketObject The SWIFT_Ticket Object Pointer
	 * @param SWIFT_Staff $_SWIFT_StaffObject The SWIFT_Staff Object Pointer
	 * @param constant $_creationMode The Creation Mode
	 * @param string $_contents The Reply Contents
	 * @param string $_subject The Reply Subject
	 * @param bool $_dontSendEmail (OPTIONAL) Whether to send a email to client or not
	 * @param bool $_isHTML (OPTIONAL) Whether the contents contain HTML data
	 * @param string $_overrideFromEmail (OPTIONAL) Whether to override the from email address with the given address
	 * @param bool $_isPrivate (OPTIONAL) Whether its private post
	 * @param string $_dataline(OPTIONAL) Whether any custom dateline provided
	 * @param array $_attachmentStoreStringContainer (OPTIONAL) Whether attachments provided
	 * @return int Ticket Post ID
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function CreateStaff(SWIFT_Ticket $_SWIFT_TicketObject, SWIFT_Staff $_SWIFT_StaffObject, $_creationMode, $_contents, $_subject, $_dontSendEmail = false, $_isHTML = false, $_overrideFromEmail = '', $_isPrivate = false, $_dateline = DATENOW, $_attachmentStoreStringContainer = array())
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded() ||
				!$_SWIFT_StaffObject instanceof SWIFT_Staff || !$_SWIFT_StaffObject->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		} else if (empty($_contents) || !SWIFT_Ticket::IsValidCreationMode($_creationMode)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}
		// Notification Event
		$_SWIFT_TicketObject->NotificationManager->SetEvent('newstaffreply');

		// Retrieve the signature of the staff/queue
		$_signatureContentsDefault = $_SWIFT_TicketObject->GetSignature($_isHTML, $_SWIFT_StaffObject);
		$_signatureContentsHTML = $_SWIFT_TicketObject->GetSignature(true, $_SWIFT_StaffObject);

		// First create the ticket post
		$_finalPostContents = $_contents . SWIFT_CRLF . $_signatureContentsDefault;
		$_finalDispatchContents = $_contents . SWIFT_CRLF;
		$_ticketPostID = self::Create($_SWIFT_TicketObject, $_SWIFT_StaffObject->GetProperty('fullname'), $_SWIFT_StaffObject->GetProperty('email'),
				$_finalPostContents, SWIFT_Ticket::CREATOR_STAFF, $_SWIFT_StaffObject->GetStaffID(), $_creationMode, $_subject, '', $_isHTML, false, false, $_dateline, $_isPrivate);

		// Clear overdue time?
		if ($_SWIFT->Settings->Get('t_slaresets') == '1')
		{
			/*
			 * BUG FIX - Bishwanath Jha
			 *
			 * SWIFT-2078: SLA plan is not applied correctly when ticket status is changed with staff reply
			 *
			 * Comments: Added this method to execute on shutdown. which allow SLA calculation first then clear overdue time.
			 */
			register_shutdown_function(array($_SWIFT_TicketObject, 'ClearOverdue'));
		}

		$_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($_ticketPostID));

		$_SWIFT_TicketObject->ProcessPostAttachments($_SWIFT_TicketPostObject, 'replyattachments');

		if (count($_attachmentStoreStringContainer) > 0) {
			foreach ($_attachmentStoreStringContainer as $_SWIFT_AttachmentStoreStringObject) {
				if ($_SWIFT_AttachmentStoreStringObject instanceof SWIFT_AttachmentStoreString) {
					$_SWIFT_AttachmentObject = SWIFT_Attachment::Create(SWIFT_Attachment::LINKTYPE_TICKETPOST, $_ticketPostID, $_SWIFT_AttachmentStoreStringObject, $_SWIFT_TicketObject->GetTicketID());

					if (!$_SWIFT_AttachmentObject instanceof SWIFT_Attachment || !$_SWIFT_AttachmentObject->GetIsClassLoaded()) {
						return false;
					}
				}
			}

			SWIFT_Ticket::RecalculateHasAttachmentProperty(array($_SWIFT_TicketObject->GetTicketID()));
		}

		if (!$_dontSendEmail && !$_isPrivate)
		{
			// Carry out the email dispatch logic
			$_SWIFT_TicketEmailDispatchObject = new SWIFT_TicketEmailDispatch($_SWIFT_TicketObject);
			$_SWIFT_TicketEmailDispatchObject->DispatchStaffReply($_SWIFT_StaffObject, $_finalDispatchContents, $_isHTML, $_overrideFromEmail, array($_signatureContentsDefault, $_signatureContentsHTML));
		}

		return $_SWIFT_TicketPostObject;
	}

	/**
	 * Create a Forward
	 *
	 * @author Varun Shoor
	 * @param SWIFT_Ticket $_SWIFT_TicketObject The SWIFT_Ticket Object Pointer
	 * @param SWIFT_Staff $_SWIFT_StaffObject The SWIFT_Staff Object Pointer
	 * @param constant $_creationMode The Creation Mode
	 * @param string $_contents The Reply Contents
	 * @param string $_subject The Reply Subject
	 * @param string $_emailTo The Destination Email Address
	 * @param bool $_dontSendEmail (OPTIONAL) Whether to send a email to client or not
	 * @param bool $_isHTML (OPTIONAL) Whether the contents contain HTML data
	 * @param string $_overrideFromEmail (OPTIONAL) Whether to override the from email address with the given address
	 * @param bool $_isPrivate (OPTIONAL) Whether its private post
	 * @return int Ticket Post ID
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function CreateForward(SWIFT_Ticket $_SWIFT_TicketObject, SWIFT_Staff $_SWIFT_StaffObject, $_creationMode,
			$_contents, $_subject, $_emailTo, $_dontSendEmail = false, $_isHTML = false, $_overrideFromEmail = '', $_isPrivate = false)
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded() ||
				!$_SWIFT_StaffObject instanceof SWIFT_Staff || !$_SWIFT_StaffObject->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		} else if (empty($_contents) || !SWIFT_Ticket::IsValidCreationMode($_creationMode)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA);
		}

		// Retrieve the signature of the staff/queue
		$_signatureContentsDefault = $_SWIFT_TicketObject->GetSignature($_isHTML, $_SWIFT_StaffObject);
		$_signatureContentsHTML = $_SWIFT_TicketObject->GetSignature(true, $_SWIFT_StaffObject);

		// First create the ticket post
		$_finalDispatchContents = $_contents . SWIFT_CRLF;
		$_finalPostContents = $_contents . SWIFT_CRLF . $_signatureContentsDefault;
		$_ticketPostID = self::Create($_SWIFT_TicketObject, $_SWIFT_StaffObject->GetProperty('fullname'), $_SWIFT_StaffObject->GetProperty('email'),
		$_finalPostContents, SWIFT_Ticket::CREATOR_STAFF, $_SWIFT_StaffObject->GetStaffID(), $_creationMode, $_subject, $_emailTo, $_isHTML, true, false, DATENOW, $_isPrivate);

		$_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($_ticketPostID));

		$_SWIFT_TicketObject->ProcessPostAttachments($_SWIFT_TicketPostObject, 'forwardattachments');

		// Carry out the email dispatch logic
		if ($_dontSendEmail == false) {
			$_SWIFT_TicketEmailDispatchObject = new SWIFT_TicketEmailDispatch($_SWIFT_TicketObject);

			/*
			* BUG FIX - Ravi Sharma
			*
			* SWIFT-3402 Edit Subject Field option should be available on ticket forwarding page.
			*/
			$_SWIFT_TicketEmailDispatchObject->DispatchForwardReply($_emailTo, $_SWIFT_StaffObject, $_finalDispatchContents, $_isHTML, $_overrideFromEmail, array(
																																								 $_signatureContentsDefault,
																																								 $_signatureContentsHTML
																																							), $_subject);
		}

		return $_ticketPostID;
	}

	/**
	 * Create a Client Ticket Post
	 *
	 * @author Varun Shoor
	 * @param SWIFT_Ticket $_SWIFT_TicketObject The SWIFT_Ticket Object Pointer
	 * @param SWIFT_User $_SWIFT_UserObject The SWIFT_User Object Pointer
	 * @param constant $_creationMode The Creation Mode
	 * @param string $_contents The Reply Contents
	 * @param string $_subject The Reply Subject
	 * @param constant $_creatorType The Creator Type
	 * @param bool $_isHTML (OPTIONAL) Whether the contents contain HTML data
	 * @param string $_customEmail (OPTIONAL) The custom email from which the post was received
	 * @param string $_attachmentsContainer (OPTIONAL) The Attachments Container
	 * @param string $_dataline(OPTIONAL) Whether any custom dateline provided
	 * @param string $_attachmentStoreStringContainer (OPTIONAL) The AttachmentStoreStringObject Container
	 * @return int Ticket Post ID
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function CreateClient(SWIFT_Ticket $_SWIFT_TicketObject, SWIFT_User $_SWIFT_UserObject, $_creationMode, $_contents, $_subject, $_creatorType, $_isHTML = false, $_customEmail = '', $_attachmentsContainer = array(), $_dateline = DATENOW, $_attachmentStoreStringContainer = array())
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded() ||
				!$_SWIFT_UserObject instanceof SWIFT_User || !$_SWIFT_UserObject->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA . '2');
		} else if (empty($_contents) || !SWIFT_Ticket::IsValidCreationMode($_creationMode)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA . '3');
		}

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

		$_isThirdParty = false;
		if ($_creatorType == self::CREATOR_THIRDPARTY)
		{
			$_isThirdParty = true;
		}

		$_finalEmail = '';
		if (empty($_customEmail))
		{
			$_userEmailList = $_SWIFT_UserObject->GetEmailList();
			$_finalEmail = $_userEmailList[0];
		} else {
			$_finalEmail = $_customEmail;
		}

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

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1140 "Ticket Status (Post Parse)" criteria does not work
		 *
		 * Comments: Added has status changed property to make sure that this does not override the status set by parser rule
		 */
		if (isset($_ticketStatusCache[$_SWIFT->Settings->Get('t_cstatusupd')]) && $_SWIFT_TicketObject->GetHasStatusChanged() == false)
		{
			$_SWIFT_TicketObject->SetStatus($_SWIFT->Settings->Get('t_cstatusupd'));
		}

		// First create the ticket post
		$_finalPostContents = $_contents;
		$_ticketPostID = self::Create($_SWIFT_TicketObject, $_SWIFT_UserObject->GetProperty('fullname'), $_finalEmail,
				$_finalPostContents, $_creatorType, $_SWIFT_UserObject->GetUserID(), $_creationMode, $_subject, '', $_isHTML, $_isThirdParty, false, $_dateline);

		// Execute SLA
		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-2563 Resolution time gets reset on ticket after every client reply
		 *
		 */
		$_SWIFT_TicketObject->ExecuteSLA(false);

		// Processing Attachments
		if (count($_attachmentStoreStringContainer) > 0) {
			foreach ($_attachmentStoreStringContainer as $_SWIFT_AttachmentStoreStringObject) {
				if ($_SWIFT_AttachmentStoreStringObject instanceof SWIFT_AttachmentStoreString) {
					$_SWIFT_AttachmentObject = SWIFT_Attachment::Create(SWIFT_Attachment::LINKTYPE_TICKETPOST, $_ticketPostID, $_SWIFT_AttachmentStoreStringObject, $_SWIFT_TicketObject->GetTicketID());

					if (!$_SWIFT_AttachmentObject instanceof SWIFT_Attachment || !$_SWIFT_AttachmentObject->GetIsClassLoaded()) {
						return false;
					}
				}
			}
			SWIFT_Ticket::RecalculateHasAttachmentProperty(array($_SWIFT_TicketObject->GetTicketID()));
		}

		// Carry out the email dispatch logic

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1736 Help desk should not send reply to recipient address if it is already added in the email as CC or TO
		 *
		 * Comments: Dont send the emails to other recipients if the creation mode is email. This prevents the system from sending duplicate replies to other recipients.
		 */
		if ($_creationMode != SWIFT_Ticket::CREATIONMODE_EMAIL) {
			$_SWIFT_TicketEmailDispatchObject = new SWIFT_TicketEmailDispatch($_SWIFT_TicketObject);
			$_SWIFT_TicketEmailDispatchObject->DispatchUserReply($_SWIFT_UserObject, $_contents, $_isHTML, $_attachmentsContainer, $_finalEmail, $_isThirdParty);
		}

		return $_ticketPostID;
	}

	/**
	 * Create a Client Ticket Post
	 *
	 * @author Varun Shoor
	 * @param SWIFT_Ticket $_SWIFT_TicketObject The SWIFT_Ticket Object Pointer
	 * @param SWIFT_User $_SWIFT_UserObject The SWIFT_User Object Pointer
	 * @param constant $_creationMode The Creation Mode
	 * @param string $_contents The Reply Contents
	 * @param string $_subject The Reply Subject
	 * @param constant $_creatorType The Creator Type
	 * @param bool $_isHTML (OPTIONAL) Whether the contents contain HTML data
	 * @param string $_customEmail (OPTIONAL) The custom email from which the post was received
	 * @return int Ticket Post ID
	 * @throws SWIFT_Ticket_Exception If Invalid Data is Provided
	 */
	static public function CreateClientSurvey(SWIFT_Ticket $_SWIFT_TicketObject, SWIFT_User $_SWIFT_UserObject, $_creationMode, $_contents, $_subject, $_creatorType,
			$_isHTML = false, $_customEmail = '')
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded() ||
				!$_SWIFT_UserObject instanceof SWIFT_User || !$_SWIFT_UserObject->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA . '2');
		} else if (empty($_contents) || !SWIFT_Ticket::IsValidCreationMode($_creationMode)) {
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA . '3');
		}

		$_isThirdParty = false;
		if ($_creatorType == self::CREATOR_THIRDPARTY)
		{
			$_isThirdParty = true;
		}

		$_finalEmail = '';
		if (empty($_customEmail))
		{
			$_userEmailList = $_SWIFT_UserObject->GetEmailList();
			$_finalEmail = $_userEmailList[0];
		} else {
			$_finalEmail = $_customEmail;
		}

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

		// First create the ticket post
		$_finalPostContents = $_contents;
		$_ticketPostID = self::Create($_SWIFT_TicketObject, $_SWIFT_UserObject->GetProperty('fullname'), $_finalEmail,
				$_finalPostContents, $_creatorType, $_SWIFT_UserObject->GetUserID(), $_creationMode, $_subject, '', $_isHTML, $_isThirdParty, true);

		return $_ticketPostID;
	}

	/**
	 * Create a new Ticket Post
	 *
	 * @author Varun Shoor
	 * @param object $_SWIFT_TicketObject The SWIFT_Ticket Object Pointer
	 * @param string $_fullName The Fullname
	 * @param string $_email The Email Address
	 * @param string $_contents The contents of the post
	 * @param constant $_creatorType The Creator Type
	 * @param int $_creatorID The Creator ID
	 * @param constant $_creationMode The Creation Mode
	 * @param string $_subject (OPTIONAL) The Subject
	 * @param string $_emailTo (OPTIONAL) The Email to which this post was received for, generally the email address of the queue
	 * @param bool $_isHTML (OPTIONAL) Whether this is a HTML post
	 * @param bool $_isThirdParty (OPTIONAL) Whether its a third party reply
	 * @param bool $_isSurveyComment (OPTIONAL) Whether its a survey comment
	 * @param bool $_isPrivate (OPTIONAL) Whether its private post
	 * @return mixed "_ticketPostID" (INT) 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(SWIFT_Ticket $_SWIFT_TicketObject, $_fullName, $_email, $_contents, $_creatorType, $_creatorID, $_creationMode,
			$_subject, $_emailTo = '', $_isHTML = false, $_isThirdParty = false, $_isSurveyComment = false, $_dateline = DATENOW, $_isPrivate = false)
	{
		$_SWIFT = SWIFT::GetInstance();

		$_creatorID = intval($_creatorID);

		if (!$_SWIFT_TicketObject instanceof SWIFT_Ticket || !$_SWIFT_TicketObject->GetIsClassLoaded() || empty($_fullName) || empty($_email) ||
				$_contents == '' || !self::IsValidCreatorType($_creatorType) ||
				!SWIFT_Ticket::IsValidCreationMode($_creationMode))
		{
			throw new SWIFT_Ticket_Exception(SWIFT_INVALIDDATA . '4');

			return false;
		}

		$_staffID = $_userID = 0;
		if ($_creatorType == SWIFT_Ticket::CREATOR_STAFF)
		{
			$_staffID = intval($_creatorID);
		} else if ($_creatorType == SWIFT_Ticket::CREATOR_USER) {
			$_userID = intval($_creatorID);
		}

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

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

		/*
		 * BUG FIX - Rajat Garg
		 *
		 * SWIFT-2210 Response times in reports are not calculated in accordance with SLA-defined working hours
		 *
		 * Comments: GetWorkingSeconds call if SLA is applicable, otherwise simple time difference
		 */
		$SLAManager = new SWIFT_SLAManager();
		$_SLA       = false;

		if ($_SWIFT_TicketObject->GetProperty('ticketslaplanid') != '0') {
			$_SLA = new SWIFT_SLA(new SWIFT_DataID($_SWIFT_TicketObject->GetProperty('ticketslaplanid')));
		}

		if (!$_SLA && $_SWIFT_TicketObject->GetProperty('slaplanid') != '0') {
			$_SLA = new SWIFT_SLA(new SWIFT_DataID($_SWIFT_TicketObject->GetProperty('slaplanid')));
		}

		/**
		 * BUG FIX - Ashish Kataria <ashish.kataria@kayako.com>, Nidhi Gupta <nidhi.gupta@kayako.com>
		 *
		 * SWIFT-2210 Response times in reports are not calculated in accordance with SLA-defined working hours
		 *
		 * Comments: Calculated SLA response time
		 */
		// Calculate average response time
		// Does this ticket have a last post?
		$_responseTime = $_SLAResponseTime = 0;

		if ($_SWIFT_TicketObject->GetProperty('lastpostid') != '0') {
			try {
				$_TicketPost   = new SWIFT_TicketPost(new SWIFT_DataID($_SWIFT_TicketObject->GetProperty('lastpostid')));
				$_responseTime = DATENOW - $_TicketPost->GetProperty('dateline');

				$_replyTimeline = self::GetReplyTimeline($_SWIFT_TicketObject->GetID());

				if ($_SLA && $_creatorType == self::CREATOR_STAFF && $_replyTimeline > 0 ) {
					$_SLAResponseTime = $SLAManager->GetSLAResponseTime($_SLA, $_replyTimeline, DATENOW);
				}

				// Was the last post by client?
				if ($_creatorType == self::CREATOR_STAFF && $_TicketPost->GetProperty('creator') != self::CREATOR_STAFF) {
					$_SWIFT_TicketObject->UpdateAverageResponseTime($_responseTime);
					//$_SWIFT_TicketObject->UpdateAverageSLAResponseTime($_SLAResponseTime, $_TicketPost->Get('ticketid'));
				}
			} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
			}
		}

		// The creator of post is staff, first response time is empty AND we have a last post.. and the total replies is less than four
		$_firstResponseTime = 0;
		if ($_creatorType == self::CREATOR_STAFF && $_SWIFT_TicketObject->GetProperty('firstresponsetime') == '0' && $_SWIFT_TicketObject->GetProperty('lastpostid') != '0' && $_SWIFT_TicketObject->GetProperty('totalreplies') <= 4 && $_isPrivate == false) {
			$_firstResponseTime = DATENOW - $_SWIFT_TicketObject->GetProperty('dateline');
		}

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'ticketposts', array(
																		  'ticketid'        => intval($_SWIFT_TicketObject->GetTicketID()),
																		  'fullname'        => $_fullName, 'email' => mb_strtolower($_email), 'emailto' => mb_strtolower($_emailTo),
																		  'subject'         => $_subject, 'ipaddress' => $_ipAddress,
																		  'creator'         => intval($_creatorType), 'isemailed' => intval($_isEmailed), 'staffid' => intval($_staffID),
																		  'userid'          => intval($_userID),
																		  'contents'        => $_contents, 'contenthash' => sha1($_contents), 'subjecthash' => sha1($_subject),
																		  'creationmode'    => intval($_creationMode),
																		  'dateline'        => $_dateline, 'ishtml' => intval($_isHTML), 'isthirdparty' => intval($_isThirdParty),
																		  'issurveycomment' => intval($_isSurveyComment),
																		  'responsetime'    => intval($_responseTime),
																		  'firstresponsetime' => intval($_firstResponseTime),
																		  'slaresponsetime' => intval($_SLAResponseTime),
																		  'isprivate'       => intval($_isPrivate)
																	 ), 'INSERT');

		$_ticketPostID = $_SWIFT->Database->Insert_ID();

		if (!$_ticketPostID) {
			throw new SWIFT_Exception(SWIFT_CREATEFAILED);
		}

		$_SWIFT_TicketPostObject = new SWIFT_TicketPost(new SWIFT_DataID($_ticketPostID));

		// Was the last post by staff?
		$_SWIFT_TicketObject->UpdateAverageSLAResponseTime($_SLAResponseTime, $_SWIFT_TicketPostObject->Get('ticketid'));

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

		$_SWIFT_TicketObject->UpdatePool('lastpostid', intval($_ticketPostID));
		$_SWIFT_TicketObject->UpdatePool('lastactivity', DATENOW);
		$_SWIFT_TicketObject->UpdatePool('lastreplier', $_fullName);
		$_SWIFT_TicketObject->UpdatePool('autoclosestatus', SWIFT_Ticket::AUTOCLOSESTATUS_NONE);
		$_SWIFT_TicketObject->UpdatePool('autoclosetimeline', '0');

		if ($_creatorType == SWIFT_Ticket::CREATOR_STAFF && $_isPrivate == false)
		{
			$_SWIFT_TicketObject->UpdatePool('laststaffreplytime', DATENOW);
		} else if ($_creatorType == SWIFT_Ticket::CREATOR_USER) {
			$_SWIFT_TicketObject->UpdatePool('lastuserreplytime', DATENOW);
		}

		if ($_isPrivate == false)
		{
			$_totalTicketReplies = intval($_SWIFT_TicketObject->GetProperty('totalreplies'));
			$_SWIFT_TicketObject->UpdatePool('totalreplies', $_totalTicketReplies + 1);
		}

		$_SWIFT_TicketObject->SetWatcherProperties($_fullName, sprintf($_SWIFT->Language->Get('watcherprefix'), $_fullName, $_email) . SWIFT_CRLF . $_contents);


		// Index the words in the post for searching
		$eng = new SWIFT_SearchEngine();
		$eng->Insert($_SWIFT_TicketObject->GetTicketID(), $_ticketPostID, SWIFT_SearchEngine::TYPE_TICKET, $_contents);

		// Create unique message id
		SWIFT_TicketMessageID::Create($_SWIFT_TicketObject, $_SWIFT_TicketPostObject);

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1609 ticketpostid is always set 0 in swticketauditlogs table
		 */
		// Create Audit Log
		SWIFT_TicketAuditLog::AddToLog($_SWIFT_TicketObject, $_SWIFT_TicketPostObject, SWIFT_TicketAuditLog::ACTION_NEWTICKETPOST,
				sprintf($_SWIFT->Language->Get('al_newreply'), $_fullName, $_email), SWIFT_TicketAuditLog::VALUE_NONE, 0, '',
				0, '');

		return $_ticketPostID;
	}

	/**
	 * Get Timeline for consecutive posts by user
	 *
	 * @author Nidhi Gupta <nidhi.gupta@kayako.com>
	 *
	 * @param $_ticketID
	 *
	 * @return int
	 */
	public static function GetReplyTimeline($_ticketID)
	{
		$_SWIFT                  = SWIFT::GetInstance();
		$_staffLastReplyTimeline = $_SWIFT->Database->QueryFetch('SELECT dateline FROM  ' . TABLE_PREFIX . 'ticketposts
																   WHERE ticketid = ' . $_SWIFT->Database->Escape($_ticketID) . '
															  		 AND creator = ' . self::CREATOR_STAFF . '
																  ORDER BY ticketpostid DESC');

		// Need to pick dateline from staff post.
		$_whereCondition = (is_array($_staffLastReplyTimeline) && array_key_exists('dateline', $_staffLastReplyTimeline)) ? ' AND dateline > ' . $_staffLastReplyTimeline['dateline'] : '';

		$_currentTimeline = $_SWIFT->Database->QueryFetch('SELECT dateline FROM ' . TABLE_PREFIX . 'ticketposts
															WHERE ticketid = ' . $_SWIFT->Database->Escape($_ticketID) . '
															  AND creator = ' . self::CREATOR_CLIENT . $_whereCondition . '
														   ORDER BY ticketpostid ASC');

		return (is_array($_currentTimeline) && array_key_exists('dateline', $_currentTimeline)) ?  $_currentTimeline['dateline'] : 0;
	}

	/**
	 * Update the Ticket Post Record
	 *
	 * @author Varun Shoor
	 * @param string $_contents The Ticket Post Contents
	 * @param int $_staffID (OPTIONAL) The Staff ID making the change
	 * @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($_contents, $_staffID = 0)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Ticket_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// Search engine index
		$eng = new SWIFT_SearchEngine();
		$eng->Update($this->GetProperty('ticketid'), $this->GetProperty('ticketpostid'), SWIFT_SearchEngine::TYPE_TICKET, $_contents);

		$this->UpdatePool('contents', $_contents);
		$this->UpdatePool('contenthash', sha1($_contents));
		$this->UpdatePool('edited', '1');
		$this->UpdatePool('editedbystaffid', intval($_staffID));
		$this->UpdatePool('editeddateline', DATENOW);

		$this->ProcessUpdatePool();

		return true;
	}

	/**
	 * Retrieve the display contents for this ticket post
	 *
	 * @author Varun Shoor
	 * @return string The display contents
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetDisplayContents() {
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_SWIFT = SWIFT::GetInstance();

		$_parsedContents = $this->GetProperty('contents');

		// Decoding emoji characters
		$_emojiObject = new SWIFT_Emoji();

		$_parsedContents  = $_emojiObject->decode($_parsedContents);

		$_isHTML = SWIFT_HTML::DetectHTMLContent($this->GetProperty('contents'));

		/*
		 * BUG FIX - Ravi Sharma
		 *
		 * SWIFT-4026 DOMDocument::loadHTML(): Empty string supplied as input (./__apps/tickets/models/Ticket/class.SWIFT_TicketPost.php:737
		 *
		 * Comment: Support for inline "cid" image sources, skipping for non html or empty content
		 */
		if ($this->Get('ishtml') == '1' && !empty($_parsedContents)) {
			$_Ticket = new SWIFT_Ticket(new SWIFT_DataID($this->Get('ticketid')));
			$_ticketAttachmentContainer = IIF($_Ticket->Get('hasattachments') == '1', $_Ticket->GetAttachmentContainer(), array());

			if (isset($_ticketAttachmentContainer[$this->GetID()]) && _is_array($_ticketAttachmentContainer[$this->GetID()])) {
				$_DOMDocument = new DOMDocument();

				$_previousErrorState = libxml_use_internal_errors(true);
				/**
				 * BUG FIX : Saloni Dhall <saloni.dhall@kayako.com>
				 *
				 * SWIFT-4333 : An extra space is added to the contents of ticket created from Outlook
				 *
				 * Comments : Microsoft(Outlook) uses namespaces in its documents <o:p>, which in turns converted to <p> tags causing additional spaces in staff CP.
				 */
				$_DOMDocument->loadHTML(mb_convert_encoding(preg_replace('/<(meta|o:p)[^>]*\>/i', '', $_parsedContents), 'HTML-ENTITIES', $_SWIFT->Language->Get('charset')));

				$_imageContainer = $_DOMDocument->getElementsByTagName('img');
				foreach ($_ticketAttachmentContainer[$this->GetID()] as $_attachmentContainer) {
					$_attachmentSource = SWIFT::Get('basename') . '/Tickets/Ticket/GetAttachment/' . $_Ticket->GetID() . '/' . $_attachmentContainer['attachmentid'];

					for ($index = 0; $index < $_imageContainer->length; $index++) {
						if (isset($_imageContainer->item($index)->attributes->getNamedItem('src')->nodeValue) && $_imageContainer->item($index)->attributes->getNamedItem('src')->nodeValue == "cid:" . $_attachmentContainer['contentid']) {
							$_imageContainer->item($index)->attributes->getNamedItem('src')->nodeValue = $_attachmentSource;

							break;
						}
					}
				}

				$_parsedContents = $_DOMDocument->saveHTML();
				libxml_use_internal_errors($_previousErrorState);
			}
		}

		// Staff Creator?
		if ($this->GetProperty('creator') == SWIFT_Ticket::CREATOR_STAFF) {
			$_parsedContents = self::GetParsedContents($_parsedContents, $this->Settings->Get('t_ochtml'), $_isHTML);
			$_parsedContents = SWIFT_HTML::HTMLBreaklines($_parsedContents, $_isHTML);

		// Client Creator?
		} else {
			$_parsedContents = self::GetParsedContents($_parsedContents, $this->Settings->Get('t_chtml'), $_isHTML);
			$_parsedContents = SWIFT_HTML::HTMLBreaklines($_parsedContents, $_isHTML);
		}

		// Always strip javascript out of the contents.. ALWAYS!
		/*
		 * BUG FIX - Simaranjit Singh
		 *
		 * SWIFT-3437 Vulnerability issue
		 *
		 * Comments: Sanitizing final results
		 */
		return $this->Input->SanitizeForXSS($_parsedContents);
	}


	/**
	 * Retrieve the parsed contents
	 *
	 * @author Varun Shoor
	 * @param string $_contents The Contents to Parse
	 * @param string $_settingValue The Setting Value
	 * @param bool $_isContentHTML
	 * @param string $_overrideAllowableTags (OPTIONAL)
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If Invalid Data is Provided
	 */
	static public function GetParsedContents($_contents, $_settingValue, $_isContentHTML = false, $_overrideAllowableTags = false) {
		$_SWIFT = SWIFT::GetInstance();

		$_SWIFT_StringHTMLToTextObject = new SWIFT_StringHTMLToText();

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1826 Replies that contain the code <base href="x-msg://27/"> , does not allow ticket tabs to work properly
		 *
		 * Comments: Cleanup base tags
		 */
		$_searchBase = array('@<base[^>]*?>@si');
		$_contents = preg_replace($_searchBase, '', $_contents);


		// SWIFT-393 - If no HTML is present, no need to strip.
		if (!preg_match("/([\<])([^\>]{1,})*([\>])/i", $_contents) && $_SWIFT->Interface->GetInterface() != SWIFT_Interface::INTERFACE_STAFFAPI)
		{
			$_settingValue = 'entities';
		}

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1377 Any text between angular brackets is stripped even if it arrives in text part of email.
		 * SWIFT-1752 Encoded entities appearing in ticket posts
		 *
		 * Comments: If we dont find the base HTML tags and the mode is set to strip, then we force it to use entities. This prevents any false tag cleanup from the system.
		 */
		if ($_settingValue == 'strip' && !preg_match("/<(\s+)?(div|p|span|br)([\s]+(.*)|[\s]*\/)?(\s+)?>/i", $_contents) && $_SWIFT->Interface->GetInterface() != SWIFT_Interface::INTERFACE_STAFFAPI) {
			$_settingValue = 'entities';
		}

		switch ($_settingValue) {
			case 'entities':
				// If its HTML, try to convert to readable text first
				if ($_isContentHTML) {
					$_contents = $_SWIFT_StringHTMLToTextObject->Convert($_contents);
				}

				return AutoLink(htmlspecialchars($_contents));
				break;

			case 'htmlpurifier':
			{
				return $_contents;

				$_SWIFT_HTMLPurifierObject = $_SWIFT->HTMLPurifier;
				if (!$_SWIFT->HTMLPurifier instanceof SWIFT_HTMLPurifier) {
					$_SWIFT_HTMLPurifierObject = new SWIFT_HTMLPurifier();
					$_SWIFT->SetClass('HTMLPurifier', $_SWIFT_HTMLPurifierObject);
				}

				return $_SWIFT_HTMLPurifierObject->Purify($_contents);
			}

			case 'html':
				/*
				 * BUG FIX - Varun Shoor
				 *
				 * SWIFT-1780 In case of No processing, style tag should be removed from the contents
				 *
				 * Comments: Strip style tags completely
				 */
				/*
				 * BUG FIX - Parminder Singh
				 *
				 * SWIFT-2162: Extra line spaces are showing in ticket post, if we send an email from outlook
				 *
				 */
				/*$_search = array('@<style[^>]*?>.*?</style>@si');
				$_contents = preg_replace($_search, '', $_contents);*/
				$HTML = new SWIFT_HTML();
				return $HTML->Beautify($_contents, $_isContentHTML);

			case 'strip':
				{
					$_preAllowableTags = $_allowableTags = $_allowableTagsAttributes = '';

					if ($_SWIFT->Settings->Get('t_allowhtml') == '1') {
						$_preAllowableTags = $_SWIFT->Settings->Get('t_allowableadvtags');
						$_allowableTagsAttributes = $_SWIFT->Settings->Get('t_allowableadvtagsattributes');
					}

					if ($_overrideAllowableTags !== false) {
						$_preAllowableTags = $_overrideAllowableTags;
					}

					if (strstr($_preAllowableTags, ',')) {
						$_tagsContainer = explode(',', $_preAllowableTags);
						foreach ($_tagsContainer as $_tagName) {
							$_allowableTags .= '<' . Clean(trim($_tagName)) . '>';
						}
					} else if (!empty($_preAllowableTags)) {
						$_allowableTags = '<' . Clean($_preAllowableTags) . '>';
					}

					/*
					 * BUG FIX - Varun Shoor
					 *
					 * SWIFT-1472 In case of strip tags, <style> tag does not process correctly.
					 *
					 * Comments: None
					 */
					if (!strstr($_allowableTags, '<style>')) {
						// Strip style tags properly
						$_search = array('@<style[^>]*?>.*?</style>@si');
						$_contents = preg_replace($_search, '', $_contents);
					}

					/*
					 * BUG FIX - Varun Shoor
					 *
					 * SWIFT-1473 Software does not process <br/> and <br /> tags, in case of strip tags.
					 *
					 * Comments: None
					 */
					$_contents = preg_replace('/<(\s+)?br(\s+)?(\/)?>/i', '<br>', $_contents);

					// strip_tags() appears to become nauseated at the site of a <!DOCTYPE> declaration (Ref: http://php.net/manual/en/function.strip-tags.php)
					$_contents = str_replace('<!DOCTYPE', '<DOCTYPE', $_contents);

					/*
					 * BUG FIX - Varun Shoor
					 *
					 * SWIFT-1674 Replies/Tickets from Outlook render with an abnormal amount of line spaces and broken HTML tags
					 *
					 * Comments: None
					 */
					return preg_replace('/\n{2,}/', "\n\n", strip_tags_attributes($_contents, $_allowableTags, $_allowableTagsAttributes));
				}

			default:
				break;
		}

		return false;
	}

	/**
	 * Delete the Ticket Post 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->GetTicketPostID()));

		$this->SetIsClassLoaded(false);

		return true;
	}

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

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

		$_finalTicketPostIDList = array();
		$_SWIFT->Database->Query("SELECT ticketpostid FROM " . TABLE_PREFIX . "ticketposts WHERE ticketpostid IN (" . BuildIN($_ticketPostIDList) .
				")");
		while ($_SWIFT->Database->NextRecord())
		{
			$_finalTicketPostIDList[] = intval($_SWIFT->Database->Record['ticketpostid']);
		}

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

		$_SWIFT->Database->Query("DELETE FROM " . TABLE_PREFIX . "ticketposts WHERE ticketpostid IN (" . BuildIN($_finalTicketPostIDList) . ")");

		// Clear Attachments
		SWIFT_Attachment::DeleteOnTicketPost($_finalTicketPostIDList);

		// Clear Notes
		SWIFT_TicketPostNote::DeleteOnTicketPost($_finalTicketPostIDList);

		return true;
	}

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

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

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

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

		// Search engine index
		//
		// We're nuking all of these ticket posts, based on ticket IDs.
		// In the search index, tickets are objects and ticket posts are sub-objects.
		// So, what we do is delete all of the objects (tickets) and the posts go with them.
		// No other data about tickets is stored in the index
		$eng = new SWIFT_SearchEngine();
		$eng->DeleteList($_ticketIDList, SWIFT_SearchEngine::TYPE_TICKET);

		self::DeleteList($_ticketPostIDList);

		return true;
	}

	/**
	 * Replace the current ticket id all tickets with the new one
	 *
	 * @author Varun Shoor
	 * @param array $_ticketIDList The Old Ticket ID List
	 * @param SWIFT_Ticket $_SWIFT_ParentTicketObject The Parent Ticket Object
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If Invalid Data is Provided
	 */
	static public function ReplaceTicket($_ticketIDList, SWIFT_Ticket $_SWIFT_ParentTicketObject) {
		$_SWIFT = SWIFT::GetInstance();

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

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

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'ticketposts', array('ticketid' => intval($_SWIFT_ParentTicketObject->GetTicketID())), 'UPDATE', "ticketid IN (" . BuildIN($_ticketIDList) . ")");

		return true;
	}

	/**
	 * Retrieve the processed HTML & Text Contents
	 *
	 * @author Varun Shoor
	 * @param string $_contents The Real Contents
	 * @param bool $_isHTML Whether the content is HTML
	 * @return array array(text contents, html contents)
	 * @throws SWIFT_Exception If Invalid Data is Provided
	 */
	static public function RetrieveProcessedContent($_contents, $_isHTML)
	{
		$_textContents = $_htmlContents = '';

		if ($_isHTML == true)
		{
			$_textContents = strip_tags(br2nl($_contents));
			$_htmlContents = $_contents;

			$_htmlContents = self::GetParsedContents($_htmlContents, 'strip', true);
		} else {
			$_textContents = $_contents;
			$_htmlContents = nl2br(htmlspecialchars($_contents));
		}

		return array($_textContents, $_htmlContents);
	}

	/**
	 * Retrieve contents for quote dispatch
	 *
	 * @author Varun Shoor
	 * @return string The Quote Contents
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetQuoteContents()
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_SWIFT_StringHTMLToTextObject = new SWIFT_StringHTMLToText();

		/*
		 * BUG FIX - Varun Shoor
		 *
		 * SWIFT-1499 Quote button removes the line breakes while we quote the ticket post in staff CP
		 *
		 */
		// Decoding emoji characters
		$_emojiObject = new SWIFT_Emoji();

		$_ticketContents = $_emojiObject->decode($this->GetProperty('contents'));
		$_finalContents  = $_SWIFT_StringHTMLToTextObject->Convert(preg_replace("#(\r\n|\r|\n)#s", "<br>", $_ticketContents), false);

		$_finalContentsContainer = explode(SWIFT_CRLF, $_finalContents);

		$_dispatchContents = '';
		foreach ($_finalContentsContainer as $_line)
		{
			$_dispatchContents .= ' > ' . $_line . SWIFT_CRLF;
		}

		return $_dispatchContents;
	}

	/**
	 * Retrieve the total ticket post count
	 *
	 * @author Varun Shoor
	 * @return int The Total Ticket Post Count
	 */
	static public function GetPostCount()
	{
		$_SWIFT = SWIFT::GetInstance();

		$_ticketPostCount = $_SWIFT->Database->QueryFetch("SELECT COUNT(*) AS totalitems FROM " . TABLE_PREFIX . "ticketposts");
		if (isset($_ticketPostCount['totalitems']))
		{
			return intval($_ticketPostCount['totalitems']);
		}

		return 0;
	}

	/**
	 * Update the Full Name and Email on Ticket & User ID
	 *
	 * @author Varun Shoor
	 * @param int $_ticketID
	 * @param int $_existingUserID
	 * @param int $_newUserID
	 * @param int $_newFullName
	 * @param int $_newEmail
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If Invalid Data is Provided
	 */
	static public function UpdateFullnameAndEmailOnTicketUser($_ticketID, $_existingUserID, $_newUserID, $_newFullName, $_newEmail)
	{
		$_SWIFT = SWIFT::GetInstance();

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

		$_SWIFT->Database->AutoExecute(TABLE_PREFIX . 'ticketposts', array('userid' => intval($_newUserID), 'fullname' => $_newFullName, 'email' => $_newEmail), 'UPDATE', "ticketid = '" . intval($_ticketID) . "' AND userid = '" . intval($_existingUserID) . "'");

		return true;
	}

	/**
	 * Update hasattachments property of ticket post
	 *
	 * @author Ruchi Kothari
	 * @param int $_hasAttachments Has Attachment Value(0 or 1)
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function UpdateHasAttachments($_hasAttachments)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(__CLASS__ . ':  ' . SWIFT_CLASSNOTLOADED);
		}

		$this->UpdatePool('hasattachments', intval($_hasAttachments));
		$this->ProcessUpdatePool();

		return true;
	}

	/**
	 * Retrieve ticket post attachments
	 *
	 * @author Simaranjit Singh
	 *
	 * @param SWIFT_Ticket $_Ticket
	 *
	 * @return array
	 * @throws SWIFT_Exception If the Class is not Loaded OR If Invalid Data is Provided
	 */
	public function RetrieveAttachments(SWIFT_Ticket $_Ticket)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		} else if (!$_Ticket->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_INVALIDDATA);
		}

		$_ticketAttachmentContainer = array();

		$this->Database->Query("SELECT attachmentid FROM " . TABLE_PREFIX . SWIFT_Attachment::TABLE_NAME . "
								WHERE ticketid = " . intval($_Ticket->GetTicketID()) . "
								  AND linktype = " . SWIFT_Attachment::LINKTYPE_TICKETPOST . "
								  AND linktypeid = " . intval($this->GetTicketPostID()));

		while ($this->Database->NextRecord()) {
			$_ticketAttachmentContainer[$this->Database->Record["attachmentid"]] = $this->Database->Record["attachmentid"];
		}

		return $_ticketAttachmentContainer;
	}
}
?>