<?php
/*********************************************************************************
 * The contents of this file are subject to the TimeTrex Public License Version
 * 1.1.0 ("License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.TimeTrex.com/TPL
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * All copies of the Covered Code must include on each user interface screen:
 *    (i) the "Powered by TimeTrex" logo and
 *    (ii) the TimeTrex copyright notice
 * in the same form as they appear in the distribution.  See full license for
 * requirements.
 *
 * The Original Code is: TimeTrex Open Source
 * The Initial Developer of the Original Code is TimeTrex Payroll Services
 * Portions created by TimeTrex are Copyright (C) 2004-2007 TimeTrex Payroll Services;
 * All Rights Reserved.
 *
 ********************************************************************************/
/*
 * $Revision: 2453 $
 * $Id: MessageFactory.class.php 2453 2009-03-20 16:34:04Z ipso $
 * $Date: 2009-03-20 09:34:04 -0700 (Fri, 20 Mar 2009) $
 */

/**
 * @package Module_Message
 */
class MessageFactory extends Factory {
	protected $table = 'message';
	protected $pk_sequence_name = 'message_id_seq'; //PK Sequence name
	protected $obj_handler = NULL;

	function _getFactoryOptions( $name ) {

		$retval = NULL;
		switch( $name ) {
			case 'type':
				$retval = array(
										5 => 'email',
										//10 => 'default_schedule',
										//20 => 'schedule_amendment',
										//30 => 'shift_amendment',
										40 => 'authorization',
										50 => 'request',
										60 => 'job',
										70 => 'job_item',
										80 => 'client',
										90 => 'timesheet',
										100 => 'user' //For notes assigned to users?
									);
				break;
			case 'object_name':
				$retval = array(
										5 => TTi18n::gettext('Email'), //Email from user to another
										10 => TTi18n::gettext('Recurring Schedule'),
										20 => TTi18n::gettext('Schedule Amendment'),
										30 => TTi18n::gettext('Shift Amendment'),
										40 => TTi18n::gettext('Authorization'),
										50 => TTi18n::gettext('Request'),
										60 => TTi18n::gettext('Job'),
										70 => TTi18n::gettext('Task'),
										80 => TTi18n::gettext('Client'),
										90 => TTi18n::gettext('TimeSheet'),
										100 => TTi18n::gettext('Employee') //For notes assigned to users?
									);
				break;

			case 'folder':
				$retval = array(
										10 => TTi18n::gettext('Inbox'),
										20 => TTi18n::gettext('Sent')
									);
				break;
			case 'status':
				$retval = array(
										10 => TTi18n::gettext('UNREAD'),
										20 => TTi18n::gettext('READ')
									);
				break;
			case 'priority':
				$retval = array(
										10 => TTi18n::gettext('LOW'),
										50 => TTi18n::gettext('NORMAL'),
										100 => TTi18n::gettext('HIGH'),
										110 => TTi18n::gettext('URGENT')
									);
				break;

		}

		return $retval;
	}


	function getParent() {
		if ( isset($this->data['parent_id']) ) {
			return $this->data['parent_id'];
		}

		return FALSE;
	}
	function setParent($id) {
		$id = trim($id);

		if ( empty($id) ) {
			$id = 0;
		}

		$mlf = new MessageListFactory();

		if ( $id == 0
				OR $this->Validator->isResultSetWithRows(	'parent',
															$mlf->getByID($id),
															TTi18n::gettext('Parent is invalid')
															) ) {
			$this->data['parent_id'] = $id;

			return TRUE;
		}

		return FALSE;
	}

	function getObjectHandler() {
		if ( is_object($this->obj_handler) ) {
			return $this->obj_handler;
		} else {
			switch ( $this->getObjectType() ) {
				case 5:
				case 100:
					$this->obj_handler = new UserListFactory();
					break;
				case 40:
					$this->obj_handler = new AuthorizationListFactory();
					break;
				case 50:
					$this->obj_handler = new RequestListFactory();
					break;
				case 90:
					$this->obj_handler = new PayPeriodTimeSheetVerifyListFactory();
					break;
			}

			return $this->obj_handler;
		}
	}

	function getObjectType() {
		if ( isset($this->data['object_type_id']) ) {
			return $this->data['object_type_id'];
		}

		return FALSE;
	}
	function setObjectType($type) {
		$type = trim($type);

		$key = Option::getByValue($type, $this->getOptions('type') );
		if ($key !== FALSE) {
			$type = $key;
		}

		if ( $this->Validator->inArrayKey(	'object_type',
											$type,
											TTi18n::gettext('Object Type is invalid'),
											$this->getOptions('type')) ) {

			$this->data['object_type_id'] = $type;

			return TRUE;
		}

		return FALSE;
	}

