<?php
/**
 * Unitmain.php
 *
 * The main library to hanlde all the unit/template page features.
 * This is the core of the whole template system so becareful what you change here.
 *
 * DO NOT MODIFY THE CODE IN THIS FILE UNLESS YOU HAVE PERMISSON FROM YOU KNOW WHO.
 *
 * @author $Author: dtong $
 * @version $Id: Unitmain.php,v 1.83 2011/05/26 07:12:22 dtong Exp $
 * @copyright Copyright (c) 2009, Tiller Software Co., Ltd.
 */

if ( ! defined('BASEPATH')) exit('No direct script access allowed');
require_once('configfactory.php');
require_once('unit_resource.php');
require_once('unit_title.php');
require_once('unit_select.php');
require_once('unit_lt.php');
require_once('unit_itstd.php');
require_once('unit_last.php');
require_once('unit_os.php');

//Simple class to keep track of variables. This object gets passed to all modules.
class template_module_params {
	//The course id. (This is usually zero or any number for non-unit features like goal, survey, system stuff)
	//We should assign different number to the non-unit templates to spread the index in the DB.
	//The type will differentiate the actual courseid so there is no conflict
	public $courseid = FALSE;
	//The id in the unit table. (goalid for goal, survey id for survey, can be zero or any number for system resources)
	public $unitid = FALSE;
	//The current stage number
	public $stagenum  = FALSE;
	//The divid for refresh. This is usually based on the satge number.
	public $divid = FALSE;
	//Template action
	public $action = FALSE;
	//The file part like ubd pyp
	public $unit_template = FALSE;
	//The actual large template object form the factory
	public $template_object = NULL;
	//For compare feature
	public $use_cssid = FALSE;
	//Resource id, gets reassign whenever unit_buttons is called.
	public $resid = FALSE;
	//Used by related delete and edit controllers
	public $type = FALSE;

	function __set($var, $value) {
		echo __METHOD__ . " - You are not allowed to set undeclared class property '$var', bye bye.";
		exit;
	}
}
/*
 * Main library for the template engine. This started as unit-only template engine but it grew to support
 * all other templates in the system due to the fact it was originally designed to be fully encapsulated
 * and it would work with any templates with very minimal code changes. OOP...
 *
 * It will take too much effort to fully make this generic and we are leaving it like this for now.
 * So, all the code in unt library are not just for unit templates, they are for all templates.
 * Yeah, I don't like it but...
 */
class Unitmain {
	private $config=NULL;
	//The return generated html
	private $html='';
	private $CI=NULL;
	//Read and edit for now
	private $action = CMS_ACTION_READ;
	private $current_page=1;
	//Filename of the template without .php
	private $unit_template=FALSE;
	//The original $data passed to the constructor
	private $original_data_input=FALSE;
	//For PDF to skip page handle check
	private $skip_stage_page_check = FALSE;
	//private $has_full_security = FALSE;
	private $use_cssid = FALSE;
	//TODO: There is some logic involved in the divid, have to look and cleanup later.
	private $divid=FALSE;
	private $courseid=FALSE;
	private $unitid=FALSE;
	//Unit parent id for integrated, shared
	private $parentid=FALSE;
	//The page array from the template or suto generated if there isn't one
	private $page=FALSE;
	//The unit type like normal, shared etc.
	private $unittype=CMS_UNIT_TYPE_NORMAL;

	/////////////////////////////////////////////////
	//These are the initial template module objects. All newer modules are done thru dynamic loading plugins now.
	//All the objects here will need to be initiated by the init_template_object function before use
	private $resource=NULL;
	private $title=NULL;
	private $select=NULL;
	private $ltobj=NULL;
	private $itstdobj=NULL;
	private $lastobj=NULL;
	private $osobj=NULL;
	////////////////////////////////////////////////

