<?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
*/

/*
статусы
1 - опубликован
2 - ожидает модерации
3 - удален
*/

class lc_comments_comment extends DefaultObject
{
    //устанавливаем тип учета рейтинга, чтобы можно было задать коэффициент
    protected $vote_type=1;
	protected $allowed_keys=array(
		'parent_id', 'text', 'updated', 'login', 'email', 'status', 'level', 'left_key', 'right_key',
		'abuse', 'total_votes', 'vote_result', 'rating'
	);
	
	function __construct($id=null)
	{
		$this->data['id']=&$this->data['comment_id'];
		if ($id) {
			$this->loadDataById($id);
			if (!$this->id) {
				return $this->_error(_m('Комментарий не найден'));
			}
		}
	}
	
	public function set($data)
	{
		foreach ($data as $k=>$v) {
			if ($k=='item_id' && $v!=$this->item_id) {
			}//обновляем объект item
			if ($k=='user_id' && $v!=$this->user_id) {
			}//обновляем объект user
			$this->__set($k, $v);
		}
		$this->_prepareData();
	}
	
	protected function _updateDB(&$data)
	{
		return Db::i()->query(
			"UPDATE ?_comments SET ?a, updated=? WHERE comment_id=?", $data, time(), $this->id
		);
	}
	
	protected function _resetItemCache()
	{
		$this->resetCache();
	}

	
	protected function _prepareData()
	{
		$this->text_html=getbb($this->text);
		$this->negative=($this->total_votes-$this->vote_result)/2;
		$this->positive=$this->total_votes-$this->negative;
		if (!is_array($this->abuse)) $this->abuse=unserialize($this->abuse);
		$this->abuse_count=$this->abuse?count($this->abuse):0;
		$this->leaf=($this->right_key-$this->left_key-1)?false:true;
	}
	
	public function setAccesses()
	{
		$this->access=$access=array();
		//набор правил
		switch($this->status)
		{
			case(1): //опубликовано
				$access['add']=access('module.lc_comments.add');
				$access['edit']=(
					(access('module.lc_comments.edit')
					&& $this->user_id==User::i()->id)
					|| access('module.lc_comments.moderator, module.lc_comments.admin')
				);
				$access['delete']=(
					(access('module.lc_comments.edit')
						&& $this->user_id==User::i()->id)
						|| access('module.lc_comments.moderator, module.lc_comments.admin')
				);
				$access['delete_branch']=access('module.lc_comments.admin');
				$access['abuse']=(
					access('module.lc_comments.abuse') && (!$this->abuse
						|| !array_key_exists(User::i()->id, (array)$this->abuse))
				);
				break;
			case(2): //ожидает модерации
				if (!access('module.lc_comments.moderator, module.lc_comments.admin')) {
					$this->text_html="Комментарий ожидает модерации";
				}
				$access['unhide']=access('module.lc_comments.moderator, module.lc_comments.admin');
				$access['edit']=access('module.lc_comments.moderator, module.lc_comments.admin');
				$access['delete']=access('module.lc_comments.moderator, module.lc_comments.admin');
				$access['delete_branch']=access('module.lc_comments.admin');
				break;
			case(3): //удалено
				if (!access('module.lc_comments.admin')) $this->text_html="Комментарий удален";
				$access['undelete']=access('module.lc_comments.admin');
				$access['delete_branch']=access('module.lc_comments.admin');
				break;
		}
		$this->access=$access;
	}
	
	public function setRating()
	{
		if (config::get('module.lc_comments.rating_enable')) {
			$voter=Rating_Generic::init();
			$voter->setModuleId(LabCMS::i()->getModuleIdByName('lc_comments'));

			if ($votes=$voter->getUserItemVotes($this->id)) {
				$this->voted=$votes[$this->id];
			}
		}
	}
	
	public function edit($data)
	{
		if (!$this->_checkCommentDeleted()) return false;
		$update=array(
			'text'=>$data['text']
		);
		if (!empty($data['login'])) $update['login']=$data['login'];
		if (!empty($data['email'])) $update['email']=$data['email'];
		return $this->update($update);
	}
	
	public function delete()
	{
		if ($this->_checkCommentExists() && $this->_checkCommentDeleted()) {
			return $this->update(array('status'=>3, 'abuse'=>null));
		}
		return false;
	}
	
	public function unhide()
	{
		if ($this->_checkCommentExists() && $this->_checkCommentDeleted()) {
			return $this->update(array('status'=>1));
		}
	}
	
	public function undelete()
	{
		if ($this->_checkCommentExists()) {
			if (!$this->_commentDeleted()) {
				return $this->_error(_m('Ошибка восстановления комментария'));
			}
			$this->update(array('status'=>1));
			return true;
		}
		return false;
	}

