# This implements a java Hashtable

# Keys and values are stored in arrays KEYS and VALUES, such that the
# same index is used for the same ordered pair in the hash.

use Error;

package Hashtable;

sub new {
  my $proto=shift;
  my $class=ref($proto) || $proto;
  my $self={};
  my @foo=();
  my @bar=();

  $self->{KEYS}=\@foo;
  $self->{VALUES}=\@bar;
  bless($self, $class);
  return($self);
}

sub contains {
  my $self=shift;
  my $key=$_[0];
  my $keyclass=ref($key);
  my $i;
  my (@keys, $ref);

  $ref=$self->{KEYS};
  @keys=@$ref;
  if ($#keys==-1) {
# print "contains: no keys; returning 0\n";
    return(0);
  }
  for ($i=0;$i<=$#keys;$i++) {

# What are we looking at?  Strings can be compared directly;
# otherwise, we have to use the ->equals function.  of course, if this
# object doesn't define that, we're SOL.

    if ($keyclass eq "") { # String, we hope
      if ($keys[$i] eq $key) {
# print "contains: found; returning 1\n";
	return(1);
      }
    } else {
      $foo=$keys[$i];
      if ($key->equals($foo)) {
# print "contains: found; returning 1\n";
	return(1);
      }
    }
  }
# print "contains: not found; returning 0\n";
  return(0);
}

sub get {
  my $self=shift;
  my $key=$_[0];
  my $keyclass=ref($key);
  my $i;
  my ($keys_ref, $values_ref);

  $keys_ref=$self->{KEYS};
# If this hash is empty, we're outta here.
  if ($#$keys_ref==-1) {
    return(0);
  }
  $values_ref=$self->{VALUES};

  for ($i=0;$i<=$#$keys_ref;$i++) {
    if ($keyclass eq "") { # String, we hope
      if ($$keys_ref[$i] eq $key) {
	return($$values_ref[$i]);
      }
    } else {
      $foo=$$keys_ref[$i];
#      if ($key->{FAST_COMPARE} eq $foo->{FAST_COMPARE}) {
	if ($key->equals($foo)) {
	  return($$values_ref[$i]);
	}
#      }
    }
  }
  return(0);
}

sub keys {
  my $self=shift;
  return($self->{KEYS});
}

sub push_into_array {
# Input: push_key, push_value
# Requires: VALUES is an array of stuff.
# Effects: matches on push_key.  If match, does a push(VALUES[i], push_value)
#     Otherwise, adds a new entry into KEYS and VALUES
  my $self=shift;
  my $i;
  my ($push_key, $push_value)=@_;
  my $push_key_class=ref($push_key);
  my ($keys_ref, $values_ref);
  my (@foo, $bar);

  $debug=0;

  $keys_ref=$self->{KEYS};
  $values_ref=$self->{VALUES};

  for ($i=0;$i<=$#$keys_ref;$i++) {
    if ($push_key_class eq "") { # String, we hope
      last if ($$keys_ref[$i] eq $push_key);
    } else {
      if ($$keys_ref[$i]->{FAST_COMPARE} eq $push_key->{FAST_COMPARE}) {
	last if ($$keys_ref[$i]->equals($push_key));
      }
    }
  }

  if ($i>$#$keys_ref) { # need to create an array
    push(@$keys_ref, $push_key);
    push(@foo, $push_value);
    push(@$values_ref, \@foo);
  } else {
    $fooref=$$values_ref[$i];
    @foo=@$fooref;
    push(@foo, $push_value);
    $$values_ref[$i]=\@foo;
  }

  $keys_ref=$self->{KEYS};
  $values_ref=$self->{VALUES};
}

sub put {
  my $self=shift;
  my($key, $value)=@_;
  my $keyclass=ref($key);
  my $i;
  my ($keys_ref, $values_ref);

  $keys_ref=$self->{KEYS};
  $values_ref=$self->{VALUES};
  if ($#$keys_ref>-1) {
    for ($i=0;$i<=$#$keys_ref;$i++) {
      if ($keyclass eq "") { # String, we hope
	if ($$keys_ref[$i] eq $key) {
	  $$values_ref[$i]=$value;
	  $self->{VALUES}=$values_ref;
	  return;
	}
      } elsif ($key->equals($$keys_ref[$i])) {
	$$values_ref[$i]=$value;
	$self->{VALUES}=$values_ref;
	return;
      }
    } # for
  }

  # new key
  push(@$keys_ref, $key);
  push(@$values_ref, $value);
  $self->{KEYS}=$keys_ref;
  $self->{VALUES}=$values_ref;
}

sub remove {
  my $self=shift;
  my $element=$_[0];
  my ($keys_ref, $values_ref, $i);
  my ($this, @this);

  $keys_ref=$self->{KEYS};
  if ($#$keys_ref>-1) {
    for($i=0;$i<=$#$keys_ref;$i++) {
      $this=$$keys_ref[$i];
      if (ref($this) eq "ARRAY") {
	@this=@$this;
      }
      if ($element->equals($this)) {
	if ($i==$#$keys_ref) {
	  pop(@$keys_ref);
	  $this=$$keys_ref[0];
	} else {
	  $$keys_ref[$i]=pop(@$keys_ref);
	}
	$self->{KEYS}=$keys_ref; # is this necessary?


	$values_ref=$self->{VALUES};
	if ($i==$#$values_ref) {
	  pop(@$values_ref);
	} else {
	  $$values_ref[$i]=pop(@$values_ref);
	}
	$self->{VALUES}=$values_ref; # is this necessary?

	return;
      }
    }
  }
  General::log("Hashtable:remove -- element not found");
}

1;