	//DO NOT ADD MORE TO THIS VAR LIST.
	//The valid index names in the $data parameter to the constructor.
	//If supplying anything other than this list the object will stop running
	private $valid_vars =
		array('unitid', 'action', 'courseid', 'unit_template', 'current_page',
				'divid', 'unittype', 'parentid', 'use_cssid');
	/*
		$data should contain courseid, unitid, action, unit_template(optional and without .php)

		Currently used params in $data:
			unitid, action, courseid, unit_template, current_page,
			divid, unittype, parentid

		Some of the params were added after the implementation and they are making the interface very messy.
		So, ***** PLEASE DO NOT ADD MORE PARAMS TO MAKE IT EVEN MORE MESSY! *****

		TODO: Clean up this mess described above.
				- Cleaned most of the unnecessary variables but still need to double check.
	 */
	function __construct($data) {
		if ( !is_array($data) || count($data) <= 0 ) {
			return FALSE;
		}
		foreach($data as $key => $value) {
			if ( !in_array($key, $this->valid_vars) ) {
				//This will be shown during development time.
				echo __METHOD__ . " - Invalid parameter input '$key', aborted.";
				exit;
			}
		}
		osa_load_lang('template');
		$this->CI = & get_instance();
		$this->CI->load->library('cms/cms_template/cms_template');
		$this->original_data_input = & $data;

		if ( !is_array($data) ) {
			log_message('error', __METHOD__ . ' - Input parameter $data is not an array.');
			return osa_buildererror();
		}
		if ( !array_key_exists('unitid', $data) || !is_numeric($data['unitid']) ) {
			log_message('error', __METHOD__ . ' - Unitid is missing or not a number.');
			return osa_buildererror();
		}
		if ( !array_key_exists('action', $data) ) {
			log_message('error', __METHOD__ . ' - Action is missing.');
			return osa_buildererror();
		}
		if ( !array_key_exists('courseid', $data) || !is_numeric($data['courseid']) ) {
			log_message('error', __METHOD__ . ' - Courseid is missing or not a number.');
			return osa_buildererror();
		}
		$this->courseid = $data['courseid'];
		$this->unitid = $data['unitid'];
		$this->action = $data['action'];
		if (isset($data['current_page']) && osa_is_int($data['current_page']) && $data['current_page'] > 0) {
			$this->current_page = $data['current_page'];
		}
		$this->divid = 'page_content';
		if (isset($data['divid']) && $data['divid'] != FALSE) {
			$this->divid = $data['divid'];
		}

		////////////////// Load the template object
		$template = '';
		$file_part = '';
		if(!empty($data['unit_template'])){
			$file_part = $data['unit_template'];
			//Usually non-unit templates like goal and survey
			$system_templates = $this->CI->cms_template->templateid_filenames(CMS_TEMPLATE_SYSTEM_IDENTIFIER);
			if ( in_array($data['unit_template'], $system_templates)) {
				//Handle system templates differently
				$template = CMS_TEMPLATE_SYSTEM_IDENTIFIER . '_' . $data['unit_template'];
			}
			else {
				$template =  $this->CI->config->item('cms_unit_org').'_'. $data['unit_template'];
			}
		}
		else {
			//try to get the unit_template if it was not supplied
			//you can still supply the unit_template form the various objects to save one extra query
			$this->CI->load->model('unit/unit_model');
			$unitobj = $this->CI->unit_model->get_unit_any($this->unitid);
			if ( $unitobj != FALSE ) {
				$template_ext = $unitobj->template;
				if ( !empty($template_ext) ) {
					$template =  $this->CI->config->item('cms_unit_org').'_'.$template_ext;
					$file_part = $template_ext;
				}
			}
		}
		$folder_hint = $this->CI->cms_template->filename_templateid($file_part);
		$this->config = configfactory::factory($template, $folder_hint);
		if ( $this->config == FALSE ) {
			osa_errorlog(__METHOD__ . ' - Failed to get template configuration.', $data);
			//echo osa_ajaxmsg(lang('gen_internalservererror'));
			echo osa_ajaxmsg(sprintf(lang('template_missing_template_error_msg'), $template));
			exit;
		}
		//Just assign again since this is the ture template partial file name like ubd pyp etc. set from the factory
		$this->unit_template = $this->config->template_file_part;
		///////////////////////////
/*
		if(isset($data['completedate'])){
			$this->completedate = $data['completedate'];
		}
*/
/*
		if (isset($data['goalid']))
			$this->goalid = $data['goalid'];
*/
		if(isset($data['use_cssid'])) {
			$this->use_cssid = $data['use_cssid'];
		}
		if ( array_key_exists('parentid', $data) ) {
			$this->parentid = $data['parentid'];
		}
		if ( isset($this->config->page) && is_array($this->config->page) && count($this->config->page) > 0 ) {
			$this->page = $this->config->page;
		}

		if ( array_key_exists('unittype', $data) ) {
			$this->unittype = $data['unittype'];
		}
		else {
			//Defaults to normal if not supplied
			$this->unittype = CMS_UNIT_TYPE_NORMAL;
		}

		$this->CI->load->library('cms/cms_security');
		$this->CI->cms_security->init($this->action, $this->unit_template, $this->unitid, $this->courseid);
	}

