<?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 >= 0 && $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
}