<?php
/**
 * FILE_NAME_HERE - FILE_DESCRIPTION_HERE
 *
 * @author $Author: dtong $
 * @version $Id: unit_model.php,v 1.92 2011/06/08 09:46:34 dtong Exp $
 * @copyright Copyright (c) 2009, Tiller Software Co., Ltd.
*/

class Unit_model extends CI_Model {
	//Only update the unit edit access time if more than this value (seconds)
	const UNIT_EDIT_UPDATE_INTERVAL = 300;
	//To prevent the edit access time gets updated twice.
	private $last_access_time_upate_id = FALSE;

	public $STATUS_CURRENT = CMS_UNIT_STATUS_PUBLISH;
	public $STATUS_EDIT = CMS_UNIT_STATUS_EDIT;
	public $STATUS_ARCHIVE = CMS_UNIT_STATUS_ARCHIVE;
	public $STATUS_DELETE = CMS_UNIT_STATUS_DELETE;
	public $STATUS_NOTACTIVE = CMS_UNIT_STATUS_NOTACTIVE;

	public $TYPE_NORMAL = CMS_UNIT_TYPE_NORMAL;
	public $TYPE_META = CMS_UNIT_TYPE_META;
   public $TYPE_INT_PARENT = CMS_UNIT_TYPE_INTEGRATED;
   public $TYPE_INT = CMS_UNIT_TYPE_INTEGRATED_CHILD;
   public $TYPE_UNI_PARENT = CMS_UNIT_TYPE_UNIFIED;
	public $TYPE_UNI = CMS_UNIT_TYPE_UNIFIED_CHILD;

 	function __construct() {
		parent::__construct();
        osa_load_lang('general');
        osa_load_lang('unit');
    }

	function update($data, $unitid) {
		$this->db->where('id', $unitid);
		return $this->db->update('unit', $data);
	}

	function getunits($courseid, $sortfield=FALSE, $direction='asc',$hide=FALSE) {
		if ( !is_numeric($courseid) )
			return FALSE;
		if ( $sortfield !== FALSE )
			$this->db->order_by($sortfield, $direction);
		else
			$this->db->order_by('title', $direction);
		$this->db->where('courseid',$courseid);
	   if ($hide != CMS_ADMIN_ALL)
			$this->db->where('hidden', $hide);
		$this->db->where_in('status',array($this->STATUS_CURRENT,$this->STATUS_EDIT));
		$res = $this->db->get_where('unit');
		if ( $res->num_rows() <= 0 )
			return FALSE;
		return $res->result();
	}

	function getunits_bystartdate($courseid,$hide=FALSE) {
		return $this->getunits($courseid, 'startdate','asc',$hide);
	}

	function get_course($unitid) {
		$this->db->select('course_sis.*');
		$this->db->from('unit');
		$this->db->join('course_sis', 'unit.courseid=course_sis.id', 'inner');
		$this->db->where('unit.id',$unitid);
		$resobj = $this->db->get();
	   if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();
		return $rows[0];
	}

	/*
	 * Gets the parent unit data and course name. Input can be the child unit object or parent id
	 */
	function get_parentinfo($unit) {
		if ( is_object($unit) && isset($unit->parentid) )
			$parentid = $unit->parentid;
		else
			$parentid = $unit;
		if ( !is_numeric($parentid) )
			return FALSE;

		$this->db->select('course_sis.name coursename,unit.*');
		$this->db->from('unit');
		$this->db->join('course_sis', 'unit.courseid=course_sis.id', 'inner');
		$this->db->where('unit.id',$parentid);
		$resobj = $this->db->get();
	   if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();
		return $rows[0];
	}

	//Doesn't get archived and deleted units
	//Added cahcing, problem if you call this, update unit and update this again in the same request.
	//You have to clear the DB cache if there is the "dirty" problem above in your code.
	function get_unit($unitid) {
		$cachekey = $unitid;
		if ( ($cache_value = $this->cms_cache->db_get(__METHOD__, $cachekey)) !== NULL ) {
			return $cache_value;
		}
		if ( !osa_is_int_one($unitid) ) {
			return FALSE;
		}
		$this->db->select('*');
		$this->db->where('id', $unitid);
		$this->db->where_in('status',array($this->STATUS_CURRENT,$this->STATUS_EDIT));
		$resobj = $this->db->get('unit');
		if ( $resobj->num_rows() <= 0 ) {
			$this->cms_cache->db_add(__METHOD__, $cachekey, FALSE);
			return FALSE;
		}
		$rows = $resobj->result();
		$this->cms_cache->db_add(__METHOD__, $cachekey, $rows[0]);
		return $rows[0];
	}

	//Gets unit with any status like edit, archive etc.
	function get_unit_any($unitid) {
		$cachekey = $unitid;
		if ( ($cache_value = $this->cms_cache->db_get(__METHOD__, $cachekey)) !== NULL ) {
			return $cache_value;
		}
		if ( !osa_is_int_one($unitid) ) {
			return FALSE;
		}
		$this->db->select('*');
		$this->db->where('id', $unitid);
		$resobj = $this->db->get('unit');
		if ( $resobj->num_rows() <= 0 ) {
			$this->cms_cache->db_add(__METHOD__, $cachekey, FALSE);
			return FALSE;
		}
		$rows = $resobj->result();
		$this->cms_cache->db_add(__METHOD__, $cachekey, $rows[0]);
		return $rows[0];
	}

	function add($data) {
		$this->db->trans_begin();
			$this->db->insert('unit', $data);
			$id = osa_db_lastinsertid($this->db);
			if ( !$id ) {
				$this->db->trans_rollback();
				return FALSE;
			}
			$this->db->where('id', $id);
			$this->db->update('unit', array('groupid'=>$id));
			if ($this->db->trans_status() === FALSE) {
    			$this->db->trans_rollback();
    			return FALSE;
			}
    	$this->db->trans_commit();
		return TRUE;
	}

	//Deletes one unit version, usually called from undo editing unit
	function del_unit($unit) {
		$this->db->trans_start();
			$this->db->where('id', $unit->id);
			$this->db->update('unit', array('status'=>$this->STATUS_DELETE,
				'modifydate'=>osa_dbdate(), 'editorid'=>NULL));
			if ( !is_null($unit->currentunitid) ) {
				$this->db->where('id', $unit->currentunitid);
				$this->db->update('unit', array('editunitid'=>NULL));
			}
		$this->db->trans_complete();
		if ($this->db->trans_status() === FALSE)
			return FALSE;
		osa_remove_uploaddir($unit->courseid, $unit->id, '');
		return TRUE;
	}

	//Deletes the current unit plus the editing unit if there's one
	//Only use this when deleting the publishing unit
	function remove_unit($unit, $remove_edit_flag=FALSE) {
		$dbdate = osa_dbdate();
		//if ( !is_null($unit->editunitid) )
			//$editunit = get_unit($unit->editunitid);

		$this->db->trans_start();
			$this->db->where('id', $unit->id);
			$this->db->update('unit', array('status'=>$this->STATUS_DELETE, 'modifydate'=>$dbdate, 'editorid'=>NULL));
			if ( $remove_edit_flag && !is_null($unit->editunitid) ) {
				$this->db->where('id', $unit->editunitid);
				$this->db->update('unit', array('status'=>$this->STATUS_DELETE, 'modifydate'=>$dbdate, 'editorid'=>NULL));
			}
			elseif (!is_null($unit->editunitid)) {
				//This is a bug fix for editing unit still contains current id after
				//current unit is deleted. A error message appears when deleting the editing unit
				$this->db->where('id', $unit->editunitid);
				$this->db->update('unit', array('currentunitid'=>NULL));
			}
			if ( !is_null($unit->currentunitid) ) {
				$this->db->where('id', $unit->currentunitid);
				$this->db->update('unit', array('status'=>$this->STATUS_DELETE, 'modifydate'=>$dbdate, 'editorid'=>NULL));
			}
		$this->db->trans_complete();
		if ($this->db->trans_status() === FALSE)
				return FALSE;
		osa_remove_uploaddir($unit->courseid, $unit->id, '');
		if ( $remove_edit_flag && !is_null($unit->editunitid) )
			osa_remove_uploaddir($unit->courseid, $unit->editunitid, '');
		if ( !is_null($unit->currentunitid) )
			osa_remove_uploaddir($unit->courseid, $unit->currentunitid, '');
		return TRUE;
	}

	function max_version($groupid) {
		$this->db->select_max('version');
		$this->db->where('groupid', $groupid);
		$this->db->where('status', $this->STATUS_ARCHIVE);
		$resobj = $this->db->get('unit');
		if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();
		$data = $rows[0];
		return $data->version;
	}

