<?php
/**
 * FILE_NAME_HERE - FILE_DESCRIPTION_HERE
 *
 * @author $Author: dtong $
 * @version $Id: resource_model.php,v 1.19 2011/05/10 16:11:56 dtong Exp $
 * @copyright Copyright (c) 2009, Tiller Software Co., Ltd.
*/

class Resource_model extends CI_Model {
	//We need this becuase funtion get_res_urls() is used in multiple functions
	//all of them don't need prefetch except one. Use this to tell get_res_urls() to use prefetch.
	//This is the template filepart like ubd, pyp and prefetch needs to know.

	private $skip_non_prefetch = FALSE;
	public $prefetch_filepart = FALSE;

	function __construct() {
		parent::__construct();
		$this->load->library('cms/cms_prefetch');
		osa_load_lang('general');
		osa_load_lang('unit');
    }

	function insert($data, $files, $pid1=FALSE, $pid2=FALSE) {
		$selections = FALSE;
		if ( isset($data->selects_data) ) {
			$selections = $data->selects_data;
			unset($data->selects_data);
		}
		$data->createdate = osa_dbdate();
		$this->db->trans_begin();
			$this->db->insert('resource', $data);
			$resid = osa_db_lastinsertid($this->db);
			if ( is_numeric($resid) && $resid>0 && $data->unitid == 0 && $pid1 !== FALSE ) {
				//update the resource_link table
				$linkdata->resourceid = $resid;
				$linkdata->pid1 = $pid1;
				if ($pid2 !== FALSE)
					$linkdata->pid2 = $pid2;
				$linkdata->type = $data->type;
				$this->db->insert('resource_link', $linkdata);
			}
			$this->add_files($resid, $files);
			$this->update_selections($resid, $selections);
		if ($this->db->trans_status() === FALSE || !is_numeric($resid) ||  $resid < 1) {
		    $this->db->trans_rollback();
		    return FALSE;
		}
		else {
		    $this->db->trans_commit();
		    return $resid;
		}
	}

	function update($data, $unitid, $resid, $files, $deletefiles) {
		if ( !is_numeric($unitid) || !is_numeric($resid) ) {
			return FALSE;
		}
		$selections = FALSE;
		//$select_rows = FALSE;
		if ( isset($data->selects_data) ) {
			$selections = $data->selects_data;
			unset($data->selects_data);
			//Selections are no longer inside the resource table
			//Get the current DB selections for this resource
			/*$this->db->where('resourceid', $resid);
			$res = $this->db->get('resource_select');
			if ( $res->num_rows() > 0 )
				$select_rows = $res->result();*/
		}
		$user = & osa_login_object();
		if ( is_object($user) && isset($user->id) ) {
			$data->modifierid = $user->id;
		}
		$data->modifydate = osa_dbdate();

		$this->db->trans_start();
			$this->db->where('id', $resid);
			$this->db->where('unitid', $unitid);
			$this->db->update('resource', $data);
			$this->delete_files($resid, $deletefiles);
			$this->add_files($resid, $files);
			$this->update_selections($resid, $selections, TRUE);
		$this->db->trans_complete();
    	return $this->db->trans_status();
	}

	/*
	 * Get all the selections for a resource
	 */
	function get_selections($resid) {
   	if ( !is_numeric($resid) )
   		return FALSE;
   	$this->db->where('resourceid', $resid);
   	$this->db->order_by('type,choice');
   	$res = $this->db->get('resource_select');
   	if ( $res->num_rows() <= 0 )
			return FALSE;
		return $res->result();
   }

