#Copyright Massachusetts Institute of technology, 1998.
#Written by Eric Prud'hommeaux for the World Wide Web Consortium

use strict;
require Exporter;
require AutoLoader;

use W3C::Database::DBStreamHandle;

package W3C::Database::DbInterface;
use vars qw($VERSION $REVISION $DSLI @ISA @EXPORT @EXPORT_OK @TODO);
@ISA = qw(Exporter AutoLoader);
@EXPORT = qw();
@EXPORT_OK = qw();
$VERSION = 0.97;
$REVISION = '$Id: DbInterface.pm,v 1.18 2003/03/24 14:13:56 eric Exp $ ';
$DSLI = 'adpO';
@TODO = ();

@W3C::Database::DBHandle::ISA = qw(W3C::Database::DBMHandle);
@W3C::Database::GDBMHandle::ISA = qw(W3C::Database::DBMHandle);
@W3C::Database::NDBMHandle::ISA = qw(W3C::Database::DBMHandle);
@W3C::Database::SDBMHandle::ISA = qw(W3C::Database::DBMHandle);

package W3C::Database::DbConn;
use W3C::Util::Exception;
use POSIX;

use vars qw(%AllHandles);
%AllHandles = ();

# overloadable defaults
use vars qw($DEFAULT_DB_TYPE);
$DEFAULT_DB_TYPE = 'NDBM_File';

sub new {
    my ($proto, $name, $mode, $type) = @_;
    my $class = ref($proto) || $proto;
    my $self  = {};
    bless ($self, $class);

    my $dbType = $DEFAULT_DB_TYPE;
    if (defined $type) {
	if ($type =~ m/^db$/i) {
	    $dbType = 'DB_File';
	} elsif ($type =~ m/^gdbm$/i) {
	    $dbType = 'GDBM_File';
	} elsif ($type =~ m/^ndbm$/i) {
	    $dbType = 'NDBM_File';
	} elsif ($type =~ m/^sdbm$/i) {
	    $dbType = 'SDBM_File';
	} else {
	    &throw(new W3C::Util::Exception(-message => "db type \"$type\" unknown"));
	}
    }
    require "$dbType.pm";

    my %db;
    $self->{DB} = \%db;
    $self->{NAME} = $name;
    $self->{MODE} = $mode;
    $self->{MODE} = $W3C::DBStreamHandle::READ_WRITE if (!defined $self->{MODE});

    my $openMode;
    if ($self->{MODE} == $W3C::DBStreamHandle::READ_ONLY) {
	$openMode = O_RDONLY; # &GDBM_File::GDBM_READER;
    } elsif ($self->{MODE} == $W3C::DBStreamHandle::WRITE_ONLY) {
	if (-e $self->{NAME}) {
	    $openMode = O_RDWR; # &GDBM_File::GDBM_WRITER;
	} else {
	    $openMode = O_RDWR | O_CREAT; # &GDBM_File::GDBM_WRCREAT;
	}
    } elsif ($self->{MODE} == $W3C::DBStreamHandle::CREATE) {
	$openMode = O_RDWR | O_CREAT; # &GDBM_File::GDBM_WRCREAT;
    } else {
	&throw(new W3C::Util::Exception(-message => "open what datebase file with what access?"));
    }

    if (!tie(%db, $dbType, $self->{NAME}, $openMode, 0644)) {
	&throw(new W3C::Util::Exception(-message => 'couldn\'t open "'.$self->{NAME}.'" : '.$!));
    }

    $AllHandles{$self} = $self;
    return $self;
}

sub getDB {
    my ($self) = @_;
    return $self->{DB};
}

sub close {
    my ($self) = @_;
    untie $self->{DB};
    delete $AllHandles{$self};
}

sub END {
    foreach my $connString (keys %AllHandles) {
	$AllHandles{$connString}->close;
    }
}

package W3C::Database::DBMHandle;
use W3C::Util::Exception;

@W3C::Database::DBMHandle::ISA = ('W3C::Database::DelimStreamHandle'); # grab encoding methods

sub new {
    my ($proto, $dbFile) = (shift, shift);
    my $class = ref($proto) || $proto;
    my $self  = $class->SUPER::new(@_);
    bless ($self, $class);
    $self->{DB_CONN} = W3C::Database::DbInterface::newConnection($dbFile, $self->{ACCESS}, $self->getType());
    $self->{DB} = $self->{DB_CONN}->getDB;
    return $self;
}

sub getType {
    &throw(new W3C::Util::NotImplementedException());
}

sub put {
    my ($self, @values) = @_;
    my $encoded = $self->encode(@values[1..$#values]);
    eval {
	$self->{DB}{$values[0]} = $encoded;
    }; if ($@) {&throw()}
}

sub forEach {
    my ($self) = @_;
    foreach my $key (keys %{$self->{DB}}) {
	my $value = $self->{DB}{$key};
	$self->{SINK}->put($key, $self->decode($value));
    }
}

sub close {
    my ($self, $disposition) = @_;
    my @ret = $self->SUPER::close($disposition);
    $self->{DB_CONN}->close;
    return @ret;
}

sub W3C::Database::DBHandle::getType {return 'db';}
sub W3C::Database::GDBMHandle::getType {return 'gdbm';}
sub W3C::Database::NDBMHandle::getType {return 'ndbm';}
sub W3C::Database::SDBMHandle::getType {return 'sdbm';}

package W3C::Database::DbInterface;

sub newConnection {
    return new W3C::Database::DbConn(@_);
}

1;

__END__

=head1 NAME

W3C::Database::DbInterface - DBStreamHandle to talk to db,gdbm,ndbm and sdbm databases

=head1 SYNOPSIS

see ddb.pl

=head1 DESCRIPTION

This module is part of the W3C::Database CPAN module.

=head1 AUTHOR

Eric Prud\'hommeaux <eric@w3.org>

=head1 SEE ALSO

perl(1).

=cut
