<?php
/**
 * This file is part of the mobileOK Pythia plug-in for Moodle and defines the
 * {@link mobileOKPythiaForMoodle} class that contains most of the logic of the
 * mobileOK Pythia plug-in.
 * 
 * @author Sylvain Lequeux
 * @author Francois Daoust <fd@w3.org>
 * @package mobileOKPythia
 * @subpackage Moodle
 * @version $Revision: 1.2 $
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License v3 or later
 * @copyright Copyright (c) 2009, W3C (MIT, ERCIM, Keio)
 */

/**
 * Include required files.
 */
// AskPythia's DDR Service configuration
require_once(dirname(__FILE__) . '/../common/plugins/DDRServiceConfigurationFactory.php');
require_once(dirname(__FILE__) . '/WURFLServiceConfiguration.php'); 
// TransPythia 
require_once(dirname(__FILE__) . '/../common/transcoding/transcoder.php');
// AskPythia
require_once(dirname(__FILE__) . '/../common/ddrsimpleapi/interface/serviceFactory.php');
// Possible errors will be reported using AskPythia's SystemException class
require_once(dirname(__FILE__) . '/../common/ddrsimpleapi/interface/systemException.php');
// Log possible errors in a file 
require_once(dirname(__FILE__) . '/../common/logger/implementation/filelogger/filelogger.php');


/**
 * The mobileOKPythiaForMoodle class contains the logic of the
 * mobileOK Pythia plugin for Wordpress for regular non-admin pages.
 * 
 * The class wraps the common AskPythia and TransPythia libraries for
 * use in Moodle.
 * 
 * The mobileOK Pythia plugin is designed to help generate a mobileOK
 * version of a course.
 *
 * @author Sylvain Lequeux
 * @author Francois Daoust <fd@w3.org>
 * @package mobileOKPythia
 * @subpackage Moodle
 * @version $Revision: 1.2 $
 * @license http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231.html W3C Software Notice and License
 * @copyright Copyright (c) 2009, W3C (MIT, ERCIM, Keio)
 */
class mobileOKPythiaForMoodle {
	/**
	 * @var Service The interface to use to retrieve device properties from an
	 *              underlying Device Description Repository (DDR). 
	 */
	private $service;
	/**
	 * @var Evidence Evidence that uniquely identifies the requesting device.
	 */
	private $evidence;
	/**
	 * @var string The root HTTP URI for the Moodle site
	 */
	private $rootUri;
	/**
	 * @var string The root file folder that contains Moodle
	 */
	private $rootFolder;
	/**
	 * @var string The data root folder
	 */
	private $dataRoot;
	/**
	 * @var string The cache folder that will be used to cache images
	 */
	private $cacheFolder;
	
	/**
	 * Creates an empty instance of the mobileOKPythia class
	 * 
	 * @return A new mobileOKPythia instance.
	 */
	public function __construct() {
	}
	
