<?php


/**
 *
 * @author Peter Csubak (chuby)
 * @copyright Peter Csubak (chuby)
 */

/** @Target("class") */
class Stateful extends Annotation{}

/** @Target("class") */
class Stateless extends Annotation{}

/** @Target("method") */
class Params extends Annotation{
	public $value;
}

/** @Target("class") */
class AjaxStartPoint extends Annotation{}

/** @Target("method") */
class AjaxMethod extends Annotation{}

class SessionPeaHandler {

	private static $Instance = null;

	private $objects;
	private $schemaName;
	private $result = null;
	private $lastCalled = null;
	private $sid;
	private $logusr;

	/**
	 * Szabályos singleton példánykérő metódus. Tehát egy példányt ad vissza, ha már létezik egy példány,
	 * akkor mindig ugyan azt. Ha nem akkor, létrehoz egyet. Gyakorlatilag ez a metódus szolgál a 
	 * példányosító utasítás helyett.
	 *
	 * @return SessionPeaHandler A kért példány
	 */
	public static function getInstance(){
		if (SessionPeaHandler::$Instance == null){
			SessionPeaHandler::$Instance = new SessionPeaHandler();
		}
		return SessionPeaHandler::$Instance;
	}

	/**
	 * A singleton miatt kell hogy privát metódus legyen a konstruktor, pélányosítás helyett a 
	 * getInstance metódust kell használni.
	 */
	private function __construct(){
	}

	/**
	 * Az AjaxConnectorból érkező metódushívásokat hivatott kezelni.
	 * Egyelőre az AjaxConnector megírásáig biztosan nem készül el.
	 */
	public function ajaxMethodCall($className, $methodName, $params){
		try{
			$clazz = new ReflectionAnnotatedClass($className);
			if ($clazz->hasAnnotation("AjaxStartPoint")){
				if ($clazz->hasMethod($methodName)){
					$meth = new ReflectionAnnotatedMethod($className, $methodName);
					if ($meth->hasAnnotation("AjaxMethod") && $meth->isStatic() && $meth->isPublic() && ($meth->getNumberOfParameters() == (($params === null) ? 0 : count($params)))){
						if ($params === null){
							$meth->invoke(null);
						}else{
							$meth->invoke(null, $params);
						}
					}else{
						throw new AjaxException("Nem létezik a meghívni kívánt metódus.", null, 902);
					}
				}else{
					throw new AjaxException("Nem létezik a meghívni kívánt metódus.", null, 902);
				}
			}else{
				throw new AjaxException("A megadott osztály nem ajax belépési pont: <<class>>", array("class" => $clazz->getName()), 901);
			}
		}catch (Exception $e){
			$this->result = $e;
		}
	}

	/**
	 * Elemzi és végrehajtja a kért metódushívást. Egyedül a PeaConnector-nak kell használnia.
	 *
	 * @param SimpleXmlElement $xmlNode A metódushívást leíró xml node
	 * @param string $objectId A kezelendő objektum távoli objektum azonosítója.
	 */
	public function parseMethodCall($xmlNode, $objectId){
		try{
			if (is_array($this->objects)){
				if (isset($this->objects[(int) $objectId])){
					$obj = $this->objects[(int) $objectId];
					$method = XmlSerializer::deserializeMethod($obj, $xmlNode, $this->schemaName);
					if (($method->name != "") && ($method->object != null)){
						$this->lastCalled = $method;
						$this->result = $method->invoke();
					}else{
						throw new PeaException("Hibás metódushívás, a leírás alapján nem lehetett felépíteni a metódushívást.", null, 204);
					}
				}else{
					throw new PeaException("Hibás metódushívás, nincs ilyen objektum azonosítóval rendelkező egyed.", null, 203);
				}
			}else{
				throw new PeaException("Hibás metódushívás, nincs aktív session.", null, 202);
			}
		}catch (Exception $e){
			$this->result = $e;
		}
	}

	/**
	 * A metódushívás eredményét serializáló metódus. TODO ITT TARTOTTAM!!!
	 */
	public function serializeResult(){ //<< ha kivétel volt, akkor is ez serializálja, mert ahhoz ez is jó lesz.
		try {
			if (is_object($this->result)){
				if ($this->result instanceof Exception){
					return XmlSerializer::serializeException($this->result);
				}else{
					return XmlSerializer::serialize($this->result, $this->schemaName);
				}
			}else{
				if (is_array($this->result)){
					if ($this->lastCalled == null){
						return null;
					}else{
						return XmlSerializer::serializeArray($this->lastCalled->object, $this->lastCalled->name, $this->result, $this->schemaName, true);
					}
				}else{
					return $this->result;
				}
			}
		}catch (Exception $e){
			$this->result = $e;
			return $this->serializeResult();
		}
	}
	
	public function serializeExportableEvents($ajax = false){
		if ($ajax && ($this->result instanceof Exception)){
			return XmlSerializer::serializeException($this->result);
		}
		
		$res = "<events>";
		if (is_array(EventHandler::getExportableEvents())){
			foreach (EventHandler::getExportableEvents() as $event){
				$res .= XmlSerializer::serializeEvent($event, $this->schemaName);
			}
		}
		$res .= "</events>";
		return $res;
	}