	//This is a major system class so protect it from lazy coders...
	function __set($var, $value) {
		echo __METHOD__ . " - You are not allowed to set undeclared class property '$var', bye bye.";
		exit;
	}

	//Prints the paging numbers
	//Calling this function will make render() to handle paging with the stages.
	//Else, all stages will be displayed in render()
	//$page_urls should contain a url, FALSE uses the default unit url
	function render_page($unitid, $current_page, $page_url=FALSE) {
		if ( !$this->CI->cms_template->ispaging($this->unit_template) ) {
			//Return empty string if template has no paging
			return '';
		}
		$html_page = '';
		$count_page = count($this->config->page);
		if ( empty($current_page) || !osa_is_int($current_page) || $current_page < 0 || $current_page > $count_page ) {
			$current_page = 1;
		}
		$html_page = '<div class="paging_column">';
		$url_template = base_url(). 'unit/unit/index_template/';
		if ($this->divid != 'page_content') {
			$url_template = base_url(). 'unit/unit/index_paging/';
		}
		if ($this->action == CMS_ACTION_EDIT) {
			$url_template = base_url(). 'unit/unit/edit/';
		}
		//This is necessary to support non-unit templates like goal
		if ( $page_url ) {
			$url_template = base_url() . $page_url;
		}

		$html_page .= lang('gen_template_page_title') . ' ';
		$this->CI->load->library('unit/paging/paging_handle_main');
		for ($i=1; $i<=$count_page; $i++) {
			$current_number_no_link = " <span class=\"pagingnormal\">{$i}</span> ";
			$url = $url_template.$unitid.'/'.$i;
			if ($i == $current_page){
				$html_page .= $current_number_no_link;
			}
			if ($i != $current_page){
				//Check to see does the user has permission to see the page
				if ( ($retcode = $this->CI->paging_handle_main->run($i, $this->config, $this->original_data_input)) === FALSE ) {
					//No permission just print the plain page number
					//TODO: This only disables the page number click but accessing the page link URL directly will
					//still bring up the page. Have to make render() and/or render_stage() to check page handle too
					$html_page .= " <font color='grey'>$i</font> ";
				}
				elseif ( $retcode !== TRUE ) {
					//Return code contains error message
					$html_page .= " $i " . $retcode;
				}
				else {
					//return code is TRUE and go ahead print clickable page number
					$onclick = " onclick=\"ajaxGetpage('$this->divid','$url',false); ";
					if ($this->divid != 'page_content') {
						$onclick = " onclick=\"updateWindow('$url','form_ro_unit','','$this->divid'); ";
					}
					$html_page .= " <a href=\"$url\" class=\"paginglink\" {$onclick} return false;\">$i</a> ";
				}
			}

		}
		$html_page .= '</div>';
		return $html_page;
	}