	/*
    * Get all the selections for a resource type in a unit
    * Group the selections by resourceid in a 2-d array
    */
   /*
   function get_selections_by_restype($unitid, $type) {
   	if ( !is_numeric($unitid) || !is_numeric($type) )
   		return FALSE;
   	//$this->db->select('r.id as resid, r.courseid, r.unitid, r.type, s.type sel_type, s.choice');
   	$this->db->select('r.id as resid, s.type, s.choice');
   	$this->db->from('resource as r');
   	$this->db->join('resource_select as s', 'r.id=s.resourceid');
   	$this->db->where('r.unitid', $unitid);
   	$this->db->where('r.type', $type);
   	$this->db->order_by('r.id,s.type', 'asc');
   	$res = $this->db->get();
   	if ( $res->num_rows() <= 0 )
   		return FALSE;
   	$rows = $res->result();
   	$retarray = array();
   	//Build the data structure to be used in the dropdown function for each select in each resource
   	//The index is resource id and select type joined by '_'
   	foreach ($rows as $row) {
   		$index = $row->resid . '_' . $row->type;
   		if (!array_key_exists($index, $retarray)) {
   			$retarray[$index] = array();
   		}
   		$retarray[$index][] = $row->choice;
   	}
   	return $retarray;
   }
	*/
	function get_selections_by_restype($unitid, $restype, $file_part) {
		if ( !osa_is_int_one($unitid) || (!osa_is_int_one($restype) && !osa_is_int_one_array($restype)) ) {
			return FALSE;
		}
		//Make sure you know prefetch is not affected before changing any field.
		$fields = 'r.id resid,r.type,s.type select_type,s.choice';
		$this->skip_non_prefetch = FALSE;

		//Prefetch set and get
		if ( $this->config->item('cms_db_prefetch_enable_resource') && $this->cms_prefetch->enabled() ) {
			$res_table = $this->db->dbprefix('resource');
			$select_table = $this->db->dbprefix('resource_select');
			$types = $this->cms_template->types_exclude_stages_usehidden(FALSE, $file_part, 'resource');
			$sql = "select $fields from $res_table r " .
					 "join $select_table s on r.id=s.resourceid " .
					 "where r.unitid={$unitid} and r.type in ({$types})";
			if ( $types && $this->cms_prefetch->reset(__METHOD__, $unitid, $file_part) ) {
				if ( $this->cms_prefetch->set_sql($sql) ) {
					if ( !($rows = $this->cms_prefetch->get($restype)) ) {
						//No data so return false, just like the non-prefetch code
						return FALSE;
					}
					//We have data that needs to be hashed by resource id below and need
					//to tell the non-prefetch code not to run.
					$this->skip_non_prefetch = TRUE;
				}
				else {
					//Soemthing went wrong turn off all susequent resource prefetch
					$this->resource_prefetch_off(__METHOD__);
				}
			}
			else {
				//Soemthing went wrong turn off all susequent resource prefetch
				$this->resource_prefetch_off(__METHOD__);
			}
		}

		//Non-prefetch
		if ( !$this->skip_non_prefetch ) {
	   	$this->db->select($fields);
	   	$this->db->from('resource as r');
	   	$this->db->join('resource_select as s', 'r.id=s.resourceid');
	   	$this->db->where('r.unitid', $unitid);
	   	if ( is_array($restype) ) {
				$this->db->where_in('r.type', $restype);
	   	}
			else {
				$this->db->where('r.type', $restype);
			}
	   	//$this->db->order_by('r.id, s.type', 'asc');
	   	$res = $this->db->get();
	   	if ( $res->num_rows() <= 0 )
				return FALSE;
	   	$rows = $res->result();
		}

   	//Build the data structure to be used in the dropdown function for each select in each resource
   	//The index is resource id and select type joined by '_'
   	$retarray = array();
   	foreach ($rows as $row) {
   		$index = $row->resid . '_' . $row->select_type;
   		if (!array_key_exists($index, $retarray)) {
   			$retarray[$index] = array();
   		}
   		$retarray[$index][] = $row->choice;
   	}
   	return $retarray;
	}

	function update_selections($resid, $selections, $is_update=FALSE) {
		if ( !is_array($selections) || !is_numeric($resid) )
			return;
		$values = ''; $sep='';
		foreach($selections as $type=>$choices) {
			//_select1: type is 1, _select2: type is 2 and so on
			if ( !is_numeric($type) || $type < 1 )
				continue;
			foreach($choices as $choice) {
				if ( is_numeric($choice) && $choice>0 ) {
					$values .= $sep . "($resid,$type,$choice)";
					$sep=',';
				}
			}
		}
		if ($is_update) {
			$this->db->where('resourceid', $resid);
			$this->db->delete('resource_select');
		}
		if ($values != '') {
			$table = $this->db->dbprefix('resource_select');
			$sql = "insert into $table (resourceid,type,choice) values $values";
			$this->db->query($sql);
		}
	}

