<?php
/**
 * Cms_template.php - Library to provide all the template data structures.
 * 						 This is the read interface and the data structures are created from the init file.
 *
 * @author $Author: dtong $
 * @version $Id: Cms_template.php,v 1.14 2011/05/13 03:39:31 dtong Exp $
 * @copyright Copyright (c) 2010, Tiller Software Co., Ltd.
*/
require_once 'cms_template_data.php';

class Cms_template {
	private $data_obj = NULL;
	private $CI = NULL;

	function __construct () {
		$this->CI = & get_instance();
		$this->CI->load->library('cms/cms_template/cms_template_init');
		$this->data_obj = $this->CI->cms_template_init->get();
	}

	/*
	 * Get templates types based on the input parameters.
	 *
	 * @param string $filename
	 * 	The file part of a template file such as 'ubd', 'pyp', 'myp', 'ubd' etc.
	 * @param int $stage
	 * 	The stage number.
	 * @param string $modulename
	 * 	The module name such as 'resource', 'lt' etc. This is the '_type' parameter in the templates.
	 *
	 * @return string|bool
	 * 	A string containing a list of types separated by commas - '1,2,3' or FALSE if no types were found.
	 */
	function types($filename, $stage=FALSE, $modulename=FALSE) {
		//Use different function if stage and modulename are passed in
		if ( $stage !== FALSE && $modulename !== FALSE )
			return ($this->types_module($filename, $stage, $modulename));

		$index = $filename;
		if ( $stage !== FALSE ) {
			$index = "stage{$stage}_" . $filename;
		}
		if ( array_key_exists($index, $this->data_obj->type_array) ) {
			return implode(',', $this->data_obj->type_array[$index]);
		}
		return FALSE;
	}

	//Similiar to types() but can't suppliy a modulename. Needed by btnsort prefetch.
	//Meta types are needed if you assign a sort type diferent than the actual data type.
	//LT and OS don't need this because they don't use btnsort prefetch.
	function stage_types_include_meta($filename, $stage) {
		$normal_types = $this->types($filename, $stage);
		$meta_types = '';
		$sep = '';
		foreach($this->data_obj->meta_types as $type => $meta_row) {
			if ($meta_row['file_part'] == $filename && $meta_row['stage'] ) {
				$meta_types . "{$sep}{$type}";
				$sep=',';
			}
		}
		if ( $meta_types && $normal_types ) {
			return "{$normal_types},{$meta_types}";
		}
		if ( $meta_types ) {
			return $meta_types;
		}
		if ( $normal_types ) {
			return $normal_types;
		}
		return FALSE;
	}

	/*
	 * Similiar to types() but also returns hidden types and meta types. Used by btnsort.
	 * This piggy backs on types_exclude_stages_usehidden().
	 * Sample template array: 'stage1_nothing' => array('_type' => 'nothing', '_hidden_typeid' => 1)
	 * 							  'stage2_nothing' => array('_type' => 'nothing', '_meta_typeid' => CMS_SORT_AE_UNIT)
	 *
	 * @param string $filename
	 * 	The file part of a template file such as 'ubd', 'pyp', 'myp', 'ubd' etc.
	 * @param string $modulename
	 * 	The module name such as 'resource', 'lt' etc. This is the '_type' parameter in the templates.
	 *
	 * @return string|bool
	 * 	A string containing a list of types separated by commas - '1,2,3' or FALSE if no types were found.
	 */
	/*
	function alltypes($filename) {
		$ret = $this->types_exclude_stages_usehidden(FALSE, $filename, FALSE);
		if ( $ret ) {
			$sep = ',';
		}
		else {
			$sep = '';
			$ret = '';
		}
		foreach ($this->data_obj->meta_types as $type => $value) {
			if ($value['file_part'] == $filename) {
				$ret .= "{$sep}{$type}";
				$sep = ',';
			}
		}
		if ( $ret == '' ) {
			return FALSE;
		}
		return $ret;
	}
	*/
	//Like alltypes() but no meta types
	/*
	function alltypes_exclude_meta($filename) {
		return $this->types_exclude_stages_usehidden(FALSE, $filename, FALSE);
	}
	*/

