package SimpleDB::Hash;
# $Id: Hash.pm,v 1.2 2000/12/14 17:45:40 tom Exp $
################################################################


=head1 NAME

SimpleDB::Hash - ハッシュファイル結合

=head1 SYNOPSIS

 use SimpleDB::Hash;

 tie %s, 'SimpleDB::Hash', "foo.dat";
 $s{'a'} = "abc";
 print $s{'a'};

=head1 DESCRIPTION

 tie $s, 'SimpleDB::Hash', "foo.dat", 1;

とすると read only として扱う。

=cut

################################################################

use strict;
use Fcntl ':flock';
use vars qw(@ISA $Delimiter);
use SimpleDB::Base;

@ISA = qw(SimpleDB::Base);

$Delimiter = "\t";

sub TIEHASH ($@)
{
    my ($class, $filename, @options) = @_;
    my $self = new SimpleDB::Base($filename, @options);
    bless $self, $class;
}
sub FETCH ($$)
{
    my ($self, $key) = @_;

    $self->SUPER::FETCH;
    return $self->{contents}->{$key};
}
sub STORE ($$$)
{
    my ($self, $key, $value) = @_;

#    die "$key: $value";
    $self->SUPER::STORE;
    $self->{contents}->{$key} = $value;
}
sub DESTROY ($)
{
    my $self = shift;

    return unless $self->{modified};    # 変更がなければ何もしない
    return if $self->SUPER::DESTROY;

    unless (open(HASH_WRITE, ">$self->{filename}")){
	die "cannot write : $self->{filename}";
    }
    eval 'flock(HASH_WRITE, LOCK_EX)';
    my ($k, $c);
    while (($k, $c) = each(%{$self->{contents}})){
	print HASH_WRITE "$k$Delimiter$c\n";
    }
    eval 'flock(HASH_WRITE, LOCK_UN)';
    close (HASH_WRITE);
}
sub FIRSTKEY
{
    my $self = shift;

#    print "FIRSTKEY", $self->{read};
    $self->Read;
#    print each %{$self->{contents}};

    return each (%{$self->{contents}});
}
sub NEXTKEY
{
    return each %{shift->{contents}};
}
sub EXISTS
{
    my ($self, $key) = @_;
    $self->Read;
    return exists $self->{contents}->{$key};
}
sub DELETE
{
    my ($self, $key) = @_;
    $self->Read;
    delete $self->{contents}->{$key};
    return undef;
}

################################################################
sub Read ($)
{
    my $self = shift;

    return if $self->SUPER::Read;
    open(HASH_READ, $self->{filename}) || return;
    eval 'flock(HASH_READ, LOCK_EX)';
    while (<HASH_READ>){
	chomp;
#	print "Read: line:$_";
	my ($tkey, $content) = /^(.*?)$Delimiter(.*)$/;
	$self->{contents}->{$tkey} = $content;
    }
    eval 'flock(HASH_READ, LOCK_UN)';
    close (HASH_READ);
}

1;
