<?php
	require_once("class.dispatcher.php");

	/**
	* JSON Request handler
	*
	* This class handles all incoming JSON requests from the client. In short, it receives the JSON,
	* decodes JSON data, then sends the requests to the correct modules, and builds the reply JSON. The reply
	* JSON is encoded and then returned for reply.
	* @package core
	*/
	class JSONRequest
	{
		/**
		 * @var object the Dispatcher object (PHP Class)
		 */
		var $dispatcher;
		
		/**
		 * Constructor
		 */
		function JSONRequest()
		{
			
		}

		/**
		 * Execute incoming JSON request
		 *
		 * This function executes the actions in the JSON, which are received from
		 * the client. The entire JSON request is processed at once here, and this function
		 * is therefore called only once for each HTTP request to the server.
		 *
		 * @param string $json the json string which is received by the client
		 * @return string the built json which will be sent back to the client		 
		 * @todo Reduce overhead by outputting created JSON by outputting directly to php://output instead of returning a
		 *       (possibly huge) string containing the serialized JSON
		 */
		function execute($json)
		{
			try {
				// decode JSON data
				$data = JSON::Decode($json, true);

				// Create Dispatcher object
				$this->dispatcher = new Dispatcher();

				// Reset the bus
				$GLOBALS["bus"]->reset();

				// notify modules that wants to do something at the start of a request
				$GLOBALS["bus"]->notify(REQUEST_ENTRYID, REQUEST_START);

				// Check if the JSON is parsed correctly into an array
				$data = $data["zarafa"] ? $data["zarafa"] : false;

				// @TODO throw exception if zarafa tag is not present
				if(is_array($data)) {
					// Check if the client wants to reset the Bus and remove all the registered modules
					if(isset($data["reset"])) {
						$GLOBALS["bus"]->deleteAllRegisteredModules();
					}

					// iterate over all module names
					foreach($data as $moduleName => $modules) {
						// each module can contain multiple requests using different module ids
						foreach($modules as $moduleId => $moduleData) {
							// Module object
							$moduleObj = false;

							// Check if module already exists in the Bus
							if($moduleObj = $GLOBALS["bus"]->moduleExists($moduleName, $moduleId)) {
								// Set Data
								$moduleObj->setData($moduleData);
							} else {
								// Create the module via the Dispatcher
								$moduleObj = $this->dispatcher->loadModule($moduleName, $moduleId, $moduleData);
							}

							// Check if the module is loaded
							if(is_object($moduleObj)) {
								$moduleObj->loadSessionData();

								// Execute the actions in the module
								$moduleObj->execute();

								$moduleObj->saveSessionData();

								// Clean up the data within the module.
								$moduleObj->reset();

								// Update the object in the bus, so all variables are still 
								// there if the object is called in the next request
								$GLOBALS["bus"]->setModule($moduleObj);
							}
						}
					}

					// Check if the client wants to delete a module
					if(isset($data["deletemodule"]) && isset($data["deletemodule"]["module"])) {
						// Delete the registered modules
						foreach($data["deletemodule"]["module"] as $moduleID)
						{
							$GLOBALS["bus"]->deleteRegisteredModule($moduleID);
						}
					}

					if (isset($data["request_webaccess_reload"])){
						// add "reload_webaccess" to output
						$GLOBALS["bus"]->responseData["reload_webaccess"] = true;
					}
				}

				// notify modules that wants to do something at the end of a request
				$GLOBALS["bus"]->notify(REQUEST_ENTRYID, REQUEST_END);

				// Build the JSON and return it
				return JSON::Encode(array("zarafa" => $GLOBALS["bus"]->getData()));

			} catch (ZarafaException $e) {
				if(!$e->isHandled) {
					$data = array(
						"error" => array(
							"type" => ERROR_ZARAFA,
							"info" => array(
								"file" => $e->getFileLine(),
								"display_message" => $e->getDisplayMessage(),
								"original_message" => $e->getMessage()
							)
						)
					);

					return JSON::Encode(array("zarafa" => $data));
				}
			} catch (ZarafaErrorException $e) {
				if(!$e->isHandled) {
					$data = array(
						"error" => array(
							"type" => ERROR_GENERAL,
							"info" => array(
								"file" => $e->getFileLine(),
								"display_message" => $e->getDisplayMessage(),
								"original_message" => $e->getMessage()
							)
						)
					);

					return JSON::Encode(array("zarafa" => $data));
				}
			} catch (Exception $e) {
				// handle exceptions that are not handled by modules
				dump($e);
			}
		}
	}
?>