<?php

class RootController {
    
    private static 
$instance;
    private 
$pageHead# Module
    
private $task;     # Task
    
private $module;   # Module
    
private $pageFoot# Module
    
private $outputModuleOnly# boolean
    
    
private function __construct(){}
    private function 
__clone(){}
    public static function 
getInstance() {
        
        if (!
self::$instance) {
            
self::$instance = new self;
            
            
# create page head
            
self::$instance->pageHead = new Module();
            
self::$instance->pageHead->controller = new PageHeadController();
            
self::$instance->pageHead->model = new PageHeadModel();
            
self::$instance->pageHead->view = new PageHeadView();
            
            
# create task
            
            
self::$instance->task = new Task();
            
            
# ..module
            
if (isset($_REQUEST['mod'])) {    self::$instance->task->moduleName $_REQUEST['mod'];
            } else {                        
self::$instance->task->moduleName 'default';
            }
            
# ..controller
            
if (isset($_REQUEST['c'])) {
                
self::$instance->task->moduleControllerName ucfirst($_REQUEST['c'].'Controller');
                
self::$instance->task->moduleControllerDir self::$instance->task->moduleName ;
            } else {
                if (
is_file(LIBRARY.'modules/'.self::$instance->task->moduleName.'/'.self::$instance->task->moduleName.'Controller'.'.php')) {
                    
self::$instance->task->moduleControllerName ucfirst(self::$instance->task->moduleName.'Controller');
                    
self::$instance->task->moduleControllerDir self::$instance->task->moduleName ;
                } else {
                    
self::$instance->task->moduleControllerName ucfirst('default'.'Controller');
                    
self::$instance->task->moduleControllerDir 'default' ;
                }
            }
            
# ..model
            
if (isset($_REQUEST['m'])) {
                
self::$instance->task->moduleModelName ucfirst($_REQUEST['m'].'Model');
                
self::$instance->task->moduleModelDir self::$instance->task->moduleName ;
            } else {
                if (
is_file(LIBRARY.'modules/'.self::$instance->task->moduleName.'/'.self::$instance->task->moduleName.'Model'.'.php')) {
                    
self::$instance->task->moduleModelName ucfirst(self::$instance->task->moduleName.'Model');
                    
self::$instance->task->moduleModelDir self::$instance->task->moduleName ;
                } else {
                    
self::$instance->task->moduleModelName ucfirst('default'.'Model');
                    
self::$instance->task->moduleModelDir 'default' ;
                }
            }
            
# ..view
            
if (isset($_REQUEST['v'])) {
                
self::$instance->task->moduleViewName ucfirst($_REQUEST['v'].'View');
                
self::$instance->task->moduleViewDir self::$instance->task->moduleName ;
            } else {
                if (
is_file(LIBRARY.'modules/'.self::$instance->task->moduleName.'/'.self::$instance->task->moduleName.'View'.'.php')) {
                    
self::$instance->task->moduleViewName ucfirst(self::$instance->task->moduleName.'View');
                    
self::$instance->task->moduleViewDir self::$instance->task->moduleName ;
                } else {
                    
self::$instance->task->moduleViewName ucfirst('default'.'View');
                    
self::$instance->task->moduleViewDir 'default' ;
                }
            }
            
# ..action
            
if (isset($_REQUEST['a'])) {        self::$instance->task->moduleAction $_REQUEST['a'];
            } else {                
self::$instance->task->moduleAction 'display' ;
            }
            
# ..action parameters
            
if (isset($_REQUEST['ap'])) {        self::$instance->task->moduleActionParameters explode('|'$_REQUEST['ap']);
            } else {                
self::$instance->task->moduleActionParameters = array();
            }
            
            
# create module
            
self::$instance->module = new Module();
            
            
# create module controller
            
self::$instance->module->controller = new self::$instance->task->moduleControllerName();
            if (!(
self::$instance->module->controller)) {
                
$bt debug_backtrace(); $backtraceFlat '['.__CLASS__.'::'.__FUNCTION__.' / line '.__LINE__.' ] [caller: '.$bt[0]['file'].' / line '.$bt[0]['line'].']';
                
Errors::log('module controller is null '.$backtraceFlat);
            }
            
# create module model
            
self::$instance->module->model = new self::$instance->task->moduleModelName();
            if (!(
self::$instance->module->model)) {
                
$bt debug_backtrace(); $backtraceFlat '['.__CLASS__.'::'.__FUNCTION__.' / line '.__LINE__.' ] [caller: '.$bt[0]['file'].' / line '.$bt[0]['line'].']';
                
Errors::log('module model is null '.$backtraceFlat);
            }
            
# create module view
            
self::$instance->module->view = new self::$instance->task->moduleViewName();
            if (!(
self::$instance->module->view)) {
                
$bt debug_backtrace(); $backtraceFlat '['.__CLASS__.'::'.__FUNCTION__.' / line '.__LINE__.' ] [caller: '.$bt[0]['file'].' / line '.$bt[0]['line'].']';
                
Errors::log('module view is null '.$backtraceFlat);
            }
            
            
# create page foot
            
self::$instance->pageFoot = new Module();
            
self::$instance->pageFoot->controller = new PageFootController();
            
self::$instance->pageFoot->model = new PageFootModel();
            
self::$instance->pageFoot->view = new PageFootView();
        }
        return 
self::$instance;
    }
    