	function getObject() {
		if ( isset($this->data['object_id']) ) {
			return $this->data['object_id'];
		}

		return FALSE;
	}
	function setObject($id) {
		$id = trim($id);

		if ( $this->Validator->isResultSetWithRows(	'object',
													$this->getObjectHandler()->getByID($id),
													TTi18n::gettext('Object ID is invalid')
													) ) {
			$this->data['object_id'] = $id;

			return TRUE;
		}

		return FALSE;
	}

	function getPriority() {
		if ( isset($this->data['priority_id']) ) {
			return $this->data['priority_id'];
		}

		return FALSE;
	}
	function setPriority($priority = NULL) {
		$priority = trim($priority);

		if ( empty($priority) ) {
			$priority = 50;
		}

		$key = Option::getByValue($priority, $this->getOptions('priority') );
		if ($key !== FALSE) {
			$priority = $key;
		}

		if ( $this->Validator->inArrayKey(	'priority',
											$priority,
											TTi18n::gettext('Invalid Priority'),
											$this->getOptions('priority')) ) {

			$this->data['priority_id'] = $priority;

			return FALSE;
		}

		return FALSE;
	}

	function getStatus() {
		if ( isset($this->data['status_id']) ) {
			return $this->data['status_id'];
		}

		return FALSE;
	}
	function setStatus($status) {
		$status = trim($status);

		$key = Option::getByValue($status, $this->getOptions('status') );
		if ($key !== FALSE) {
			$status = $key;
		}

		if ( $this->Validator->inArrayKey(	'status',
											$status,
											TTi18n::gettext('Incorrect Status'),
											$this->getOptions('status')) ) {

			$this->setStatusDate();

			$this->data['status_id'] = $status;

			return FALSE;
		}

		return FALSE;
	}

	function getStatusDate() {
		if ( isset($this->data['status_date']) ) {
			return $this->data['status_date'];
		}

		return FALSE;
	}
	function setStatusDate($epoch = NULL) {
		$epoch = trim($epoch);

		if ($epoch == NULL) {
			$epoch = TTDate::getTime();
		}

		if 	(	$this->Validator->isDate(		'status_date',
												$epoch,
												TTi18n::gettext('Incorrect Date')) ) {

			$this->data['status_date'] = $epoch;

			return TRUE;
		}

		return FALSE;

	}

	function getSubject() {
		if ( isset($this->data['subject']) ) {
			return $this->data['subject'];
		}

		return FALSE;
	}
	function setSubject($text) {
		$text = trim($text);

		if 	(	strlen($text) == 0
				OR
				$this->Validator->isLength(		'subject',
												$text,
												TTi18n::gettext('Invalid Subject length'),
												2,
												100) ) {

			$this->data['subject'] = htmlspecialchars( $text );

			return TRUE;
		}

		return FALSE;
	}

	function getBody() {
		if ( isset($this->data['body']) ) {
			return $this->data['body'];
		}

		return FALSE;
	}
	function setBody($text) {
		$text = trim($text);

		if 	(	$this->Validator->isLength(		'body',
												$text,
												TTi18n::gettext('Invalid Body length'),
												5,
												1024) ) {

			$this->data['body'] = htmlspecialchars( $text );

			return TRUE;
		}

		return FALSE;
	}


	function isAck() {
		if ($this->getRequireAck() == TRUE AND $this->getAckDate() == '' ) {
			return FALSE;
		}

		return TRUE;
	}

	function getRequireAck() {
		return $this->fromBool( $this->data['require_ack'] );
	}
	function setRequireAck($bool) {
		$this->data['require_ack'] = $this->toBool($bool);

		return true;
	}

	function getAck() {
		return $this->fromBool( $this->data['ack'] );
	}
	function setAck($bool) {
		$this->data['ack'] = $this->toBool($bool);

		if ( $this->getAck() == TRUE ) {
			$this->setAckDate();
			$this->setAckBy();
		}

		return true;
	}

	function getAckDate() {
		if ( isset($this->data['ack_date']) ) {
			return $this->data['ack_date'];
		}

		return FALSE;
	}
	function setAckDate($epoch = NULL) {
		$epoch = trim($epoch);

		if ($epoch == NULL) {
			$epoch = TTDate::getTime();
		}

		if 	(	$this->Validator->isDate(		'ack_date',
												$epoch,
												TTi18n::gettext('Invalid Acknowledge Date') ) ) {

			$this->data['ack_date'] = $epoch;

			return TRUE;
		}

		return FALSE;

	}

