<?php
/*
* @package LabCMS
* @copyright (c) 2006 Alexander Levin aka Loki (loki_angel@mail.ru)
* @support http://labcms.ru
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/


//статусы
//0 - отправлено
//1 - удалено отправителем
//2 - удалено получателем

class lc_pm_message extends DefaultObject
{
	public $inbox=true;
	public $max_outbox=250;
	public $max_inbox=250;
	
	protected $allowed_keys=array('status', 'unread');
	
	function __construct($id=null, $inbox=true, $boxowner=null)
	{
		$this->boxowner=($boxowner)?$boxowner:User::i();

		$this->data['id']=&$this->data['mess_id'];
		if ($id) {
			$this->loadDataById($id, $inbox);
		}

		if (config::get('max_outbox')) $this->max_outbox=config::get('max_outbox');
		if (config::get('max_inbox')) $this->max_inbox=config::get('max_inbox');
	}
	
	public function __set($key, $value)
	{
		parent::__set($key, $value);
		if ($key=='msg') $this->data['msg_html']=getbb($value);
	}
	
	public function loadDataById($id, $inbox=true)
	{
		if (
			$data=Db::i()->selectRow(
				"SELECT * FROM ?_lc_pm
				WHERE mess_id=? AND status IN(?a)
				{AND sender_id=?} {AND receiver_id=?}",
				$id,
				($inbox)?lc_pm_main::$in_statuses:lc_pm_main::$out_statuses,
				($inbox)?DBSIMPLE_SKIP:$this->boxowner->id,
				($inbox)?$this->boxowner->id:DBSIMPLE_SKIP
			)
		) {
			$this->inbox=$inbox;
			$this->set($data);
			if ($this->inbox) {
				$this->receiver=$this->boxowner;
				if ($this->sender_id) $this->sender=User::getUser($this->sender_id);
			} else {
				$this->sender=$this->boxowner;
				$this->receiver=User::getUser($this->receiver_id);
			}
		}
	}
	
	public function markAsReaded()
	{
		$this->update(array('unread'=>0));
		$this->updateUserCounter($this->receiver->id, 0, -1);
	}
	
	public function send($receiver, $sender, $subj, $msg)
	{
		$this->sender=$sender;
		$this->receiver=$receiver;
		
		$this->subj=$subj;
		$this->msg=$msg;
		
		if ($this->check_msg()) {
			$this->status=$this->getStatus();
			if ($this->id=$this->_send()) {
				if (0==$this->status) $this->updateUserCounter($this->receiver->id, 1, 1);
				return true;
			}
		}
		return false;
	}
	
	public function sendSystem($receivers, $subj=false, $msg=false)
	{
		if (!is_array($receivers)) $receivers=array($receivers);
		if ($subj) $this->subj=$subj;
		if ($msg) $this->msg=$msg;
		$this->receiver_id=$receivers;
		
		if ($this->check_msg()) {
			$this->sender_id=0;
			if ($this->_send()) {
				$this->updateUserCounter($this->receiver_id, 1, 1);
				return true;
			}
		}
		return false;
	}
	
	public function isSendPossible($sender, $receiver)
	{
		if (!$this->isSenderAvalible($sender)) return false;
		if (!$this->isReceiverAvalible($receiver)) return false;
		return true;
	}
	
	protected function _send()
	{
		if (is_array($this->receiver_id)) {
			return Db::i()->query(
				"INSERT INTO ?_lc_pm (sender_id, receiver_id, subj, msg, putdate, `status`)
				VALUES".$this->prepareMultipleData()
			);
		} else {
			return Db::i()->query(
				"INSERT INTO ?_lc_pm (sender_id, receiver_id, subj, msg, putdate, `status`)
				VALUES(?, ?, ?, ?, NOW(), ?)",
				$this->sender->id,
				$this->receiver->id,
				$this->subj,
				$this->msg,
				$this->status
			);
		}
	}
	
	protected function prepareMultipleData()
	{
		$data=array();
		foreach ($this->receiver_id as $id) {
			$data[]='('
			.$this->sender_id.','
			.$id.','
			."'".mysql_real_escape_string($this->subj)."',"
			."'".mysql_real_escape_string($this->msg)
			."', NOW(), 1 )";
		}
		return implode(",", $data);
	}
	
	public function _updateDB(&$data)
	{
		return Db::i()->query("UPDATE ?_lc_pm SET ?a WHERE mess_id=?", $data, $this->id);
	}
	
	protected function _resetItemCache()
	{
	}
	
	function updateUserCounter($user_id, $mess_cnt=1, $umess_cnt=1)
	{
		if (empty($user_id)) return false;
		if (!is_array($user_id)) $user_id=array($user_id);
		if (count($user_id)!=Db::i()->query(
			"UPDATE ?_lc_pm_stat
			SET mess=mess+?d, umess=umess+?d
			WHERE user_id IN (?a)",
			$mess_cnt,
			$umess_cnt,
			$user_id
		)
		) {
			foreach ($user_id as $id) {
				Db::i()->query(
					"INSERT IGNORE INTO ?_lc_pm_stat (user_id, mess, umess)
					VALUES(?, ?, ?)",
					$id,
					$mess_cnt,
					$umess_cnt
				);
			}
		}
	}
	
	function isSenderAvalible($user)
	{
		if (Db::i()->selectCell(
			"SELECT COUNT(mess_id)
			FROM ?_lc_pm
			WHERE sender_id=? AND `status` IN (?a)",
			$user->id,
			lc_pm_main::$out_statuses
		)>=$this->max_outbox) {
			return self::_error(_m('Ваш ящик исходящих сообщений переполнен. Вы не можете отправлять сообщения.'));
		}
		return true;
	}
	
	function isReceiverAvalible($user)
	{
		$info=Db::i()->selectRow(
			"SELECT mess, login 
			FROM ?_users u 
			LEFT JOIN ?_lc_pm_stat ms ON ms.user_id=u.user_id 
			WHERE u.user_id=? AND `status`>0", $user->id
		);
		if (empty($info)) return self::_error(_m('Пользователь не найден.'));
		if ($info['mess']>=$this->max_inbox) {
			return self::_error(_m('Ящик пользователя переполнен - он не сможет получить Ваше сообщение.'));
		}
		$this->receiver=$user;
		return true;
	}
	
	function getStatus()
	{
		//если в списке игнорирования - возвращаем статус "удалено получателем"
		return (Db::i()->selectCell(
			"SELECT user_id
			FROM ?_lc_pm_ignore
			WHERE ignore_id=? AND user_id=?",
			$this->sender->id,
			$this->receiver->id
		)
		)?2:0;
	}
	
	function check_msg()
	{
		if (!trim($this->subj)) self::_error(_m('Тема письма не может быть пустой'));
		if (!trim($this->msg)) self::_error(_m('Сообщение не может быть пустым'));
		if (mb_strlen($this->msg)>2048) {
			self::_error(
				sprintf(
					_m("Сообщение слишком длинное. Максимальная длина сообщения %s"),
					'2Kb'
				)
			);
		}
		return LabCMS::i()->no_errors;
	}
	
	protected function _getUserObj($user_id, &$users)
	{
		if ($user_id) return $users[$user_id];
		return User::getUser();
	}
	
	function deleteMessage($msg=null)
	{
		if (!$msg && !$this->id) return false;
		if (!$msg) {
			$messsages=array($this->id=>$this->data);
		} else {
			if (!is_array($msg)) $msg=array($msg);
			$messsages=Db::i()->select(
				"SELECT mess_id AS ARRAY_KEY, sender_id, receiver_id, status, unread
				FROM ?_lc_pm WHERE mess_id IN (?a) AND (sender_id=? OR receiver_id=?)",
				$msg, $this->boxowner->id, $this->boxowner->id
			);
		}
		
		/*
		$delete - сообщения подлежащие полному удалению
		$updateS - сообщения, которые нужно убрать из отправленных
		$updateR - сообщения, которые нужно убрать из принятых
		$undead - непрочитанные сообщения которые удалены из входящих
		$total - всего сообщений которые удалены из входящих
		*/
		
		$delete=$updateS=$updateR=array();
		$total=$unread=0;
		foreach ($messsages as $msg_id=>$msg) {
			//удаляем из отправленных
			if ($msg['sender_id']==$this->boxowner->id && !$this->inbox) {
				//если сообщение не удалено
				if ($msg['status']==0) $updateS[]=$msg_id;
				//если сообщение удалено получателем
				if ($msg['status']==2) $delete[]=$msg_id;
			}
			//удаляем из принятых
			if ($msg['receiver_id']==$this->boxowner->id && $this->inbox) {
				//если сообщение не удалено
				if ($msg['status']==0) $updateR[]=$msg_id;
				//если сообщение удалено отправителем
				if ($msg['status']==1) $delete[]=$msg_id;
				
				if ($msg['unread']) $unread++;
				$total++;
			}
		}

		if (count($updateS)) Db::i()->query("UPDATE ?_lc_pm SET status=1 WHERE mess_id IN (?a)", $updateS);
		if (count($updateR)) Db::i()->query("UPDATE ?_lc_pm SET status=2 WHERE mess_id IN (?a)", $updateR);
		if (count($delete)) Db::i()->query("DELETE FROM ?_lc_pm WHERE mess_id IN (?a)", $delete);

		if ($total) $this->updateUserCounter($this->boxowner->id, -$total, -$unread);
		return (count($updateS)+count($updateR)+count($delete));
	}
	
	public function getNext()
	{
		if ($this->inbox) {
			return Db::i()->selectCell(
				"SELECT MAX(mess_id)
				FROM ?_lc_pm 
				WHERE receiver_id=? AND mess_id<?  AND status IN (?a)",
				$this->boxowner->id, $this->id, lc_pm_main::$in_statuses
			);
		} else {
			return Db::i()->selectCell(
				"SELECT MAX(mess_id)
				FROM ?_lc_pm
				WHERE sender_id=? AND mess_id<? AND status IN (?a)",
				$this->boxowner->id, $this->id, lc_pm_main::$out_statuses
			);
		}
	}
	
	public function getPrev()
	{
		if ($this->inbox) {
			return Db::i()->selectCell(
				"SELECT MIN(mess_id)
				FROM ?_lc_pm
				WHERE receiver_id=? AND mess_id>?  AND status IN (?a)",
				$this->boxowner->id, $this->id, lc_pm_main::$in_statuses
			);
		} else {
			return Db::i()->selectCell(
				"SELECT MIN(mess_id)
				FROM ?_lc_pm
				WHERE sender_id=? AND mess_id>? AND status IN (?a)",
				$this->boxowner->id, $this->id, lc_pm_main::$out_statuses
			);
		}
	}

}