	/*
	 * Makes the editing unit becoming the published unit
	 * Archives the old publixhed unit and delete its uploads
	 */
	function confirm_unit($unit) {
		$origunitid = $unit->currentunitid;
		$dbdate = osa_dbdate();
		$update_unit->id = $unit->id;
		$update_unit->status = $this->STATUS_CURRENT;
		$update_unit->modifydate = $dbdate;
		$update_unit->currentunitid = NULL;
		$update_unit->editorid = NULL;

		if (!is_null($origunitid)) {
			$orig_unit->id = $origunitid;
			$orig_unit->status = $this->STATUS_ARCHIVE;
			$orig_unit->editunitid = NULL;
			//$orig_unit->modifydate = $dbdate;
			$orig_unit->archivedate = $dbdate;
			$maxversion = $this->max_version($unit->groupid);
			if ( $maxversion === FALSE)
				return FALSE;
			$orig_unit->version = ++$maxversion;
		}
		$TYPE_INT_PARENT = $this->TYPE_INT_PARENT;
		$TYPE_UNI_PARENT = $this->TYPE_UNI_PARENT;
		$TYPE_INT        = $this->TYPE_INT;
		$TYPE_UNI        = $this->TYPE_UNI;
		//when publish int and uni then update childs modifydate and new parentid
		$childs    = FALSE;
		$childs_id = FALSE;
		if  ( isset($unit->type) && ( $unit->type==$TYPE_INT_PARENT || $unit->type==$TYPE_UNI_PARENT ) && !is_null($unit->currentunitid) ) {
			//echo $unit->currentunitid;

	    	$childs = $this->get_childs_unit($unit->currentunitid);
	    	if ($childs != FALSE && is_array($childs)) {
	    		$childs_id = array();
		    	foreach ($childs as $child) {
					$childs_id[] = $child->id;
				}
	    	}
		}

		$this->db->trans_start();
			if (is_array($childs_id)) {
				$update_child->modifydate = $dbdate;
				$update_child->parentid   = $unit->id;
				$this->db->where_in('id', $childs_id);
				$this->db->where_in('status', array($this->STATUS_EDIT, $this->STATUS_CURRENT) );
				$this->db->where_in('type', array($TYPE_INT, $TYPE_UNI) );
				$this->db->update('unit', $update_child);
			}
			$this->db->where('id', $update_unit->id);
			$this->db->update('unit', $update_unit);
			if ( isset($orig_unit) && is_object($orig_unit) ) {
				$this->db->where('id', $orig_unit->id);
				$this->db->update('unit', $orig_unit);
			}
		$this->db->trans_complete();
		if ($this->db->trans_status() === FALSE)
			return FALSE;

		if ( isset($orig_unit) && is_object($orig_unit) ) {
			osa_remove_uploaddir($unit->courseid, $orig_unit->id, '');
		}
		return TRUE;
	}

	//For editing a unit. Copy from the published unit to the new editing unit
	function copy_editunit($unitid, $user) {
		return $this->duplicate_unit($unitid, $user, FALSE, FALSE);
	}

	//For copying a unit, used for the web copy unit function
	function copy_unit($unitid, $user, $courseid) {
		return $this->duplicate_unit($unitid, $user, $courseid, TRUE);
	}

