<?php
/**
* Web Application Component Toolkit
*
* @link http://www.phpwact.org/
*
* @author Wact Development Team
* @link http://www.phpwact.org/team
*
* @copyright Copyright 2006, Jeff Moore
* @license http://opensource.org/licenses/mit-license.php MIT
*/

/**
* The view composer is a collecting parameter.  As focus decends down the
* tree of controllers, each controller that receives focus registers itself
* with the view composer.
* This list of controllers is known as the focus path.
* After the focus path has been determined, the views associated with each
* controller are composed into a single master view, which is then rendered.
*/
class Wact_Controller_ViewComposer {

    /**
    * A list of all controllers that receivedFocus.
    */
    protected $controllerList = array();

    /**
    * An ordered list of the current focus path.
    */
    protected $focusPath = array();

    /**
    */
    function addToFocusPath($controller) {
        $this->controllerList[] = $controller;
        $this->focusPath[] = $controller;
    }

    /**
    * Forward the focus to a new controller.
    */
    function forwardFocus($forward, $request, $responseModel) {
        if (count($this->focusPath) > 0) {
            $controller = $this->focusPath[count($this->focusPath) - 1];
            if ($controller->hasChild($forward)) {
                $child = $controller->getChild($forward);
                $child->receiveFocus($this, $request, $responseModel);
            } else {
                array_pop($this->focusPath);
                $this->forwardFocus($forward, $request, $responseModel);
            }
        }
    }

    /**
    * render the composed view
    */
    function renderView($request, $responseModel) {
        $view = NULL;
        $viewName = NULL;
        foreach(array_reverse(array_keys($this->focusPath)) as $key) {
            $controller = $this->focusPath[$key];
            $parentView = $controller->getView();
            if (is_object($parentView)) {

                // If we don't bind the proper controller to the view,
                // we don't know how to properly handle shared
                // parameters.
                $parentView->setController($controller);

                if (is_null($view)) {
                    $view = $parentView;
                    $viewName = $controller->getPartialViewName();
                } elseif (is_object($parentView)) {
                    // we need to compose the two views here
                    $compositionPoint = $parentView->findChild($viewName);
                    if (is_object($compositionPoint)) {
                        $compositionPoint->appendChild($view);
                        $view = $parentView;
                        $viewName = $controller->getPartialViewName();
                    } else {
                        throw new Wact_Controller_Exception('Cannot find composition point "{View}"', $viewName);
                    }
                }
                
                if (empty($viewName)) {
                    break;
                }
            }
        }

        // What should we do here if viewName is not null?

        // we need to insert a view dumper here tommorrow

        if (is_object($view)) {
            $view->setModel($responseModel);
            $view->display();
        }

        foreach(array_reverse(array_keys($this->controllerList)) as $key) {
            $this->controllerList[$key]->triggerUnFocusEvent($request, $responseModel);
        }
    }

}

?>