<?php
namespace apexl\Io;
use apexl\Config\Singleton;
use apexl\Io\includes\Hook;
use apexl\Io\includes\System;
use apexl\Io\services\Output;


class Client{
    public static $instance;
    protected $configDir;
    protected $configFile;
    protected $coreConfigPath;

    /** @var System */
    protected $system;

    private function __construct(){}

    /**
     * Turn Io into a singleton.
     * @return Client
     */
    public static function getInstance(){
        if(!self::$instance){
            self::$instance = new Client();
        }
        return self::$instance;
    }

    /**
     * Set the primary configuration Dir for IO
     * @param $dir
     * @return $this
     */
    public function setConfigDir($dir){
        $this->configDir = realpath(rtrim($dir, DIRECTORY_SEPARATOR));
        //check if we have a config cacheDir - if not, create a default one.
        $cacheDir = Singleton::getCacheDirectory();
        if($cacheDir){
            $this->setConfigCacheDir($cacheDir);
        }
        return $this;
    }

    /**
     * Set the directory used to store the amalgamated config files / data as cache.
     * @param $dir
     * @return $this
     */
    public function setConfigCacheDir($dir){
        Singleton::setCacheDirectory($dir);
        return $this;
    }

    /**
     * Set the application base path
     * @param $basePath
     */
    public function setBasePath($basePath){
        System::setBasePath($basePath);
    }

    /**
     * Bootstrap IO CMF
     */
    private function bootstrap(){
        $this->coreConfigPath = $this->configDir.DIRECTORY_SEPARATOR.ltrim($this->configFile, DIRECTORY_SEPARATOR);
        Singleton::load($this->coreConfigPath);

        // Attempt Initialise the System
        $this->system = System::getInstance();
        $this->system->startApplication();
        /** Add a boot hook so modules can set various defaults as soon as the start process is finished*/
        Hook::processHook("boot", Singleton::getInstance());
    }

    /**
     * Bootstrap and run Io
     */
    public function start($configFile){
        $this->configFile = $configFile;
        //In order to correctly pass cors and output something, we need to make sure we catch any bootstrap errors
        //store them in the systemError output, and continue to try and start the application.
        try {
            $this->bootstrap();
        } catch (\Exception $e){
            error_log("[IO Exception :: Start] -". $e->getCode()." | ".$e->getMessage());
            Output::addSystemError($e);
        }
        $this->system->start();
    }
}