	/*
	 * This is the big one that copies the whole unit into a new editing unit
	 * This has to be modified if new tables are added to the unit
	 *
	 * $courseid - use this course id instead the courseid in the copy-from unit
	 * $flag_copyunit - this is from the web copy unit feature, so the hidden resources should not be copied
	 */
	function duplicate_unit($unitid, $user, $courseid=FALSE, $flag_copyunit=FALSE) {
		$unit = $this->get_unit_any($unitid);
		if ( !$unit )
			return FALSE;

		$this->load->library('cms/cms_template/cms_template');
		//The following are needed for integrated units
		//$stage1_types = $this->cms_template->types($unit->template, 1);

		//Depending on what you need to copy, these can include the hidden types (misunderstanding) or not
		$non_stage1_types = FALSE;
		$stage1_types = FALSE;
		$all_types = FALSE;

		//Set all the proper types and always exclude static types since they are always pointing
		//to the groupid (which is the orginal unitid when first created) instead of the unitid
		if ( $flag_copyunit ) {
			//Don't copy hidden types like reflection since it is private and you don't want
			//anyone able to copy a teacher's private data
			$non_stage1_types = $this->cms_template->types_exclude_stages(1, $unit->template);
			$non_stage1_types = $this->cms_template->clear_static_types($non_stage1_types);
			$stage1_types = $this->cms_template->types($unit->template, 1); //Does not include hidden types
			$stage1_types = $this->cms_template->clear_static_types($stage1_types);
			$all_types = $this->cms_template->types_exclude_stages(FALSE, $unit->template);
			$all_types = $this->cms_template->clear_static_types($all_types);
		}
		else {
			//For turn editing on - copy everything including hidden resources
			$non_stage1_types = $this->cms_template->types_exclude_stages_usehidden(1, $unit->template);
			$non_stage1_types = $this->cms_template->clear_static_types($non_stage1_types);
			//False for exclude stage will get all stages.
			$all_types = $this->cms_template->types_exclude_stages_usehidden(FALSE, $unit->template);
			$all_types = $this->cms_template->clear_static_types($all_types);
		}
		$origcourseid = $unit->courseid;
		$origunitid = $unit->id;

		//Set the new unit
		$unit->id = NULL;
		$unit->currentunitid = $unitid;
		if ( $flag_copyunit ) {
			$unit->currentunitid = NULL;
		}
		$unit->editunitid = NULL;
		//Not sure do we need this or not
		//$unit->type = $this->TYPE_NORMAL;
		$unit->status = $this->STATUS_EDIT;
		//$unit->creatorid = $user->id;
		$unit->lasteditorid = $user->id;
		$dbdate = osa_dbdate();
		$unit->modifydate = $dbdate;
		$unit->editdate = $dbdate;
		//Edit page access date. Mainly for multi-editor support but always save even in single editor mode
		$unit->edit_accessdate = $dbdate;
		//Copying unit from another course
		if ( $courseid !== FALSE && is_numeric($courseid) ) {
			$unit->courseid = $courseid;
		}

		/////////////////////////////////////////////////////
		//Do file copy
		//Don't copy if it is unified unit child since there is nothing to copy
		if ( $unit->type != $this->TYPE_UNI ) {
			if ( !osa_prepare_unitfiles($origcourseid, $origunitid, $unit->courseid) )
				return FALSE;
		}
		$data = new stdClass;
		$filestat = TRUE;

		/*
		   The following prepares the part deals with private resources copy, involes one
		   select query so put it outside of the transaction.

			* User with unit admin access or current user is course teacher in the copy-from-course
				will copy everything including private resources.
			* Don't think this logic applies to goal, survey etc. since they don't involve with edit version and unit copy
			* Even if they do then checking the creatorid and the modifierid in the query should be sufficient
			* $resource_check_public_where is only needed for copy unit feature else it is just creating a editing unit
				which should copy everyhting
		*/
		$tmp_uid = $user->id;
		if ( !$flag_copyunit || $this->access_model->checkaccess_any_noexit('admin_unit_write') ||
			  $this->is_mycourse($origcourseid, $tmp_uid) ) {
			$resource_check_public_where = '';
		}
		else {
			$db_true = CMS_DB_BOOLEAN_TRUE;
			//This checks for private/pulbic resources and also checks the copy from owner and the current user
			//If you owned it before then you should able to copy it even if its private.
			//Don't think this will ever get executed since without editing rights, this will not get run.
			//It is here so may be in the future we allow users without editing rights to copy.
			//But, I am sure this is not good enough though if it really happens...
			$resource_check_public_where = " and (ispublic={$db_true} or creatorid={$tmp_uid} or modifierid={$tmp_uid})";
		}

		//////////////////////////////////////////////////////////////////////////////
		//Begin the DB transaction since there are a lot to copy for a unit
		//Any tables related to the unit table have to be handled differently for integrated units
		//Make sure nothing from stage 1 is copied!
		$this->db->trans_begin();

			/////////////////////////////////////////////////////
			//Copy new unit
			$this->db->insert('unit', $unit);
			$newid = osa_db_lastinsertid($this->db);
			if ($flag_copyunit == FALSE) {
				//Update current unit with edit unit id
				$data->editunitid = $newid;
				$this->db->where('id', $origunitid);
				$this->db->update('unit', $data);
			}

			//For unified unit we only need to copy the record in unit table and no need to copy anyhting else
			//So, we stop here.
			if ( $unit->type == $this->TYPE_UNI ) {
				if ($this->db->trans_status() === FALSE) {
					$this->db->trans_rollback();
					return FALSE;
				}
				$this->db->trans_commit();
				return $newid;
			}

			/////////////////////////////////////////////////////
			//Copy resources
			$table = $this->db->dbprefix('resource');
			//$fields = 'creatorid,type,select1,select2,select3,select4,select5,ispublic,uploadsize1,upload1,url1,text1';
			//$fields = 'creatorid,type,ispublic,uploadsize1,upload1,url1,text1';
			//TODO: take out date1
			$fields = 'creatorid,type,ispublic,modifierid,createdate,modifydate,text1,date1';
			$sql = "insert into $table " .
 					 "(unitid,origid,courseid,$fields) " .
					 "(select " .
			 		 "{$newid} as unitid,id as origid,{$unit->courseid} as courseid,$fields " .
 					 "from $table where "; //No unitid and ')' at the end yet, have to add it below.

			if ($unit->type == $this->TYPE_INT) {
				//Integrated child units don't need stage 1 data
				//Copy all resource except resource from stage 1
				//Uses all types, non-resource types will get ignored in the resource table specific query
				if ( $non_stage1_types ) {
					//Copy all non stage 1 types for int unit
	 				//$tmp_sql = "$sql unitid={$origunitid} and type in ($non_stage1_types))";
	 				$tmp_sql = "$sql unitid={$origunitid} and type in ({$non_stage1_types}){$resource_check_public_where})";
					$this->db->query($tmp_sql);
					//Copy stage 1 from parent for int. unit
					if ( $unit->parentid != NULL && is_numeric($unit->parentid) && $stage1_types && $flag_copyunit) {
						//$sql .= " unitid={$unit->parentid} and type in ($stage1_types))";
						$sql .= " unitid={$unit->parentid} and type in ($stage1_types){$resource_check_public_where})";
						$this->db->query($sql);
					}
				}
			}
			else { //For normal units, copy all resources from all stages
				if ( $flag_copyunit ) {
					//An empty array will make types_exclude_stages return all stages
					//This function does not include hidden types
					//$types_nohidden = $this->cms_template->types_exclude_stages(array(), $unit->template);
					//$types_nohidden = $this->cms_template->clear_static_types($types_nohidden);
					if ( $all_types ) {
						$sql .= " unitid={$origunitid} and type in ($all_types){$resource_check_public_where})";
						$this->db->query($sql);
					}
				}
				else {
					if ( $all_types ) {
						//This is for "Turn edit on" so copy everything
						$sql .= " unitid={$origunitid} and type in ({$all_types}))";
						$this->db->query($sql);
					}
				}
			}

			/////////////////////////////////////////////////////
			//All the following resource related copies rely on the new unitid and resource original id.
			//All non-unit resources will have a null origid so even if there is a duplicated unitid in resource, it will not copy.
			//So, it is assumed that data integrity is enforced for all.
			//If there is data integrity issue then add types to all resource related copies will fix the problem.
			//The template types are always and should be unique across template types - unit, goal, survey, system and any
			//new template types in the future.

			/////////////////////////////////////////////////////
			//Copy uploads
			$table = $this->db->dbprefix('upload');
			$table_r = $this->db->dbprefix('resource');
			$fields = 'resourceid,size,filename';
			/*
			$sql = "insert into $table ($fields)" .
					 "(select d.id,c.size,c.filename from " .
					 "(select a.courseid, a.type, b.size, b.filename from $table_r as a,$table as b where a.unitid=$unitid and a.id=b.resourceid) as c," .
					 "(select id,courseid,type from $table_r where unitid=$newid) as d " .
					 "where c.courseid=d.courseid and c.type=d.type)";
					 */
			$sql = "insert into $table ($fields)" .
					 "(select d.id,c.size,c.filename from " .
					 "(select a.id, b.size, b.filename from $table_r as a,$table as b where a.unitid=$unitid and a.id=b.resourceid) as c," .
					 "(select id,origid from $table_r where unitid=$newid) as d " .
					 "where c.id=d.origid)";
			$this->db->query($sql);

			/////////////////////////////////////////////////////
			//multi url
			//Copy resource_url
			$table = $this->db->dbprefix('resource_url');
			$table_r = $this->db->dbprefix('resource');
			$fields = 'resourceid,url';
			$sql = "insert into $table ($fields)" .
					 "(select d.id,c.url from " .
					 "(select a.id, b.url from $table_r as a,$table as b where a.unitid=$unitid and a.id=b.resourceid) as c," .
					 "(select id,origid from $table_r where unitid=$newid) as d " .
					 "where c.id=d.origid)";
			$this->db->query($sql);

			/////////////////////////////////////////////////////
			//Copy Resource selections
			$table_s = $this->db->dbprefix('resource_select');
			$table_r = $this->db->dbprefix('resource');
			$table_u = $this->db->dbprefix('unit');
			$fields = 'resourceid,type,choice';
			$sql = "insert into $table_s ($fields) " .
					 "(select r.id, s.type,s.choice from $table_s s " .
					 "join $table_r r on r.origid=s.resourceid " .
					 "join $table_u u on u.id=r.unitid " .
					 "where u.id=$newid)";
			$this->db->query($sql);

			/////////////////////////////////////////////////////
			//Copy unit selections
			$table = $this->db->dbprefix('unit_selection');
			$fields = 'catid,textid,type,select1,select2,select3,select4,select5';
			$sql = "insert into $table " .
					 "(unitid,$fields) " .
					 "(select {$newid} as unitid,$fields from $table where ";

			if ($unit->type == $this->TYPE_INT) {
				//Copy any unit_target that is not in stage 1
				if ( $non_stage1_types ) {
					$tmp_sql = "$sql unitid={$origunitid} and type in ($non_stage1_types))";
					$this->db->query($tmp_sql);
				}
				//Copy stage 1 from parent for int. unit
				if ( $unit->parentid != NULL && is_numeric($unit->parentid) && $stage1_types && $flag_copyunit) {
					$sql .= " unitid={$unit->parentid} and type in ($stage1_types))";
					$this->db->query($sql);
				}
			}
			else {
				//Copy everything for non integrated unit
				$sql .= " unitid={$origunitid})";
				$this->db->query($sql);
			}

			/////////////////////////////////////////////////////
			//Copy unit_target
			$table=$this->db->dbprefix('unit_target');
			$fields = 'targetid,benchmarkid,target_type,select1,select2,select3,data';
			$sql =  "insert into $table " .
					  "(unitid,$fields) " .
					  "(select {$newid} as unitid,$fields from $table where ";

			if ($unit->type == $this->TYPE_INT) {
				//Copy any unit_target that is not in stage 1
				if ( $non_stage1_types ) {
					$tmp_sql = "$sql unitid={$origunitid} and target_type in ($non_stage1_types))";
					$this->db->query($tmp_sql);
				}
				//Copy stage 1 from parent for int. unit
				if ( $unit->parentid != NULL && is_numeric($unit->parentid) && $stage1_types && $flag_copyunit) {
					$sql .= " unitid={$unit->parentid} and target_type in ($stage1_types))";
					$this->db->query($sql);
				}
			}
			else {
				//Copy everything for non integrated unit
				$sql .= " unitid={$origunitid})";
				$this->db->query($sql);
			}

			/////////////////////////////////////////////////////
			//File system changes for folder names
			if ( $this->db->trans_status() !== FALSE ) {
				$this->db->select('id,origid,type');
				$this->db->where('unitid',$newid);
				$resources = $this->db->get('resource');
				if ($resources->num_rows()>0)
					$resource_dirs = $resources->result();
				else
					$resource_dirs = array();
				//Rename the resource id folders
				$filestat = osa_rename_tmpunit($unit->courseid, $newid, $resource_dirs);
			}

		////////////////////////////////////////////////
		//Check to see everything was OK else rollback
		//If a rollback happens then the files on the file system will be left there :(
		if ($this->db->trans_status() === FALSE || !$filestat ) {
			$this->db->trans_rollback();
			return FALSE;
		}
		$this->db->trans_commit();

		/////////////////////////////////////////////////////
		//Copy btnsort table. This will copy all the proper btnsort records for all records on a single unit page.
		//This will not copy static types and it automatically updates the resource ids to the new ones.
		//btnsort table is myisam and not critical data so no transaction/rollback and expect it to always work.
		//This is because of choosing performance over data integrity. Only resource records need linkid update,
		//the rest stays the same.
			$btn_table = $this->db->dbprefix('btnsort');
			$res_table = $this->db->dbprefix('resource');
			/*
			 * We now assign different filehash for LT and outcomes so no need to check for their types
			 */
			//Meta types are lt and outcomes which don't belong to a unit. But, the template design forces
			//they to have types so we create meta types for them.
			//$alltypes = $this->cms_template->alltypes_exclude_meta($unit->template);
			$filehash = $this->cms_template->filehash_filepart($unit->template);
			if ( $filehash ) {
				$type_cond='';
				$static_types = osa_getarrayvalue($this->cms_template->static_types($unit->template));
				if ( $static_types ) {
					$type_cond = " and b.realtype not in ($static_types)";
				}
				$sql = "insert into $btn_table (linkid,coreid,type,sortkey,realtype,filehash) " .
						 		'(select case when r.id is not null then r.id else b.linkid end linkid,' .
						 		"{$newid} unitid,b.type,b.sortkey,b.realtype,b.filehash " .
						 "from $btn_table b " .
						 "left join $res_table r on b.linkid=r.origid and r.unitid={$newid} and r.type=b.realtype " .
						 "where b.coreid={$origunitid} and b.filehash={$filehash}{$type_cond})";
				//Not checking error stat on purpose
				@$this->db->simple_query($sql);
			}

		//Return the new unit id so we can show the neely created unit.
		//Are you confused how everything worked together nicely? A good DB design can be extremely flexible!
		return $newid;
	}

	//Is current user editor of the course
	public function iseditor($courseid, $user=FALSE) {
		$canedit = $this->access_model->checkaccess_courseeditor('unit_write', $courseid, $user);
		if ( !$canedit )
			$canedit = $this->access_model->checkaccess_any('admin_unit_write', $user, FALSE, FALSE);
		return $canedit;
	}