	/*
	 * Checks if the type is a valid type for the supplied template filename suffix.
	 *
	 * @param string $filename
	 * 	The file part of a template file such as 'ubd', 'pyp', 'myp', 'ubd' etc.
	 * @param int $type
	 * 	The type number
	 *
	 * @return bool
	 * 	True if type is valid therwise false.
	 */
	function valid_type($filename, $type) {
		$types = $this->types($filename);
		if ( $types === FALSE )
			return FALSE;
		$array = explode(',', $types);
		if (in_array($type, $array))
			return TRUE;
		return FALSE;
	}

	/*
	 * Returns a list of types according to the 3 input parameters. Used by types().
	 */
	private function types_module($filename, $stage, $modulename) {
		if ( !array_key_exists($filename, $this->data_obj->template_stagemodule_types) ||
			  !array_key_exists($stage, $this->data_obj->template_stagemodule_types[$filename]) ||
			  !array_key_exists($modulename, $this->data_obj->template_stagemodule_types[$filename][$stage]) )
			  return FALSE;
		return implode(',', $this->data_obj->template_stagemodule_types[$filename][$stage][$modulename]);
	}

	//Actual function for types_exclude_stages() and types_exclude_stages_usehidden
	private function types_exclude_stages_main($data_array, $exclude_stages, $filename, $modulename=FALSE) {
		if ( !is_array($exclude_stages) )
			$exclude_stages = array($exclude_stages);
		$ret = array();
		if ( array_key_exists($filename, $data_array)) {
			foreach($data_array[$filename] as $stage => $stage_data) {
				//Skip if stage in $exclude_stages
				if ( in_array($stage, $exclude_stages) )
					continue;
				//See if we have the $modulename
				if ( $modulename !== FALSE && array_key_exists($modulename, $data_array[$filename][$stage])) {
					$ret = array_merge($ret, $data_array[$filename][$stage][$modulename]);
					continue;
				}
				foreach ($data_array[$filename][$stage] as $module_key => $module_array) {
					if ( $modulename === FALSE || $modulename == $module_key )
						$ret = array_merge($ret, $module_array);
				}
			}
		}
		if ( count($ret) > 0 ) {
			$ret = osa_array_remove_duplicate($ret);
			sort($ret);
			return implode(',', $ret);
		}
		return FALSE;
	}

	/*
	 * Gets all types except the ones belonging to the list of supplied stage numbers.
	 * The same concept of multiple stages is not used for types() function since you can call it multiple times but not here.
	 *
	 * @param int|array $exclude_stages
	 * 	All types in these stage numbers will be excluded in the return. Can be an integer of an array of integers.
	 * @param string $filename
	 * 	The file part of a template file such as 'ubd', 'pyp', 'myp', 'ubd' etc.
	 * @param string $modulename
	 * 	The module name such as 'resource', 'lt' etc. This is the '_type' parameter in the templates.
	 *
	 * @return string|bool
	 * 	A string containing a list of types separated by commas - '1,2,3' or FALSE if no types were found.
	 */
	function types_exclude_stages($exclude_stages, $filename, $modulename=FALSE) {
		return $this->types_exclude_stages_main($this->data_obj->template_stagemodule_types, $exclude_stages, $filename, $modulename);
	}

	/*
	 * Gets all types except the ones belonging to the list of supplied stage numbers.
	 * The same concept of multiple stages is not used for types() function since you can call it multiple times but not here.
	 * This one is the same as types_exclude_stages but includes hidden typeids.
	 *
	 * @param int|array $exclude_stages
	 * 	All types in these stage numbers will be excluded in the return. Can be an integer of an array of integers.
	 * @param string $filename
	 * 	The file part of a template file such as 'ubd', 'pyp', 'myp', 'ubd' etc.
	 * @param string $modulename
	 * 	The module name such as 'resource', 'lt' etc. This is the '_type' parameter in the templates.
	 *
	 * @return string|bool
	 * 	A string containing a list of types separated by commas - '1,2,3' or FALSE if no types were found.
	 */
	function types_exclude_stages_usehidden($exclude_stages, $filename, $modulename=FALSE) {
		return $this->types_exclude_stages_main($this->data_obj->template_stagemodule_types_special, $exclude_stages, $filename, $modulename);
	}