	function delete_files($resid, $files) {
		if (!is_numeric($resid) || $files === FALSE || !is_array($files))
			return FALSE;
		$this->db->where_in('id', $files);
		$this->db->where('resourceid', $resid);
		$this->db->delete('upload');
	}

	function add_files($resid, $files) {
		if ( !is_array($files) || !is_numeric($resid) )
			return FALSE;

		if ( count($files) > 0 ) {
			$table = $this->db->dbprefix('upload');
			$sql = "insert into $table (resourceid,size,filename) values ";
			$sep = '';
			foreach($files as $file) {
				$tmp_filename = $this->db->escape_str($file['name']);
				if ( array_key_exists('size', $file) && array_key_exists('name', $file) ) {
					$sql .= $sep . "({$resid},{$file['size']},'{$tmp_filename}')";
					$sep = ',';
				}
			}
			if ($sep == ',') { //Make sure we have insert values
				return $this->db->query($sql);
			}
		}
		return TRUE;
	}

	function delete($unitid, $resid) {
		if ( !is_numeric($unitid) || !is_numeric($unitid) )
			return FALSE;
		$resobj = $this->get_resource($unitid, $resid);
		if ( !$resobj )
			return FALSE;

		/*if ( ($filename = osa_uploadfilepath($resobj))) {
			if ( ($deletefile = osa_uploadfolder_deleted($resobj))) {
				$deletefile .= '/' . $resobj->upload1;
			}
		}*/

		$this->db->where('resourceid', $resid);
		$res = $this->db->get('upload');
		//$filearray = array();
		//$upload_ids = '';
		$id_array = array();
		if ( $res->num_rows > 0 ) {
			$objs = $res->result();
			//$sep = '';
			foreach ($objs as $obj) {
				//$filearray[] = array('orig'=>osa_uploadfilepath($resobj, $obj),
											//'delete'=>osa_uploadfolder_deleted($resobj) . "/{$obj->filename}");
				//$upload_ids .= $sep . $obj->id;
				//$sep = ',';
				$id_array[] = $obj->id;
			}
		}

		//$table = $this->db->dbprefix('upload');
		//$sql = 'delete $table';
		$this->db->trans_start();
			if ( count($id_array) > 0 ) {
				$this->db->where_in('id', $id_array);
				$this->db->delete('upload');
			}
			$this->db->where('resourceid', $resid);
			$this->db->delete('resource_link');

			//delete resource url
			$table_resource_url = $this->db->dbprefix('resource_url');
			$this->db->where('resourceid', $resid);
			$this->db->delete($table_resource_url);

			//delete res_sort
			$table_res_sort = $this->db->dbprefix('res_sort');
			$this->db->where('fk1', $unitid);
			$this->db->where('fk3', $resid);
			$this->db->delete($table_res_sort);

			$this->db->where('id', $resid);
			$this->db->where('unitid', $unitid);
			$this->db->delete('resource');
		$this->db->trans_complete();

		if ($this->db->trans_status() === FALSE) {
			return FALSE;
		}
		//Keeping everything becuase it will get deleted when a unit becomes archived or deleted
		/*
		foreach ($filearray as $file) {
			$filename = $file['orig'];
			$deletefile = $file ['delete'];
			//Save deleted file to folder deleted
			//Don't care much about error here
			if ( is_file($deletefile)) {
				//unlink($deletefile);
				@osa_rename($deletefile, $deletefile . '_' . time());
			}
			@osa_rename($filename, $deletefile);
		}*/

		//Just to mark the folder as deleted by addind this directory
		//This is easier to check in the file system
		//osa_mkdir(osa_uploadfolder_deleted($resobj, $resid));
		if ( is_numeric($resobj->courseid) && is_numeric($resobj->unitid) && is_numeric($resobj->type) )
			osa_remove_uploaddir($resobj->courseid, $resobj->unitid, $resobj->type, $resid);
		return TRUE;
	}