	//Main function that renders the whole template or a page in the template
	function render($meta_flag=FALSE) {
		global $g_pdf_mode;

		//Runs the code first time to check full edit access to the current template Later calls will just return the result form this call
		$this->CI->cms_security->has_full_security($this->action);

		$this->html = '';
		if ( !$this->config ) {
			return '';
		}
		$config = $this->config;
		$stage_order = array();
		if ( isset($config->stage_order) && is_array($config->stage_order) && count($config->stage_order) > 0 ) {
			//We can actually use stage order to skip stages if we want but it should be most likely done
			//by stage pre_processing handle
			$stage_order = $config->stage_order;
		}
		else {
			for ( $i=1; $i<=$config->stage_num; $i++) {
				$stage_order[] = $i;
			}
		}
		//(issue: 177)
		if ( isset($g_pdf_mode) && $g_pdf_mode === TRUE ) {
			$this->skip_stage_page_check = TRUE;
		}
		//Added support for stage order
		//for ( $i=1; $i<=$config->stage_num; $i++) {
		foreach ( $stage_order as $stage_number ) {
			//Special meta unit only contains the first stage
			if ($meta_flag && $stage_number != 1) {
				//This used to be a break but since we made the change that the first stage
				//in the loop doesn't have to stage 1 then we had to continue instead.
				//Note, meta units can't have admin notes
				continue;
			}
			//Check page permission where the stage belongs to
			if ( !$this->check_stage_page_permission($stage_number) ) {
				continue;
			}
			$stage = @$config->stage[$stage_number];
			if ( !is_array($stage) ) {
				continue;
			}
			$stagediv = "stage{$stage_number}_div";
			$this->html .= "<div id=\"{$stagediv}\">";

			/*$TYPE_INT = FALSE;
			$TYPE_UNI = FALSE;
			if (isset($this->CI) && isset($this->CI->unit_model->TYPE_INT)) {
				$TYPE_INT = $this->CI->unit_model->TYPE_INT;
			}
			if (isset($this->CI) && isset($this->CI->unit_model->TYPE_UNI) ) {
				$TYPE_UNI = $this->CI->unit_model->TYPE_UNI;
			}*/

			$TYPE_INT = CMS_UNIT_TYPE_INTEGRATED_CHILD;
			$TYPE_UNI = CMS_UNIT_TYPE_UNIFIED_CHILD;

			//Prepare int. and shared children
			if  (osa_is_int_one($this->parentid) &&
				 ( $this->unittype==$TYPE_INT || $this->unittype==$TYPE_UNI) ) {
				if ($this->unittype==$TYPE_INT) {
					// Integrated child units show stage 1 from parent, and stage 2-3 can edit
					if ($stage_number==1) { // 1 is stage 1
						$params = $this->get_params($stage_number);
						$params->action =CMS_ACTION_READ;
						$params->unitid = $this->parentid;
						//$this->do_stage_noparams($stage, $i, $params, $meta_flag);
						$this->do_stage($stage, $stage_number, $meta_flag, $params);
					}
					else {
						//Stages other than 1 are just like a normal unit.
						$this->do_stage($stage, $stage_number, $meta_flag);
					}
				}
				elseif ($this->unittype==$TYPE_UNI) {
					// Shared units show stage 1-2-3 from parent and none can be edited.
					$params = $this->get_params($stage_number);
					$params->action =CMS_ACTION_READ;
					$params->unitid = $this->parentid;
					//$this->do_stage_noparams($stage, $i, $params, $meta_flag);
					$this->do_stage($stage, $stage_number, $meta_flag, $params);
				}
			}
			else {
				//This is normal units or parent int./shared units.
				$this->do_stage($stage, $stage_number, $meta_flag);
			}
			$this->html .= '</div>';
		}//for

		//Saves the security session, whatever function uses do_stage() has to call this
		$this->CI->cms_security->save();
		return $this->html;
	}

	//Renders a single stage, usually resulted from a ajax update, we can assume the whole template was rendered before this
	function render_stage($stagenum, $meta_flag=FALSE) {
		if ( !osa_is_int($stagenum) || empty($this->config) || !isset($this->config->stage[$stagenum]) ) {
			return '';
		}
		//Set the stahe hint so prefetch routines can get the proper types
		$this->CI->load->library('cms/cms_prefetch');
		$this->CI->cms_prefetch->set_stage_hint($stagenum);
		$this->html = '';
		if ( array_key_exists($stagenum,$this->config->stage) ) {
			if ( $this->CI->cms_template->ispaging($this->unit_template) ) {
				//Need to set page number here else do_stage() will not continue
				$page_number = FALSE;
				foreach ($this->page as $index => $page_array) {
					if ( in_array($stagenum, $page_array) ) {
						$page_number = $index;
						break;
					}
				}
				if ( $page_number === FALSE ) {
					//Can't find the page number for the stage
					return '';
				}
				$this->current_page = $page_number;
			}
			//This will populate $this->html
			$this->do_stage($this->config->stage[$stagenum], $stagenum, $meta_flag);
		}

		//Saves the security session, whatever function uses do_stage() has to call this
		$this->CI->cms_security->save();
		return $this->html;
	}