	//Check course edit access, can exit
	public function checkEditAccess($courseid, $isExit=TRUE) {
		if ( ! $this->access_model->checkaccess_courseeditor('unit_write', $courseid, FALSE, TRUE, $isExit) )
			  return $this->access_model->checkaccess_any('admin_unit_write', FALSE, TRUE, $isExit); //This will exit if fails
		return TRUE;
	}

	public function has_admin_write_access() {
		return $this->access_model->checkaccess_any('admin_unit_write', FALSE, FALSE, FALSE);
	}

	//Checks course access from a unit, returns unit db obj on success or exit and print ajax error
	public function check_unit_editaccess($unitid) {
		if ( !is_numeric($unitid) ) {
			echo osa_ajaxmsg(lang('gen_internalservererror'));
			exit;
		}
		$user = $this->login_model->getLogin();
		$unit = $this->get_unit($unitid);
		if ( !$unit ) {
			echo osa_ajaxmsg(lang('gen_internalservererror'));
			exit;
		}
		$this->checkEditAccess($unit->courseid);
		return $unit;
	}

	////ajax msg won't work for iframe
	//Checks course access from a unit, returns unit db obj on success or exit and print html error
	public function check_unit_editaccess_iframe($unitid) {
		if ( !$this->login_model->isAuthenticated() ) {
			$this->load->view('unit/unit_htmltimeout_view');
			return FALSE;
		}
		if ( !is_numeric($unitid) ) {
			$this->load->view('unit/unit_htmlerror_view', array('errormsg'=>lang('unit_internalservererror')));
			return FALSE;
		}
		$user = $this->login_model->getLogin();
		$unit = $this->get_unit($unitid);
		if ( !$unit ) {
			$this->load->view('unit/unit_htmlerror_view', array('errormsg'=>lang('unit_internalservererror')));
			return FALSE;
		}
		if (!$this->checkEditAccess($unit->courseid, FALSE) ) {
			$this->load->view('unit/unit_htmlerror_view', array('errormsg'=>lang('unit_no_permissionmsg')));
			return FALSE;
		}
		return $unit;
	}

	function get_unit_by_group_status($groupid, $stat) {
		if ( !is_numeric($groupid) || !is_numeric($stat) ) {
			return FALSE;
		}
		$this->db->where('groupid', $groupid);
		$this->db->where('status', $stat);
		$res = $this->db->get('unit');
		if ( $res->num_rows() <= 0 )
			return FALSE;
		return $res->result();
	}

	/*
	 * Finds the current published unit based on any unit in the same group/version-tree
	 */
	function get_current_unit($unitid) {
		$unit = $this->get_unit_any($unitid);
		if ( !$unit )
			return FALSE;

		if ( $unit->status == $this->STATUS_CURRENT || $unit->status == $this->STATUS_EDIT )
			return $unit;

		$record = $this->get_unit_by_group_status($unit->groupid, $this->STATUS_CURRENT);
		if ( !$record || count($record) <= 0 ) {
			//$record = $this->get_unit_by_group_status($unit->groupid, $this->STATUS_EDIT);
			//if ( !$record ) {
				return FALSE;
			//}
		}
		return $record[0];
	}

	/*
	 * Finds the editing unit, returns the current if no editing already
	 */
	function get_edit_unit($unitid) {
		$unit = $this->get_unit_any($unitid);
		if ( !$unit )
			return FALSE;
		if ( $unit->status == $this->STATUS_EDIT)
			return $unit;
		$record = $this->get_unit_by_group_status($unit->groupid, $this->STATUS_EDIT);
		if ( !$record || count($record) <= 0 ) {
			$record = $this->get_unit_by_group_status($unit->groupid, $this->STATUS_CURRENT);
			if ( !$record ) {
				return FALSE;
			}
		}
		return $record[0];
	}

	function get_enable_courses($skip_courseid=FALSE, $enabled=CMS_DB_BOOLEAN_TRUE, $sortby_name=TRUE) {
	    $this->db->select('c.id as courseid, c.name as course, d.name as dept, d.id as deptid, ');
		$this->db->from('course_sis c');
	    $this->db->join('department d','c.departmentid=d.id','left');
	    $this->db->where('c.enabled', $enabled);
	    if ( is_numeric($skip_courseid ) )
	    	$this->db->where('c.id !=', $skip_courseid);

	    //$this->db->order_by('d.name');

	    if ($sortby_name===TRUE)
	    	$this->db->order_by('c.name');
	    else
	    	$this->db->order_by($sortby_name);

		$res = $this->db->get();
		if ( $res->num_rows() <= 0 )
			return FALSE;
		return $res->result();
	}

	function get_unit_all( ) {
	    $this->db->select('d.name as dept, c.name as course, d.id as deptid, c.id as courseid');
		$this->db->from('department d');
	    $this->db->join('course_sis c','c.departmentid=d.id','left');

	    $this->db->order_by('d.name');
	    $this->db->order_by('c.name');

		$res = $this->db->get();
		if ( $res->num_rows() <= 0 )
			return FALSE;
		return $res->result();
	}

	function get_childs_unit($unitid) {
		$unit = $this->get_edit_unit($unitid);

	   $this->db->select('u.id,u.parentid,u.title,u.courseid,c.name,u.status,u.currentunitid,c.departmentid');
		$this->db->from('unit u');
		$this->db->join('course_sis c','c.id=u.courseid','left');
		$unitid_arr = array($unitid);

		if (isset($unit->currentunitid) && $unit->currentunitid != null)
			$unitid_arr[] = $unit->currentunitid;

		$this->db->where_in('parentid',$unitid_arr);
 		$this->db->where('status !=',$this->STATUS_DELETE);

		$res = $this->db->get();
		if ( $res->num_rows() <= 0 )
			return FALSE;
		return $res->result();
	}

	function get_childs_name($unitid) {
	    $childs = $this->get_childs_unit($unitid);
	    if ( !$childs ) {
	    	return '';
	    }
	    $child_name = '<br />';
	    $showstatus = '';
	    foreach ($childs as $value) {
	    	$color = 'red';
	    	$showstatus = '(not active)';
	    	if ((int)$value->status == (int)$this->STATUS_EDIT) {
	    		$color = 'green';
	    		$showstatus = '';
	    	} elseif ((int)$value->status == (int)$this->STATUS_DELETE) {
	    		$color = 'gray';
	    		$showstatus = '(delete)';
	    	} elseif ((int)$value->status == (int)$this->STATUS_CURRENT) {
	    		$color = 'blue';
	    		$showstatus = '(publish)';
	    	}
	    	$child_name .= '<font color='.$color.'>'. $value->name .' '. $showstatus .'</font><br /> ';
	    }
	    return $child_name;
	}

	function add_master_child($data,$courseids,$coursenames) {
		$courseid_array = array();
		if (isset($courseids)) {
			$courseid_array = explode(' ', $courseids);
		}
	//	$coursename_array = array();
	//	if (isset($coursenames)) {
	//		$coursename_array = split('\|', $coursenames);
	//	}

		$datainsert = array();
		if (strlen($courseids) > 0 &&  is_array($courseid_array)  ) {
			for ($i=0;$i < count($courseid_array); $i++) {
				$temp = $data;
				$childid   = $courseid_array[$i];
			//	$childname = $coursename_array[$i];

				if ((int)$temp['type'] == $this->TYPE_INT_PARENT) {
					$temp['type'] =  $this->TYPE_INT;
				} elseif ((int)$temp['type'] == $this->TYPE_UNI_PARENT) {
					$temp['type'] =  $this->TYPE_UNI;
				}

				$temp['status'] =  $this->STATUS_NOTACTIVE;
				$temp['courseid'] =  $childid;
				//$temp['title']    =  $childname;
				$datainsert[] = $temp;
			}
		}

		$this->db->trans_begin();
			$this->db->insert('unit', $data);
			$id = osa_db_lastinsertid($this->db);
			if ( !$id ) {
				$this->db->trans_rollback();
				return FALSE;
			}
			$this->db->where('id', $id);
			$this->db->update('unit', array('groupid'=>$id));
			if ($this->db->trans_status() === FALSE) {
    			$this->db->trans_rollback();
    			return FALSE;
			}


			if (count($datainsert) > 0 ) {
				foreach ($datainsert as $temp) {
					//$temp['groupid'] =  $id;
					$temp['parentid'] =  $id;
					$this->db->insert('unit', $temp);
					$child_id = osa_db_lastinsertid($this->db);
					if ( !$child_id ) {
						$this->db->trans_rollback();
						return FALSE;
					}
					$this->db->where('id', $child_id);
					$this->db->update('unit', array('groupid'=>$child_id));
					if ($this->db->trans_status() === FALSE) {
		    			$this->db->trans_rollback();
		    			return FALSE;
					}
				}
			}

		$this->db->trans_complete();
		if ($this->db->trans_status() === FALSE)
			return FALSE;
//    	$this->db->trans_commit();
		return $id;
	}

