<?php

final class Loader
{
    protected $registry;

    public function __construct($registry)
    {
        $this->registry = $registry;
    }

    public function __get($key)
    {
        return $this->registry->get($key);
    }

    public function __set($key, $value)
    {
        $this->registry->set($key, $value);
    }

    public function library($library)
    {
        $file = DIR_SYSTEM . 'library/' . $library . '.php';

        if (file_exists($file)) {
            include_once($file);
        } else {
            trigger_error('Error: Could not load library ' . $library . '!');
            exit();
        }
    }


    public function type($type)
    {
        $file = DIR_SYSTEM . 'types/' . $type . '.php';

        if (file_exists($file)) {
            include_once($file);
        } else {
            trigger_error('Error: Could not load type ' . $type . '!');
            exit();
        }
    }

    public function helper($helper)
    {
        $file = DIR_SYSTEM . 'helper/' . $helper . '.php';

        if (file_exists($file)) {
            include_once($file);
        } else {
            trigger_error('Error: Could not load helper ' . $helper . '!');
            exit();
        }
    }

    public function controller($controller)
    {
        $file = DIR_APPLICATION . 'controller/' . $controller . '.php';

        if (file_exists($file)) {
            include_once($file);
        } else {
            trigger_error('Error: Could not load Controller ' . $controller . '!');
            exit();
        }
    }

    public function controllerRegistry($controller, $settings = [])
    {
        $file = DIR_APPLICATION . 'controller/' . $controller . '.php';
        $class = 'Controller' . preg_replace('/[^a-zA-Z0-9]/', '', $controller);

        if (file_exists($file)) {
            include_once($file);

            $this->registry->set('controller_' . str_replace('/', '_', $controller), new $class($this->registry, $settings));
        } else {
            trigger_error('Error: Could not load generic controller ' . $controller . '!');
            exit();
        }
    }

    public function model($model)
    {
        $file = DIR_APPLICATION . 'model/' . $model . '.php';
        $class = 'Model' . preg_replace('/[^a-zA-Z0-9]/', '', $model);

        if (file_exists($file)) {
            include_once($file);

            if(in_array($model, Type_abstractFactory::getEnumListConst())){
              $absClass = $this->typeClassAbstract($class);
              $this->registry->set('model_' . str_replace('/', '_', $model), $absClass);
            }else{
              $this->registry->set('model_' . str_replace('/', '_', $model), new $class($this->registry));
            }

        } else {
            trigger_error('Error: Could not load model ' . $model . '!');
            exit();
        }
    }


    public function dmodel($model)
    {
        $file = DIR_SYSTEM . 'dmodel/' . $model . '.php';
        $class = 'DModel' . preg_replace('/[^a-zA-Z0-9]/', '', $model);

        if (file_exists($file)) {
            include_once($file);

            $this->registry->set('dmodel_' . str_replace('/', '_', $model), new $class($this->registry));
        } else {
            trigger_error('Error: Could not load generic dmodel ' . $model . '!');
            exit();
        }
    }

    public function database($driver, $hostname, $username, $password, $database)
    {
        $file = DIR_SYSTEM . 'database/' . $driver . '.php';
        $class = 'Database' . preg_replace('/[^a-zA-Z0-9]/', '', $driver);

        if (file_exists($file)) {
            include_once($file);

            $this->registry->set(str_replace('/', '_', $driver), new $class($hostname, $username, $password, $database));
        } else {
            trigger_error('Error: Could not load database ' . $driver . '!');
            exit();
        }
    }

    public function typeForTwig($parentClass)
    {
        $newClass;
        eval('$newClass = new class("anonymous") extends ' . $parentClass . ' {
      public function __construct() {
        $consts = parent::getEnumListConst();
        foreach ($consts as $const_name => $const_value) {
          $this->$const_name = $const_value;
        }
      }
    };');

        return $newClass;
    }

    public function typeClassAbstract($parentClass){
      $newClass;
        eval('$newClass = '.$parentClass.'::getInstance($this->registry);');

      return $newClass;
    }



    public function config($config)
    {
        $this->config->load($config);
    }

    public function language($language, $directory = null, $defaultLanguage = true)
    {
        return $this->language->load($language, $directory, $defaultLanguage);
    }
}