	/*
	 * Should have just return the template array data instead of copying all variables
	 * Later template types such as select and learning target use the template array directly
	 */
	function resource_popup_data($type, $unitid) {
		if ( !$this->config ) {
			return FALSE;
		}
		$this->init_template_object('resource');
		if ( !$this->init_obj($type, $unitid, $this->resource) ) {
			return FALSE;
		}
		return $this->resource->popup_data();
	}

	function get_resourceobj($type, $unitid) {
		if ( !$this->config ) {
			return FALSE;
		}
		$this->init_template_object('resource');
		if ( !$this->init_obj($type, $unitid, $this->resource) )
			return FALSE;
		return $this->resource;
	}

	function get_select_obj($type, $unitid) {
		if ( !$this->config ) {
			return FALSE;
		}
		$this->init_template_object('select');
		if ( !$this->init_obj($type, $unitid, $this->select) )
			return FALSE;
		return $this->select;
	}

	//Gets the LT edit data array, this is for the LT add/edit page link
	function get_lt_edittemplate() {
		$type = FALSE;
		//The LT edit data should be hardcoded with {LT_TYPE_NUMBER}_edit
		if ( isset($this->config->lt_type) ) {
			$type = $this->config->lt_type . '_edit';
		}
		else {
			$lt_data = $this->find_data_by_module_type('lt');
			if ( $lt_data && isset($lt_data['_typeid']) ) {
				$type = $lt_data['_typeid'] . '_edit';
			}
		}
		$ret = $this->find_type_data($type);
		return $ret;
	}

	/*
	 * Learning Target data type
	 */
	function get_lt_obj($type, $unitid) {
		if ( !$this->config ) {
			return FALSE;
		}
		$this->init_template_object('ltobj', 'unit_lt');
		if ( !$this->init_obj($type, $unitid, $this->ltobj) ) {
			return FALSE;
		}
		return $this->ltobj;
	}

	/*
	 * It Standard data type
	 */
	function get_itstd_obj($type, $unitid) {
		if ( !$this->config ) {
			return FALSE;
		}
		$this->init_template_object('itstdobj', 'unit_itstd');
		if ( !$this->init_obj($type, $unitid, $this->itstdobj) )
		return FALSE;
		return $this->itstdobj;
	}

	/*
	 *  Initialize the various template objects based on the template data
	 *  The unit_base class contains a rest function for this purpose
	 */
	private function init_obj($type, $unitid, $obj) {
		if ( !($data = $this->find_type_data($type)) ) {
			return FALSE;
		}
		if ( !($stagenum = $this->find_stage($type)) ) {
			return FALSE;
		}
		$params = $this->get_params($stagenum);
		$params->type = $type;
		$obj->reset($data, $params);
		return TRUE;
	}

	function get_os_edittemplate() {
		$type = FALSE;
		//The LT edit data should be hardcoded with {OS_TYPE_NUMBER}_edit
		if ( isset($this->config->os_type) ) {
			$type = $this->config->os_type . '_edit';
		}
		else {
			$lt_data = $this->find_data_by_module_type('os');
			if ( $lt_data && isset($lt_data['_typeid']) ) {
				$type = $lt_data['_typeid'] . '_edit';
			}
		}
		$ret = $this->find_type_data($type);
		return $ret;
	}

	/*
	 * Outcome Skill data type
	 */
	function get_os_obj($type, $unitid) {
		if ( !$this->config ) {
			return FALSE;
		}
		$this->init_template_object('osobj', 'unit_os');
		if ( !$this->init_obj($type, $unitid, $this->osobj) ) {
			return FALSE;
		}
		return $this->osobj;
	}