	// add child units with parentid
	function add_childs($data, $parentid) {
		if (count($data) == 0 ) { return FALSE; }
		if ( !is_numeric($parentid) ) {
			return FALSE;
		}
		$id_childs = '';
		$this->db->trans_begin();
		foreach ($data as $temp) {
			$temp['parentid'] =  $parentid;
			$this->db->insert('unit', $temp);
			$child_id = osa_db_lastinsertid($this->db);
			if ( !$child_id ) {
				$this->db->trans_rollback();
				return FALSE;
			}
			$this->db->where('id', $child_id);
			$this->db->update('unit', array('groupid'=>$child_id));
			if ($this->db->trans_status() === FALSE) {
		  		$this->db->trans_rollback();
		 		return FALSE;
			}
			$id_childs .= $temp['courseid'].' ';
		}

		$this->db->trans_complete();
		if ($this->db->trans_status() === FALSE)
			return FALSE;

		return $id_childs;
	}

	// delete child units
	function remove_childs($data_array) {
	    if (!is_array($data_array) || count($data_array) == 0 ) { return FALSE; }

		$this->db->trans_begin();
		foreach ($data_array as $course) {
			$unit_id = $course->id;
			$currentunitid = $course->currentunitid;

			$this->db->where('id', $unit_id);
			$this->db->update('unit', array('status'=>$this->STATUS_DELETE, 'modifydate'=>osa_dbdate()));
			if ( !is_null($currentunitid) ) {
				$this->db->where('id', $currentunitid);
				$this->db->update('unit', array('editunitid'=>NULL));
			}
			if ($this->db->trans_status() === FALSE) {
		  		$this->db->trans_rollback();
		 		return FALSE;
			}
		}
	    $this->db->trans_complete();
	    if ($this->db->trans_status() === FALSE)
	    	return FALSE;

		return TRUE;
	}

	/*
	 * Makes the editing unit becoming the published unit
	 * Archives the old publixhed unit and delete its uploads
	*/
	function confirm_distribute_unit($unit) {
		if (!isset($unit) )
			return FALSE;

		if (!is_null($unit->currentunitid))
			$parent = $this->get_unit($unit->currentunitid);

		//if ($parent->type==$this->TYPE_INT_PARENT || $parent->type==$this->TYPE_UNI_PARENT)
			//$this->db->where('parentid',$unit->currentunitid);
		//	$unitid = $unit->currentunitid;
		//else
			$unitid = $unit->id;
			//$this->db->where('parentid',$unit->id);
		/*if (is_null($unit->currentunitid))
			$unitid =$unit->id;
		else
			$unitid = $unit->currentunitid;
*/
		$dbdate = osa_dbdate();
		$update_unit->status = $this->STATUS_EDIT;
		$update_unit->editdate = $dbdate;
		$update_unit->modifydate = $dbdate;
		$update_unit->parentid = $unitid;
		$update_unit->title = $unit->title;
		$update_unit->description = $unit->description;

		//Added for keep track of first distributed

		/*
		$parentunit = FALSE;
		if ( $unit->distributed != 1 ) {
			$parentunit = new stdClass;
			$parentunit->distributed = 1;
		}
		*/
		$this->db->trans_start();
		/*
			if ( $parentunit ) {
				//So, we know this unit had been distributed before
				//If we don't do this then deleting all child units would cause
				//the condition like it never distributed before
				//This is necessary in order to not print Stage 2 and 3 during the initial edit
				$this->db->where('id', $unitid);
				$this->db->update('unit', $parentunit);
			}
		*/
			if ($unit->type== $this->TYPE_INT_PARENT) {
				$this->db->where('type', $this->TYPE_INT);
			} else if ($unit->type== $this->TYPE_UNI_PARENT) {
				$this->db->where('type', $this->TYPE_UNI);
			}
			$this->db->where('parentid', $unitid);
			$this->db->where('status', $this->STATUS_NOTACTIVE);
			$this->db->update('unit', $update_unit);
		$this->db->trans_complete();

		if ($this->db->trans_status() === FALSE)
			return FALSE;
		return TRUE;
	}

	function get_last_unit($current_unit) {
		$courseid = $current_unit->courseid;
		//$status   = $this->STATUS_ARCHIVE;
		$groupid  = $current_unit->groupid;
		$type     = $current_unit->type;

	    $this->db->select('u.id, u.courseid, u.groupid, u.status, u.type, u.version');
		$this->db->from('unit u');
	    $this->db->where('courseid',$courseid);
	   // $this->db->where('status',$status);
	    $this->db->where_in('status',array($this->STATUS_CURRENT,$this->STATUS_ARCHIVE));
	    $this->db->where('groupid',$groupid);
 	 	$this->db->where('type',$type);
 	 	$this->db->order_by('status');
 	    $this->db->order_by('version','DESC');

		$res = $this->db->get();
		if ( $res->num_rows() <= 0 )
			return FALSE;
		return $res->result();
	}


	function status_distribute($unit,$isedit=FALSE) {
		$parent = FALSE;
		if (!is_null($unit->currentunitid))
			$parent = $this->get_unit($unit->currentunitid);

		$this->db->select('u.id, u.parentid, u.courseid, u.groupid, u.status, u.type, u.version');
		$this->db->from('unit u');

		//if ($parent != FALSE && ($parent->type==$this->TYPE_INT_PARENT || $parent->type==$this->TYPE_UNI_PARENT))
		//	$this->db->where('parentid',$unit->currentunitid);
		//else
			$this->db->where('parentid',$unit->id);


		//if (!is_null($unit->id))
		//	$this->db->where('parentid',$unit->id);

		if ( !$isedit )
			$this->db->where('status',$this->STATUS_NOTACTIVE);
		else
		 	$this->db->where_in('status',array($this->STATUS_NOTACTIVE, $this->STATUS_EDIT));

 		$this->db->where_in('type',array($this->TYPE_INT, $this->TYPE_UNI));
 		$res = $this->db->get();

		if ($res->num_rows() > 0) {
			//$rows = $res->result();
			return TRUE;
		}
		return FALSE;
	}

	function get_publish_units_bygroup($unit) {
		if (!isset($unit->groupid) && is_numeric($unit))
			 $groupid  = $unit;
		else
			 $groupid  = $unit->groupid;

	    $this->db->select('u.id,u.parentid,u.title,u.courseid,c.name,u.status,u.currentunitid,c.departmentid');
		$this->db->from('unit u');
		$this->db->join('course_sis c','c.id=u.courseid','left');
 		$this->db->where('status',$this->STATUS_CURRENT);
	    $this->db->where('groupid',$groupid);

		$res = $this->db->get();
		if ( $res->num_rows() <= 0 )
			return FALSE;
		//return $res->result();
		$rows = $res->result();
		return $rows[0];
	}

	function get_childs_dynamic($unitid,$isName=FALSE,$sep=' ') {
		$childs = FALSE;
	    $childs = $this->get_childs_unit($unitid);
	    $ids = Array();

	    if ( !$childs )
			return osa_getarrayvalue($ids,$sep);

		foreach ($childs as $value) {
			if (!$isName)
				$tmp = $value->courseid;
			else
				$tmp = $value->id; 		//unit id

			if (!in_array($tmp,$ids)) {
				$ids[]=$tmp;
			}
		}
		return osa_getarrayvalue($ids,$sep);
	}

	function update_change_type($unitid, $unit) {
		if (!is_numeric($unitid) )
			return FALSE;

		$update_unit->type = $unit->type;
		$this->db->where('id', $unitid);
		$this->db->update('unit', $update_unit);
	}

	//TODO: This looks uncessary, see if we can get rid of this.
	//Looks like getting the DB result and then put the title for each record. This is toally bad logic
	function get_units($unitids=FALSE) {
		if ($unitids == FALSE)
			return FALSE;

		$this->db->select('u.id, c.name course, u.title,u.type');
		$this->db->from('unit u');
		$this->db->join('course_sis c','c.id=u.courseid','join');
 		//$this->db->where('status',$this->STATUS_CURRENT);
	   // $this->db->where('groupid',$groupid);


		if (is_array($unitids) == FALSE)
			$unitids = array($unitids);

		//$this->db->where('status',$this->STATUS_CURRENT);
		$this->db->where_in('u.id',$unitids);
		$this->db->order_by('c.name, c.id, u.title, u.groupid, u.id, u.status');

		$resobj = $this->db->get();
		if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();

		$result = array();
		foreach($rows as $value) {
			/*
			if ($value->type ==$this->TYPE_NORMAL)
					$value->type = 'Normal';
			elseif ($value->type ==$this->TYPE_META)
					$value->type = 'Meta Unit';
			elseif ($value->type ==$this->TYPE_INT_PARENT)
					$value->type = 'Integrated Unit';
			elseif ($value->type ==$this->TYPE_INT)
					$value->type = 'Integrated Unit';
			elseif ($value->type ==$this->TYPE_UNI_PARENT)
					$value->type = 'Unified Unit';
			elseif ($value->type ==$this->TYPE_UNI)
					$value->type = 'Unified Unit';
			*/
			$result[$value->id] = $value;
		}
		return $result;
	}

