package Lire::Extensions::WWW::UserSessionSchema;

# vim:syntax=perl

use strict;

use vars qw/ $VERSION @ISA $not_page_re/;

use Lire::AsciiDlf::DerivedRecordsCreator;
use Lire::AsciiDlf::ExtendedFieldsCreator;

# define allowed inactive time
use constant SESSION_EXPIRES => 30 * 60; # 30 minutes

use Carp;

BEGIN {
    ($VERSION)	= '$Revision: 1.7 $' =~ m!Revision: ([.\d]+)!;
    @ISA = qw( Lire::AsciiDlf::ExtendedFieldsCreator
	       Lire::AsciiDlf::DerivedRecordsCreator );

    $not_page_re = qr/\.(png|jpg|jpeg|gif|css)$/i;
}

sub init_computation {
    my ( $self, $dlf_info, $writer_cb ) = @_;

    $self->{session_cache}	= {};

    # Cache field's index
    $self->{time_idx} =
      $self->schema->base->field( "time" )->pos;
    $self->{client_host_idx} =
      $self->schema->base->field( "client_host" )->pos;
    $self->{ua_idx} =
      $self->schema->base->field( "useragent" )->pos;
    $self->{page_idx} =
      $self->schema->base->field( "requested_page" )->pos;

    my @fields = map { $_->name } $self->schema->fields;
    @fields = grep { ! /page/ } @fields
      unless $dlf_info->is_field_available( "requested_page" );

    $self->{dlf_record_maker} =
      $self->schema->make_hashref2asciidlf_func( @fields );
}

sub create_extended_fields {
    my ( $self, $dlf ) = @_;

    my $session = $self->get_session( $dlf );
    if ( defined $session && ! $self->is_session_expired( $session, $dlf ) ) {
	[ $session->{session_id} ];
    } else {
	[$self->create_session( $dlf )->{session_id} ];
    }
}

sub dlf_record {
    my ( $self, $dlf, $writer_cb ) = @_;

    # Keep the last record around for end_session
    $self->{last_dlf} = $dlf;

    my $session = $self->get_session( $dlf );
    if ( defined $session ) {
	if ( $self->is_session_expired( $session, $dlf ) ) {
	    # Session is ended write it
	    $session->{completed} = 'yes';
	    $self->end_session( $session, $writer_cb );

	    # Create a new one
	    $self->create_session( $dlf );
	} else {
	    # Update the session
            $session->{session_end} = $dlf->[ $self->{time_idx} ];
	    $session->{session_length} =
	      $session->{session_end} - $session->{session_start};
	    $session->{req_count}++;

	    my $url = $dlf->[ $self->{page_idx} ];

	    if ( $url ne "LIRE_NOTAVAIL" && $url !~ /$not_page_re/ ) {
		$session->{first_page} = $url
		  if ! defined $session->{first_page};
		$session->{last_page} = $url;
		my $cnt = $session->{page_count} += 1;
		$session->{"page_$cnt"} = $url if ( $cnt <= 5 );
	    }
	}
    } else {
	$self->create_session( $dlf );
    }

}

sub end_computation {
    my ( $self, $writer_cb ) = @_;

    if ($writer_cb) {
	# Write all unfinished session
	foreach my $session ( values %{$self->{session_cache}} ) {
	    $session->{completed} =
	      $self->is_session_expired( $session, $self->{last_dlf} )
		? 'yes' : 'no';

	    $self->end_session( $session, $writer_cb );
	}
    }

    # Free memory
    delete $self->{session_cache};
}

sub create_session {
    my ( $self, $dlf ) = @_;

    my $client_host = $dlf->[$self->{client_host_idx}];
    my $ua	    = $dlf->[$self->{ua_idx}];
    my $time	    = $dlf->[$self->{time_idx}];

    my $visit_number =
      $self->{session_cache}{$client_host . $ua}{visit_number} || 0;

    my $session = $self->{session_cache}{$client_host . $ua} =
      {
       session_id	=> join( ":", $time, $client_host, $ua ),
       session_start	=> $time,
       session_end	=> $time,
       session_length	=> 0,
       req_count	=> 1,
       visit_number	=> $visit_number + 1,
      };

    my $url = $dlf->[$self->{page_idx}];
    if ( $url ne "LIRE_NOTAVAIL" && $url !~ /$not_page_re/ ) {
	$session->{first_page} = $url;
	$session->{last_page}  = $url;
	$session->{page_count} = 1;
    }

    return $session;
}

sub end_session {
    my ( $self, $session, $writer_cb ) = @_;

    my $cnt = $session->{page_count} || 0; # In case of only images session
    for ( my $i = $cnt; $i ne "LIRE_NOTAVAIL" && $i <= 5; $i++) {
	next if $i < 2;
	$session->{"page_$i"} = "None";
    }

    $writer_cb->( $self->{dlf_record_maker}->($session) );
}

sub get_session {
    my ( $self, $dlf ) = @_;


    my $client_host = $dlf->[$self->{client_host_idx}];
    my $ua	    = $dlf->[$self->{ua_idx}];

    return $self->{session_cache}{$client_host . $ua };
}

sub is_session_expired {
    my ( $self, $session, $dlf ) = @_;

    my $time = $dlf->[$self->{time_idx}];
    return ($session->{session_end} + SESSION_EXPIRES) < $time;
}

# keep perl happy
1;

__END__

=pod

=head1 NAME

Lire::UserSessionSchema -

=head1 SYNOPSIS


=head1 DESCRIPTION

=head1 VERSION

$Id: UserSessionSchema.pm,v 1.7 2002/03/16 05:18:24 flacoste Exp $

=head1 COPYRIGHT

Copyright (C) 2001 Stichting LogReport Foundation LogReport@LogReport.org

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program (see COPYING); if not, check with
http://www.gnu.org/copyleft/gpl.html or write to the Free Software 
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.

=head1 AUTHOR

Francis J. Lacoste <flacoste@logreport.org>

=cut
