<?php
namespace Kant\Routing;

use Kant\Http\RedirectResponse;
use Kant\Session\Session;
use Kant\Session\Store as SessionStore;

class Redirector
{

    /**
     * The URL generator instance.
     *
     * @var \Kant\Routing\UrlGenerator
     */
    protected $generator;

    /**
     * The session store instance.
     *
     * @var \Kant\Session\Store
     */
    protected $session;

    /**
     * Create a new Redirector instance.
     *
     * @param \Kant\Routing\UrlGenerator $generator            
     * @return void
     */
    public function __construct(UrlGenerator $generator, Session $session)
    {
        $this->generator = $generator;
        $this->session = $session;
    }

    /**
     * Create a new redirect response to the "home" route.
     *
     * @param int $status            
     * @return \Kant\Http\RedirectResponse
     */
    public function home($status = 302)
    {
        return $this->to($this->generator->route('home'), $status);
    }

    /**
     * Create a new redirect response to the previous location.
     *
     * @param int $status            
     * @param array $headers            
     * @param mixed $fallback            
     * @return \Kant\Http\RedirectResponse
     */
    public function back($status = 302, $headers = [], $fallback = false)
    {
        return $this->createRedirect($this->generator->previous($fallback), $status, $headers);
    }

    /**
     * Create a new redirect response to the current URI.
     *
     * @param int $status            
     * @param array $headers            
     * @return \Kant\Http\RedirectResponse
     */
    public function refresh($status = 302, $headers = [])
    {
        return $this->to($this->generator->getRequest()
            ->path(), $status, $headers);
    }

    /**
     * Create a new redirect response, while putting the current URL in the session.
     *
     * @param string $path            
     * @param int $status            
     * @param array $headers            
     * @param bool $secure            
     * @return \Kant\Http\RedirectResponse
     */
    public function guest($path, $status = 302, $headers = [], $secure = null)
    {
        $this->session->put('url.intended', $this->generator->full());
        
        return $this->to($path, $status, $headers, $secure);
    }

    /**
     * Create a new redirect response to the previously intended location.
     *
     * @param string $default            
     * @param int $status            
     * @param array $headers            
     * @param bool $secure            
     * @return \Kant\Http\RedirectResponse
     */
    public function intended($default = '/', $status = 302, $headers = [], $secure = null)
    {
        $path = $this->session->pull('url.intended', $default);
        
        return $this->to($path, $status, $headers, $secure);
    }

    /**
     * Create a new redirect response to the given path.
     *
     * @param string $path            
     * @param int $status            
     * @param array $headers            
     * @param bool $secure            
     * @return \Kant\Http\RedirectResponse
     */
    public function to($path, $status = 302, $headers = [], $secure = null)
    {
        return $this->createRedirect($this->generator->to($path, [], $secure), $status, $headers);
    }

    /**
     * Create a new redirect response to an external URL (no validation).
     *
     * @param string $path            
     * @param int $status            
     * @param array $headers            
     * @return \Kant\Http\RedirectResponse
     */
    public function away($path, $status = 302, $headers = [])
    {
        return $this->createRedirect($path, $status, $headers);
    }

    /**
     * Create a new redirect response to the given HTTPS path.
     *
     * @param string $path            
     * @param int $status            
     * @param array $headers            
     * @return \Kant\Http\RedirectResponse
     */
    public function secure($path, $status = 302, $headers = [])
    {
        return $this->to($path, $status, $headers, true);
    }

    /**
     * Create a new redirect response to a named route.
     *
     * @param string $route            
     * @param array $parameters            
     * @param int $status            
     * @param array $headers            
     * @return \Kant\Http\RedirectResponse
     */
    public function route($route, $parameters = [], $status = 302, $headers = [])
    {
        return $this->to($this->generator->route($route, $parameters), $status, $headers);
    }

    /**
     * Create a new redirect response to a controller action.
     *
     * @param string $action            
     * @param array $parameters            
     * @param int $status            
     * @param array $headers            
     * @return \Kant\Http\RedirectResponse
     */
    public function action($action, $parameters = [], $status = 302, $headers = [])
    {
        return $this->to($this->generator->action($action, $parameters), $status, $headers);
    }

    /**
     * Create a new redirect response.
     *
     * @param string $path            
     * @param int $status            
     * @param array $headers            
     * @return \Kant\Http\RedirectResponse
     */
    protected function createRedirect($path, $status, $headers)
    {
        return tap(new RedirectResponse($path, $status, $headers), function ($redirect) {
            if (isset($this->session)) {
                $redirect->setSession($this->session);
            }
            
            $redirect->setRequest($this->generator->getRequest());
        });
    }

    /**
     * Get the URL generator instance.
     *
     * @return \Kant\Routing\UrlGenerator
     */
    public function getUrlGenerator()
    {
        return $this->generator;
    }

    /**
     * Set the active session store.
     *
     * @param \Kant\Session\Store $session            
     * @return void
     */
    public function setSession(SessionStore $session)
    {
        $this->session = $session;
    }
}