    public static function 
getPageHeadController() {return self::getInstance()->pageHead->controller;    }
    public static function 
getPageHeadModel() {        return self::getInstance()->pageHead->model;    }
    public static function 
getPageHeadView() {        return self::getInstance()->pageHead->view;    }
    
    public static function 
getModuleController() {    return self::getInstance()->module->controller;    }
    public static function 
getModuleModel() {        return self::getInstance()->module->model;    }
    public static function 
getModuleView() {        return self::getInstance()->module->view;    }
    public static function 
getModuleName() {        return self::getInstance()->task->moduleName;    }
    public static function 
getModuleAction() {        return self::getInstance()->task->moduleAction;    }
    public static function 
getModuleParameters() {    return self::getInstance()->task->moduleActionParameters;    }
    public static function 
getModuleParameter($index) {
        if (
$index >= && $index count(self::getInstance()->task->moduleActionParameters)) {
            return 
self::getInstance()->task->moduleActionParameters[$index];
        } else {
            
$bt debug_backtrace(); $backtraceFlat '['.__CLASS__.'::'.__FUNCTION__.' / line '.__LINE__.' ] [caller: '.$bt[0]['file'].' / line '.$bt[0]['line'].']';
            
Errors::log('invalid array index: '.$index.' '.$backtraceFlat);
        }
        return 
null;
    }
    
    public static function 
getPageFootController() {return self::getInstance()->pageFoot->controller;    }
    public static function 
getPageFootModel() {        return self::getInstance()->pageFoot->model;    }
    public static function 
getPageFootView() {        return self::getInstance()->pageFoot->view;    }
    
    public static function 
setOutputModuleOnly($bool) {    self::getInstance()->outputModuleOnly $bool true false;    }
    
    
/**
     * calls the process methods of the page head, module and page foot controllers
     */
    
public function process() {
        
# process pageHead
        
$headOutput $this->pageHead->controller->process();
        
        
# process task
        
if ($this->module->controller) {
            if (
method_exists($this->module->controller'process')) {
                
$moduleOuput $this->module->controller->process();
            } else {
                
$bt debug_backtrace(); $backtraceFlat '['.__CLASS__.'::'.__FUNCTION__.' / line '.__LINE__.' ] [caller: '.$bt[0]['file'].' / line '.$bt[0]['line'].']';
                
Errors::log('module controller of class "'.get_class($this->module->controller).'" has no method named "process" '.$backtraceFlat);
            }
        } else {
            
$bt debug_backtrace(); $backtraceFlat '['.__CLASS__.'::'.__FUNCTION__.' / line '.__LINE__.' ] [caller: '.$bt[0]['file'].' / line '.$bt[0]['line'].']';
            
Errors::log('module controller is null '.$backtraceFlat);
        }
        
        
# process pageHead
        
$footOutput $this->pageFoot->controller->process();
        
        
# output
        
if (!empty($_REQUEST['redirectWhenProcessed'])) {
            
Helper::redirect($_REQUEST['redirectWhenProcessed'], true);
        } else if (
$this->outputModuleOnly) {
            print 
$moduleOuput;
            
        } else {
            
?><!--div style="border: 1px solid gray;"><pre id="ajaxdebugdiv"></pre></div--><?php
            
            
print $headOutput;
            
            print 
$moduleOuput;
            
            print 
$footOutput;
            
            
Helper::addDebugDiv('debug_RootController''RootController'self::$instance);
            
Helper::addDebugDiv('debug_SESSION''SESSION'$_SESSION);
            
Helper::addDebugDiv('debug_REQUEST''REQUEST'$_REQUEST);
            
Helper::addDebugDiv('debug_GET''GET'$_GET);
            
Helper::addDebugDiv('debug_POST''POST'$_POST);
            
            print 
'<br/><hr/>';
            
Helper::printDebugDivs();
        }
    }
}

class 
Task {
    public 
$moduleName;
    public 
$moduleControllerName# uppercase (classname)
    
public $moduleControllerDir;
    public 
$moduleModelName# uppercase (classname)
    
public $moduleModelDir;
    public 
$moduleViewName# uppercase (classname)
    
public $moduleViewDir;
    public 
$moduleAction;
    public 
$moduleActionParameters;
}

class 
Module {
    public 
$controller# object
    
public $model# object
    
public $view# object
}