	/*
	 * There should be only 2 places that sets the stage div names.
	 * Here and in the function render above. Should always get the stage "divid" from params
	 */
	private function get_params($stagenum) {
		$params = new template_module_params();
		$params->courseid = $this->courseid;
		$params->unitid = $this->unitid;
		$params->stagenum = $stagenum;
		$params->use_cssid = $this->use_cssid;
		$params->action = $this->action;

		if ( $stagenum != 'extra' ) {
			$params->divid = "stage{$stagenum}_div";
		}
		else {
			$params->divid = '';
		}
		if (isset($this->unit_template)) {
			$params->unit_template = $this->unit_template;
		}
		//Added the template array so all the objects can get access to the template
		if ( !empty($this->config) ) {
			$params->template_object = $this->config;
		}
		return $params;
	}

	/*
	 * Finds the stage number based on the data type. This means each data type has to be unique
	 * Yes, it would be a problem if you want to put the same data type on 2 different locations, but
	 * why would anyone wants to do that?
	 */
	private function find_stage($type) {
		$config = & $this->config;
		for ( $i=1; $i<=$config->stage_num; $i++) {
			$stage = @$config->stage[$i];
			if ( !is_array($stage) )
			continue;
			if ( array_key_exists($type, $stage) )
			return $i;
			//return $stage[$type];
		}
		if ( array_key_exists($type, $config->extra) )
		return "extra";
		return FALSE;
	}

	/*
	 * Gets the array data for this type from the template
	 */
	private function find_type_data($type) {
		if ( empty($type) ) {
			return FALSE;
		}
		$config = $this->config;
		$stagenum = $config->stage_num + 1;
		//Easier to search by just adding extra to stages
		$config->stage[$stagenum] = $config->extra;
		for ( $i=1; $i<=$stagenum; $i++) {
			$stage = @$config->stage[$i];
			if ( !is_array($stage) )
				continue;
			if ( array_key_exists($type, $stage) )
				return $stage[$type];
		}
		return FALSE;
	}