	public function deleteBranch()
	{
		$count=Db::i()->query(
			"DELETE FROM ?_comments
			WHERE left_key>=? AND right_key<=? AND item_id=?",
			$this->left_key, $this->right_key, $this->item_id
		);
		Db::i()->query(
			"UPDATE ?_comments
			SET left_key=IF(left_key>?d, left_key-(?d-?d + 1), left_key),
			right_key=right_key-(?d-?d+1)
			WHERE right_key>?d
			 AND item_id=?",
			$this->left_key,
			$this->right_key,
			$this->left_key,
			$this->right_key,
			$this->left_key,
			$this->right_key,
			$this->item_id
		);
		$this->item->changeCounter(-$count);
		return true;
	}
	
	public function abuse()
	{
		if (!$this->_checkCommentExists() || !$this->_checkCommentDeleted()) return; 
		if (!array_key_exists(User::i()->id, (array)$this->abuse)) {
			$this->abuse[User::i()->id]=User::i()->login;
			$this->update(array('abuse'=>serialize($this->abuse)));
			return true;
		}
		return false;
	}
	
	public function loadDataById($comment_id)
	{
		$data=Db::i()->selectRow(
			"SELECT *, INET_NTOA(ip) as ip FROM ?_comments
			WHERE comment_id=?", $comment_id
		);
		if ($data) {
			$this->set($data);
			$this->item=Factory::create('lc_comments.item', $this->item_id);
			$this->_setUser();
			$this->setAccesses();
			$this->setRating();
		}
	}
	
	protected function _setUser()
	{
		$this->user=User::getUser($this->user_id);
		if ($this->user->isGuest()) {
			$this->user->set(array('login'=>$this->login, 'email'=>$this->email));
		}
	}
	
	public function resetAbuse()
	{
		$this->update(array('abuse'=>null));
	}
	
	public static function updateUrl($item_id, $url)
	{
		Db::i()->query(
			"UPDATE ?_comments_items SET url=?
			WHERE item_id=? AND module_id=?",
			$url, $item_id, LabCMS::i()->getModuleId()
		);
	}
	
	public function vote($vote)
	{
		if (!$this->_checkCommentExists() || !$this->_checkCommentDeleted()) return; 
		$data=array(
			'item_id'=>$this->id,
			'type'=>$this->getVoteType(),
			'user_id'=>$this->user_id,
			'total_votes'=>$this->total_votes,
			'vote_result'=>$this->vote_result,
			'rating'=>$this->rating,
			'vote'=>$vote
		);

		$voter=Rating_Generic::init();
        $voter->setModuleId(LabCMS::i()->getModuleIdByName('lc_comments'));
		$voter->vote($data);
		
		if (LabCMS::i()->no_errors) {
			$data['comment_id']=$data['item_id'];
			Db::i()->query(
				"UPDATE ?_comments SET total_votes=?, vote_result=?, rating=?
				WHERE comment_id=?",
				$data['total_votes'], $data['vote_result'],
				$data['rating'], $data['item_id']
			);
			return $data;
		}
	}
	
	protected function _checkCommentExists()
	{
		if (!$this->id) return $this->_error(_m('Комментарий не найден'));
		return true;
	}
	
	
	protected function _checkCommentDeleted()
	{
		if ($this->_commentDeleted()) return $this->_error(_m('Комментарий удален'));
		return true;
	}
	
	protected function _commentDeleted()
	{
		return $this->status==3;
	}
	
	public function repairComments()
	{
		if ($items=Db::i()->selectCol(
			"SELECT item_id FROM ?_comments_items WHERE counter>0"
		)) {
			foreach ($items as $item_id) {
				self::buildNestedKeys(NULL, 0, 0, $item_id);
			}
		}
		
		Db::i()->query(
			"UPDATE ?_comments_items ci SET counter=
			(SELECT COUNT(*) FROM ?_comments c WHERE ci.item_id=c.item_id)"
		);
	}
	
	public function resetCache($ids=null)
	{
		if (null==$ids) $ids=array($this->id);
		elseif(!is_array($ids)) $ids=array($ids);
		foreach ($ids as $k=>$v) {
			$ids[$k]='comment_'.$v;
		}
		Cache_Generic::init()->remove($ids);
	}
	
	protected static function buildNestedKeys($parent_id, $left, $level, $item_id)
	{
		$right = $left+1;
		$level++;
		if ($rows = DB::i()->select(
			"SELECT comment_id FROM ?_comments
			WHERE item_id = ? { and parent_id = ? }
			{ AND parent_id IS NULL and 1=?d}
			ORDER BY comment_id ASC",
			$item_id, !is_null($parent_id) ? $parent_id:DBSIMPLE_SKIP,
			is_null($parent_id) ? 1:DBSIMPLE_SKIP
		)) {
			foreach ($rows as $row) {
				$right = self::buildNestedKeys(
					$row['comment_id'], $right, $level, $item_id
				);
			}
		}
		$level--;
		if (!is_null($parent_id)) {
			DB::i()->query(
				"UPDATE ?_comments
				SET left_key=?d, right_key=?d , `level`=?d
				WHERE comment_id=? ", $left, $right, $level, $parent_id
			);
		}
		return $right+1;
	}
	
	public function getVoteType()
	{
		return $this->vote_type;
	}
	
}