<?php

// In : utf8 url_encoded (get et post)
// Out : utf8 


// TODO : gerer les retours : dans ce controleur : code retour et envoi ...
class JRest {
    
  /**
     * Parsed configuration file
     * @var str[]
     */
    var $config;
    
    /**
     * The HTTP request method used.
     * @var str
     */
    var $method = 'GET';

    /**
     * The HTTP request data sent (if any).
     * @var str
     */
    var $requestData = NULL;

    
    /**
     * Array of strings to convert into the HTTP response.
     * @var str[]
     */
    var $output = array();
   
    /** Nom resource   */
    var $resource = NULL;
    
    /** Identifiant unique resource 
     */
     
    var $uid = NULL;
     



    /**
     * Constructor. Parses the configuration file "JRest.ini", grabs any request data sent, records the HTTP
     * request method used and parses the request URL to find out the requested resource
     * @param str iniFile Configuration file to use
     */
     
    function JRest($iniFile="jrest.ini.php") {
        
        $this->config = parse_ini_file($iniFile, TRUE);
        if (isset($_SERVER['REQUEST_URI']) &&
            isset($_SERVER['REQUEST_METHOD']) && 
            isset($_SERVER['QUERY_STRING'])) {
	    
            if (isset($_SERVER['CONTENT_LENGTH']) &&
                $_SERVER['CONTENT_LENGTH'] > 0) {
	
                $this->requestData = '';
                $httpContent = fopen('php://input', 'r');
                while ($data = fread($httpContent, 1024)) {
                    $this->requestData .= $data;
                }
                fclose($httpContent);
            }
		
			if (strlen($_SERVER['QUERY_STRING'])==0) {
			 $len=strlen($_SERVER['REQUEST_URI']);
		    }	
	    	else {
               $len=-(strlen($_SERVER['QUERY_STRING']) + 1);
	    	}
            $urlString = substr($_SERVER['REQUEST_URI'], strlen($this->config['settings']['baseURL']),$len);

            $urlParts = explode('/', $urlString);

            if (isset($urlParts[0])) $this->resource = $urlParts[0];
            if (count($urlParts) > 1 && $urlParts[1] != '') {
                array_shift($urlParts);
                foreach ($urlParts as $uid) {
                    if ($uid != '') {
                        $this->uid[] = urldecode($uid);
                    }
                }
            }
            
            $this->method = $_SERVER['REQUEST_METHOD'];
	    
        } else {
            trigger_error('I require the server variables REQUEST_URI, REQUEST_METHOD and QUERY_STRING to work.', E_USER_ERROR);
        }
    }
    
    /**
     * Execute the request.
     */
    function exec() {
	
        switch ($this->method) {
            case 'GET':
                $this->get();
                break;
            case 'POST':
                $this->post();
                break;
        }
   
        
    }

    
    /**
     * Execute a GET request. A GET request fetches a list of resource when no resource name is given, a list of element 
     * when a resource name is given, or a resource element when a resource and resource unique identifier are given. It does not change the
     * database contents.
     */
    function get() {

        if ($this->resource) {
                $resource_file ='services/'.ucfirst($this->resource).'.php';
                $resource_class =ucfirst($this->resource);
                if (file_exists($resource_file)) {    
                    include_once $resource_file; 
					if (class_exists($resource_class)) {
						$service = new $resource_class($this->config);
		                if ($this->uid) { // get a resource element 
							if (method_exists($service,'getElement')) {
								$service->getElement($this->uid);
							}
		                }
		                else { // get all elements of a ressource
		                	if (method_exists($service,'getRessource')) {
								$service->getRessource();
							}
		                }
					}
                }
        }
					
        else { // get resources
// include set.jrest.php, instanticiation et appel

        }
        
        
    }


