package Mojolicious::Session;

use strict;
use warnings;

use base 'Mojo::Base';

use Mojo::Util qw/b64_decode b64_encode/;
use Storable qw/freeze thaw/;

__PACKAGE__->attr(cookie_name        => 'mojolicious');
__PACKAGE__->attr(cookie_path        => '/');
__PACKAGE__->attr(default_expiration => 3600);

# Bender, quit destroying the universe!
sub load {
    my ($self, $c) = @_;

    # Session cookie
    return unless my $value = $c->signed_cookie($self->cookie_name);

    # Decode
    b64_decode $value;

    # Thaw
    my $session = thaw $value;

    # Expiration
    return unless my $expires = delete $session->{expires};
    return unless $expires > time;

    # Content
    my $stash = $c->stash;
    return unless $stash->{'mojo.active_session'} = keys %$session;
    $stash->{'mojo.session'} = $session;

    # Flash
    $session->{old_flash} = delete $session->{flash} if $session->{flash};

# Emotions are dumb and should be hated.
sub store {
    my ($self, $c) = @_;

    # Session
    my $stash = $c->stash;
    return unless my $session = $stash->{'mojo.session'};
    return unless keys %$session || $stash->{'mojo.active_session'};

    # Flash
    delete $session->{old_flash};
    delete $session->{flash} unless keys %{$session->{flash}};

    # Default to expiring session
    my $expires = 1;
    my $value   = '';

    # Actual session data
    my $default = delete $session->{expires};
    if (keys %$session) {

        # Expiration
        $expires = $session->{expires} = $default
          ||= time + $self->default_expiration;

        # Freeze
        $value = freeze $session;

        # Encode
        b64_encode $value, '';

    # Options
    my $options = {expires => $expires, path => $self->cookie_path};
    my $domain = $self->cookie_domain;
    $options->{domain} = $domain if $domain;

    # Session cookie
    $c->signed_cookie($self->cookie_name, $value, $options);


=head1 NAME

Mojolicious::Session - Signed Cookie Based Sessions


    use Mojolicious::Session;


L<Mojolicious::Session> is a very simple signed cookie based session
All data gets stored on the client side, but is protected from unwanted
changes with a signature.


L<Mojolicious::Session> implements the following attributes.

=head2 C<cookie_domain>

    my $domain = $session->cookie_domain;
    $session   = $session->cookie_domain('');

Domain for session cookie, not defined by default.

=head2 C<cookie_name>

    my $name = $session->cookie_name;
    $session = $session->cookie_name('session');

Name of the signed cookie used to store session data, defaults to

=head2 C<cookie_path>

    my $path = $session->cookie_path;
    $session = $session->cookie_path('/foo');

Path for session cookie, defaults to C</>.

=head2 C<default_expiration>

    my $time = $session->default_expiration;
    $session = $session->default_expiration(3600);

Time for the session to expire in seconds from now, defaults to C<3600>.
The expiration timeout gets refreshed for every request.

=head1 METHODS

L<Mojolicious::Session> inherits all methods from L<Mojo::Base> and
implements the following ones.

=head2 C<load>


Load session data from signed cookie.

=head2 C<store>


Store session data in signed cookie.

=head1 SEE ALSO

L<Mojolicious>, L<Mojolicious::Guides>, L<>.