/usr/local/CPAN/oEdtk/oEdtk/Record.pm


package oEdtk::Record;

use strict;
use warnings;

use Scalar::Util qw(blessed);
our $VERSION		= 0.01;

sub debug {
	my ($self) = @_;
	$self->{'_DEBUG'} = 1;
}


# A record is a sequence of fields.
sub new {
	my ($class, @fields) = @_;

	my $template = '';
	foreach my $i (0 .. $#fields) {
		my $field = $fields[$i];
		if (!blessed($field) || !$field->isa('oEdtk::Field')) {
			die "ERROR: oEdtk::Record::new only accepts oEdtk::Field objects\n";
		}
		my $len = $field->get_len();
		if ($len eq '*' && $i < $#fields) {
			die "ERROR: oEdtk::Record::new: catch-all field must be the last\n";
		}
		if ($i != 0) {
			$template .= ' ';
		}
		$template .= "A$len";
	}

	my $self = {
		fields => \@fields,
		template => $template,
		bound => {}
	};
	bless $self, $class;
	return $self;
}


sub parse {
	my ($self, $line) = @_;
	my @values;

	my $bound = $self->{'bound'};
	if ($line !~ /^.{8}(.*)$/) {
		die "ERROR: Line too short\n";
	}

	$line = $1;
	my @vals = unpack($self->{'template'}, $line);
	my %hvals = ();
	foreach my $i (0 .. $#{$self->{'fields'}}) {
		my $field = $self->{'fields'}->[$i];
		my $name = $field->get_name();
		if (exists($bound->{$name})) {
			$hvals{$name} = $field->process($vals[$i]);
		}
	}
	return %hvals;
}


sub bind {
	my ($self, %map) = @_;

	my %bound;
	foreach my $field (@{$self->{'fields'}}) {
		my $name = $field->get_name();
		if (exists($map{$name})) {
			my $new = $map{$name};
			$field->set_name($new);
			$bound{$new} = 1;
		}
	}
	$self->{'bound'} = { %{$self->{'bound'}}, %bound };
}


sub bind_all {
	my ($self) = @_;

	my $count = 0;
	my $pos = 0;
	my %identifiers;
	foreach my $field (@{$self->{'fields'}}) {
		my $name = $field->get_name();
		$name =~ s/(?:-\d+)?$//;

		# Select the longest component.
		my @parts = split(/-/, $name);
		my $id = (reverse sort { length($a) <=> length($b) } @parts)[0];

		my $orig = $field->get_name();
		my $len = $field->get_len();
		warn "DEBUG: $orig \t($pos/$len) \t=> $id \t(index: $count)\n" if $self->{'_DEBUG'};
		$pos += $len+1 if ($len ne '*');
		
		$field->set_name($id);
		$identifiers{$id} = 1;

		$self->{'bound'} = { %{$self->{'bound'}}, $id => 1 };
		$count++;
	}
}


# Bind all the fields in a record, following the old Compuset convention.
sub bind_all_c7 {
	my ($self) = @_;

	my $count = 0;
	my %identifiers;
	foreach my $field (@{$self->{'fields'}}) {
		my $name = $field->get_name();
		$name =~ s/(?:-\d+)?$//;

		# Select the longest component.
		my @parts = split(/-/, $name);
		my $id = (reverse sort { length($a) <=> length($b) } @parts)[0];
		$id = substr($id, 0, 7);
		$id .= 'x' x (7 - length($id));
		if (exists($identifiers{$id})) {
			$id = substr($id, 0, 4) . sprintf("%03d", $count);
			my $char = ord('a');
			while (exists($identifiers{$id})) {
				$id = substr($id, 0, 3) . $count . chr($char);
			}
		}

		my $orig = $field->get_name();
		warn "DEBUG: $orig => $id (index: $count)\n" if $self->{'_DEBUG'};
		
		$field->set_name($id);
		$identifiers{$id} = 1;

		$self->{'bound'} = { %{$self->{'bound'}}, $id => 1 };
		$count++;
	}
}


1;