<?php
/**
* @version	$Id: rating_helper.php 16513 2017-01-20 14:10:53Z 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 RatingHelper extends kHelper {

		/**
		 * One star width/height in pixels
		 *
		 * @var int
		 */
		var $ratingUnitWidth = 25;
		var $ratingSmallUnitWidth = 10; //20;

		/**
		 * Maximal star count
		 *
		 * @var int
		 */
		var $ratingMaximal = 5;

		var $_phrases = Array (
			'current_rating' => 'lu_CurrentRating',
			'vote_title' => 'lu_VoteTitle',
			'vote_count' => 'lu_VoteCount',
			'invalid_rating' => 'lu_InvalidRating',
			'already_voted' => 'lu_AlreadyVoted',
			'thanks_for_voting' => 'lu_ThanksForVoting',
		);

		/**
		 * Draws rating bar for a given category item
		 *
		 * @param kDBItem $object
		 * @param bool $show_div
		 * @param string $additional_msg
		 * @param string $additional_style
		 * @return string
		 * @access public
		 */
		public function ratingBar(&$object, $show_div = true, $additional_msg = '', $additional_style = '')
		{
			// 1. user is allowed to vote by permissions
			$perm_prefix = $this->Application->getUnitOption($object->Prefix, 'PermItemPrefix');
			$static = !$this->Application->CheckPermission($perm_prefix . '.RATE', 0, $object->GetDBField('CategoryId'));

			// 2. user isn't voting too frequently
			$spam_helper =& $this->_getSpamHelper($object);
			$user_voted = $spam_helper->InSpamControl();

			if ( !$static && !$user_voted ) {
				// allow to set rating when not static and user not voted before
				$voting_js = $this->getVotingControl($object, $additional_style);
			}
			else {
				$voting_js = '';
			}

			$msg_info = Array ('text' => $additional_msg, 'class' => Array ());

			if ( $static ) {
				$msg_info['class'][] = 'static';
			}

			if ( $user_voted ) {
				$msg_info['class'][] = 'voted';
			}

			$rater = $this->ratingBarSimple($this->getAverageRating($object), $voting_js, $msg_info, $additional_style);

			if ( $show_div ) {
				// adds div around rating stars (when drawing rating first time)
				$rater = '<div class="inline-rating" id="page_rating_' . $object->GetID() . '">' . $rater . '</div>';
			}

			return $rater;
		}

		/**
		 * Returns average rating
		 *
		 * @param kDBItem $object
		 * @return float|int
		 */
		function getAverageRating(&$object)
		{
			$total_votes = $object->GetDBField('CachedVotesQty');
			$total_rating = $object->GetDBField('CachedRating') * $total_votes;

			return $total_votes ? $total_rating / $total_votes : 0;
		}

		/**
		 * Draws rating bar for a given category item
		 *
		 * @param float $average_rating
		 * @param string $voting_js
		 * @param Array $msg_info
		 * @param string $additional_style
		 * @return string
		 * @access public
		 */
		public function ratingBarSimple($average_rating, $voting_js = '', $msg_info = null, $additional_style = '')
		{
			if ( !isset($msg_info) || !is_array($msg_info) ) {
				$msg_info = Array ('text' => '', 'class' => Array ());
			}

			$unit_selected_width = $additional_style ? $this->ratingSmallUnitWidth : $this->ratingUnitWidth;
			$rating_width = $average_rating ? @number_format($average_rating, 2) * $unit_selected_width : 0;

			$rating2 = $average_rating ? @number_format($average_rating, 2) : 0;
			$current_rating_text = $this->_replaceInPhrase('current_rating', Array ('<strong>' . $rating2 . '</strong>', $this->ratingMaximal));

			$rater = '	<span class="inline-rating">
							<ul class="star-rating ' . $additional_style . '" style="width: ' . $unit_selected_width * $this->ratingMaximal . 'px;">
								<li class="current-rating" style="width: ' . $rating_width . 'px;">' . $current_rating_text . '</li>' . "\n" .
					 			$voting_js . '
					 		</ul>
					 	</span>';

			// this part is disabled for now, will be addressed once properly review
			/*$rating1 = $average_rating ? @number_format($average_rating, 1) : 0;
			$rater .= '	<p class="' . implode(' ', $msg_info['class']) . '">' . $this->_replaceInPhrase('vote_title', Array ('<strong>' . $rating1 . '</strong>', $this->ratingMaximal)) . ' (' . $this->_replaceInPhrase('vote_count', Array ($total_votes)) . ') </p>';*/

			if ( $voting_js ) {
				$rater .= '&nbsp;<span class="' . implode(' ', $msg_info['class']) . '">' . $msg_info['text'] . '</span>';
			}
			else {
				// adds div around rating stars (when drawing rating first time)
				$rater = '<div class="inline-rating">' . $rater . '</div>';
			}

			return $rater;
		}

		/**
		 * Returns control, used to vote on a given $object
		 *
		 * @param kDBItem $object
		 * @param string $additional_style
		 * @return string
		 */
		function getVotingControl(&$object, $additional_style = '')
		{
			$ret = '';

			for ($i = 1; $i <= $this->ratingMaximal; $i++) {
				$ret .= '<li><a href="#vote-' . $i . '" onclick="aRatingManager.makeVote(' . $i . ', \'' . $object->Prefix . '\', ' . $object->GetID() . ', \'' . $additional_style . '\'); return false;" title="' . $this->_replaceInPhrase('vote_title', Array ($i, $this->ratingMaximal)) . '" class="r' . $i . '-unit rater" rel="nofollow">' . $i . '</a></li>' . "\n";
			}

			return $ret;
		}

		/**
		 * Saves user's vote, when allowed
		 *
		 * @param kDBItem $object
		 * @return string
		 */
		function makeVote(&$object)
		{
			$spam_helper =& $this->_getSpamHelper($object);

			if (!$object->isLoaded() || $spam_helper->InSpamControl()) {
				return '@err:' . $this->_replaceInPhrase('already_voted');
			}

			$perm_prefix = $this->Application->getUnitOption($object->Prefix, 'PermItemPrefix');
			$can_rate = $this->Application->CheckPermission($perm_prefix . '.RATE', 0, $object->GetDBField('CategoryId'));
			$rating = (int)$this->Application->GetVar('rating'); // not numeric rating is from GoogleBot :(
			$additional_style = $this->Application->GetVar('size');

			if (($rating <= 0) || ($rating > $this->ratingMaximal) || !$can_rate) {
				return '@err:' . $this->_replaceInPhrase('invalid_rating');
			}

			// save current rating
			$fields_hash = Array (
				'ItemId'		=>	$object->GetID(),
				'RatingValue'	=>	$rating,
				'IPAddress'		=>	$this->Application->getClientIp(),
				'CreatedOn'		=>	adodb_mktime(),
			);
			$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'CatalogRatings');

			// recalculate average rating
			$votes_count = $object->GetDBField('CachedVotesQty');
			$avg_rating = $object->GetDBField('CachedRating');

			$avg_rating = round((($votes_count * $avg_rating) + $rating) / ($votes_count + 1), 2);
			$object->SetDBField('CachedRating', "$avg_rating");
			$object->Update();

			$sql = 'UPDATE '.$object->TableName.'
					SET CachedVotesQty = CachedVotesQty + 1
					WHERE '.$object->IDField.' = '.$object->GetID();
			$this->Conn->Query($sql);

			$object->SetDBField('CachedVotesQty', $object->GetDBField('CachedVotesQty') + 1); // for using in template

			// prevent user from voting too quickly
			$spam_helper->AddToSpamControl();

			return $this->ratingBar($object, false, '<span class="thanks">' . $this->_replaceInPhrase('thanks_for_voting') . '</span>', $additional_style);
		}

		/*function purgeVotes()
		{
			$expired = adodb_mktime() - 86400 * $this->Application->ConfigValue('Timeout_Rating'); // 3600

			$sql = 'DELETE FROM ' . TABLE_PREFIX . 'CatalogRatings
					WHERE CreatedOn < ' . $expired;
			$this->Conn->Query($sql);
		}*/

		/**
		 * Performs sprintf on phrase translation using given variables
		 *
		 * @param string $phrase
		 * @param Array $arguments
		 * @return string
		 */
		function _replaceInPhrase($phrase, $arguments = Array ())
		{
			$value = $this->Application->Phrase($this->_phrases[$phrase], false);

			if ($arguments) {
				return vsprintf($value, $arguments);
			}

			return $value;
		}

		/**
		 * Returns SpamHelper object linked to given object
		 *
		 * @param kDBItem $object
		 * @return SpamHelper
		 * @access protected
		 */
		protected function &_getSpamHelper(&$object)
		{
			/** @var SpamHelper $spam_helper */
			$spam_helper = $this->Application->recallObject('SpamHelper');

			// 2. user isn't voting too frequently
			$config_mapping = $this->Application->getUnitOption($object->Prefix, 'ConfigMapping');
			$review_settings = $config_mapping['RatingDelayValue'] . ':' . $config_mapping['RatingDelayInterval'];
			$spam_helper->InitHelper($object->GetDBField('ResourceId'), 'Rating', $review_settings, $object->GetCol('ResourceId'));

			return $spam_helper;
		}
	}