    function post() {
    
   	$pairs = array() ; 
	
	// Safari ne sait pas envoyer des DELETE avec gwt ... et en plus c'est bien plus simple comme ca !
         if ($this->requestData) {
             $pairs = $this->parseRequestData();
         }
	
         if ($pairs['action']=='DELETE') {
         	$this->delete();
         	return;
         }
    
	// gestion de l'upload de fichiers
	if(isset($_FILES))
	{
	
		$pairs_and_files = array()  ;
	
		foreach($_FILES as $file)
		{
			
			$pairs_and_files = array_merge($pairs,$file) ;
		}
		
		if(sizeof($pairs_and_files) != 0)
		{
			$pairs = $pairs_and_files ;
		}
	} 
	
	// gestion du contenu du post
	if(isset($_POST))
	{
	
		$pairs_and_post = array()  ;
	
		foreach($_POST as $post)
		{
			
			$pairs_and_post = array_merge($pairs,$post) ;
		}
		
		if(sizeof($pairs_and_post) != 0)
		{
			$pairs = $pairs_and_post ;
		}
	} 

         $resource_file ='services/'.ucfirst($this->resource).'.php';
         $resource_class =ucfirst($this->resource);
         if (file_exists($resource_file)) { 
             include_once $resource_file; 
	    
		     if (class_exists($resource_class)) 
		     {
				$service = new $resource_class($this->config);
				
				if ($this->uid) { // get a resource element 
				
				
				    if (count($pairs) != 0) {
								 if (method_exists($service,'updateElement')) { // Update element
								 // TODO : a voir le retour ...
									if($service->updateElement($this->uid,$pairs)) $this->created();
								 }
					    } else {
						$this->lengthRequired();
					    }
					    
					  
    
				
				}
				else { // get all elements of a ressource
				   if (count($pairs) != 0) {
				   
								 if (method_exists($service,'createElement')) { // Create a new element
									if($service->createElement($pairs)) $this->created();
								 }
					    } else {
						$this->lengthRequired();
					    }
				
				}
			}
             }
    	
    }
    
    
    function delete() {
    	 $resource_file ='services/'.ucfirst($this->resource).'.php';
         $resource_class =ucfirst($this->resource);
         if (file_exists($resource_file)) {    
             include_once $resource_file; 
		     if (class_exists($resource_class)) {
						$service = new $resource_class($this->config);
		                if ($this->uid) { // get a resource element 
		 					 if (method_exists($service,'deleteElement')) { // Delete element
									if($service->deleteElement($this->uid)) $this->noContent();
	 						 }
		                }
		     }
         }
    }
    
     /**
     * Parse the HTTP request data.
     * @return str[] Array of name value pairs
     */
    function parseRequestData() {
        $values = array();
        $pairs = explode("&", $this->requestData);
        foreach ($pairs as $pair) {
            $parts = explode('=', $pair);
            if (isset($parts[0]) && isset($parts[1])) {
                $parts[1] = rtrim(urldecode($parts[1]));
                $values[$parts[0]] = $parts[1];
            }
        }
        return $values;
    }
    
        
    /**
     * Send a HTTP 201 response header.
     */
    function created($url = FALSE) {
        header('HTTP/1.0 201 Created');
        if ($url) {
            header('Location: '.$url);   
        }
	
    }
    
    /**
     * Send a HTTP 204 response header.
     */
    function noContent() {
        header('HTTP/1.0 204 No Content');
    }
    
    /**
     * Send a HTTP 400 response header.
     */
    function badRequest() {
        header('HTTP/1.0 400 Bad Request');   
    }
    
    /**
     * Send a HTTP 401 response header.
     */
    function unauthorized($realm = 'JRest') {
        if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) {
            header('WWW-Authenticate: Basic realm="'.$realm.'"');
        }
        header('HTTP/1.0 401 Unauthorized');   
    }
    
    /**
     * Send a HTTP 404 response header.
     */
    function notFound() {
        header('HTTP/1.0 404 Not Found');
    }
    
    /**
     * Send a HTTP 405 response header.
     */
    function methodNotAllowed($allowed = 'GET, HEAD') {
        header('HTTP/1.0 405 Method Not Allowed');
        header('Allow: '.$allowed);
    }
    
    /**
     * Send a HTTP 406 response header.
     */
    function notAcceptable() {
        header('HTTP/1.0 406 Not Acceptable');
        echo join(', ', array_keys($this->config['renderers']));
    }
    
    /**
     * Send a HTTP 411 response header.
     */
    function lengthRequired() {
        header('HTTP/1.0 411 Length Required');
    }
    
    /**
     * Send a HTTP 500 response header.
     */
    function internalServerError() {
        header('HTTP/1.0 500 Internal Server Error');
    }
    
}

?>