	/**
	 * Initializes this instance, i.e. prepares the identification
	 * of the requesting device.
	 */
	public function init() {
		global $CFG;
		
		$ddrName = "WURFL";
		$config = DDRServiceConfigurationFactory::getServiceConfiguration(
			$ddrName, NULL);
		$this->service = ServiceFactory::newService(
			$ddrName, 
			'http://www.w3.org/2008/01/ddr-core-vocabulary',
			$config->getConfig());
		
		// Initialize the evidence that identifies the requesting device.
		$map = array();
		foreach ($_SERVER as $name=>$value) {
			if (strpos($name, 'HTTP_') == 0) {
				$name = str_replace('_', '-', substr($name, strlen('HTTP_')));
				$map[$name] = $value;
			}
		}
		$this->evidence = $this->service->newHTTPEvidenceM($map);
		
		// Add POWDER link and make sure POWDER file was created
		if ($CFG->filter_mobileOKPythia_link_powder) {
			$this->addPowderLink($CFG->filter_mobileOKPythia_powder_file);
		}
		
		$this->rootUri = $CFG->wwwroot . '/';
		$this->rootFolder = $CFG->dirroot . '/';
		$this->dataRoot = $CFG->dataroot . '/';
		$this->cacheFolder = $CFG->dataroot . '/cache/';
	}
	
	
	/**
	 * Determines the Content-Type that should be used based on the
	 * Accept HTTP header sent by the requesting device.
	 * 
	 * @return string 'application/xhtml+xml' or 'text/html', depending
	 *   on whether the requesting device supports the XHTML media type
	 */
	public function getContentType() {
		global $CFG;
		
		if ($CFG->filter_mobileOKPythia_serve_xhtml) {
			if ($_SERVER['HTTP_ACCEPT']) {
				if (strpos($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml') !== false) {
					// TODO: handle the case where the XHTML media type is
					// explicitly set with a qvalue of 0  
					return 'application/xhtml+xml';
				}
			}
		}
		
		return 'text/html';
	}
	
	/**
 	* Transcodes content before delivery.
 	* 
 	* @param $content string The content to transcode.
 	* @return string transcoded content.
 	*/
	function filter($content){
		try{
			$transcoder = $this->getTranscoder();
			$content = $transcoder->apply($content, $this->evidence);
			unset($transcoder);
			return $content;
		}
		catch(SystemException $e){
			$log = new FileLogger();
			$message = 'An error has occured in the content analysis. Error ' . $e->getCode()
				. ' (' . $e->getFile() . ':'. $e->getLine() . ')' . ' : '.$e->getMessage();
			$log->add_message($message, 'error');
			return $message;
		}
	}


	/**
	 * Retrieves a transcoder that applies to HTML content.
	 * 
	 * The transcoding actions are selected based on the options of the plugin.
	 * 
	 * @param $factor
	 * @return Transcoder a transcoder initialized with transcoding actions.
	 */
	function getTranscoder() {
		global $CFG;
		
		$transcoder = new Transcoder($this->service);	
		
		if ($CFG->filter_mobileOKPythia_delete_script) {
			$trans = $transcoder->newTranscodingAction('DeleteScript');
			$transcoder->addTranscodingAction($trans);
		}
		
		if ($CFG->filter_mobileOKPythia_delete_popup) {
			$trans = $transcoder->newTranscodingAction('DeletePopup');
			$transcoder->addTranscodingAction($trans);
		}
		
		if ($CFG->filter_mobileOKPythia_delete_embeds) {
			$trans = $transcoder->newTranscodingAction('DeleteEmbeds');
			$transcoder->addTranscodingAction($trans);
		}
		
		if ($CFG->filter_mobileOKPythia_serve_xhtml) {
			$trans = $transcoder->newTranscodingAction('ReplaceEntities');
			$transcoder->addTranscodingAction($trans);
		}
		
		if ($CFG->filter_mobileOKPythia_resize_img) {
			$trans = $transcoder->newTranscodingAction('ResizeIMG');
			
			$requestedUri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
			
			// Adjust maximum image size if user is browsing the home page
			$maxSize = intVal($CFG->filter_mobileOKPythia_max_image_size) * 1024;
			$trans->setOption('max_img_size', $maxSize);
			$trans->setOption('img_cache', $this->cacheFolder);
			$trans->setOption('img_cache_uri', $this->rootUri . 'filter/mobileOKPythia/img.php?file=');
			$trans->setOption('base_uri', $requestedUri);
			$trans->setOption('uri_mappings', $this->rootUri . 'file.php/' . '|' . $this->dataRoot);
			
			$transcoder->addTranscodingAction($trans);
			
		}
		
		if ($CFG->filter_mobileOKPythia_linear_tables) {
			$trans = $transcoder->newTranscodingAction('LinearTables');
			$transcoder->addTranscodingAction($trans);		
		}
		
		if ($CFG->filter_mobileOKPythia_pagination) {
			$trans = $transcoder->newTranscodingAction('Pagination');
			
			// Adjust maximum weight based on the average weight of the remaining content,
			// and on whether we are browsing the home page or not.
			$maxSize = intVal($CFG->filter_mobileOKPythia_max_weight) * 1024;
			
			// CSS Stylesheet and other divs in the page usually account for
			// about 6Kb.
			$maxSize -= 8 * 1024;
			
			// Allowed markup size should be half of the total size
			$maxMarkupSize = intVal($maxSize / 2);
			 
			$requestedUri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
			
			if ($requestedUri == ($this->rootUri)) {
				// Replace prev/next links on the home page by a "Read more" link
				$trans->setOption('nav_block',
					'<div><p>[...] <a href="' . '#TODO' . '">Read more</a></p></div>');
			}
			
			$trans->setOption('max_size', $maxSize);
			$trans->setOption('max_markup_size', $maxMarkupSize);
			$trans->setOption('page_index', intVal($_GET['pagination'] ? $_GET['pagination'] : 1));
			$trans->setOption('base_uri', $requestedUri);
			$trans->setOption('uri_mappings',
				$this->rootUri . 'file.php/'
				. '|' . $this->dataRoot
				. ' ' . $this->rootUri . 'filter/mobileOKPythia/img.php?file='
				. '|' . $this->cacheFolder);
		
			$transcoder->addTranscodingAction($trans);
		}
		return $transcoder;
	}
	
	
	/**
	 * Switches template based on the requesting device.
	 * 
	 * A mobile template is used when the requesting device is identified as
	 * mobile, the regular desktop template is used otherwise.
	 * 
	 * This method is a wrapper around the {@link TranscodingActionSwitchTemplate}
	 * transcoding action.
	 */
	public function switchTemplate() {
		$transcoder = new Transcoder($this->service);
		$trans = $transcoder->newTranscodingAction('SwitchTemplate');
		$transcoder->addTranscodingAction($trans);
		
		// TODO: add option
		$default_template = 'standard';
		$mobile_template = 'mobileok_default';
		
		$trans->setOption('default', $default_template);
		$trans->setOption('mobile', $mobile_template);
		
		$template = $transcoder->apply('', $this->evidence);
		
		return $template;
	}
	
	/**
 	* Serves the page with an HTTP Link header to a POWDER file
 	* that asserts that the blog is mobileOK.
 	*/
	function addPowderLink($powderFile) {
		// Import the POWDER generator factory
		require_once(dirname(__FILE__) . '/../common/powder/powder.php' );
		
		// Create the mobileOK POWDER file for the blog if not already done
		$powder = MobileOKPowderFactory::generatePowderFile(
			$this->rootUri,
			$powderFile);
			
		if ($powder == NULL) {
			throw new SystemException(
				'The POWDER file could not be generated.',
				SystemException::$CANNOT_PROCEED
			);
		}
		
		// Send the Link HTTP header to the mobileOK POWDER file
		// TODO: map cache folder to URI!
		header('Link: <' . $this->rootUri . $powderFile . '>; rel="describedby"; type="application/powder+xml";');
		
		return;
	}
}
?>