# ===================================
# RDB.pm
#
# Parse data into a hash:
#
#
# $tbl{headers_name} = @ of the column header name.
# $tbl{headers_spec} = @ of the specs for the columns.
# $tbl{comments}     = @ of the comments.
# $tbl{data}         = % (indexed by header names) of the @ of the data.
#
#

# This only provides read services, not writing.

package RDB;

use strict;
use vars qw($VERSION @ISA @EXPORT_OK);

require Exporter;

$VERSION = "0.1";
@ISA = qw(Exporter);
@EXPORT_OK = qw(RDB_parse_string RDB_parse_array RDB_splice_data);


# Params:
#  $tbl = Main hash, see top.
sub RDB_parse_init
  {
    my ($tbl) = @_;

    $tbl->{headers_name} = ();
    $tbl->{headers_spec} = ();
    $tbl->{comments} = ();
    $tbl->{data} = ();
  }


# Params:
#  $line = String of the next line to add to the hash.
#  $tbl  = Main hash, see top.
sub RDB_parse_comment
  {
    my ($line, $tbl) = @_;

    if ($line !~ /^\#/)
      {
	return (0);
      }

    push (@{$tbl->{comments}}, $line);
  }

# Params:
#  $line = String of the next line to add to the hash.
#  $tbl  = Main hash, see top.
sub RDB_parse_headers_name
  {
    my ($line, $tbl) = @_;

    my @cells = split ("\t", $line, -1);

    @{$tbl->{headers_name}} = @cells;

    my $i = undef;
    for $i (@cells)
      {
	$tbl->{data}->{$i} = ();
      }

    return (1);
  }

# Params:
#  $line = String of the next line to add to the hash.
#  $tbl  = Main hash, see top.
sub RDB_parse_headers_spec
  {
    my ($line, $tbl) = @_;


    my @cells = split ("\t", $line, -1);

    if (scalar (@cells) != scalar(@{$tbl->{headers_name}}))
      { return (0); }

    @{$tbl->{headers_spec}} = @cells;

    return (1);
  }

# Params:
#  $line = String of the next line to add to the hash.
#  $tbl  = Main hash, see top.
sub RDB_parse_entry
  {
    my ($line, $tbl) = @_;

    my @cells = split ("\t", $line, -1);

    if (scalar (@cells) != scalar(@{$tbl->{headers_name}}))
      { return (0); }

    my @cell_names = @{$tbl->{headers_name}};

    my $i = undef;
    for $i (@cells)
      {
	my $header = shift (@cell_names);
	push (@{$tbl->{data}->{$header}}, $i);
      }

    ++$tbl->{entries};

    return (1);
  }

# Params:
#  @lines = Array of strings (lines of a "file" to parse).
sub RDB_parse_array
  {
    my @lines = @_;

    my $table = {};

    RDB_parse_init($table);

    while ((scalar(@lines) > 2) &&
	   RDB_parse_comment($lines[0], $table))
      { shift (@lines); }

    if (scalar(@lines) < 3)
      { return (undef); }
    if (!RDB_parse_headers_name($lines[0], $table))
      { return (undef); }

    shift (@lines);

    if (!RDB_parse_headers_spec($lines[0], $table))
      { return (undef); }

    shift (@lines);

    my $i = undef;
    for $i (@lines)
      {
	if (!RDB_parse_entry($i, $table))
	  { return (undef); }
      }
    
    return ($table);
  }

# Params:
#  $content = Multiline string of the "file" to parse.
sub RDB_parse_string
  {
    my ($content) = @_;

    my @lines = split ('\n', $content);

    return (RDB_parse_array(@lines));
  }

# Params:
#  $tbl    = An object from RDB_parse_array etc.
#  $entry  = The number of the entry to delete.
#  $number = The number of entries to delete (can be undef).
# Returns: a hash of the entry(s) removed.
sub RDB_splice_data
  {
    my ($tbl, $entry, $num) = @_;
    my ($ret) = {};

    if (!defined($num))
      {	$num = 1; }

    if ($entry < 0)
      {
	return (undef);
      }
    
    for my $i (keys %{$tbl->{data}})
      {
	if ($entry > $#{$tbl->{data}->{$i}})
	  {
	    return (undef);
	  }

	@{$ret->{$i}} = splice (@{$tbl->{data}->{$i}}, $entry, $num);
      }

    return ($ret);
  }

1;
