<?php
/**
 * MY_Loader adding ajax support extending CI_Loader
 *
 * @category	Libraries
 * @author		David Mulder
 * @link		http://codeigniter.com/forums/viewthread/191441/	
 */
 
class MY_Loader extends CI_Loader {
	
	protected $javascriptBaseNeedOutput = true;

	/**
	 * Ajax proxy
	 *
	 * Acts as the actual proxy between javascript and the php model. It is 
	 * loaded from a controller which is called with post data containing
	 * a modelname and method.
	 *
	 * @output 	json	JSON encoded object returned from the model
	 */
	function ajax_proxy(){
		
		$CI =& get_instance();		
		$this->model($_POST['model']);
		$per = $CI->$_POST['model']->__JS();
		
		if($per===true or (array_key_exists('type',$per) and $per['type']=="excluded")){
			
			$excluded_methods = array("__construct","__get","__JS");
			
			if($per['type']=="excluded"){
				$excluded_methods = array_merge($excluded_methods,$per['methods']);
			}
			
			if(in_array($_POST['method'],$excluded_methods)){
				echo json_encode(array("error"=>"PERMISSION DENIED")); return false;
			}
			
		}else if(array_key_exists('type',$per) and $per['type']=="included"){
			
			if(!in_array($_POST['method'],$per['methods'])){
				echo json_encode(array("error"=>"PERMISSION DENIED")); return false;	
			}
			
		}else{
			
			echo json_encode(array("error"=>"PERMISSION DENIED")); return false;	
			
		}
		
		echo @json_encode(call_user_func_array(array($CI->$_POST['model'],$_POST['method']),json_decode($_POST['data'],true)));
	}

	/**
	 * Ajax model
	 *
	 * Loads the javascript code which initializes the javascript object and  
	 * outputs the necessary backend code.
	 *
	 * It should be used in the header portion of a template
	 *
	 * @param 	string	model being loaded
	 * @param 	string	javascript name of the model
	 * @output 	string	JS Code which initializes the model
	 */
	function ajax_model($name, $js_name =''){
		
		$CI =& get_instance();
		
		if (in_array($name, $this->_ci_models, TRUE)){
		
			$newname = $name;
		
		}else{
		
			$newname = "AJAX_".$name;
			$this->model($name,$newname);
		
		}
		
		$per = $CI->$newname->__JS();
		
		if($per===true or (array_key_exists('type',$per) and $per['type']=="excluded")){
		
			$excluded_methods = array("__construct","__get","__JS");
		
			if($per['type']=="excluded"){
				$excluded_methods = array_merge($excluded_methods,$per['methods']);
			}
			
			$methods = get_class_methods($CI->$newname);
			
			foreach($methods as $key=>$method){
				if(in_array($method,$excluded_methods)){
					unset($methods[$key]);	
				}
			}
			
		}else if(array_key_exists('type',$per) and $per['type']=="included"){
		
			$methods = $per['methods'];
		
		}else{
		
			return false;		
		
		}
		
		echo "<script>\n";
		if($this->javascriptBaseNeedOutput){
			
			//Output javascript backend code needed to handle the ajax requests
			echo   "\tfunction makeRequest(model,method,data) {";
			echo "\n\t\tif (window.XMLHttpRequest) { // Mozilla, Safari, �";
			echo "\n\t\t\thttpRequest = new XMLHttpRequest();";
			echo "\n\t\t} else if (window.ActiveXObject) { // IE";
			echo "\n\t\t\ttry {";
			echo "\n\t\t\t\thttpRequest = new ActiveXObject('Msxml2.XMLHTTP');";
			echo "\n\t\t\t}"; 
			echo "\n\t\t\tcatch (e) {";
			echo "\n\t\t\t\ttry {";
			echo "\n\t\t\t\t\thttpRequest = new ActiveXObject('Microsoft.XMLHTTP');";
			echo "\n\t\t\t\t}"; 
			echo "\n\t\t\t\tcatch (e) {}";
			echo "\n\t\t\t}";
			echo "\n\t\t}";
			echo "\n\t\thttpRequest.open('POST', '".$CI->config->site_url($CI->config->item('ajax_proxy'))."', false);";
			echo "\n\t\tvar formData = new FormData();";
			echo "\n\t\tformData.append('model', model);";
			echo "\n\t\tformData.append('method', method);";
			echo "\n\t\tformData.append('data', data);";
			echo "\n\t\thttpRequest.send(formData);";
			echo "\n\t\tif (httpRequest.readyState === 4) {";
			echo "\n\t\t\tif (httpRequest.status === 200) {";
			echo "\n\t\t\t\treturn JSON.parse(httpRequest.responseText);";	
			echo "\n\t\t\t}else{";
			echo "\n\t\t\t\treturn 'There was a problem with the request.';";
			echo "\n\t\t\t}";
			echo "\n\t\t}";
			echo "\n\t}\n";
			
			$this->javascriptBaseNeedOutput = false;
			
		}
		
		echo "\tfunction CI_".$name."(){\n";
		foreach($methods as $method){
			echo "\t\tthis.".$method." = function(){return makeRequest('".$name."','".$method."',JSON.stringify(arguments))}\n";
		}
		echo "\t}\n";
		
		if($js_name == "") $js_name = $name;
		echo "\t$js_name = new CI_$name();\n";
		
		
		echo "</script>\n";
	}
}