<?php
/**
* @version	$Id: mailing_list_helper.php 15230 2012-03-26 10:13:31Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

	defined('FULL_PATH') or die('restricted access!');

	class MailingListHelper extends kHelper {

		var $_mailingId = false;

		/**
		 * Adds new email from given mailing to emails queue
		 *
		 * @param string $email
		 * @param int $mailing_id
		 * @param Array $mailing_data
		 */
		function queueEmail($email, $mailing_id, &$mailing_data)
		{
			$esender = $this->Application->recallObject('EmailSender');
			/* @var $esender kEmailSendingHelper */

			if ($this->_mailingId != $mailing_id) {
				if (is_numeric($this->_mailingId)) {
					// clear fields after previous mailing processing
					$esender->Clear();
				}

				// 1. set headers same for all emails
				list ($mailing_data['FromName'], $mailing_data['FromEmail']) = $this->_getSenderData($mailing_data);
				$esender->SetFrom($mailing_data['FromEmail'], $mailing_data['FromName']);

				$esender->SetSubject($mailing_data['Subject']);
				if ( !$mailing_data['MessageText'] ) {
					$mailing_data['MessageText'] = $esender->ConvertToText($mailing_data['MessageHtml']);
				}

				$esender->SetBody($mailing_data['MessageHtml'], $mailing_data['MessageText']);

		    	// 2. add attachment if any
		    	$attachments = $mailing_data['Attachments'] ? explode('|', $mailing_data['Attachments']) : Array ();

				foreach ($attachments as $attachment) {
					$esender->AddAttachment(FULL_PATH . ITEM_FILES_PATH . $attachment);
				}

				$this->_mailingId = $mailing_id;
			}

			// 3. set recipient specific fields
			$esender->SetTo($email, $email);

			if ( $this->Application->ConfigValue('EmailLogRotationInterval') != '' ) {
				// 4. write to log
				$log_fields_hash = Array (
					'From' => $mailing_data['FromName'] . '(' . $mailing_data['FromEmail'] . ')',
					'To' => $email,
					'Subject' => $mailing_data['Subject'],
					'HtmlBody' => $mailing_data['MessageHtml'],
					'TextBody' => $mailing_data['MessageText'],
					'SentOn' => TIMENOW,
					'EventParams' => serialize( Array ('MailingId' => $mailing_id) ),
				);

				$esender->setLogData($log_fields_hash);
			}

			$esender->Deliver(null, $mailing_id, false);
		}

		/**
		 * Returns mass mail sender name & email
		 *
		 * @param Array $mailing_data
		 * @return Array
		 * @access protected
		 */
		protected function _getSenderData(&$mailing_data)
		{
			$is_root = true;
			$email_address = $name = '';

			if ( $mailing_data['PortalUserId'] > 0 ) {
				$sender = $this->Application->recallObject('u.-item', null, Array ('skip_autoload' => true));
				/* @var $sender UsersItem */

				$sender->Load($mailing_data['PortalUserId']);

				$email_address = $sender->GetDBField('Email');
				$name = trim($sender->GetDBField('FirstName') . ' ' . $sender->GetDBField('LastName'));
				$is_root = false;
			}

			if ( $is_root || !$email_address ) {
				$email_address = $this->Application->ConfigValue('DefaultEmailSender');
			}

			if ( $is_root || !$name ) {
				$name = strip_tags($this->Application->ConfigValue('Site_Name'));
			}

			return Array ($name, $email_address);
		}

		/**
		 * Generates recipients emails based on "To" field value
		 *
		 * @param int $id
		 * @param Array $fields_hash
		 */
		function generateRecipients($id, $fields_hash)
		{
			// for each group convert ids to names
			$recipient_emails = Array ();
			$recipients_grouped = $this->groupRecipientsByType(explode(';', $fields_hash['To']));

			foreach ($recipients_grouped as $recipient_type => $group_recipients) {
				$recipient_emails = array_merge($recipient_emails, $this->_getRecipientEmails($recipient_type, $group_recipients));
			}

			$recipient_emails = array_unique($recipient_emails);

			return Array (
				'ToParsed' => serialize($recipient_emails),
				'EmailsTotal' => count($recipient_emails),
			);
		}

		/**
		 * Groups recipients by type
		 *
		 * @param Array $recipients
		 * @return Array
		 * @access public
		 */
		public function groupRecipientsByType($recipients)
		{
			$recipients_grouped = Array ();

			foreach ($recipients as $recipient) {
				if ( strpos($recipient, '_') !== false ) {
					list ($recipient_type, $recipient_id) = explode('_', $recipient);
				}
				else {
					$recipient_type = 'direct';
					$recipient_id = $recipient;
				}

				if ( !array_key_exists($recipient_type, $recipients_grouped) ) {
					$recipients_grouped[$recipient_type] = Array ();
				}

				$recipients_grouped[$recipient_type][] = $recipient_id;
			}

			return $recipients_grouped;
		}

		function _getRecipientEmails($recipient_type, $recipient_ids)
		{
			if (strpos($recipient_type, '.') !== false) {
				// remove special
				list ($recipient_type, ) = explode('.', $recipient_type);
			}

			if ($recipient_type != 'u' && $recipient_type != 'g') {
				// these are already emails
				return $recipient_ids;
			}

			switch ($recipient_type) {
				case 'u':
					$sql = 'SELECT Email
							FROM ' . TABLE_PREFIX . 'Users
							WHERE (PortalUserId IN (' . implode(',', $recipient_ids) . ')) AND (Email <> "")';
					break;

				case 'g':
					$sql = 'SELECT u.Email
							FROM ' . TABLE_PREFIX . 'UserGroupRelations ug
							LEFT JOIN ' . TABLE_PREFIX . 'Users u ON u.PortalUserId = ug.PortalUserId
							WHERE (ug.GroupId IN (' . implode(',', $recipient_ids) . ')) AND (u.Email <> "")';
					break;

				default:
					$sql = '';
					break;
			}

			return $this->Conn->GetCol($sql);
		}

		function getRecipientNames($recipient_type, $recipient_ids)
		{
			if (strpos($recipient_type, '.') !== false) {
				// remove special
				list ($recipient_type, ) = explode('.', $recipient_type);
			}

			switch ($recipient_type) {
				case 'u':
					$title_field = 'Email';
					break;

				case 'g':
					$title_field = 'Name';
					break;

				default:
					$title_field = false;
					break;
			}

			if ($title_field === false || !$recipient_ids) {
				return $recipient_ids;
			}

			$id_field = $this->Application->getUnitOption($recipient_type, 'IDField');
			$table_name = $this->Application->getUnitOption($recipient_type, 'TableName');

			$sql = 'SELECT ' . $title_field . '
					FROM ' . $table_name . '
					WHERE ' . $id_field . ' IN (' . implode(',', $recipient_ids) . ')';
			return $this->Conn->GetCol($sql);
		}

		/**
		 * Updates information about sent email count based on given totals by mailings
		 *
		 * @param Array $mailing_totals
		 */
		function _updateSentTotals($mailing_totals)
		{
			if (array_key_exists(0, $mailing_totals)) {
				// don't update sent email count for mails queued directly (not via mailing lists)
				unset($mailing_totals[0]);
			}

			$id_field = $this->Application->getUnitOption('mailing-list', 'IDField');
			$table_name = $this->Application->getUnitOption('mailing-list', 'TableName');

			// update sent email count for each processed mailing
			foreach ($mailing_totals as $mailing_id => $mailing_total) {
				$sql = 'UPDATE ' . $table_name . '
						SET EmailsSent = EmailsSent + ' . $mailing_total . '
						WHERE ' . $id_field . ' = ' . $mailing_id;
				$this->Conn->Query($sql);
			}

			// mark mailings, that were processed completely
			$sql = 'UPDATE ' . $table_name . '
					SET Status = ' . MailingList::PROCESSED . '
					WHERE (Status = ' . MailingList::PARTIALLY_PROCESSED . ') AND (EmailsSent = EmailsTotal)';
			$this->Conn->Query($sql);
		}

		/**
		 * Sent given messages from email queue
		 *
		 * @param Array $messages
		 */
		function processQueue(&$messages)
		{
			$esender = $this->Application->recallObject('EmailSender');
			/* @var $esender kEmailSendingHelper */

			$queue_table = $this->Application->getUnitOption('email-queue', 'TableName');

			$i = 0;
			$message = Array ();
			$mailing_totals = Array ();
			$message_count = count($messages);

			while ($i < $message_count) {
				$message[0] = unserialize($messages[$i]['MessageHeaders']);
				$message[1] =& $messages[$i]['MessageBody'];

				$esender->setLogData( unserialize($messages[$i]['LogData']) );
				$delivered = $esender->Deliver($message, true); // immediate send!

				if ($delivered) {
					// send succeeded, delete from queue
					$sql = 'DELETE FROM ' . $queue_table . '
							WHERE EmailQueueId = ' . $messages[$i]['EmailQueueId'];
					$this->Conn->Query($sql);

					$mailing_id = $messages[$i]['MailingId'];
					if (!array_key_exists($mailing_id, $mailing_totals)) {
						$mailing_totals[$mailing_id] = 0;
					}
					$mailing_totals[$mailing_id]++;
				}
				else {
					// send failed, increment retries counter
					$sql = 'UPDATE ' . $queue_table . '
							SET SendRetries = SendRetries + 1, LastSendRetry = ' . adodb_mktime() . '
							WHERE EmailQueueId = ' . $messages[$i]['EmailQueueId'];
					$this->Conn->Query($sql);
				}
				$i++;
			}

			$this->_updateSentTotals($mailing_totals);
		}
	}