	private function do_stage($stage, $stagenum, $meta_flag=FALSE, $params=FALSE) {
		if ( !$params ) {
			$params = $this->get_params($stagenum);
		}

		//TODO: Should this rely on the page number from outside of Unitmain or get the page number from stagenum???
		//Logic looks like it is external page number dependent and outside routines have to make sure to pass in the proper page number
		$page_number = $this->current_page;
		//This stops when it reaches a stage belonging to the next page or end of the page/template
		/* if ($page_number <= count($this->page) &&  !in_array($stagenum, $this->page[$page_number])) {
			return;
			} */
		//(issue: 177)
		if ( !$this->skip_stage_page_check && $this->CI->cms_template->ispaging($this->unit_template) &&
		( isset($this->page[$page_number]) && !in_array($stagenum, $this->page[$page_number])) ) {
			return;
		}

		//Check stage against page permission and stop rendering if the stage belongs to a page
		//that should not be shown.
		if ( !$this->check_stage_page_permission($stagenum) ) {
			return;
		}
		//Invoke a stage preprocess handle if there is one and see should we render this stage or not
		if ( !$this->stage_preprocess($stage, $stagenum, $meta_flag, $params) ) {
			return;
		}

		//Event handle can change the action so save it here
		//$orig_action = $params->action;
		$this->CI->load->library('unit/event/event_handle_main');

		//Lt's save the original params so we can refresh in every loop
		$orig_template_obj = $params->template_object;
		//Make sure we don't clone the large template object from the factory
		$params->template_object = NULL;
		$orig_params = clone $params;
		//Assign the object back.
		$params->template_object = &$orig_template_obj;

		//This is the absolute core of the template engine!
		//Loops thru each array element for a particulr stage
		foreach ($stage as $data) {
			$type = osa_value($data, '_type', FALSE);
			$flag = osa_value($data, '_meta_nodisplay_flag', FALSE);
			// For meta units to skip it standard
			if ( $flag === TRUE && $meta_flag === TRUE ) {
				continue;
			}

			//Is this the right type (read and edit)
			if ( ! $this->checkaction($data) ) {
				continue;
			}

			//Check read,write access for each template object
			//The buttons are different, they have to be checked inside unit_buttons.php
			//If there is no access for a object then it will continue/skip to the next one even before the switch below
			if ( !$this->CI->event_handle_main->run($data, $params) ) {
				$this->html .= $this->CI->event_handle_main->html_error_msg;
				continue;
			}
			$this->html .= $this->CI->event_handle_main->html_error_msg;

			if ( !$this->CI->cms_security->has_full_security($params->action) ) {
				//Only save security settings when user does not have full access and it is edit action
				//Note: event handle can change from read sction to edit action for a particular resource or type
				//to a user with no full access therefore this code has to fall behind event handle processing
				if ( ($typeid = osa_value($data, '_typeid', FALSE)) !== FALSE ) {
					//This allows the current user to get write access for all resources
					//belonging to this courseid, unitid/goalid/surveyid and template type
					//All non-unit templates relies on this for security control.
					$this->CI->cms_security->add($params->action, $typeid);
				}
			}

			switch ($type) {
				case 'nothing':
				case 'pre_process':
					break;
				case 'title': //Regular title for stages
				case 'title_big_wb': //Bigger title for stages and with border
				case 'subtitle':
					$this->init_template_object('title');
					$this->title->color_track_reset(); //This resets all the classes based on unit_base class
					$this->html .= $this->title->render($data, $params);
					break;
				case 'linkunit':
				case 'resource':
					$this->init_template_object('resource');
					$this->html .= $this->resource->render($data, $params);
					break;
				case 'select':
					$this->init_template_object('select');
					$this->html .= $this->select->render($data, $params);
					break;
				case 'std_bench':
					$this->init_template_object('ltobj', 'unit_lt');
					$this->html .= $this->ltobj->render($data, $params);
					break;
				case 'lt_list':
					$this->init_template_object('ltobj', 'unit_lt');
					$this->html .= $this->ltobj->render_lt($data, $params);
					break;
				case 'itstd':
					$this->init_template_object('itstdobj', 'unit_itstd');
					$this->html .= $this->itstdobj->render($data, $params);
					break;
				case 'last':
					$this->init_template_object('lastobj', 'unit_last');
					$this->html .= $this->lastobj->render($data, $params);
					break;
				case 'os':
					$this->init_template_object('osobj', 'unit_os');
					$this->html .= $this->osobj->render($data, $params);
					break;
				case 'newline':
					$size = $type = osa_value($data, '_px', FALSE);
					if ( $size === FALSE ) {
						$size=0;
					}
					$this->html .= "<div style='margin-top:{$size}px; border-bottom:solid 1px black;'></div>";
					break;
				case 'html_text':
					if ( ($text = osa_value($data, '_text', FALSE)) !== FALSE )
					$this->html .= $text;
					break;
				default:
					//Try to load and run a unit proess object. All newer module implementations are done this way.
					//This is a flexible way to extend the template engine.
					$this->html .= $this->unit_process_handle($type, $data,$params );
			} //switch

			//if an event handle changed the action then change it back here
			//so the next template module would get the proper action
			//if ( $orig_action != $params->action )
				//$params->action = $orig_action;

			//These are the only ones need to be refresh so far.
			$params->action = $orig_params->action;
			$params->courseid = $orig_params->courseid;
			$params->unitid = $orig_params->unitid;
			$params->resid = $orig_params->resid; //This is always false
			$params->use_cssid = $orig_params->use_cssid;
		}//foreach
	}

	//This function is used to only initiate the necessary template objects
	private function init_template_object($var, $class=FALSE) {
		if ( !isset($this->$var) || empty($this->$var) ) {
			if ( !$class ) {
			$class = 'unit_' . $var;
			}
			$this->$var = new $class;
			$this->$var->set_unitmain($this);
		}
	}

	private function checkaction($data) {
		//if no action in array then it means all actions, changed this to no
		if ( !array_key_exists('_action', $data) ) {
			return FALSE;
		}
		$action = $data['_action'];
		//if ( $action == $this->action )
		return osa_valid_action($action, $this->action);
	}

