#
# This software is Copyright 2005 by Elsevier Inc.  You may use it
# under the terms of the license at http://perl.plover.com/hop/LICENSE.txt .
#



###
### FlatDB.pm
###

## Chapter 4 section 3.4

package FlatDB;
my $FIELDSEP = qr/:/;

sub new {
  my $class = shift;
  my $file = shift;
  open my $fh, "< $file" or return;
  chomp(my $schema = <$fh>);
  my @field = split $FIELDSEP, $schema;
  my %fieldnum = map { uc $field[$_] => $_ } (0..$#field);
  bless { FH => $fh, FIELDS => \@field, FIELDNUM => \%fieldnum,
          FIELDSEP => $FIELDSEP }   => $class;
}


## Chapter 4 section 3.4.1

# usage: $dbh->query(fieldname, value)
# returns all records for which (fieldname) matches (value)
use Fcntl ':seek';
sub query {
  my $self = shift;
  my ($field, $value) = @_;
  my $fieldnum = $self->{FIELDNUM}{uc $field};
  return unless defined $fieldnum;
  my $fh = $self->{FH};
  seek $fh, 0, SEEK_SET;
  <$fh>;                # discard header line
  my $position = tell $fh;

  return Iterator {
    local $_;
    seek $fh, $position, SEEK_SET;
    while (<$fh>) {
      $position = tell $fh;         
      my @fields = split $self->{FIELDSEP};
      my $fieldval = $fields[$fieldnum];
      return $_ if $fieldval eq $value;
    }
    return;
  };
}


## Chapter 4 section 3.4.1

# callbackquery with bug fix
use Fcntl ':seek';
sub callbackquery {
  my $self = shift;
  my $is_interesting = shift;
  my $fh = $self->{FH};
  seek $fh, 0, SEEK_SET;
  <$fh>;                # discard header line
  my $position = tell $fh;

  return Iterator {
    local $_;
    seek $fh, $position, SEEK_SET;
    while (<$fh>) {
      $position = tell $fh;         
      my %F;
      my @fieldnames = @{$self->{FIELDS}};
      my @fields = split $self->{FIELDSEP};
      for (0 .. $#fieldnames) {
        $F{$fieldnames[$_]} = $fields[$_];
      }
      return [$position, $_] if $is_interesting->(%F);
    }
    return;
  };
}

1;