	function getAckBy() {
		if ( isset($this->data['ack_by']) ) {
			return $this->data['ack_by'];
		}

		return FALSE;
	}
	function setAckBy($id = NULL) {
		$id = trim($id);

		if ( empty($id) ) {
			global $current_user;

			if ( is_object($current_user) ) {
				$id = $current_user->getID();
			} else {
				return FALSE;
			}
		}

		$ulf = new UserListFactory();

		if ( $this->Validator->isResultSetWithRows(	'ack_by',
													$ulf->getByID($id),
													TTi18n::gettext('Incorrect User')
													) ) {

			$this->data['ack_by'] = $id;

			return TRUE;
		}

		return FALSE;
	}

	function getEmailMessageAddresses() {
		$olf = $this->getObjectHandler();
		if ( is_object( $olf ) ) {

			$olf->getById( $this->getObject() );
			if ( $olf->getRecordCount() > 0 ) {
				$obj = $olf->getCurrent();

				switch ( $this->getObjectType() ) {
					case 5:
					case 100:
						Debug::Text('Email Object Type... Parent ID: '. $this->getParent(), __FILE__, __LINE__, __METHOD__,10);
						if ( $this->getParent() == 0 ) {
							$user_ids[] = $obj->getId();
						} else {
							$mlf = new MessageListFactory();
							$mlf->getById( $this->getParent() );
							if ( $mlf->getRecordCount() > 0 ) {
								$m_obj = $mlf->getCurrent();

								$user_ids[] = $m_obj->getCreatedBy();
							}
							Debug::Text('cEmail Object Type... Parent ID: '. $this->getParent(), __FILE__, __LINE__, __METHOD__,10);
						}
						break;
					case 40:
						$user_ids[] = $obj->getId();
						break;
					case 50: //Request
						//Get all users who have contributed to the thread.
						$mlf = new MessageListFactory();
						$mlf->getMessagesInThreadById( $this->getId() );
						Debug::Text(' Messages In Thread: '. $mlf->getRecordCount() , __FILE__, __LINE__, __METHOD__,10);
						if ( $mlf->getRecordCount() > 0 ) {
							foreach( $mlf as $m_obj ) {
								$user_ids[] = $m_obj->getCreatedBy();
							}
						}
						unset($mlf, $m_obj);
						//Debug::Arr($user_ids, 'User IDs in Thread: ', __FILE__, __LINE__, __METHOD__,10);

						//Only alert direct supervisor to request at this point. Because we need to take into account
						//if the request was authorized or not to determine if we should email the next higher level in the hierarchy.
						if ( $this->getParent() == 0 ) {
							//Get direct parent in hierarchy.
							$u_obj = $obj->getUserObject();

							//Find proper hierarchy to use for this object
							$hotlf = new HierarchyObjectTypeListFactory();
							$control_id = $hotlf->getByCompanyIdAndObjectTypeId( $u_obj->getCompany(), $this->getObjectType() )->getCurrent()->getHierarchyControl();
							Debug::Text(' Hierarchy Control ID: '. $control_id , __FILE__, __LINE__, __METHOD__,10);

							$hlf = new HierarchyListFactory();
							$node_data = $hlf->getByHierarchyControlIdAndUserId( $control_id, $u_obj->getId() );
							if ( $node_data['parent_id'] != 0 ) {
								$user_ids[] = $node_data['parent_id'];
							}
							unset($hotlf,$control_id, $hlf, $node_data);
						}

						global $current_user;
						if ( isset($current_user) AND is_object( $current_user ) AND isset($user_ids) AND is_array($user_ids) ) {
							$user_ids = array_unique( $user_ids );
							$current_user_key = array_search($current_user->getId(), $user_ids );
							Debug::Text(' Current User Key: '. $current_user_key, __FILE__, __LINE__, __METHOD__,10);
							if ( $current_user_key !== FALSE ) {
								Debug::Text(' Removing Current User From Recipient List...'. $current_user->getId() , __FILE__, __LINE__, __METHOD__,10);
								unset($user_ids[$current_user_key]);
							}
						} else {
							Debug::Text(' Current User Object not available...', __FILE__, __LINE__, __METHOD__,10);
						}
						unset($current_user, $current_user_key);

						break;
					case 90:
						$user_ids[] = $obj->getUser();
						break;
				}
			}

			if ( isset($user_ids) AND is_array($user_ids) ) {
				//Get user preferences and determine if they accept email notifications.
				Debug::Arr($user_ids, 'Recipient User Ids: ', __FILE__, __LINE__, __METHOD__,10);

				$uplf = new UserPreferenceListFactory();
				$uplf->getByUserId( $user_ids );
				if ( $uplf->getRecordCount() > 0 ) {
					foreach( $uplf as $up_obj ) {
						if ( $up_obj->getEnableEmailNotificationMessage() == TRUE AND $up_obj->getUserObject()->getStatus() == 10 ) {
							if ( $up_obj->getUserObject()->getWorkEmail() != '' ) {
								$retarr[] = $up_obj->getUserObject()->getWorkEmail();
							}

							if ( $up_obj->getEnableEmailNotificationHome() AND $up_obj->getUserObject()->getHomeEmail() != '' ) {
								$retarr[] = $up_obj->getUserObject()->getHomeEmail();
							}
						}
					}

					if ( isset($retarr) ) {
						Debug::Arr($retarr, 'Recipient Email Addresses: ', __FILE__, __LINE__, __METHOD__,10);
						return $retarr;

					}
				}
			}
		}

		return FALSE;
	}