	/*
	 * Get resource records by unitid and resource type
	 * It is like getting all the Enduring understaning records etc.
	 * $use_groupid is for static resource so we always use the first unitid which is also the gorupid
	 */
	function get_resources($unitid, $restype, $file_part, $use_groupid=FALSE) {
		if ( !osa_is_int_one($unitid) || (!osa_is_int_one($restype) && !osa_is_int_one_array($restype))) {
   		return FALSE;
		}

		$table = $this->db->dbprefix('resource');
		$sql = "select * from $table where unitid={$unitid} and ";
		$sql_override = FALSE;
		if ( $use_groupid ) {
			//For static resource. Does not support multi-type yet.
			$unit_table = $this->db->dbprefix('unit');
			$sql_override = "select r.* from $table r " .
								 "join $unit_table u on u.id={$unitid} and r.unitid=u.groupid and r.type={$restype}";
		}
		//Prefetch set and get. This is not used for static types ($use_groupid) since they point to old unitids
		if ( $this->config->item('cms_db_prefetch_enable_resource') && $this->cms_prefetch->enabled() && !$use_groupid ) {
			if ( $this->cms_prefetch->reset(__METHOD__, $unitid, $file_part) ) {
				//Hidden types not needed but this is the only call can support a module without telling the stage.
				//The hidden types should not affect performance much.
				$types = $this->get_prefetch_types($file_part);
				if ( $types ) {
					$tmp_sql = "{$sql}type in ($types)";
					if ( $this->cms_prefetch->set_sql($tmp_sql, array('type','text1','id')) ) {
						$tmp = $this->cms_prefetch->get($restype);
						return $tmp;
					}
				}
			}
			//If the return $tmp did not happen then it will get here.
			//This will continue to the non-prefecth code. All subsequent resource prefetches
			//in this model will be disabled for the session.
			$this->resource_prefetch_off(__METHOD__);
		}

		//Non-prefetch query
		if ( is_array($restype) ) {
			$tmp = osa_getarrayvalue($restype);
			$sql .= "type in ({$tmp})";
		}
		else {
			$sql .= "type={$restype}";
		}
		if ( $sql_override ) {
			//This is for the static resource type. Uses the groupid as the unitid.
			$sql = $sql_override;
		}
		$resobj = $this->db->query($sql);
	   if ( $resobj->num_rows() <= 0 ) {
			return FALSE;
	   }
		$ret= $resobj->result();
		//Sorting consistent with prefetch
		osa_array_natsort($ret, array('text1','id'));
		return $ret;
   }

   /*
    * Get one resource
    * Don't really need the unitid, but just to make sure it is the right resource for the unit
    */
   function get_resource($unitid, $resid) {
   	if ( !is_numeric($unitid) || !is_numeric($resid) )
   		return FALSE;
   	$this->db->where('id', $resid);
		$this->db->where('unitid', $unitid);
		$resobj = $this->db->get('resource');
	   if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();
		//return $rows[0];
		$row = $rows[0];
		$selects = $this->get_selections($resid);
		if (!$selects)
			return $row;
		//Add the selects as arrays to the db result
		//It is like the old select1, selects except that are arrays instead of integrers
		foreach($selects as $select) {
			$type = $select->type;
			$choice = $select->choice;
			$select_member = 'select' . $type;
			//if ( !isset($row->$select_member) && !is_null($row->$select_member) )
			if ( !property_exists($row, $select_member) || is_null($row->$select_member) )
				$row->$select_member = array();
			//How to use address of array? Had to recopy array below
			$tmp = $row->$select_member;
			$tmp[] = $choice;
			$row->$select_member = $tmp;
		}
		return $row;
   }