	function get_publish_unit($courseid, $notin_unit=FALSE, $notin=TRUE, $all_unit=FALSE) {
		if (!is_numeric($courseid) )
			return FALSE;

		$this->db->select('id ,title');
 		$this->db->where('courseid',$courseid);

 		if ($notin_unit != FALSE) {
 			if ($notin)
				$this->db->where_not_in('id',$notin_unit);
			else
				$this->db->where_in('id',$notin_unit);
 		}


		//if ($all_unit == FALSE)
		// 	$all_unit = $this->STATUS_CURRENT;

			//var_dump($is_publish);
		//	echo $in_publish;
	///	if (is_array($in_publish)==FALSE)
	//		$in_publish = array($in_publish);

		$this->db->where_in('status',$this->STATUS_CURRENT);
		$this->db->where_in('hidden', FALSE);
		$this->db->group_by('id');
		$this->db->order_by('title, groupid, id, status');

		$resobj = $this->db->get('unit');
		if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();

		$result = array();
		foreach($rows as $value) {
			$result[$value->id] = $value->title;
		}
		return $result;
	}

	function get_course_unit($join=FALSE) {
		$this->db->select('count(u.id),c.id,c.name');
	    $this->db->from('course_sis c');
	    //$this->db->join('unit u',"u.courseid=c.id and u.hidden=false and u.status='{$this->STATUS_CURRENT}'");
	    $this->db->join('unit u',"u.courseid=c.id and u.hidden=false and u.status='{$this->STATUS_CURRENT}'");
	    $this->db->group_by('c.id, c.name');
	    $this->db->where('c.enabled',CMS_ADMIN_ENABLE);
	    $this->db->where('c.hidden',FALSE);
	    $this->db->having('count(u.id) > 0');
	    $this->db->order_by('name, id');

	    $res = $this->db->get();
		if ($res->num_rows() <= 0)
			return FALSE;

		$user = $res->result();
		$result = array();
		foreach($user as $value) {
			$result[$value->id] = $value->name;
		}
		return $result;
	}

	function get_courseall() {
		$this->db->select('id, name');
	    $this->db->from('course_sis');
	    $this->db->where('enabled',CMS_ADMIN_ENABLE);
	    $this->db->order_by('name');
	    $res = $this->db->get();
			if ( $res->num_rows() <= 0 )
			return FALSE;

		$user = $res->result();
		$result = array();
		foreach($user as $value) {
			$result[$value->id] = $value->name;
		}
		return $result;
	}
	function get_sel_course($courseid) {
		if ( !is_numeric($courseid) )
			return FALSE;
		$this->db->select('id, name');
	    $this->db->from('course_sis');
	  	$this->db->where('id',$courseid);
	    $this->db->order_by('name');
	  	 $res = $this->db->get();
			if ( $res->num_rows() <= 0 )
			return FALSE;
		$rows = $res->result();
		return $rows[0];
	}

	function insert($courseid, $unit) {
		if ( !is_numeric($courseid) || is_array($unit) == FALSE )
			return FALSE;

		$tbunit = $this->db->dbprefix('unit');

		$wherein = implode(",", $unit);

		$fields  = "courseid, origunitid, editunitid, currentunitid, groupid, course_intid, ";
		$fields .= "lasteditorid, creatorid, type, status, ";
		$fields .= "startdate, enddate, createdate, editdate, modifydate, archivedate,";
		$fields .= "version, title, description";

		$sql_ins = "INSERT INTO $tbunit ($fields, parentid)  ";
	    //$courseid as $fields for set target courseid to new unit
		$sql_sel = "SELECT $courseid as $fields, parentid FROM $tbunit WHERE id in ($wherein)";
	 	$res     = $this->db->query($sql_ins . $sql_sel);
		if ($res != FALSE) {
			$sql_upd = "UPDATE $tbunit SET groupid=id WHERE groupid in ($wherein) and courseid=$courseid and groupid != id";
			$res     = $this->db->query($sql_upd);
		}


		$this->db->select('u.id, u.parentid, o.id oldunitid');
	    $this->db->from('unit u');
	    $this->db->join('unit o','o.groupid = u.parentid and o.groupid != o.id','left');
		$this->db->where_in('u.parentid',$wherein);
		$this->db->order_by('u.parentid');
		$res = $this->db->get();
		if ( $res->num_rows() <= 0 )
			return FALSE;
		$resobj = $res->result();
/*
		if ($res != FALSE) {
			$sql_upd = "UPDATE $tbunit SET groupid=id WHERE groupid in ($wherein) and courseid=$courseid and groupid != id";
			$res     = $this->db->query($sql_upd);
		}
*/
		$lastparentid = '';
		foreach ($resobj as $row) {
			if ($lastparentid == '')
			    $lastparentid =  $row->parentid;

			if ($lastparentid != $row->parentid) {
			    $lastparentid =  $row->parentid;

			    $wherein = implode(",", $temp);
				$sql_ins = "INSERT INTO $tbunit ($fields, parentid)  ";
				$sql_sel = "SELECT $fields, $row->oldunitid as parentid FROM $tbunit WHERE id in ($wherein)";
				$res     = $this->db->query($sql_ins . $sql_sel);
				if ($res != FALSE) {
					$sql_upd = "UPDATE $tbunit SET groupid=id WHERE groupid in ($wherein) and groupid != id";
					$res     = $this->db->query($sql_upd);
				}

			    $temp = array();
			}

			$temp[] = $row->id;
		}

		if (count($temp) != 0) {
			$wherein = implode(",", $temp);
			$sql_ins = "INSERT INTO $tbunit ($fields, parentid)  ";
			$sql_sel = "SELECT $fields, $row->oldunitid as parentid FROM $tbunit WHERE id in ($wherein)";
			$res     = $this->db->query($sql_ins . $sql_sel);
			if ($res != FALSE) {
				$sql_upd = "UPDATE $tbunit SET groupid=id WHERE groupid in ($wherein) and groupid != id";
				$res     = $this->db->query($sql_upd);
			}
		}


		 return FALSE;
	}
	function edit_showhide($groupid,$showhide) {
		if ( !is_numeric($groupid) && !is_numeric($showhide))
		return FALSE;
		$this->db->where('groupid', $groupid);
		$this->db->update('unit', array('hidden'=>$showhide));
		return TRUE;
	}
	//Get unit history
	function get_unit_history($unit, $history=FALSE) {
		$ismycourse = FALSE;
		$groupid = FALSE;
		$status = array($this->STATUS_CURRENT,$this->STATUS_ARCHIVE);

		if (is_object($unit) && isset($unit->id) && isset($unit->groupid) && isset($unit->courseid)) {
			 $has_admin_unitwrite = $this->has_admin_write_access();
			 if ($has_admin_unitwrite===FALSE)
			 	  $ismycourse = $this->course_model->isMyCourse(FALSE, $unit->courseid);
			 else
			 	  $ismycourse = $has_admin_unitwrite;
			 $groupid = $unit->groupid;
		}

		if ($ismycourse===TRUE && is_array($status))
			 $status[] = $this->STATUS_EDIT;

		$this->db->select('id,title, modifydate,type,status,version');
	   $this->db->from('unit');
	   $this->db->where('groupid', $groupid);
		$this->db->where_in('status', $status);
	   $this->db->order_by('modifydate desc');
	   $res = $this->db->get();
		if ( $res->num_rows() <= 0 )
			return FALSE;

		$deps = $res->result();
		if ($history!=FALSE){
			return $res->result();
		}
		$result = array();
		//$result[0] ='Current Version';
		foreach($deps as $value) {
			if (isset($value) && $value != FALSE) {
				$version = $value->version;
				if ($value->version == null || $value->version == '') {
					if (isset($value->status)) {
						if ($value->status ==  CMS_UNIT_STATUS_PUBLISH)
							$version = lang('unit_history_current') . $version;
						if ($value->status ==  CMS_UNIT_STATUS_EDIT)
							$version = lang('unit_history_editting') . $version;
					}
					else
						$version = lang('unit_compare_prev') . $version;
				}
				else
					$version = lang('unit_compare_prev') . $version;


				$result[$value->id] = $version ." " ."(" .osa_date_format($value->modifydate).")" ;
				}
			}
		return $result;

	}
	//Get group by unit
	function get_groupbyunit($unitid) {
		$this->db->select('*');
		$this->db->where('id', $unitid);
		//$this->db->where('iscurrent', '1');
		$this->db->where_in('status',array($this->STATUS_CURRENT,$this->STATUS_ARCHIVE,$this->STATUS_EDIT));
		$resobj = $this->db->get('unit');
		if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();
		return $rows[0];
	}
	function update_copyunit($unitid, $setcourseid) {
		if ( !is_numeric($unitid) && !is_numeric($setcourseid))
			return FALSE;

		$data->courseid = $setcourseid ;
		$this->update($data, $unitid);
		return TRUE;
	}

	//Init. a unit to a normal unit after using web unit copy feature
	function reinitialize($title, $unitid) {
	   $dbdate = osa_dbdate();
		$data->title   = $title;
		$data->groupid = $unitid;
		//reinitialize
		$data->origunitid = null;
		$data->editunitid = null;
		$data->currentunitid = null;
		$data->course_intid = null;
		$data->type = $this->unit_model->TYPE_NORMAL;
		$data->status = $this->unit_model->STATUS_EDIT;
		$data->createdate = $dbdate;
		$data->version = null;
		$data->archivedate = null;
		$data->parentid = null;

		$this->update($data, $unitid);
		return TRUE;
	}

