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

//module_id, item_id, type, key, user_id, voter_id, vote, value, putdate


//храним голоса с точностью до сотых, но в поле int. Поэтому при добавлении умножаем на 100, а при выводе - делим.


class Rating_Lab extends ModuleTools implements Rating_Interface
{
	public function __construct()
	{
		$this->voter_id=User::i()->id;
		$this->user_rating=intval(User::i()->rating);
		$this->module_id=LabCMS::i()->getModuleId();
	}
	
	public function setModuleId($module_id)
	{
		$this->module_id=$module_id;
	}
	
	public function vote(&$data)
	{
		//$user_id может быть пустым, так что приводим его к 0
		$data['user_id']=intval($data['user_id']);

		if (User::i()->isGuest()) return self::_error("Голосовать могут только зарегистрированные пользователи");
		
		if ($this->user_rating<(config::get('core.user_rating_vote_min_rating')/100)) {
			return self::_error("Недостаточно рейтинга для голосования");
		}

		if ($data['user_id']==$this->voter_id) return self::_error("Нельзя голосовать за себя");
		
		if (!in_array($data['vote'], array(-1, 1))) return self::_error("Ошибка голосования");
		
		if (Db::i()->query(
			"INSERT IGNORE INTO ?_rating_votes 
			(module_id,
			item_id,
			`type`,
			user_id,
			voter_id,
			`vote`,
			`value`)
			VALUES(?, ?, ?, ?, ?, ?, ?)",
			$this->module_id,
			$data['item_id'],
			$data['type'],
			$data['user_id'],
			$this->voter_id,
			$data['vote'],
			$value = $this->_getValue($data['user_id'])
		)) {
			$delta=$data['vote']*$value;
			$data['total_votes']++;
			$data['vote_result']+=$data['vote'];
			$data['rating']+=$delta;
			
			if (config::get('core.user_rating_enabled') && $delta && $data['user_id']) {
				$this->updateUserRating($data['user_id'], round($delta*config::get('core.user_rating_k'.$data['type'])));
			}
		}
		else return self::_error("Вы уже голосовали");
		
		$this->addVoteCounters($data);
		
		return true;
	}

	public function deleteVotesByIds($ids, $type=1)
	{
		return Db::i()->query(
			"DELETE FROM ?_rating_votes
			WHERE 
			module_id=?
			AND `type`=?
			AND item_id IN(?a)",
			$this->module_id, $type, $ids
		);
	}
	
	function addVoteCounters(&$data)
	{
		$data['negative']=($data['total_votes']-$data['vote_result'])/2;
		$data['positive']=$data['total_votes']-$data['negative'];
	}
	
	public function getUserItemVotes($ids, $type=1)
	{
		return Db::i()->selectCol(
			"SELECT item_id AS ARRAY_KEY, vote FROM ?_rating_votes
			WHERE module_id=? AND `type`=? AND item_id IN (?a) AND voter_id=?",
			$this->module_id, $type, (array)$ids, $this->voter_id
		);
	}
	
	public function updateUserRating($user_id, $delta=0)
	{
		Db::i()->query("UPDATE ?_users SET rating=rating+?d WHERE user_id=?", round($delta), $user_id);
	}
	
	
	public function countUserRating($user_id)
	{
		$rating=0;
		$values=Db::i()->select(
			"SELECT `type` AS ARRAY_KEY, SUM( vote * value ) as rating
			FROM ?_rating_votes
			WHERE user_id =?
			GROUP BY `type`", $user_id
		);
		
		if ($values) foreach ($values as $type=>$value) {
			$rating+=$value*floatval(config::get('user_rating_k'.$type));
		}
		$rating=round($rating);
		Db::i()->query("UPDATE ?_users SET rating=? WHERE user_id=?", $rating, $user_id);
		return $rating;
	}
	
	protected function _getValue($user_id)
	{
		if ($this->user_rating<0) return 0;
		if (!$this->_isInLimits($user_id)) return 0;
		$rating=intval($this->user_rating/100);
		$rating=($rating)?$rating:1;
		$value=round(log($rating)*100);
		if (!$value && config::get('core.user_rating_vote_equal_1')) return 100;
		return $value;
	}
	
	protected function _isInLimits($user_id)
	{
		if ($user_id) {
			if (
				config::get('core.user_rating_vote_limiter_value')
				|| config::get('core.user_rating_vote_limiter_count')
			) {
				$data=Db::i()->selectRow(
					"SELECT (SUM(value*vote)) as value, count(vote) as votes
					FROM ?_rating_votes WHERE user_id=? AND voter=?",
					$user_id, $this->voter_id
				);
				if (
					config::get('core.user_rating_vote_limiter_value')
					&& ($data['value']/100)>=config::get('core.user_rating_vote_limiter_value')
				) return false;
				if (
					config::get('core.user_rating_vote_limiter_count')
					&& $data['votes']>=config::get('core.user_rating_vote_limiter_count')
				) return false;
			}
		}
		
		if (config::get('core.user_rating_vote_limiter_day_count')) {
			$count=Db::i()->selectCell(
				"SELECT COUNT(vote)
				FROM ?_votes
				WHERE user_id=? AND voter=? AND putdate>=NOW()-INTERVAL 1 DAY",
				$user_id, $this->voter_id
			);
			if ($count>=config::get('core.user_rating_vote_limiter_day_count')) return false;
		}
		return true;
	}
}