# -*- Mode: perl -*-
#
# $Id: Medium.pm,v 0.1 2001/04/22 17:57:03 ram Exp $
#
#  Copyright (c) 1998-2001, Raphael Manfredi
#  Copyright (c) 2000-2001, Christophe Dehaudt
#  
#  You may redistribute only under the terms of the Artistic License,
#  as specified in the README file that comes with the distribution.
#
# HISTORY
# $Log: Medium.pm,v $
# Revision 0.1  2001/04/22 17:57:03  ram
# Baseline for first Alpha release.
#
# $EndLog$
#

use strict;

package CGI::MxScreen::Session::Medium;

use Carp::Datum;
use Log::Agent;

#
# ->make
#
# Creation routine.
#
sub make { logconfess "deferred" }

#
# Attributes
#

#
# The `serializer' attribute is initialized by the session object, when
# it is created.
#

sub serializer		{ $_[0]->{serializer} }
sub set_serializer	{ $_[0]->{serializer} = $_[1] }

#
# Deferred features
#

#
# ->session_id
#
# Retrieve session ID from the CGI environment.
# This is completely medium-dependant.
#
# When no CGI parameter bering a session ID is found, this routine returns
# undef, as a signal to the caller that the is no existing session.
#
sub session_id		{ logconfess "deferred" }

#
# ->is_available
#
# Look whether ID is free to use as a session ID.
# If it is free, atomically reserve it.
#
# Returns true if ID is OK for use, false if it's not available.
#
sub is_available	{ logconfess "deferred" }

#
# ->retrieve
#
# Retrieve context by session ID.
#
sub retrieve {
	DFEATURE my $f_;
	my $self = shift;
	my ($id) = @_;

	logconfess "deferred";
}

#
# ->store
#
# Store context with given session ID.
#
# Returns hash of (parameter => value) to be generated in the HTML
# to identify the session.
#
sub store {
	DFEATURE my $f_;
	my $self = shift;
	my ($id, $context) = @_;

	logconfess "deferred";
}

#
# Other features
#

#
# ->allocate_id
#
# Allocate new session ID.
# Returns allocated ID, undef if none could be allocated.
#
sub allocate_id {
	DFEATURE my $f_;
	my $self = shift;

	for (my $i = 0; $i < 100; $i++) {
		my $id = $self->_generate_session_id;
		return DVAL $id if $self->is_available($id);
	}

	logerr "could not find an unused session ID";
	return DVAL undef;
}

#
# ->_generate_session_id
#
# Generate a random session ID
#
sub _generate_session_id {
	DFEATURE my $f_;
	my $self = shift;

	require Digest::MD5;

	my $id = Digest::MD5::md5_hex(time() . {} . rand() . $$);
	$id = Digest::MD5::md5_base64($id);
	$id =~ tr|+/=|-_.|;

	return DVAL $id;
}

1;

=head1 NAME

CGI::MxScreen::Session::Medium - Abstract session saving medium

=head1 SYNOPSIS

 # Not meant to be used directly

=head1 DESCRIPTION

This class is B<deferred>, and is meant to be inherited from by classes
implementing the various session media.

=head1 SUPPORTED MEDIA

The following session media are currently supported:

=over 4

=item C<CGI::MxScreen::Session::Medium::Browser>

This saves the session within the browser, and therefore does not require
any storage on the server side.
See L<CGI::MxScreen::Session::Medium::Browser> for configuration details.

=item C<CGI::MxScreen::Session::Medium::File>

This saves the session within a file, on the server side.
See L<CGI::MxScreen::Session::Medium::File> for configuration details.

=item C<CGI::MxScreen::Session::Medium::Raw_File>

This saves the session within a file, on the server side, but bypasses
the C<CGI::MxScreen::Serializer> interface alltogether to make raw C<Storable>
calls, i.e. C<store()> and C<retrieve()>.

This is more efficient but prevents any compression (which a CPU intensive
task anyway).  As often, we're sacrifying space and genericity for performance.
See L<CGI::MxScreen::Session::Medium::Raw_File> for configuration details.

=back

=head1 INTERFACE

This section is meant for developpers wishing to implement their own
session medium.  You don't need to read it if you're only using
C<CGI::MxScreen>.

=head2 Deferred Features

These features need to be defined by heirs:

=over 4

=item C<is_available> I<session_id>

Looks whether I<session_id> is a free session ID.  If it is, atomically
reserve it.

Must return I<true> when the ID was reserved, I<false> if it is not
available.

=item C<make>

The creation routine, whose interface will necessarily be different
for every medium.

=item C<retrieve> I<session_id>

Retrieve context by session ID, and return a reference to it.

=item C<session_id>

Retrieve session ID from the CGI environment (probably in some hidden
parameter).  If there's no session ID there, return C<undef>.

=item C<store> I<session_id>, I<context>

Store I<context> by session ID.

It returns a hash ref of (parameter => value) tuples to be generated
as hidden parameters to identify the session.

=back

=head2 Attributes

The only attribute is:

=over 4

=item C<serializer>

The C<CGI::MxScreen::Serializer> object to use for serialization.
It is initialized by C<CGI::MxScreen::Session> with a C<set_serializer()> call.

=back

=head1 AUTHOR

Raphael Manfredi F<E<lt>Raphael_Manfredi@pobox.comE<gt>>

=head1 SEE ALSO

CGI::MxScreen::Session::Medium::Browser(3),
CGI::MxScreen::Session::Medium::File(3),
CGI::MxScreen::Session::Medium::Raw_File(3).

=cut