 function get_last_version($unit) {
		 if (is_object($unit)==FALSE || isset($unit->groupid)==FALSE)
		 	  return FALSE;

		$groupid = $unit->groupid;
		$table_v = $this->db->dbprefix('unit');

 		$status = array();//$this->STATUS_CURRENT;
		$in_max_version = '';
		if ($unit->status == $this->STATUS_CURRENT)  {
			 // curent vs history
			 $status[] = $this->STATUS_ARCHIVE;
			 $status[] = $this->STATUS_EDIT;
			$in_max_version = "(select case when max(version) is null then" .
									" ifnull(max(version), id) else" .
									" ( select id from unit   ".
									"   where groupid='$groupid' and status in('$this->STATUS_ARCHIVE','$this->STATUS_EDIT')   ".
									"   group by version " .
									"   order by version desc " .
									"   limit 1 " .
									" ) " .
									" end as id " .
									" from $table_v where groupid='$groupid' and status in('$this->STATUS_ARCHIVE','$this->STATUS_EDIT')) v";

		}
		elseif ($unit->status == $this->STATUS_EDIT) {
		 	 $status[] = $this->STATUS_CURRENT;
		}
		$this->db->select('u.id, u.editunitid');
		$this->db->from('unit u');

		if ($in_max_version !== '')
			 $this->db->join($in_max_version,"u.id=v.id");

		$this->db->where('u.groupid', $groupid);
		$this->db->where_in('u.status', $status);

 		$resobj = $this->db->get();
		//$resobj = $this->db->get('unit');
		if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();
		$data = $rows[0];
		return $data;
	}

	function update_unit_editorid($unitid, $value=NULL, $overwrite_userid='') {
		$user = $this->login_model->getLogin();
		$unit = $this->get_unit($unitid);
		if ( !$unit || $unit->status != $this->STATUS_EDIT ||
			  ($user->id != $unit->editorid) && !$this->has_admin_write_access() &&
			  	!is_null($unit->editorid) && $overwrite_userid != $unit->editorid)
			return FALSE;
		$this->db->where('id', $unitid);
		if ( ($ret = $this->db->update('unit', array('editorid'=>$value, 'edit_accessdate'=>osa_dbdate()))) ) {
			$this->last_access_time_upate_id = $unitid;
		}
		return $ret;
	}

	function unlock_unit($unitid) {
		return $this->update_unit_editorid($unitid);
	}

	function lock_unit($unitid, $overwrite_userid='') {
		$user = $this->login_model->getLogin();
		return $this->update_unit_editorid($unitid, $user->id, $overwrite_userid);
	}

	//Updates the edit_accessdate if no unit editor or current user is unit editor
	//returns false if no update was done. This will only update once per unit and user id
	//in a single request.
	function update_edit_accessdate($unit) {
		if ( !is_object($unit) || !isset($unit->id) ) {
			return FALSE;
		}
		if ( $this->last_access_time_upate_id == $unit->id ) {
			return TRUE;
		}
		$user = $this->login_model->getLogin();
		$cachekey = "{$user->id}_{$unit->id}";
		//Updated already in the same request so just return true
		if ( $this->cms_cache->gen_get(__METHOD__, $cachekey) ) {
			return TRUE;
		}

		//Only update if no editor locking or user is the one who locked the unit
		if ( is_null($unit->editorid) || $user->id == $unit->editorid ) {
			if ( !empty($unit->edit_accessdate) ) {
				//Only update if current edit access time is greater than the interval
				//Updates are expensive so try to minimize this
				$edit_time = strtotime($unit->edit_accessdate);
				$time = time();
				$dif = $time - $edit_time;
				if ( $edit_time && $dif < self::UNIT_EDIT_UPDATE_INTERVAL ) {
					return TRUE;
				}
			}
			$this->db->where('id', $unit->id);
			$ret = $this->db->update('unit', array('edit_accessdate'=>osa_dbdate()));
			if ( $ret ) {
				$this->cms_cache->gen_add(__METHOD__, $cachekey, TRUE);
			}
			return $ret;
		}
		return FALSE;
	}
	function get_countunit($status) {
		$this->db->select('count(id) total');
		$this->db->where('status', $status);
		$resobj = $this->db->get('unit');
		if ( $resobj->num_rows() <= 0 )
			return 0;
		$res = $resobj->result();
		$row = $res[0];
		return $row->total;
	}

	function get_publish_unit_byedit($unit, $entryid=FALSE) {
		$groupid = FALSE;
		if ($entryid == FALSE) {
			if (!isset($unit->groupid) && is_numeric($unit))
				 $groupid  = $unit;
			else
				 $groupid  = $unit->groupid;
		}
		$linkunit = $this->db->dbprefix('linkunit');
		$entry_point = $this->db->dbprefix('entry_point');
		$unit = $this->db->dbprefix('unit');

		$sub_select = "select link.unitid from {$entry_point} e " .
						  "join $linkunit link on link.extid = e.id where e.id={$entryid} ";

		$select = "select u.id,u.groupid ";
		$from = "from {$unit} u ";
		$join = '';
		if ($entryid != FALSE)
			 $join = "join ( $sub_select ) eg on eg.unitid = u.groupid ";
		$where = "where u.status = {$this->STATUS_EDIT} ";
		if ($entryid == FALSE)
			 $where .= "and u.groupid = {$groupid} ";

		$res = $this->db->query($select . $from . $join . $where);

		if ( $res->num_rows() != 1 )
			return FALSE;
		$rows = $res->result();
		//echo '<pre>'; print_r($rows); echo '</pre>';
		$editunitid = $rows[0]->id;
		if ($groupid == FALSE)
			 $groupid = $rows[0]->groupid;
		//echo $editunitid;
		$select = 'u.id,u.parentid,u.title,u.courseid,u.type,u.groupid,u.template,u.startdate,u.enddate,'.
					 'c.name,u.status,u.currentunitid,c.departmentid,c.name coursename';
		$this->db->select($select);
		$this->db->from('unit u');
		$this->db->join('course_sis c','c.id=u.courseid','left');
 		$this->db->where('u.status',$this->STATUS_DELETE);
	   $this->db->where('u.editunitid',$editunitid);
 		$this->db->where('u.groupid',$groupid);

 		$res = $this->db->get();
	   if ( $res->num_rows() <= 0 )
			return FALSE;
		$rows = $res->result();
		return $rows;

	}
	function get_publish_unit_bydelete($unit, $entryid=FALSE) {
		$groupid = FALSE;
		if ($entryid == FALSE) {
			if (!isset($unit->groupid) && is_numeric($unit))
				 $groupid  = $unit;
			else
				 $groupid  = $unit->groupid;
		}

		$linkunit = $this->db->dbprefix('linkunit');
		$entry_point = $this->db->dbprefix('entry_point');
		$unit = $this->db->dbprefix('unit');

		$sub_select = "select link.unitid from {$entry_point} e " .
						  "join $linkunit link on link.extid = e.id where e.id={$entryid} ";

		$select = "select u.id,u.groupid ";
		$from = "from {$unit} u ";
		$join = '';
		if ($entryid != FALSE)
			 $join = "join ( $sub_select ) eg on eg.unitid = u.groupid ";
		$where = "where u.status = {$this->STATUS_DELETE} ";
		if ($entryid == FALSE)
			 $where .= "and u.groupid = {$groupid} ";

		$where .= "and u.editunitid is null and u.currentunitid is null ";

		$res = $this->db->query($select . $from . $join . $where);

		if ( $res->num_rows() != 1 )
			return FALSE;
		$rows = $res->result();
		//echo '<pre>'; print_r($rows); echo '</pre>';
		$unitid = $rows[0]->id;
		if ($groupid == FALSE)
			 $groupid = $rows[0]->groupid;

		$select = 'u.id,u.parentid,u.title,u.courseid,u.type,u.groupid,u.template,u.startdate,u.enddate,'.
					 'c.name,u.status,u.currentunitid,c.departmentid,c.name coursename';
		$this->db->select($select);
		$this->db->from('unit u');
		$this->db->join('course_sis c','c.id=u.courseid','left');
 		$this->db->where('u.status',$this->STATUS_DELETE);
 		$this->db->where('u.groupid',$groupid);
 		$this->db->where('u.id',$unitid);

 		$res = $this->db->get();
	   if ( $res->num_rows() <= 0 )
			return FALSE;
		$rows = $res->result();
		return $rows;
	}