   /*
    * Get all the uploads for a resource type in a unit
    * Group the uploads by resourceid in a 2-d array
    */
   /*
   function get_uploads($unitid, $type) {
   	if ( !is_numeric($unitid) || !is_numeric($type) )
   		return FALSE;
   	$this->db->select('r.id as resid, r.courseid, r.unitid, r.type, u.*');
   	$this->db->from('resource as r');
   	//$this->db->join('upload as u', 'r.id=u.resourceid', 'right');
   	$this->db->join('upload as u', 'r.id=u.resourceid');
   	$this->db->where('r.unitid', $unitid);
   	$this->db->where('r.type', $type);
   	$this->db->order_by('resid,filename', 'asc');
   	$res = $this->db->get();
   	if ( $res->num_rows() <= 0 )
   		return FALSE;
   	$rows = $res->result();
   	$retarray = array();
   	//Build the data structure in a 2-d array
   	foreach ($rows as $row) {
   		if (!array_key_exists($row->resid, $retarray)) {
   			$retarray[$row->resid] = array();
   		}
   		$retarray[$row->resid][] = $row;
   	}
   	return $retarray;
   }
	*/
   //Get the upload records for a resource
	function get_uploads($unitid, $restype, $file_part) {
		if ( !osa_is_int_one($unitid) || (!osa_is_int_one($restype) && !osa_is_int_one_array($restype)) ) {
			return FALSE;
		}

		//Make sure you know prefetch is not affected before changing any field.
		$fields = 'r.id as resid,r.courseid,r.unitid,r.type,u.size length,u.*';
		$this->skip_non_prefetch = FALSE;

		//Prefetch set and get
		if ( $this->config->item('cms_db_prefetch_enable_resource') && $this->cms_prefetch->enabled() ) {
			$res_table = $this->db->dbprefix('resource');
			$upload_table = $this->db->dbprefix('upload');
			$types = $this->cms_template->types_exclude_stages_usehidden(FALSE, $file_part, 'resource');
			$sql = "select $fields from $res_table r " .
					 "join $upload_table u on r.id=u.resourceid " .
					 "where r.unitid={$unitid} and r.type in ({$types})";
			if ( $types && $this->cms_prefetch->reset(__METHOD__, $unitid, $file_part) ) {
				if ( $this->cms_prefetch->set_sql($sql, array('type', 'filename')) ) {
					if ( !($rows = $this->cms_prefetch->get($restype)) ) {
						//No data so return false, just like the non-prefetch code
						return FALSE;
					}
					//We have data that needs to be hashed by resource id below and need
					//to tell the non-prefetch code not to run.
					$this->skip_non_prefetch = TRUE;
				}
				else {
					//Soemthing went wrong turn off all susequent resource prefetch
					$this->resource_prefetch_off(__METHOD__);
				}
			}
			else {
				//Soemthing went wrong turn off all susequent resource prefetch
				$this->resource_prefetch_off(__METHOD__);
			}
		}

		//Non-prefetch DB query
   	if ( !$this->skip_non_prefetch ) {
   		$this->db->select($fields);
	   	$this->db->from('resource as r');
	   	$this->db->join('upload as u', 'r.id=u.resourceid');
	   	$this->db->where('r.unitid', $unitid);
		   if ( is_array($restype) )
				$this->db->where_in('r.type', $restype);
			else
				$this->db->where('r.type', $restype);
		   //$this->db->order_by('resid, filename', 'asc');
		   //Sorting consistent with prefetch
		   $this->db->order_by('filename');
		   $res = $this->db->get();
		   if ( $res->num_rows() <= 0 )
		   	return FALSE;
		   $rows = $res->result();
   	}

   	//This is used by both prefetch and non-prefetch
	   //Build the data structure in a 2-d array
	   $retarray = array();
	   foreach ($rows as $row) {
	   	if (!array_key_exists($row->resid, $retarray)) {
	   		$retarray[$row->resid] = array();
	   	}
	   	$retarray[$row->resid][] = $row;
	   }
	   return $retarray;
   }

   /*
    * Get uploads for a particular resource
    */
   function get_uploads_byresource($resid) {
   	if ( !is_numeric($resid) )
   		return FALSE;
   	$this->db->where('resourceid', $resid);
   	$this->db->order_by('filename', 'asc');
   	$res = $this->db->get('upload');
   	 if ( $res->num_rows() <= 0 )
			return FALSE;
		$rows = $res->result();
		return $rows;
   }

   function get_uploads_byids($upload_ids, $resid) {
   	if ( !is_array($upload_ids) || !is_numeric($resid) )
   		return FALSE;
   	$this->db->where('resourceid', $resid);
   	$this->db->where_in('id', $upload_ids);
   	$res = $this->db->get('upload');
   	if ( $res->num_rows() <= 0 )
			return FALSE;
		$rows = $res->result();
		return $rows;
   }

