<?php

class ViewXMLBuilder {



	public static function build(SimpleXMLElement $sx, ArrayObject $args = null) {
		if (count($sx->children()) != 1) {
			throw new Exception('exactly one root view must be defined');
		}
		if (!$args) {
			$request = RequestContext::getInstance();
			$args = $request->getArgs();
		}
		return self::parseView($sx->view, $args);
	}



	protected static function parseView(SimpleXMLElement $sx, ArrayObject $args) {
		if (!$sx['class']) {
			throw new Exception('"class" attribute required');
		}
		$class = (string)$sx['class'];
		$id = $sx['id'];
		$view = new $class($id);
		if ($template = (string)$sx['template']) {
			$view->template = $template;
		}

		$views = array();
		$listeners = array();
		foreach ($sx->children() as $tag => $element) {
			switch ((string)$tag) {
				case 'view' :
					$view->add(self::parseView($element, $args), (string)$element['alias']);
					break;
				case 'property' : 
					$property = (string)$element['name'];
					$view->$property = self::parseParam($element, $view, $args);
					break;
				case 'listener' :
					$for = $view->getChildById((string)$element['id']);
					$for->addListener(self::parseListener($element, $view, $args));
					break;
			}
		}

		return $view;
	}



	protected static function parseParam(SimpleXMLElement $sx, View $v, ArrayObject $args) {
		$out = '';
		foreach ($sx->children() as $tag => $element) {
			switch ((string)$tag) {
				case 'arg' :
					$out .= $args[(string)$element['key']];
					break;
				case 'text':
					$out .= (string)$element;
					break;
			}
		}
		return $out;
	}



	protected static function parseListener(SimpleXMLElement $sx, View $view, ArrayObject $args) {
		$class = (string)$sx['class'];
		$protocol = (string)$sx['protocol'];
		$adapters = new ArrayObject();
		foreach ($sx->children() as $tag => $element) {
			switch ((string)$tag) {
				case 'action' :
					$adapters[] = self::parseAction($element, $view, $args);
					break;
				case 'behaviour' :
					$adapters[] = new Behaviour(self::parseParam($element, $view, $args));
					break;
			}
		}
		if ($protocol) {
			return new $class($protocol, new ActionComposite($adapters));
		}
		return new $class(new ActionComposite($adapters));
	}



	protected static function parseAction(SimpleXMLElement $sx, View $view, ArrayObject $args) {
		$ctrl = (string)$sx['ctrl'];
		if (!$ctrl) {
			throw new Exception('"ctrl" attribute is mandatory');
		}
		$params = array();
		foreach ($sx->children() as $tag => $param) {
			switch ((string)$tag) {
				case 'param' :
					$params[] = self::parseParam($param, $view, $args);
					break;
				case 'valuereader' :
					$for = $view->getChildById((string)$param['id']);
					if (!$for) {
						throw new Exception('could not find view ' . (string)$param['id']);
					}
					$params[] = $for->valueReader();
					break;
			}
		}
		return new Action($ctrl, $params);
	}



} // class ViewXMLBuilder

?>