<?php

/**
 * Class Application
 * The heart of the application
 */
class Application
{
    /** @var mixed Instance of the controller */
    private $controller;

    /** @var array URL parameters, will be passed to used controller-method */
    private $parameters = array();

    /** @var string Just the name of the controller, useful for checks inside the view ("where am I ?") */
    private $controller_name;

    /** @var string Just the name of the controller's method, useful for checks inside the view ("where am I ?") */
    private $action_name;

    /** @var string Language */
    private $language;

    /**
     * Start the application, analyze URL elements, call according controller/method or relocate to fallback location
     */
    public function __construct()
    {
        // create array with URL parts in $url
        $this->splitUrl();

        // creates controller and action names (from URL input)
        $this->createControllerAndActionNames();

        // does such a controller exist ?
        if (file_exists(Config::get('PATH_CONTROLLER') . $this->controller_name . '.php')) {

            // load this file and create this controller
            // example: if controller would be "car", then this line would translate into: $this->car = new car();
            require Config::get('PATH_CONTROLLER') . $this->controller_name . '.php';
            $this->controller = new $this->controller_name();

            // check for method: does such a method exist in the controller ?
            if (method_exists($this->controller, $this->action_name)) {
                if (!empty($this->parameters)) {
                    // call the method and pass arguments to it
                    call_user_func_array(array($this->controller, $this->action_name),
                                         $this->parameters);
                } else {
                    // if no parameters are given, just call the method without parameters, like $this->index->index();
                    $this->controller->{$this->action_name}();
                }
            } else {
                header('location: ' . Config::getURL() . 'error');
            }
        } else {
            header('location: ' . Config::getURL() . 'error');
        }
    }

    /**
     * Get and split the URL
     */
    private function splitUrl()
    {
        if (Request::get('url')) {

            // split URL
            $url = trim(Request::get('url'), '/');
            $url = htmlspecialchars($url);
            $url = explode('/', $url);

            // look for sort in url and set sort order for sorting
            if (in_array('sort', $url))
            {
                $sort_key = array_search('sort', $url);
                if (isset($url[$sort_key]) &&
                    isset($url[$sort_key+1]) &&
                    isset($url[$sort_key+2]))
                {
                    Helper::setSortOrder($url[$sort_key+1],$url[$sort_key+2]);
                }
                unset($url[$sort_key], $url[$sort_key+1], $url[$sort_key+2]);
                $sorted = true;
            } else {
                $sorted = false;
            }

            // if multilanguage support is configured, get language from url and set it
            if (Config::get('MULTILANGUAGE')) {
                if (in_array($url[0], array_keys(Config::get('LANGUAGES')))) {
                    $this->language = array_shift($url);
                    Language::set($this->language);
                }
            }

            $pageURL = $url;
            $currentURL = implode('/', $pageURL);

            self::redirectToSSL($currentURL);

            if ($sorted)
            {
                Redirect::to($currentURL);
            }
            if (in_array('page', $pageURL))
            {
                $page_key = array_search('page', $pageURL);
                unset($pageURL[$page_key],$pageURL[$page_key+1]);
            }
            if (in_array('update', $pageURL))
            {
                $page_key = array_search('update', $pageURL);
                unset($pageURL[$page_key],$pageURL[$page_key+1]);
            }
            $currentPath = implode('/', $pageURL);
            Helper::setCurrentPath($currentPath);

            // look for page in url and set page number for pagination
            if (in_array('page', $url))
            {
                $page_key = array_search('page', $url);
                if (isset($url[$page_key]) && isset($url[$page_key+1]))
                {
                    $pageNumber = (int) $url[$page_key+1];
                    if (is_int($pageNumber))
                    {
                        Helper::setPageNumber($pageNumber);
                    }
                }
                unset($url[$page_key], $url[$page_key+1]);
            }

            // put URL parts into according properties
            $this->controller_name = isset($url[0]) ? $url[0] : null;
            $this->action_name = isset($url[1]) ? $url[1] : null;

            // remove controller name and action name from the split URL
            unset($url[0], $url[1]);

            // rebase array keys and store the URL parameters
            $this->parameters = array_values($url);
        } else {
            self::redirectToSSL();
        }
    }

    /**
     * Checks if controller and action names are given. If not, default values are put into the properties.
     * Also renames controller to usable name.
     */
    private function createControllerAndActionNames()
    {
        // check for controller: no controller given ? then make controller = default controller (from config)
        if (!$this->controller_name) {
            $this->controller_name = Config::get('DEFAULT_CONTROLLER');
        }

        // check for action: no action given ? then make action = default action (from config)
        if (!$this->action_name OR (strlen($this->action_name) == 0)) {
            $this->action_name = Config::get('DEFAULT_ACTION');
        }

        // rename controller name to real controller class/file name ("index" to "IndexController")
        $this->controller_name = ucwords($this->controller_name) . 'Controller';
    }

    public function getLanguage()
    {
        return $this->language;
    }

    public static function getControllerName()
    {
        return $this->controller_name;
    }

    public static function getActionName()
    {
        return $this->action_name;
    }

    public static function redirectToSSL($url = '')
    {
        if (Config::get('FORCE_SSL') && Config::get('USED_PROTOCOL') == 'http')
        {
            header("location: ".Config::getURL().$url,TRUE,301);
        }
    }
}