   /*
    * Check to see does a resource has uploads
    */
   function has_upload($resid){
   	if ( !is_numeric($resid) )
   		return FALSE;
   	$this->db->where('resourceid', $resid);
   	$res = $this->db->get('upload');
   	if ( $res->num_rows() > 0 )
   		return TRUE;
   	else
   		return FALSE;
   }

   function download_info($uploadid) {
   	if ( !is_numeric($uploadid) )
   		return FALSE;
   	$this->db->select('r.*, u.size, u.filename, u.id as uploadid');
   	$this->db->from('upload as u');
   	$this->db->join('resource as r', 'u.resourceid=r.id', 'inner');
   	$this->db->where('u.id', $uploadid);
   	$res = $this->db->get();
   	if ( $res->num_rows() <= 0 )
			return FALSE;
		$rows = $res->result();
		return $rows[0];
   }

   function get_resource_single($unitid, $type) {
   	$this->db->where('unitid', $unitid);
		$this->db->where('type', $type);
		$resobj = $this->db->get('resource');
		if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();
		return $rows[0];
   }
	function get_resource_compare($unitid, $type) {
   	$this->db->where('unitid', $unitid);
		$this->db->where('type', $type);
		$resobj = $this->db->get('resource');
		if ( $resobj->num_rows() <= 0 )
			return FALSE;
		$rows = $resobj->result();
		$result = array();
		foreach($rows as $value) {
			$result[$value->id] = $value;
		}
		return $result;
   }

   /*
    * Check for my courses, admin
    */
   function is_teacher($userid, $courseid) {
      $this->db->where('userid',$userid);
      $this->db->where('courseid',$courseid);
      $resobj = $this->db->get('user_course');
   	if ( $resobj->num_rows() > 0 )
   		return TRUE;
   	return FALSE;
   }
   //multi url
	function insert_res_urls($resid, $urls_data) {
		if ( !is_array($urls_data['urls_add']) || !is_numeric($resid) )
			return;
		$table_resource_url = $this->db->dbprefix('resource_url');
		$values = '';
		$sep='';
		foreach($urls_data['urls_add'] as $key=>$url) {
				if ( isset($url) && $url !== FALSE ) {
					$values .= $sep . "($resid,'$url')";
					$sep=',';
				}
		}
		if ($values != '') {
			$sql = "insert into $table_resource_url (resourceid,url) values $values";
			$this->db->query($sql);
		}
	}
	function update_res_urls($resid, $urls_data) {
		if (!is_numeric($resid) )
			return;
		$table_resource_url = $this->db->dbprefix('resource_url');
		$data = FALSE;
		//Update
		if ( is_array($urls_data['urls_update']) && count($urls_data['urls_update']) > 0){
			foreach($urls_data['urls_update'] as $key=>$url) {
				if ( isset($url) && $url !== FALSE ) {
					$data->url = $url;
					$this->db->where('id', $key);
					$this->db->where('resourceid', $resid);
					$this->db->update($table_resource_url, $data);
				}
			}
		}
		//Add
		if ( is_array($urls_data['urls_add']) && count($urls_data['urls_add']) > 0){
			$this->insert_res_urls($resid, $urls_data);
		}
		//Delete
		if ( is_array($urls_data['urls_delete']) && count($urls_data['urls_delete']) > 0){
				$this->db->where('resourceid', $resid);
				$this->db->where_in('id', $urls_data['urls_delete']);
				$this->db->delete($table_resource_url);
		}

	}
	function get_res_urls($unitid,$type,$resid=FALSE,$is_edit=FALSE) {
		if ( !osa_is_int($unitid) ) {
   		return FALSE;
		}
		$table_resource = $this->db->dbprefix('resource');
		$table_resource_url = $this->db->dbprefix('resource_url');
	   $fields = 'r.id as resid, r.courseid, r.unitid, r.type, ru.*';
		$table = "$table_resource r";
		$join_cond = "$table_resource_url ru on r.id=ru.resourceid";
		$cond = "r.unitid={$unitid}";

		$this->skip_non_prefetch = FALSE;

		//Have to use a class var for filepart so we don't change the function interface
		//since there are functions call this function that don't need prefetch
		if ( $this->prefetch_filepart ) {
			//We know unit_resource doesn't not need $resid and $is_edit
			if ( $this->config->item('cms_db_prefetch_enable_resource') && $this->cms_prefetch->enabled() ) {
				$types = $this->cms_template->types_exclude_stages_usehidden(FALSE, $this->prefetch_filepart, 'resource');
				$tmp_sql = "select $fields from $table join $join_cond where $cond and r.type in ({$types})";
				if ( $types && $this->cms_prefetch->reset(__METHOD__, $unitid, $this->prefetch_filepart) ) {
					if ( $this->cms_prefetch->set_sql($tmp_sql, array('type', 'url')) ) {
						if ( !($rows = $this->cms_prefetch->get($type)) ) {
							//No data so return false, just like the non-prefetch code
							return FALSE;
						}
						//We have data that needs to be hashed by resource id below and need
						//to tell the non-prefetch code not to run.
						$this->skip_non_prefetch = TRUE;
					}
					else {
						//Soemthing went wrong turn off all susequent resource prefetch
						$this->resource_prefetch_off(__METHOD__);
					}
				}
				else {
					//Soemthing went wrong turn off all susequent resource prefetch
					$this->resource_prefetch_off(__METHOD__);
				}
			}
		}

		//Non-prefetch DB query
		if ( !$this->skip_non_prefetch ) {
		if (is_array($type)){
			$type = implode(',',$type);
	   		$cond .= " and r.type in ({$type})";
   	}
   	else{
	   		$cond .= " and r.type={$type}";
	   	}
			if ($resid != FALSE) {
				$cond .= " and ru.resourceid={$resid}";
   	}

			$query = "select $fields from $table join $join_cond where $cond order by ru.url";
		$res = $this->db->query( $query );

	   	if ( $res->num_rows() <= 0 ) {
   		return FALSE;
	   	}
   	$rows = $res->result();
	   	//Sorting consistent with prefetch
			osa_array_natsort($rows, array('url'));
		}

   	if ( $is_edit ) {
   		return $rows;
   	}
		$urls =array();
		if (isset($rows) && $rows != FALSE){
			foreach ($rows as $value ){
				$urls[$value->resid][] = $value;
			}
		}
   	return $urls;
	}