	public function createInstance($className, $inside = false){
		try{
			if (is_array($this->objects)){
				$ref = new ReflectionAnnotatedClass($className);
				if ($ref->hasAnnotation("Stateful") || $ref->hasAnnotation("Stateless")){
					$obj = $ref->newInstance();
					$id = count($this->objects);
					$this->objects[$id] = $obj;
					if ($inside){
						$sessionProv = new SessionProvider($obj, $id);
						return $sessionProv;
					}
					return $id;
				}else{
					throw new PeaException("Hibás konstruktorhívás, példányosítani, és metódust hívni csak Session Pea-ken lehet.", null, 201);
				}
			}else{
				throw new PeaException("Hibás konstruktorhívás, nincs aktív session.", null, 200);
			}
		}catch (Exception $e){
			$this->result = $e;
		}
	}
	
	public function addObject($obj){
		try{
			if (is_array($this->objects)){
				$ref = new ReflectionAnnotatedClass(get_class($obj));
				if ($ref->hasAnnotation("Stateful") || $ref->hasAnnotation("Stateless")){
					$id = count($this->objects);
					$this->objects[$id] = $obj;
					return $id;
				}else{
					throw new PeaException("Hibás metódushívás, ezt a metódust hívni csak Session Pea-ken lehet.", null, 201);
				}
			}else{
				throw new PeaException("Hibás konstruktorhívás, nincs aktív session.", null, 200);
			}
		}catch (Exception $e){
			$this->result = $e;
		}
	}
	
	public function addComponent($comp){
		try{
			if (is_array($this->objects)){
				if ($comp instanceof PComponent){
					if (!is_array($this->objects["components"])){
						$this->objects["components"] = array();
					}
					$id = count($this->objects["components"]);
					$comps = $this->objects["components"];
					$comps[$id] = $comp;
					$this->objects["components"] = $comps;
					return $id;
				}else{
					throw new PeaException("Hibás metódushívás, ezt a metódust hívni csak PComponent-eken lehet.", null, 201);
				}
			}else{
				throw new PeaException("Hibás konstruktorhívás, nincs aktív session.", null, 200);
			}
		}catch (Exception $e){
			$this->result = $e;
		}
	}
	
	public function getComponent($id){
		if (is_array($this->objects)){
			if (!is_array($this->objects["components"])){
				return null;
			}
			$comps = $this->objects["components"];
			foreach ($comps as $comp){
				if ($comp->id == $id){
					return $comp;
				}
			}
			return null;
		}else{
			return null;
		}
	}
	
	public function addTriggeredObject($obj){
		try{
			if (is_array($this->objects)){
				if (is_object($obj)){
					if (!is_array($this->objects["triggered"])){
						$this->objects["triggered"] = array();
					}
					$id = count($this->objects["triggered"]);
					$this->objects["triggered"][$id] = $obj;
					return $id;
				}else{
					throw new PeaException("Hibás metódushívás, ezt a metódust hívni csak objektumokon lehet.", null, 201);
				}
			}else{
				throw new PeaException("Hibás konstruktorhívás, nincs aktív session.", null, 200);
			}
		}catch (Exception $e){
			$this->result = $e;
		}
	}

	public function startSession($clientType, $commSchemaName){
		//clientType dönti el, hogy böngészőből, vagy máshonnan jött a kérés,
		//majd akkor kell vele foglalkozni, amikor az AjaxConnection csomagot kódolom
		$schemaName = $commSchemaName;
		if ($commSchemaName == null){
			$schemaName = "--default--";
		}
		$this->schemaName = $schemaName;

		session_start();
		$res = session_id();
		$this->objects = array();
		$_SESSION["objects"] = $this->objects;
		$_SESSION["schemaName"] = $this->schemaName;
		$_SESSION["user"] = $this->logusr;
		session_commit();
		return $res;
	}

	public function endSession($sessionId){
		session_id($sessionId);
		session_start();
		$_SESSION["objects"] = null;
		$_SESSION["schemaName"] = null;
		$_SESSION["user"] = null;
		session_destroy();
	}

	public function resumeSession($sessionId){
		$this->sid = $sessionId;
		session_id($sessionId);
		session_start();
		$this->objects = $_SESSION["objects"];
		$this->schemaName = $_SESSION["schemaName"];
		$this->logusr = $_SESSION["user"];
		session_commit();
	}

	public function pauseSession($sessionId){
		session_id($sessionId);
		session_start();
		$_SESSION["schemaName"] = $this->schemaName;
		$_SESSION["objects"] = $this->objects;
		$_SESSION["user"] = $this->logusr;
		session_commit();
	}
	
	public function getTriggeredObjects(){
		return $this->objects["triggered"];
	}
	
	public function setTriggeredObjects($objs){ //NEM KÉNE HOGY MARADJON JOBB AZT DARABONKÉNT!!!
		$this->objects["triggered"] = $objs;
	}
	
	public function getComponents(){
		return $this->objects["components"];
	}
	
	public function setComponents($objs){ //NEM KÉNE HOGY MARADJON JOBB AZT DARABONKÉNT!!!
		$this->objects["components"] = $objs;
	}
	
	public function setLoggedInUser($user){
		$this->logusr = $user;
	}
	
	public function getLoggedInUser(){
		return $this->logusr;
	}

}
?>