/**
  * Starts the framework
  *
  * @param string|null $settings Path to settings file
  * @return int If all is well then it returns zero
  * @throws \Exception
  */
 public static function run(string $settings = null) : int
 {
     $settingsFile = $settings ? $settings : realpath(dirname(__FILE__) . '/../../../' . 'settings.yml');
     # load settings
     if (!Settings::load($settingsFile)) {
         return false;
     }
     if (Settings::getProduction()) {
         ini_set('display_errors', 'Off');
         ini_set('error_log', '/tmp/php-error.log');
         ini_set('log_errors', 1);
     }
     # set timezone
     Timezone::setTimezone(Settings::getTimezone());
     # set locale language
     I18n::setLocale(I18n::getLanguage());
     # generate routes
     if (Settings::getAutoroute()) {
         Routing::generateRoutes();
     }
     # load routes
     $routesFile = Settings::getRoutesFile();
     if (file_exists($routesFile)) {
         self::$routes = YAML::load($routesFile);
     } else {
         printf('[Error] Routes file %s does not exists', $routesFile);
         return false;
     }
     $dbSettings = Settings::getDBSettings();
     $db = new DB($dbSettings['dbm'], $dbSettings['host'], $dbSettings['name'], $dbSettings['user'], $dbSettings['password']);
     DB::setGlobal($db);
     # load actions
     Actions::autoloader(Settings::getActionsPath());
     Session::start();
     $request = isset($_GET[Settings::SETTINGS_ROUTE_PARAM_VALUE]) ? $_GET[Settings::SETTINGS_ROUTE_PARAM_VALUE] : '';
     if (Routing::parseRoute($request, self::$routes) == -1) {
         Response::response(Response::HTTP_FORBIDDEN);
     }
     return 0;
 }
 /**
  * Parses a route and executes the respective action
  *
  * @param string $request Route to be parsed
  * @param array $routes Array containing the routing table
  * @param null|string $module Name of the module
  * @return int Returns zero if all is well otherwise returns a value minor to zero
  * @throws \RuntimeException Throws an exception if the respective route file does
  * not exists
  * @throws \RuntimeException Throws an exception if the respective template file does
  * not exists
  */
 public static function parseRoute(string $request, array $routes, string $module = NULL) : int
 {
     foreach ($routes as $route) {
         if (substr($route['route'], -1) != '$') {
             $routePattern = sprintf('#%s.*#', $route['route']);
         } else {
             $routePattern = sprintf('#%s#', $route['route']);
         }
         $routeMatches = array();
         if (preg_match($routePattern, $request, $routeMatches) == 1) {
             if (isset($route['module'])) {
                 $routesFile = sprintf('%s/%s_routes.yml', Settings::getRoutesPath(), $route['module']);
                 if (file_exists($routesFile)) {
                     $moduleRoutes = YAML::load($routesFile);
                     $pattern = sprintf('#%s#', $route['route']);
                     $filterRequest = preg_filter($pattern, '', $request, 1);
                     $parseRoute = self::parseRoute($filterRequest, $moduleRoutes, $route['module']);
                     return $parseRoute;
                 } else {
                     throw new \RuntimeException(sprintf('%s Route file %s does not exists', __METHOD__, $routesFile), self::ROUTE_FILE_DOES_NOT_EXIST);
                 }
             } elseif (isset($route['controller']) && $module) {
                 Module::set($module);
                 $controllerFile = sprintf('%s/%s_controller.php', Settings::getControllersPath(), $module);
                 include_once $controllerFile;
                 $class = ucfirst($module);
                 $object = new $class();
                 $objectReflection = new \ReflectionClass($class);
                 if (sizeof($routeMatches)) {
                     $funcParams = array();
                     $methodReflection = $objectReflection->getMethod($route['controller']);
                     $methodParams = $methodReflection->getParameters();
                     foreach ($methodParams as $param) {
                         if (isset($routeMatches[$param->getName()])) {
                             $funcParams[] = $routeMatches[$param->getName()];
                         }
                     }
                     if (Request::isMethodPost()) {
                         if (!CsrfToken::checkPostToken()) {
                             Response::response(Response::HTTP_FORBIDDEN);
                             return 0;
                         }
                     }
                     call_user_func_array(array($object, 'callMethod'), array($route['controller'], $funcParams));
                 } else {
                     $object->{$route}['controller']();
                 }
                 unset($object);
                 unset($objectReflection);
                 return 0;
             } elseif (isset($route['template']) && $module) {
                 Module::set($module);
                 $templateFile = sprintf('%s/%s/%s', Settings::getViewsPath(), $module, $route['template']);
                 if (file_exists($templateFile)) {
                     $template = new Template();
                     echo $template->render($templateFile);
                     return 0;
                 } else {
                     throw new \RuntimeException(sprintf('%s Template file %s does not exists', __METHOD__, $templateFile), self::TEMPLATE_FILE_DOES_NOT_EXIST);
                 }
             }
         }
     }
     return -1;
 }