<?php

namespace Tools;

/**
 * Cms context
 * Contains all website informations
 * Will be passed to themes files and to modules
**/
class Context
{
    /**
     * @var \Tools\Hooks $hookManager
     * /core/tools/Hooks.php
     * allow triggering hooks and registers module's endpoints
     * Can be accessed read-only via $instance->hookManager
    **/
    private $hookManager;

	/**
	 * @var \Tools\Context $instance Singleton value
	**/
	private static $instance;

    /**
     * @var \Tools\ModuleManager $moduleManager
     * /core/tools/ModuleManager.php
     * load all active modules and contains informations about them
     * Can be accessed read-only via $instance->moduleManager
    **/
    private $moduleManager;

    /**
     * @var \Tools\Router $router
     * /core/tools/Router.php
     * Contains information about directories and paths
     * Allow user to generate links
     * Can be accessed read-only via $instance->router
    **/
    private $router;

    /**
     * TODO
     * @var \Tools\Cart $cart
     * /core/tools/Cart.php
     * Not defined yet
     * Can be accessed read-only via $instance->cart
    **/
    private $cart;

    /**
     * TODO
     * @var \Tools\User $user (entity ?)
     * /core/tools/User.php
     * Can be accessed read-only via $instance->user
    **/
    private $user;

	/**
	 * @var \Tools\AController $controller
	 * /core/tools/AController.php
	 * Controller being called by user's request
	**/
	private $controller;

	/**
	 * @var string $ip
	 * Contains the remote client's IP, or empty
	 * Can be accessed via ->ip
	**/
	private $ip;

	/**
	 * @var array $server
	 * contains $_SERVER or Unit test environment
	 **/
	private $server;

    /**
     * Create context from $_SERVER environment
     * and initialize all data
	 * @param array $server optional, contains $_SERVER configuration
	 *  -> REMOTE_ADDR client's ip
	 *  -> SCRIPT_NAME
	 *  -> DOCUMENT_ROOT
	 *  -> REQUEST_SCHEME 'http:https'
	 *  -> REQUEST_URI
	 *  -> HTTP_HOST
    **/
    public function __construct($server = null)
    {
		self::$instance = $this;
		if ($server == null)
			$server = $_SERVER;
		$this->ip = $server["REMOTE_ADDR"];
        $this->hookManager = new Hooks($this);
		$this->server = $server;
        $this->router = new Router($this->server, $this);
    }

	public function serve()
	{
		// @codeCoverageIgnoreStart
        if (!\Entity\ModelBase::init())
        {
            @require_once(getcwd().'/core/setup/index.php');
            die;
        }
		// @codeCoverageIgnoreEnd
        $this->router->init($this->server);
        $this->moduleManager = new ModuleManager($this);
        $this->hookManager->trigger("routerSetup");
		try
		{
			$this->controller = $this->router->serveUrl();
			if (!$this->controller)
				throw new \Exception\Error404();
		}
		catch (\Exception\Error404 $e)
		{
			$this->controller = new \Controller\Error404($this, array());
		}
		return $this->controller;
	}

	/**
	 * Execute controller
	**/
	public function run()
	{
		$this->controller->start();
	}

    /**
     * Getter function
    **/
    public function __get($key)
    {
        switch ($key)
        {
            case "router": return $this->router; break;
            case "cart": return $this->cart; break;
            case "user": return $this->user; break;
            case "moduleManager": return $this->moduleManager; break;
            case "hookManager": return $this->hookManager; break;
			case "ip": return $this->ip; break;
			case "controller": return $this->controller; break;
        }
        throw new \Exception("Cannot access attribute {$key}");
    }

	/**
	 * Check if executed from phpUnit
	**/
	public function isTestingEnvironment()
	{
		return isset($this->server["phpUnit"]) && $this->server["phpUnit"] == true;
	}

	/**
	 * @return \Tools\Context context
	 * Get the last Context instance
	**/
	public static function getContext()
	{
		return self::$instance;
	}
}