	function get_coursenames_by_groupids($groupids) {
		if ( $groupids == FALSE || !is_array($groupids) || count($groupids) == 0 )
			return FALSE;

		$this->db->select('u.groupid,u.title unittitle,u.hidden u_hidden,c.name,c.id courseid,c.hidden c_hidden');
	   $this->db->from('unit u');
	   $this->db->join('course_sis c', 'c.id=u.courseid and c.enabled = '.CMS_ADMIN_ENABLE);
	   $this->db->where_in('u.groupid',$groupids);
	   $this->db->where('u.status',CMS_UNIT_STATUS_PUBLISH);

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

	private function resource_prefetch_off($method) {
		osa_log($method, 'Resource prefetch is turned off due to abnormal behavior or single type stage refresh.');
		$this->config->set_item('cms_db_prefetch_enable_resource', FALSE);
		$this->skip_non_prefetch = FALSE;
}

	private function get_prefetch_types($file_part) {
		if ( $this->cms_prefetch->get_stage_hint() ) {
			if ( ($types = $this->cms_template->types($file_part, $this->cms_prefetch->get_stage_hint(), 'resource')) ) {
				//No comma means single type
				if ( strpos($types, ',') === FALSE ) {
					//If there is only one then just turn off prefetch. This will get to btnsort too
					//since it uses the same cms_prefetch library. This will result an error log message
					//but error log is turned off in production so it is ok.
					$this->cms_prefetch->disable();
					//Returning false just forces the executing code to use the non-prefetch code.
					//It might think it is an prefetch error and print some log messages...
					//This is getting so complex, afraid no one in the company can handle this prefetch sub-system...
					return FALSE;
				}
				return $types;
			}
		}
		//If the above fails then default to this.
		return $this->cms_template->types_exclude_stages_usehidden(FALSE, $file_part, 'resource');
	}

}
