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

class forum_post extends DefaultObject
{
	public $vote_type=4;
	protected $cache_key='forum_post_';

	public function __construct($mapper=null)
	{
		if (is_object($mapper)) {
			$this->mapper=$mapper;
		} else {
			$this->mapper=Factory::create('forum.mapper');
		}
		Factory::load('forum.post_entity');
	}

	public function add($post)
	{
		if ($post->user->isGuest()) {
			$post->user->login=$post->user_name;
			$post->user->email=$post->email;
		}
		$post->putdate=time();
		$post->ip=User::getIP();

		$this->mapper->addPost($post);
		$this->_updateCounters($post, 1, $post->first?1:0, $post->user, $post->putdate);
		TCache::clean('MATCH_TAG', array($this->_getCacheKeyCommon()));
	}

	public function update($post)
	{
		$this->mapper->updatePost($post);
		TCache::remove($this->_getCacheKey().$post->id);
		TCache::clean('MATCH_TAG', array($this->_getCacheKeyCommon()));
	}
	
	public function delete($post)
	{
		$this->mapper->deletePost($post);
		//очистить результаты голосований
		$this->_cleanVotesByIds(array($post->id));
		if (!$this->hidden) {
			$this->_updateCounters($post, -1);
		}
		TCache::remove($this->_getCacheKey().$post->id);
		TCache::clean('MATCH_TAG', array($this->_getCacheKeyCommon()));
	}

	public function hidePostsByTheme($theme)
	{
		$this->mapper->hidePostsByTheme($theme);
		TCache::clean('MATCH_TAG', array($this->_getCacheKeyCommon()));

	}
	
	public function deletePostsByTheme($theme)
	{
		$filter=array(
			'theme_id'=>$theme->id,
			'show_hidden'=>true,
			'order'=>'putdate DESC'
		);

		//удаляем по тысяче сообщений начиная с конца темы
		$count=1;
		while ($count) {
			//тут немного срезаем угол и получаем не объекты постов, а только их id
			//это не совсем верно с точки зрения структуры, зато довольно быстро
			if ($ids=$this->mapper->getPostsByFilter($count, $filter, 1, 1000)) {
				$this->_cleanVotesByIds($ids);
				$this->mapper->deletePostsByIds($ids);
			}
		}
		
		TCache::remove(build_cache_keys($ids, $this->_getCacheKey()));
		TCache::clean('MATCH_TAG', array($this->_getCacheKeyCommon()));
	}

	protected function _cleanVotesByIds($ids)
	{
		if (!is_array($ids)) $ids=array($ids);
		$voter=Rating_Generic::init();
		$voter->deleteVotesByIds($ids, $this->vote_type);
	}

	public function getPostById($id)
	{
		$data=$this->getPostsByArrayId(array($id));
		if (isset($data[$id])) {
			return $data[$id];
		}
		return null;
	}

	public function getLastPostByTheme($theme)
	{
		$filter=array(
			'theme_id'=>$theme->id,
			'show_hidden'=>0,
			'order'=>'putdate DESC'
		);
		$posts=$this->getPostsByFilter($filter, 1, 1);
		return array_shift($posts['collection']);
	}

	public function getPostsByTheme($theme, $page, $atPage)
	{
		$filter=array(
			'theme_id'=>$theme->id,
			'show_hidden'=>access('admin')
		);
		return $this->getPostsByFilter($filter, $page, $atPage);
	}

	public function getPostsByFilter($filter, $page, $atPage)
	{
		$page=(intval($page)<=0)?1:intval($page);

		$key='forum_posts_by_filter_'.md5(serialize($filter)).'_'.$page.'_'.$atPage;
		if (false === ($data=TCache::get($key))) {
			$data = array(
				'collection'=>$this->mapper->getPostsByFilter($count, $filter, $page, $atPage),
				'count'=>$count
			);
			TCache::set($data, $key, array($this->_getCacheKeyCommon()));
		}
		$data['collection'] = $this->getPostsByArrayId($data['collection']);
		return $data;
	}

	public function getPostsByArrayId($id)
	{
		$data=$this->_getItemsByArrayId($id);
		if ($data) {
			$this->_setAddtitionalData($data);
		}
		return $data;
	}

	public function hide($post)
	{
		if ($post->hidden) return;
		$post->hidden_by=User::i()->getCurrentUser();
		$this->update($post);
		$this->_updateCounters($post, -1);
	}
	
	public function unhide($post)
	{
		if (!$post->hidden) return;
		$post->hidden_by=null;
		$this->update($post);
		$this->_updateCounters($post, 1);
	}

	public function _getItemsByArrayIdFromStorage($id)
	{
		return $this->mapper->getPostsByArrayId($id);
	}

