<?php
/**
* @version	$Id: count_helper.php 15012 2012-01-06 20:38:49Z 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 kCountHelper extends kHelper {

		/**
		 * Returns counter value
		 *
		 * @param string $name counter name
		 * @param Array $params counter parameters
		 * @param string $query_name specify query name directly (don't generate from parmeters)
		 * @param bool $multiple_results
		 * @return mixed
		 */
		function getCounter($name, $params = Array (), $query_name = null, $multiple_results = false)
		{
			$this->resetExpiredCounters();

			$clone_counter = false;
			$query_name = isset($query_name) ? $query_name : rtrim($name.'-'.implode('-', array_values($params)), '-');
			$sql = 'SELECT *
					FROM '.TABLE_PREFIX.'Counters
					WHERE Name = '.$this->Conn->qstr($query_name);
			$count_data = $this->Conn->GetRow($sql);

			if (!$count_data && ($query_name != $name)) {
				// cloned record not found -> search for origial one
				$sql = 'SELECT *
						FROM '.TABLE_PREFIX.'Counters
						WHERE Name = '.$this->Conn->qstr($name);
				$count_data = $this->Conn->GetRow($sql);
				$clone_counter = true;
			}

			if (is_null($count_data['CountValue'])) {
				$params['PREFIX'] = TABLE_PREFIX;
				$count_sql = $count_data['CountQuery'];

				foreach ($params as $replace_from => $replace_to) {
					$count_sql = str_replace('<%'.$replace_from.'%>', $replace_to, $count_sql);
				}

				if ($multiple_results) {
					$count_data['CountValue'] = serialize($this->Conn->GetCol($count_sql));
				}
				else {
					$count_data['CountValue'] = $this->Conn->GetOne($count_sql);
				}

				if ($clone_counter && !$count_data['IsClone']) {
					// don't clone clones
					$count_data['CounterId'] = 0;
					$count_data['Name'] = $query_name;
					$count_data['IsClone'] = 1;
				}

				$count_data['LastCounted'] = adodb_mktime();
				$this->Conn->doInsert($count_data, TABLE_PREFIX.'Counters', 'REPLACE');
			}

			return $multiple_results ? unserialize($count_data['CountValue']) : $count_data['CountValue'];
		}

		/**
		 * Resets counter, which are affected by one of specified tables
		 *
		 * @param string $tables comma separated tables list used in counting sqls
		 * @return void
		 * @access public
		 */
		public function resetCounters($tables)
		{
			$tables = explode(',', $tables);
			$prefix_length = strlen(TABLE_PREFIX);
			foreach ($tables as $index => $table) {
				// remove prefixes
				if (substr($table, 0, $prefix_length) == TABLE_PREFIX) {
					$table = substr($table, $prefix_length);
				}
				$tables[$index] = '(TablesAffected LIKE "%|'.$table.'|%")';
			}

			$sql = 'UPDATE '.TABLE_PREFIX.'Counters
					SET CountValue = NULL
					WHERE '.implode(' OR ', $tables);

			$this->Conn->Query($sql);
		}

		function resetExpiredCounters()
		{
			static $reset = false;

			if (!$reset) {
				// reset expired counts
				$sql = 'UPDATE '.TABLE_PREFIX.'Counters
						SET CountValue = NULL
						WHERE (LifeTime > 0) AND (LastCounted < '.adodb_mktime().' - LifeTime)';
				$this->Conn->Query($sql);
				$reset = true;
			}
		}

		/**
		 * Counts items (of specific type) in category & subcategories
		 *
		 * @param string $prefix
		 * @param Array $params
		 * @param mixed $count_sql
		 * @return int
		 */
		function CategoryItemCount($prefix, $params, $count_sql = null)
		{
			if (!$this->Application->findModule('Var', $prefix)) {
				// this is not module item
				return $this->Application->ProcessParsedTag($prefix, 'CategoryItemCount', $params);
			}

			// 1. get root category for counting
			$category_id = isset($params['cat_id']) ? $params['cat_id'] : false;
			if (!is_numeric($category_id)) {
				$category_id = $this->Application->GetVar('m_cat_id');
			}

			if (!isset($count_sql)) {
				$count_sql = 'COUNT(*)';
			}

			$where_clauses = Array ();
			$table_name = $this->Application->getUnitOption($prefix, 'TableName');

			// 1. count category items
			$sql = 'SELECT '.$count_sql.'
					FROM '.$table_name.' item_table
					INNER JOIN '.TABLE_PREFIX.'CategoryItems ci ON (ci.ItemResourceId = item_table.ResourceId)
					INNER JOIN '.TABLE_PREFIX.'Categories c ON (ci.CategoryId = c.CategoryId)';

			// 2. count items from subcategories
			if ($category_id > 0) {
				// get subcategories of required category
				$tmp_sql = 'SELECT TreeLeft, TreeRight
							FROM '.TABLE_PREFIX.'Categories
							WHERE CategoryId = '.$category_id;
				$tree_info = $this->Conn->GetRow($tmp_sql);
				$where_clauses[] = 'c.TreeLeft BETWEEN '.$tree_info['TreeLeft'].' AND '.$tree_info['TreeRight'];
			}
			$where_clauses[] = 'item_table.Status = '.STATUS_ACTIVE;

			if (isset($params['today']) && $params['today']) {
				$today = adodb_mktime(0,0,0, adodb_date('m'), adodb_date('d'), adodb_date('Y'));
				$where_clauses[] = 'item_table.CreatedOn >= '.$today;
			}

			$sql .= ' WHERE ('.implode(') AND (', $where_clauses).')';

			return (int)$this->Conn->GetOne($sql);
		}

		/**
		 * Counts items (of specific type) from all categories
		 *
		 * @param string $prefix
		 * @param bool $today
		 * @param string $count_sql
		 * @return int
		 */
		function ItemCount($prefix, $today = false, $count_sql = null)
		{
		  	$table_name = $this->Application->getUnitOption($prefix, 'TableName');

		  	if (!isset($count_sql)) {
		  		$count_sql = 'COUNT(*)';
		  	}

		  	$sql = 'SELECT '.$count_sql.'
		  			FROM '.$table_name.' item_table
		  			INNER JOIN '.TABLE_PREFIX.'CategoryItems ci ON ci.ItemResourceId = item_table.ResourceId
		    		INNER JOIN '.TABLE_PREFIX.'Categories c ON c.CategoryId = ci.CategoryId
		    		INNER JOIN '.TABLE_PREFIX.'CategoryPermissionsCache perm_cache ON ci.CategoryId = perm_cache.CategoryId';

		  	list ($view_perm, $view_filter) = $this->GetPermissionClause($prefix, 'perm_cache');
		  	$where_clauses = Array (
		  		$view_filter, 'perm_cache.PermId = '.$view_perm, 'ci.PrimaryCat = 1', 'c.Status = '.STATUS_ACTIVE,
			);

		  	if ($today) {
		  		$today_date = adodb_mktime(0, 0, 0, adodb_date('m'), adodb_date('d'), adodb_date('Y'));
		  		$where_clauses[] = 'item_table.CreatedOn >= '.$today_date;
		  	}

		  	$sql .= ' WHERE ('.implode(') AND (', $where_clauses).')';

			return (int)$this->Conn->GetOne($sql);
		}

		/**
		 * Returns categories count in system
		 *
		 * @param bool $today
		 * @return int
		 */
		function CategoryCount($today = false)
		{
		  	$cache_key = 'category_count[%CSerial%]';

			if ($today) {
		  		$today_date = adodb_mktime(0, 0, 0, adodb_date('m'), adodb_date('d'), adodb_date('Y'));
		  		$cache_key .= ':date=' . $today_date;
		  	}

		  	$count = $this->Application->getCache($cache_key);

		  	if ($count === false) {
				$sql = 'SELECT COUNT(*)
			  			FROM ' . $this->Application->getUnitOption('c', 'TableName') . ' c
			    		INNER JOIN ' . TABLE_PREFIX . 'CategoryPermissionsCache perm_cache ON c.CategoryId = perm_cache.CategoryId';

			  	list ($view_perm, $view_filter) = $this->GetPermissionClause('c', 'perm_cache');

			  	$where_clauses = Array (
			  		$view_filter,
			  		'perm_cache.PermId = ' . $view_perm,
			  		'c.Status = ' . STATUS_ACTIVE,
				);

			  	if ($today) {
			  		$where_clauses[] = 'c.CreatedOn >= ' . $today_date;
			  	}

			    $sql .= ' WHERE ('.implode(') AND (', $where_clauses).')';

				$count = $this->Conn->GetOne($sql);

				if ($count !== false) {
					$this->Application->setCache($cache_key, $count);
				}
		  	}

		  	return $count;
		}

		/**
		 * Returns permission limitation clause for category item lists
		 *
		 * @param string $prefix
		 * @param string $table_alias
		 * @return Array
		 */
		function GetPermissionClause($prefix, $table_alias)
		{
			$permissions_ids = $this->Application->getCache(__CLASS__ . '::' . __FUNCTION__);

			if ($permissions_ids === false) {
				$this->Conn->nextQueryCachable = true;

				$sql = 'SELECT PermissionConfigId, PermissionName
						FROM '.TABLE_PREFIX.'CategoryPermissionsConfig
						WHERE PermissionName LIKE "%.VIEW"';
				$permissions_ids = $this->Conn->GetCol($sql, 'PermissionName');

				$this->Application->setCache(__CLASS__ . '::' . __FUNCTION__, $permissions_ids);
			}

			$permission_prefix = $this->Application->getUnitOption($prefix, 'PermItemPrefix');
			$view_perm = $permissions_ids[$permission_prefix . '.VIEW'];

			$groups = explode(',', $this->Application->RecallVar('UserGroups'));

			foreach ($groups as $group) {
				$view_filters[] = 'FIND_IN_SET('.$group.', '.$table_alias.'.acl)';
			}

			$view_filter = implode(' OR ', $view_filters);

			return Array ($view_perm, $view_filter);
		}

	}