	function emailMessage() {
		Debug::Text('emailMessage: ', __FILE__, __LINE__, __METHOD__,10);

		$email_to_arr = $this->getEmailMessageAddresses();
		if ( $email_to_arr == FALSE ) {
			return FALSE;
		}

		$from = $reply_to = 'DoNotReply@'.Misc::getHostName();

		global $current_user;
		if ( is_object($current_user) AND $current_user->getWorkEmail() != '' ) {
			$reply_to = $current_user->getWorkEmail();
		}
		Debug::Text('From: '. $from .' Reply-To: '. $reply_to, __FILE__, __LINE__, __METHOD__,10);

		$to = array_shift( $email_to_arr );
		Debug::Text('To: '. $to, __FILE__, __LINE__, __METHOD__,10);
		if ( is_array($email_to_arr) AND count($email_to_arr) > 0 ) {
			$bcc = implode(',', $email_to_arr);
		} else {
			$bcc = NULL;
		}

		$email_subject = TTi18n::gettext('New message waiting in').' '. APPLICATION_NAME;
		$email_body  = TTi18n::gettext('*DO NOT REPLY TO THIS EMAIL - PLEASE USE THE LINK BELOW INSTEAD*')."\n\n";
		$email_body  .= TTi18n::gettext('You have a new message waiting for you in').' '. APPLICATION_NAME."\n";
		if ( $this->getSubject() != '' ) {
			$email_body .= TTi18n::gettext('Subject:').' '. $this->getSubject()."\n";
		}
		$email_body .= TTi18n::gettext('Link:').' <a href="http://'. Misc::getHostName().Environment::getBaseURL().'">'.APPLICATION_NAME.' '. TTi18n::gettext('Login') .'</a>';

		//Define subject/body variables here.
		$search_arr = array(
							'#employee_first_name#',
							'#employee_last_name#',
							);

		$replace_arr = array(
							NULL,
							NULL,
							);

		//For some reason the EOL defaults to \r\n, which seems to screw with Amavis
		if ( !defined('MAIL_MIMEPART_CRLF') ) {
			define('MAIL_MIMEPART_CRLF', "\n");
		}

		$subject = str_replace( $search_arr, $replace_arr, $email_subject );
		Debug::Text('Subject: '. $subject, __FILE__, __LINE__, __METHOD__,10);

		$headers = array(
							'From'    => $from,
							'Subject' => $subject,
							'Bcc'	  => $bcc,
							'Reply-To' => $reply_to,
							'Return-Path' => $reply_to,
							'Errors-To' => $reply_to,
						 );
		Debug::Arr($headers, 'Headers: ', __FILE__, __LINE__, __METHOD__,10);

		$body = '<pre>'.str_replace( $search_arr, $replace_arr, $email_body ).'</pre>';
		Debug::Text('Body: '. $body, __FILE__, __LINE__, __METHOD__,10);

		require_once('Mail.php');
		require_once('Mail/mime.php');

		$mime = @new Mail_Mime();
		@$mime->setHTMLBody($body);

		@$body = $mime->get();
		@$headers = $mime->headers($headers);

		$mail = &Mail::factory('mail');
		if ( PRODUCTION == TRUE AND DEMO_MODE == FALSE ) {
			if ( $mail->send($to, $headers, $body) == TRUE ) {
				TTLog::addEntry( $this->getId(), 500,  TTi18n::getText('Email Message to').': '. $to .' Bcc: '. $headers['Bcc'], NULL, $this->getTable() );
				return TRUE;
			}
		} else {
			Debug::Text(' Not sending email, production mode not enabled...', __FILE__, __LINE__, __METHOD__,10);
		}

		return TRUE;
	}

	function postSave() {
		//Don't email messages when they are being deleted.
		if ( $this->getDeleted() == FALSE ) {
			$this->emailMessage();
		}

		if ( $this->getStatus() == 20 ) {
			global $current_user;

			$this->removeCache( $current_user->getId() );
		}

		return TRUE;
	}

}
?>