	/*
	 * Tells a template has paging or not.
	 *
	 * @param string $filename
	 *		The file part of a template file such as 'ubd', 'pyp', 'myp', 'ubd' etc.
	 *
	 * @return bool
	 */
	function ispaging($filename) {
		if ( array_key_exists($filename, $this->data_obj->template_paging_array) )
			return $this->data_obj->template_paging_array[$filename];
		return FALSE;
	}

	/*
	 * Finds an array of module names each containing an array of types according to the template file part.
	 *
	 * @param string $filename
	 * 	The file part of a template file such as 'ubd', 'pyp', 'myp', 'ubd' etc.
	 *
	 * @return array|bool
	 * 	Returns a 2D array or FALSE if no data was found.
	 */
	function filename_modules($filename) {
		if ( array_key_exists($filename, $this->data_obj->template_module_array) )
			return $this->data_obj->template_module_array[$filename];
		return FALSE;
	}

	/*
	 * Finds an array of stage numbers each containing an array of types.
	 *
	 * @param string $filename
	 * 	The file part of a template file such as 'ubd', 'pyp', 'myp', 'ubd' etc.
	 * @param int $stage
	 * 	The stage number.
	 *
	 * @return array|bool
	 * 	Returns a 2D array or FALSE if no data was found. If stage is specified then it returns an array of types.
	 */
	function filename_stagetypes($filename, $stage=FALSE) {
		if ( array_key_exists($filename, $this->data_obj->template_stage_array) ) {
			$ret = $this->data_obj->template_stage_array[$filename];
			if ( osa_is_int_one($stage) ) {
				if ( array_key_exists($stage, $ret) && osa_is_int_one_array($ret[$stage]) ) {
					return $ret[$stage];
					//return osa_getarrayvalue($ret[$stage]);
				}
			}
			return $ret;
		}
		return FALSE;
	}
/*
	//Get all types other than types in stage 1. Types are separated by commas
	//This is for integrated unit
	//Returns comma separated types
	function filename_nonstage1_types($filename) {
		if ( array_key_exists($filename, $this->data_obj->template_stage_array) ) {
			$stages = $this->data_obj->template_stage_array[$filename];
			$stagenum = count($stages);
			if ( $stagenum > 1 ) {
				$tmp_array = array();
				for ($i=2; $i<= $stagenum; $i++ ) {
					$tmp_array = array_merge($tmp_array, $stages[$i]);
				}
				sort($tmp_array);
				return implode(',',$tmp_array);
			}
		}
		return FALSE;
	}
*/
	//Returns the file part like, ubd, myp, pyp, sbd etc.
	//TODO: This is unsafe since ubd, pyp and myp share identical types
	//Checked all the code that uses this function and they are OK.
	//DO NOT USE THIS FUNCTION in new code unitl we can come up with a solution.
	function type_filename($type) {
		$ret = $this->type_reference($type, 'file_part');
		if ( !$ret && isset($this->data_obj->meta_types[$type]['file_part_hash'] ) ) {
			return $this->data_obj->meta_types[$type]['file_part'];
		}
		return $ret;
	}

	//Like type_filename() but returns the file_part's 39 digit integer hash value based on md5()
	//Also looks at the meta_types array if type_reference() fails
	//TODO: This is unsafe since ubd, pyp and myp share identical types
	function type_filename_hash($type) {
		$ret = $this->type_reference($type, 'file_part_hash');
		if ( !$ret && isset($this->data_obj->meta_types[$type]['file_part_hash'] ) ) {
			return $this->data_obj->meta_types[$type]['file_part_hash'];
		}
		return $ret;
	}

	//Retruns the stage number
	//TODO: This is unsafe since ubd, pyp and myp share identical types
	//This is not used in any code yet so commented it out
	/*
	function type_stage($type) {
		return $this->type_reference($type, 'stage');
	}
	*/

