<?php
/**
* @version	$Id: sections_helper.php 13572 2010-05-18 15:40:06Z 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!');

	/**
	 * Processes sections info from the configs
	 *
	 */
	class kSectionsHelper extends kHelper {

		/**
		 * Holds information about all sections
		 *
		 * @var Array
		 */
		var $Tree = Array();

		/**
		 * Checks, that we are in debug mode
		 *
		 * @var bool
		 */
		var $debugMode = false;

		/**
		 * Checks, that we are in super admin mode
		 *
		 * @var bool
		 */
		var $superAdminMode = false;

		/**
		 * Set's prefix and special
		 *
		 * @param string $prefix
		 * @param string $special
		 * @access public
		 */
		function Init($prefix, $special, $event_params = null)
		{
			parent::Init($prefix, $special, $event_params);

			$this->debugMode = $this->Application->isDebugMode();
			$this->superAdminMode = $this->Application->RecallVar('super_admin');

			$this->BuildTree();
		}

		/**
		 * Builds xml for tree in left frame in admin
		 *
		 * @param Array $params
		 */
		function BuildTree()
		{
			if (!isset($this->Application->Memcached) || !($data = $this->Application->Memcached->get('master:sections_parsed'))) {
				$data = $this->Conn->GetOne('SELECT Data FROM '.TABLE_PREFIX.'Cache WHERE VarName = "sections_parsed"');
			}
			if ($data) {
				$this->Tree = unserialize($data);
				return ;
			}

			if (!(defined('IS_INSTALL') && IS_INSTALL)) {
				// don't reread all configs during install, because they are reread on every install step
				$this->Application->UnitConfigReader->ReReadConfigs();
			}

			$this->Tree = Array ();

			// 1. build base tree (don't update parent with children list yet)

			// 1.1. process prefixes without priority
			$prioritized_prefixes = Array ();
			$prefixes = array_keys($this->Application->UnitConfigReader->configData);

			foreach ($prefixes as $prefix) {
				$config =& $this->Application->UnitConfigReader->configData[$prefix];

				if (array_key_exists('ConfigPriority', $config)) {
					$prioritized_prefixes[$prefix] = $config['ConfigPriority'];
					continue;
				}
				$this->_processPrefixSections($prefix);
			}

			// 2. process prefixes with priority
			asort($prioritized_prefixes);
			foreach ($prioritized_prefixes as $prefix => $priority) {
				$this->_processPrefixSections($prefix);
			}

			// 2. apply section ajustments
			foreach ($prefixes as $prefix) {
				$config =& $this->Application->UnitConfigReader->configData[$prefix];
				$section_ajustments = getArrayValue($config, 'SectionAdjustments');
				if (!$section_ajustments) continue;

				foreach ($section_ajustments as $section_name => $ajustment_params) {
					if (is_array($ajustment_params)) {
						if (!array_key_exists($section_name, $this->Tree)) {
							// don't process ajustments for non-existing sections
							continue;
						}

						$this->Tree[$section_name] = array_merge_recursive2($this->Tree[$section_name], $ajustment_params);
					}
					else {
						// then remove section
						unset($this->Tree[$section_name]);
					}
				}
			}

			// 3.
			foreach ($this->Tree as $section_name => $section_params) {
				// 3.1. update parent -> children references
				$parent_section = $section_params['parent'];
				$section_order = "{$section_params['priority']}";

				if (!isset($parent_section)) {
					// don't process parent section of "in-portal:root" section
					continue;
				}

				if (!array_key_exists('children', $this->Tree[$parent_section])) {
					$this->Tree[$parent_section]['children'] = Array ();
				}

				if (array_key_exists($section_order, $this->Tree[$parent_section]['children'])) {
					trigger_error(
						'Section "<strong>' . $section_name . '</strong>" has replaced section "<strong>' .
						$this->Tree[$parent_section]['children'][$section_order] .
						'</strong>" (parent section: "<strong>' . $parent_section .
						'</strong>"; duplicate priority: <strong>' . $section_order . '</strong>)',
						E_USER_WARNING
					);
				}

				$this->Tree[$parent_section]['children'][$section_order] = $section_name;

				if ($section_params['type'] == stTAB) {
					// if this is tab, then mark parent section as TabOnly
					$this->Tree[$parent_section]['tabs_only'] = true;
				}

				// 3.2. process icons here, because they also can be ajusted
				if (isset($section_params['icon']) && preg_match('/([^:]+):(.*)/', $section_params['icon'], $regs)) {
					$this->Tree[$section_name]['icon'] = $regs[2];
					$this->Tree[$section_name]['icon_module'] = $regs[1]; // set "icon_module" used in "combined_header" block
					$module_folder = trim( $this->Application->findModule('Name', $regs[1], 'Path'), '/');
					if ($module_folder == '') {
						$module_folder = 'core';
					}
				}
				else {
					$module_folder = $this->Application->getUnitOption($section_params['SectionPrefix'], 'ModuleFolder');
					if (!array_key_exists('icon_module', $section_params)) {
						$this->Tree[$section_name]['icon_module'] = $module_folder; // set "icon_module" used in "combined_header" block
					}
				}

				// this is to display HELP icon instead of missing one.. can be replaced with some other icon to draw attention
				$icon_file = $module_folder.'/admin_templates/img/icons/icon24_'.$this->Tree[$section_name]['icon'];

				/*$core_file = FULL_PATH.'/core/admin_templates/img/icons/icon24_' . $this->Tree[$section_name]['icon'].'.gif';
				if ($module_folder != 'core' && file_exists($core_file) && file_exists(FULL_PATH.'/'.$icon_file.'.gif')) {
					if (crc32(file_get_contents($core_file)) == crc32(file_get_contents(FULL_PATH.'/'.$icon_file.'.gif'))) {
						trigger_error('Section "<strong>' . $section_name . '</strong>" uses icon copy from "Core" module', E_USER_NOTICE);
					}
				}*/

//				if (!file_exists(FULL_PATH.'/'.$icon_file.'.png')) {
//					$this->Tree[$section_name]['icon'] = 'help';
//					$this->Tree[$section_name]['icon_module'] = 'core';
//				}
			}
			$this->Application->HandleEvent( new kEvent('adm:OnAfterBuildTree') );

			if (isset($this->Application->Memcached)) {
				$this->Application->Memcached->set('master:sections_parsed',serialize($this->Tree), 0, 0);
				return;
			}

			$this->Conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("sections_parsed", '.$this->Conn->qstr(serialize($this->Tree)).', '.adodb_mktime().')');
		}

		function _processPrefixSections($prefix)
		{
			$config =& $this->Application->UnitConfigReader->configData[$prefix];
			$sections = getArrayValue($config, 'Sections');
			if (!$sections) {
				return ;
			}

//			echo 'Prefix: ['.$prefix.'] has ['.count($sections).'] sections<br />';

			foreach ($sections as $section_name => $section_params) {
				// we could also skip not allowed sections here in future
				if ( isset($section_params['SectionPrefix']) ) {
					$section_prefix = $section_params['SectionPrefix'];
				}
				elseif ( $this->Application->getUnitOption($prefix, 'SectionPrefix') ) {
					$section_prefix = $this->Application->getUnitOption($prefix, 'SectionPrefix');
				}
				else {
					$section_prefix = $prefix;
				}
				$section_params['SectionPrefix'] = $section_prefix;
				$section_params['url']['m_opener'] = 'r';
				$section_params['url']['no_pass_through'] = 1;
				$pass_section = getArrayValue($section_params, 'url', 'pass_section');

				if ($pass_section) {
					unset($section_params['url']['pass_section']);
					$section_params['url']['section'] = $section_name;
					if (!isset($section_params['url']['module'])) {
						$module_name = $this->Application->findModule('Path', $config['ModuleFolder'].'/', 'Name');
						$section_params['url']['module'] = $module_name;
					}
				}

				if (!isset($section_params['url']['t'])) {
					$section_params['url']['t'] = 'index';
				}

				if (!isset($section_params['onclick'])) {
					$section_params['onclick'] = 'checkEditMode()';
				}

				if (!isset($section_params['container'])) {
					$section_params['container'] = 0; // for js tree printing to xml
				}

				$current_data = isset($this->Tree[$section_name]) ? $this->Tree[$section_name] : Array();

				if ($current_data) {
					trigger_error('Section "<strong>' . $section_name . '</strong>" declaration (originally defined in "<strong>' . $current_data['SectionPrefix'] . '</strong>") was overwriten from "<strong>' . $prefix . '</strong>"', E_USER_WARNING);
				}

				$this->Tree[$section_name] = array_merge_recursive2($current_data, $section_params);
			}
		}

		/**
		 * Returns details information about section
		 *
		 * @param string $section_name
		 * @return Array
		 */
		function &getSectionData($section_name)
		{
			if (isset($this->Tree[$section_name])) {
				$ret =& $this->Tree[$section_name];
			}
			else {
				$ret = Array();
			}
			return $ret;
		}

		/**
		 * Returns first child, that is not a folder
		 *
		 * @param string $section_name
		 * @param Array $tree
		 * @return stirng
		 */
		function getFirstChild($section_name, $check_permission = false)
		{
			$section_data =& $this->getSectionData($section_name);

			$children = isset($section_data['children']) && $section_data['children'] ? $section_data['children'] : false;
			if ($children) {
				// get 1st child
				ksort($children, SORT_NUMERIC);
				foreach ($children as $child_priority => $child_section) {
					if (!$this->sectionVisible($child_section, $check_permission)) {
						continue;
					}

					break;
				}

				return $this->getFirstChild($child_section, $check_permission);
			}

			return $section_name;
		}

		/**
		 * Checks if given section is visible by it's definition and optionally by user permission
		 *
		 * @param string $section_name
		 * @param bool $check_permission
		 * @return bool
		 */
		function sectionVisible($section_name, $check_permission = false)
		{
			$section_data =& $this->getSectionData($section_name);

			if (isset($section_data['show_mode']) && is_numeric($section_data['show_mode'])) {
				$show_mode = $section_data['show_mode'];

				// if super admin section -> show in super admin mode & debug mode
				$show_section = $show_mode == smNORMAL || ((($show_mode & smSUPER_ADMIN) == smSUPER_ADMIN) && ($this->superAdminMode || $this->debugMode));

				if (!$show_section) {
					// if section is in debug mode only && debug mode -> show
					$show_section = (($show_mode & smDEBUG) == smDEBUG) && $this->debugMode;
				}

				if (!$show_section) {
					// visibility by section definition
					return false;
				}
			}

			// visibility by section permission
			if ($check_permission) {
				$perm_section = $this->getPermSection($section_name);

				return $this->Application->CheckPermission($perm_section.'.view');
			}

			return true;
		}

		/**
		 * Returns section for permission checking based on given section
		 *
		 * @param string $section_name
		 * @return string
		 */
		function getPermSection($section_name)
		{
			$ret = $section_name;
			$section_data =& $this->getSectionData($section_name);

			if ($section_data && isset($section_data['perm_prefix'])) {
				// this section uses other section permissions
				$ret = $this->Application->getUnitOption($section_data['perm_prefix'].'.main', 'PermSection');
			}
			return $ret;
		}
	}