	protected function _setAddtitionalData(&$posts)
	{
		$users=$themes=array();
		foreach ($posts as $post) {
			if ($post->user_id) $users[]=$post->user_id;
			if ($post->edited_by_user_id) $users[]=$post->edited_by_user_id;
			$themes[]=$post->theme_id;
		}

		$users=User::i()->getUsersByIds($users);
		$themes=$this->_getTheme()->getThemesByArrayId($themes);

		foreach ($posts as $post) {
			$post->user=$this->getUserObj($post->user_id, $users, array('login'=>$post->user_name, 'email'=>$post->email));
			$post->edited_by=$this->getUserObj($post->edited_by_user_id, $users);
			$post->theme=$themes[$post->theme_id];

			if (!$post->hidden) {
				$post->access_add=access('add');
				$post->access_edit=(($post->isAuthor() && access("edit")) || access("moderator")) ? true : false;
				if (!$post->first) {
					$post->access_hide=access("moderator, admin");
					$post->access_extract=access("moderator, admin");
				}
			}

			if (!$post->first) {
				
				$post->access_unhide=($post->hidden && access("moderator, admin"));
				$post->access_delete=($post->isAuthor() && access('delete')) || access('admin');
			}
		}
	}
	
	protected function _updateCounters($post, $count, $user=null, $putdate=null)
	{
		$this->_getTheme()->updateStat($post->theme, $count, 0, $user, $putdate);
	}

	protected function _getTheme()
	{
		return Factory::create('forum.theme');
	}

	protected function _getForum()
	{
		return Factory::create('forum.forum');
	}

	public function moveToTheme($post, $theme)
	{
		return $this->mapper->movePostsToTheme($post, $theme);
	}

	public function vote($post, $vote)
	{
		$data=array(
			'item_id'=>$post->id,
			'type'=>$this->vote_type,
			'user_id'=>$post->user->id,
			'total_votes'=>$post->total_votes,
			'vote_result'=>$post->vote_result,
			'rating'=>$post->rating,
			'vote'=>$vote
		);

		$voter=Rating_Generic::init();
		if ($voter->vote($data)) {
			$post->total_votes=$data['total_votes'];
			$post->vote_result=$data['vote_result'];
			$post->rating=$data['rating'];
			$this->update($post);
			return $post;
		}
		return false;
	}

	public function resetCommonCache()
	{
		TCache::clean('MATCH_TAG', array($this->_getCacheKeyCommon()));
	}

	public function buildEditPostForm($post=null, $new_theme=false)
	{
		$form = Factory::create('HTML_QuickForm2', null, 'post', array('action'=>''));
		$token=$form->addElement('hidden', 'token', array('value' => User::i()->token));
		
		if (($new_theme && User::i()->isGuest ) || ($post && $post->user->isGuest())) {
			$login=$form->addElement('text', 'login', null, array('label' => _m('Имя:')));
			$login->addRule('required', _m('Необходимо указать имя'), null, $this->validation);
			$login->addRule(
				'callback', _m('Логин уже занят'),
				array('callback'=>array($this, 'IsLoginNotExists'),	'arguments'=>array(false))
			);

			$email=$form->addElement('email', 'email', null, array('label' => _m('Email:')));
		}

		if ($new_theme || ($post && $post->first)) {
			$subject=$form->addElement('text', 'subject', null, array('label' => _m('Название темы:')));
			$subject->addRule('required', _m('Нужно указать тему сообщения'), null, $this->validation);
			
			if ($post && access('moderator')) {
				$allFourms=$this->_getForum()->getAllForums();

				foreach ($allFourms['collection'] as $item) {
					$options[$item->id]=$item->name;
				}
				$forum_id=$form->addElement(
					'select', 'forum_id', null, array('options'=>$options, 'label' => _m('Перенести в форум:'))
				);
			}
		}
		
		$msg=$form->addElement('textarea', 'msg', array('class'=>'bbcode'), array('label' => _m('Сообщение:')));
		$msg->addRule('required', _m('Сообщение не может быть пустым'), null, $this->validation);
		
		$form->addElement('submit', null, array('value'=>_m('Отправить')));
		
		if (isset($login)) {
			$login->setAttribute('autofocus');
		} elseif(isset($subject)) {
			$subject->setAttribute('autofocus');
		} else {
			$msg->setAttribute('autofocus');
		}

		if ($post) {
			$data=array(
				'subject'=>$post->theme->subject,
				'msg'=>$post->msg,
				'forum_id'=>$post->theme->forum_id,
				'login'=>$post->user->login,
				'email'=>$post->user->email
			);
			
			$form->addDataSource(
				Factory::create('HTML_QuickForm2_DataSource_Array', $data)
			);
		}
		
		return $form;
	}

	public function buildAddThemeForm()
	{
		return $this->buildEditPostForm(null, true);
	}

	public function buildPostQuoteForm($post)
	{
		$form=$this->buildEditPostForm();
		$form->addDataSource(
			Factory::create(
				'HTML_QuickForm2_DataSource_Array', 
				array(
					'msg'=>'[quote="'.$post->user->login.'"]'.$post->msg.'[/quote]'
				)
			)
		);
		return $form;
	}

	public function IsLoginNotExists($login)
	{
		return (User::i()->IsLoginExists($login))?false:true;
	}
}