#!/usr/bin/perl -w
# vi: set ts=4 sw=4 :
#____________________________________________________________________________
#
#   MusicBrainz -- the open internet music database
#
#   Copyright (C) 2000 Robert Kaye
#
#   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; if not, write to the Free Software
#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#   $Id$
#____________________________________________________________________________

use strict;

package MusicBrainz::Server::PagedReport;

use Storable qw( freeze thaw );
my $intlen = length(pack "i", 0);

################################################################################
# Save
################################################################################

sub Save
{
	my ($class, $file) = @_;
	open(my $fh1, ">$file.dat") or die $!;
	open(my $fh2, ">$file.idx") or die $!;
	binmode $fh1;
	binmode $fh2;
	bless {
		NUM	=> 0,
		DAT	=> $fh1,
		IDX	=> $fh2,
	}, ref($class) || $class;
}

sub Print
{
	my ($self, $record) = @_;
	$record = freeze($record);

	my $dat = $self->{DAT};
	my $idx = $self->{IDX};

	my $pos = tell $dat;
	die if $pos < 0;
	print $dat pack("i", length($record)), $record
		or die $!;
	print $idx pack "i", $pos
		or die $!;

	++$self->{NUM};
}

sub End
{
	close $_[0]{IDX} or die $!;
	close $_[0]{DAT} or die $!;
}

################################################################################
# Load
################################################################################

sub Load
{
	my ($class, $file) = @_;
	open(my $dat, "<$file.dat") or die $!;
	open(my $idx, "<$file.idx") or die $!;
	binmode $dat;
	binmode $idx;
	bless {
		NUM	=> ((-s $idx) / $intlen),
		CUR	=> 0,
		DAT	=> $dat,
		IDX	=> $idx,
	}, ref($class) || $class;
}

sub Time { (stat $_[0]{IDX})[9] }
sub Records { $_[0]{NUM} }
sub Position { $_[0]{CUR} }

sub Seek
{
	my ($self, $pos) = @_;

	$pos = int $pos;
	$pos = $self->Records if $pos > $self->Records;

	my $dat = $self->{DAT};
	my $idx = $self->{IDX};

	seek($idx, $pos * $intlen, 0)
		or die $!;

	if (eof $idx)
	{
		seek($dat, 0, 2)
			or die $!;
	} else {
		read($idx, my $idxpos, $intlen)
			or die $!;
		seek($dat, unpack("i", $idxpos), 0)
			or die $!;
	}

	$self->{CUR} = $pos;
}

sub Get
{
	my ($self, $pos) = @_;
	
	my $dat = $self->{DAT};
	my $idx = $self->{IDX};

	$self->Seek($pos) if defined $pos;

	return undef if eof $dat;

	read($dat, my $reclen, $intlen)
		or die $!;
	read($dat, my $record, unpack("i", $reclen))
		or die $!;
	++$self->{CUR};

	thaw($record);
}

1;
# eof PagedReport.pm