	// TOxDO: Fix this slow query - Fixed
	/*
	 * Do not take out any of the select fields from the existing query since the hashit can be
	 * a query field reference.
	 *
	 * The original query foreces to look for children with STATUS_EDIT and STATUS_NOTACTIVE which
	 * is not necessary.
	 */
	function get_departbyparent($unitid, $enabled=true, $hashit=false) {
		if ( !osa_is_int_one($unitid) ) {
			return FALSE;
		}
		$table_unit = $this->db->dbprefix('unit');
		$table_course_sis = $this->db->dbprefix('course_sis');
		$table_department = $this->db->dbprefix('department');
/*
		$status = array( $this->STATUS_EDIT, $this->STATUS_NOTACTIVE);
		$subsql = ' select case when parentid is null then currentunitid else parentid end cid ' .
					 ' from ' . $table_unit .
					 ' where (id = ' . $unitid . ' or parentid =' . $unitid . ') ' .
					 ' and  status in ('.implode(',', $status).') ';
		//fix department_display
		$department = ' case when c.department_display is null then d.name else c.department_display end name, '.
					     ' case when c.department_display is null then "" else d.name end department_display ';
		$select = ' select d.id as deptid, '. $department .', c.id courseid, c.name coursename ';
		$from = ' from  ' . $table_unit . ' u ';
		$join = ' join ' . $table_course_sis . ' c on c.id = u.courseid '.
				  ' join ' . $table_department . ' d on d.id = c.departmentid ';

		$where = ' where c.enabled='.$enabled.' and u.status in ('.implode(',', $status).') ' .
					' and (u.id = '. $unitid . ' or u.parentid in ( '. $subsql .') ) ';

		$group_by = '';// group by d.id ';
		$order_by = ' order by d.name,d.id,c.department_display';

		$query = "$select $from $join $where $group_by $order_by ";
		$res = $this->db->query( $query );
*/
		if ( $enabled ) {
			$course_enabled = 'and c.enabled=' . CMS_DB_BOOLEAN_TRUE;
		}
		else {
			$course_enabled = 'and c.enabled=' . CMS_DB_BOOLEAN_FALSE;
		}
		//Use the course department name override if there is one
		//Basically we get the course and department for the supplied unit and all its active children
		/*
		$sql = 'select case when c.department_display is null then d.name else c.department_display end name,' .
  				 	'c.department_display,d.id deptid,c.id courseid,c.name coursename ' .
				"from $table_unit u " .
				"join $table_unit u2 on u.id={$unitid} and (u2.id=u.id or u2.id=u.currentunitid or u2.id=u.editunitid) " .
				"join $table_unit u3 on u3.parentid=u2.id or u3.id=u2.id " .
				"join $table_course_sis c on c.id=u3.courseid $course_enabled " .
				"join $table_department d on d.id=c.departmentid " .
				'where u3.status <> ' . CMS_UNIT_STATUS_DELETE; */
		$sql = 'select case when c.department_display is null then d.name else c.department_display end name,' .
  				 	'c.department_display,d.id deptid,c.id courseid,c.name coursename ' .
				"from $table_unit u " .
				"join $table_unit u2 on u.id={$unitid} and (u2.id=u.id or u2.id=u.currentunitid or u2.id=u.editunitid) " .
				"left join $table_unit u3 on u3.parentid=u2.id " .
				"join $table_course_sis c on (c.id=u3.courseid or c.id=u2.courseid) $course_enabled " .
				"join $table_department d on d.id=c.departmentid " .
				'where u3.id is null or u3.status <> ' . CMS_UNIT_STATUS_DELETE . ' group by c.id';
		$res = $this->db->query($sql);
		if ( $res->num_rows() <= 0 ) {
    		return FALSE;
		}
    	$rows = $res->result();
    	if ($hashit !== false) {
    		$rows = $this->hashit($rows, $hashit);
    	}
    	return $rows;
	}
	//fix display department with course department_display
	function get_department_display($courseid=false, $key='id', $toArray=FALSE) {
		//Use the CMS cache becuase someone put in code to call this function
		//in a loop from unit_lt and unit_select
		$this->load->library('cms/cms_cache');
		$cache_key = "{$courseid}_{$key}_{$toArray}";
		if ( ($cache_val = $this->cms_cache->db_get(__METHOD__, $cache_key) ) !== NULL )
			return $cache_val;

		//$enabled = true;
		if ($toArray === false && $courseid === false) {
			$this->cms_cache->db_add(__METHOD__, $cache_key, FALSE);
			return FALSE;
		}
		$table_course_sis = $this->db->dbprefix('course_sis');
		$table_department = $this->db->dbprefix('department');

		$department = ' case when c.department_display is null then d.name else c.department_display end name';
    	$select = 'select d.id, d.name department_name, c.id courseid,'.$department;
	   $from = ' from  ' . $table_course_sis . ' c ';
	   $join = ' left join ' . $table_department .' d on d.id = c.departmentid ';
	   //Don't think we should check enabled here since it is data already exist
	   //$where = ' where c.enabled = ' . $enabled;
	   /*
	   if ($deptid !== false)  {
	   	if (is_array($deptid))
	   		$where .= ' and d.id in (' . implode(",", $deptid).')' ;
	   	else
	   		$where .= ' and d.id = ' . $deptid;
	   }
	   */
	   $where='';
		if ($courseid !== false) {
	   	$where = ' where c.id=' . $courseid;
		}
	   $group_by = ' group by c.id, d.id ';
	   //$group_by = ' group by c.department_display ';
	   $query   = "$select $from $join $where $group_by ";
		$resobj = $this->db->query( $query );
		if ( $resobj->num_rows() < 1 ) {
			$this->cms_cache->db_add(__METHOD__, $cache_key, FALSE);
     	 	return FALSE;
		}
 		if ($toArray) {
 			$result = $resobj->result();
 			$ret_val = $this->toArray($result,$key);
 			$this->cms_cache->db_add(__METHOD__, $cache_key, $ret_val);
 			return $ret_val;
 		}
 		else {
 			$result = $resobj->result_array();
	 		foreach ($result as $rows) {
	 			//if ($rows['id'] == $deptid || $rows['courseid'] == $courseid ) {
	 			if ($rows['courseid'] == $courseid ) {
	 				$this->cms_cache->db_add(__METHOD__, $cache_key, $rows['name']);
					return $rows['name'];
	 			}
	 		}
 		}
 		$this->cms_cache->db_add(__METHOD__, $cache_key, FALSE);
 		return FALSE;
	}

	function get_unit_byparentid($parentid, $groupby=false) {
		if ( is_object($parentid) && isset($parentid->unitid) )
			$parentid = $parentid->parentid;
		if ( !is_numeric($parentid) )
			return FALSE;

		$this->db->select('c.name coursename,u.*');
		$this->db->from('unit u');
		$this->db->join('course_sis c', 'u.courseid = c.id', 'inner');
		$this->db->where('u.parentid',$parentid);
		$this->db->where('u.status != ',$this->STATUS_DELETE);
		if ($groupby !== false)
			$this->db->group_by($groupby);

		$resobj = $this->db->get();
	   if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();
		return $rows;
	}

	function show_department_display($courseids) {
		if (!is_array($courseids) && is_numeric($courseids))
			$courseids[] = $courseids;

		$this->db->select('id');
		$this->db->from('course_sis');
		$this->db->where_in('id',$courseids);
		$this->db->where('department_display is not null');
		$this->db->where('department_display != ""');
		$resobj = $this->db->get();
	   if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();
		return $rows;
	}

	function toArray($rows, $key='id') {
    	if (!is_array($rows))
    		return FALSE;

    	$data = array();
		foreach ($rows as $row) {
			$data[$row->$key] = $row;
		}
		return $data;
   }

   function update_user_privateres_flag($flag) {
   	$user = & osa_login_object();
   	if ( !is_object($user) || !isset($user->id) ) {
   		return FALSE;
   	}
   	$data = new stdClass();
   	if ( $flag == CMS_DB_BOOLEAN_TRUE ) {
   		$data->hide_unit_private_resource = CMS_DB_BOOLEAN_TRUE;
   	}
   	else {
   		$data->hide_unit_private_resource = CMS_DB_BOOLEAN_FALSE;
   	}
   	$ret = $this->db->update('user', $data, 'id = ' . $user->id);
   	osa_login_object_refresh();
   	return $ret;
   }

	private function hashit($array, $index, $index2='') {
		$ret=array();
		if ( !is_array($array) )
			return $ret;
		foreach($array as $item) {

			if (is_object($item)) {
				if ( $index2 == '' )
					$newindex = $item->$index;
				else
					$newindex = $item->$index . '-' . $item->$index2;
			}
			elseif (is_array($item)) {
				if ( $index2 == '' )
					$newindex = $item[$index];
				else
					$newindex = $item[$index] . '-' . $item[$index2];
			}
			$ret[$newindex] = $item;
		}
		return $ret;
	}

	private function is_mycourse($courseid, $userid) {
		if ( !osa_is_int($courseid) || $courseid<=0 ) {
			return FALSE;
		}
		$cachekey = "mycourses";
		if ( ($cache_value = $this->cms_cache->db_get(__METHOD__, $cachekey)) !== NULL ) {
			$mycourses = &$cache_value;
		}
		else {
			$this->load->model('menu/menu_model');
			$mycourses = $this->menu_model->mycourses($userid);
			if ( !is_array($mycourses) || count($mycourses) <= 0 ) {
				$mycourses = FALSE;
			}
			else {
				$tmp_array = array();
				foreach ($mycourses as $record) {
					$tmp_array[$record['id']] = TRUE;
				}
				$mycourses = &$tmp_array;
			}
			$this->cms_cache->db_add(__METHOD__, $cachekey, $mycourses);
		}
		//At this point we have $mycourses either from cache or from DB
		if ( empty($mycourses) || !is_array($mycourses) ) {
			return FALSE;
		}
		if ( isset($mycourses[$courseid]) ) {
			return TRUE;
		}
		return FALSE;
	}
}
?>