	//Returns the template identifier like goal, unit or survey
	//TODO: This is unsafe since ubd, pyp and myp share identical types.
	//		  This is actually fine as long as the types are not shared across template folders
	//		  like unit, goal, survey etc. If you have type 10 in unit then you can not have type 10 in goal or survey
	function type_templateid($type) {
		return $this->type_reference($type, 'template_id');
	}

	//Gets the templateid (unit, goal, survey, system) by filename part
	function filename_templateid($filename) {
		$types = $this->filename_stagetypes($filename);
		if ( !$types ) {
			return FALSE;
		}
		foreach ($types as $types_array) {
			if ( is_array($types_array) ) {
				foreach($types_array as $type) {
					if ( $type ) {
						return $this->type_templateid($type);
					}
				}
			}
		}
		return FALSE;
	}

	//Retunrs the file hash for the given filepart (ubd, myp, pyp etc.)
	//Mainly used for btnsort
	function filehash_filepart($filepart) {
		if ( isset($this->data_obj->file_part_hash[$filepart]) ) {
			return $this->data_obj->file_part_hash[$filepart];
		}
		return FALSE;
	}

	//Get the the array containing type values of static types
	//$file_part is like ubd pyp
	function static_types($file_part) {
		$ret = array();
		if ( $this->data_obj->static_types ) {
			foreach($this->data_obj->static_types as $key => $value) {
				if ( $value['file_part'] == $file_part ) {
					$ret[] = $key;
				}
			}
		}
		return $ret;
	}

	function is_static($type) {
		return isset($this->data_obj->static_types[$type]);
	}

	//The input $type_list is a string of types separated by $sep
	//Delete any static type from $type_list. This will compare all static types from
	//all unit templates and not just a single one like ubd. Returns a new string less any static types.
	function clear_static_types($type_list, $sep=',') {
		if ( !$type_list ) {
			return '';
		}
		if ( !$this->data_obj->static_types ) {
			return $type_list;
		}
		$ret = '';
		$array = explode($sep, $type_list);
		if ( $array && $this->data_obj->static_types ) {
			$sep_loop = '';
			$static_types = $this->data_obj->static_types;
			foreach ($array as $value) {
				if (!isset($static_types[$value])) {
					$ret .= "{$sep_loop}{$value}";
					$sep_loop = $sep;
				}
			}
		}
		return $ret;
	}

	//Duplicated data for a single type - only data from the first array is returned
	private function type_reference($type, $index) {
		if ( !array_key_exists($type, $this->data_obj->type_reference_array) ||
				!array_key_exists($index, $this->data_obj->type_reference_array[$type][0]) ) {
			//Can't find the type so try searching the data structure with hidden types
			return $this->type_type_reference_hidden($type, $index);
		}
		return $this->data_obj->type_reference_array[$type][0][$index];
	}

	//Get all the template filename/filepart (ubd, pyp etc.) for the supplied templateid (unit, goal etc.)
	public function templateid_filenames($templateid) {
		$top_array = & $this->data_obj->template_all_levels_hashidden;
		foreach ($top_array as $template_id => $template_id_array) {
			if ( $template_id == $templateid ) {
				$ret = array();
				foreach ($template_id_array as $file_part => $file_part_array) {
					$ret[] = $file_part;
				}
				if ( count($ret) > 0 )
					return $ret;
				return FALSE;
			}
		}
		return FALSE;
	}

	//This behaves just like type_reference but also searches hidden types
	private function type_type_reference_hidden($type, $index) {
		$top_array = & $this->data_obj->template_all_levels_hashidden;
		foreach ($top_array as $template_id => $template_id_array) {
			foreach ($template_id_array as $file_part => $file_part_array) {
				foreach ($file_part_array as $stage => $stage_array ) {
					foreach ($stage_array as $module => $module_array) {
						if ( in_array($type, $module_array)) {
							$ret = FALSE;
							//Because we name the keys same as the index - file_part, stage, template_id
							//eval("\$ret=$$index;");
							$ret=$$index;
							return $ret;
						}
					}
				}
			}
		}
		return FALSE;
	}
}