	//hard code for IT Standard fix resource type from IT_STANDARDS_TYPE(8)to(12)IT_STANDARDS_UPLOAD_TYPE
	function get_itstd_resourcetype() {
		return CMS_ITSTANDARDS_RESOURCE_TYPE;
	}

	//Runs any stage preprocess routines, returns true to show the stage, false to hide the stage
	private function stage_preprocess(&$stage, $stagenum, $meta_flag, $params) {
		if (!array_key_exists('pre_process', $stage)) {
			return TRUE;
		}
		$handle_array = $stage['pre_process'];
		$result = TRUE;
		foreach ( $handle_array as $handle) {
			$class = 'pph_' . $handle;
			if (@include_once('pph/' . $class . '.php')) {
				$object = new $class;
				//Decided not to use object cache becuase stage preprocess normally are invoked not more than once.
				//$object = $this->get_cache_object($class);

				//If any one handle is false in the loop then the return will be false
				//Note, even if a handle returns false, the next handle if there is one will still be executed
				if ( !$object->process($stage, $stagenum, $meta_flag, $params) ) {
					$result = FALSE;
				}
			}
			else {
				osa_errorlog(__METHOD__ . " - PPH handle $handle is not valid", $stage);
				$this->html .= osa_buildererror();
			}
		}
		return $result;
	}

	//This is where the dynamic object loading happens for handling a specific template object type.
	private function unit_process_handle($type, $data, $params) {
		$class = 'uph_' . $type;
		$html = '';
		if (@include_once('uph/' . $class . '.php')) {
			//$object = new $class;
			$object = $this->CI->cms_cache->object_get($class);
			if ( !empty($object) ) {
				$object->set_unitmain($this);
				$html = $object->render($data, $params);
			}
			else {
				osa_errorlog(__METHOD__ . " - Invalid class name $class");
				$html = osa_buildererror();
			}
		}
		else{
			osa_errorlog(__METHOD__ . " - Invalid type '{$type}'", $data);
			$html = osa_buildererror();
		}
		return $html;
	}

	function get_template() {
		if ( empty($this->config) ) {
			return FALSE;
		}
		return $this->config;
	}

	function get_template_filepart() {
		return $this->unit_template;
	}

	//Check is the user have page permission for the partcular stage
	private function check_stage_page_permission($stage_index) {
		if ( !isset($this->config->stage[$stage_index]) ) {
			//We don't even have this stage so say no
			return FALSE;
		}
		//if ( !isset($this->config->page) || !is_array($this->config->page) ) {
		if ( !$this->CI->cms_template->ispaging($this->unit_template) ) {
			//Looks like no paging so say yes
			return TRUE;
		}
		$found_stage_in_page = FALSE;
		//Check is the stage number in the page array
		foreach($this->config->page as $page_index=>$stages) {
			if ( !is_array($stages) ) {
				continue;
			}
			if (in_array($stage_index, $stages)) {
				$found_stage_in_page = TRUE;
				break;
			}
		}
		if ( !$found_stage_in_page ) {
			//Can't find the stage anywhere in the page array
			return FALSE;
		}
		$this->CI->load->library('unit/paging/paging_handle_main');
		$retcode = $this->CI->paging_handle_main->run($page_index, $this->config, $this->original_data_input);
		if ( $retcode !== TRUE ) {
			//return code can be a string and indicates an error so return FALSE here
			return FALSE;
		}
		return TRUE;
	}

	//This finds the data array by mudule type. Stops on the first match.
	//This is only useful for a unqiue module type in a single templates
	//$module_type can be 'lt', 'os', resources etc.
	private function find_data_by_module_type($module_type) {
		foreach($this->config->extra as $value) {
			if ( isset($value['_type']) ) {
				if ( $module_type == $value['_type'] ) {
					return $value;
				}
			}
		}
		foreach($this->config->stage as $stages) {
			foreach($stages as $value) {
				if ( isset($value['_type']) ) {
					if ( $module_type == $value['_type'] ) {
						return $value;
					}
				}
			}
		}
		return FALSE;
	}
}
