sub untabifulate($)
  {
    my ($linearray) = @_;
    my $cellarray;
    for my $v (@{$linearray})
      {
	my @celery = split '\s+',$v;
	if ($celery[0] eq "") { shift @celery }
	push @{$cellarray},[@celery];
      }
    return $cellarray;
  }

sub tabifulate($)
  {
    my ($linesr) = @_;
    my @linelengths;

    for my $v (0 .. scalar(@{$linesr})-1)
      {
	for my $w (0 .. scalar(@{$linesr->[$v]})-1)
	  {
	    my $cell_length = length($linesr->[$v]->[$w]);
	    if ($cell_length >= $linelengths[$w])
	      {
		$linelengths[$w] = 1+$cell_length;
	      }
	    #	    print "$v $w ",length($linesr->[$v]->[$w])," ",$linesr->[$v]->[$w],"\n";
	  }
      }
    my @aus;
    for my $v (0 .. scalar(@{$linesr})-1)
      {
	my $this_line = "";
	for my $w (0 .. scalar(@{$linesr->[$v]})-1)
	  {
	    my $this_cell = $linesr->[$v]->[$w];
	    $this_line .= $this_cell;
	    $this_line .= " "x($linelengths[$w]-length($this_cell));
	  }
	push @aus,$this_line;
      }
    return \@aus;
  }
  
sub inhale_mol2($)
  {
    my ($fn) = @_;
    # return a hashref mapping @<TRIPOS>xxx sections to their lines
    my ($inhaled, $section);
    open A,"< $fn";
    while (<A>)
      {
	chomp;
	s/\r$//; # dos line endings
	s/ +$//; # spaces at the end
	if (/^@/)
	  {
	    $section = $_;
	  }
	else
	  {
	    push @{$inhaled->{$section}},$_;
	  }
      }
    close A;
    return $inhaled;
  }

sub exhale_mol2($$)
  {
    my ($m2,$fn) = @_;
    my @order = ("MOLECULE","ATOM","BOND");
    my %used;
    open B,"> $fn";
    
    foreach my $block (@order)
      {
	my $bn = "@<TRIPOS>".$block;
	if (defined $m2->{$bn})
	  {
	    print B $bn,"\n";
	    print B join "\n",@{$m2->{$bn}};
	    print B "\n";
	    $used{$bn}=1;
	  } 
      }
    foreach my $block (keys %{$m2})
      {
	if (! exists $used{$block})
	  {
	    print B join "\n", ($block, @{$m2->{$block}});
	    print B "\n";
	  }
      }
    close B;
  }

sub assign_hydrogen_names($$)
  {
    print STDERR " WARNING: fixing atomnames for bare atoms called \'H\' based on atoms they are bonded to\n";
    my ($atx,$bdx)=@_;
    # get the list of hydrogen atoms
    my %atom_names;
    my (@hydrogens,%hydroset);
    for my $u (@{$atx})
      {
	$atom_names{$u->[0]} = $u->[1];
	if ($u->[1] eq "H") { push @hydrogens, $u->[0];
			      $hydroset{$u->[0]}=1 }
      }
    my (%hydrogens,%bonded_to);
    for my $v (@{$bdx})
      {
	my ($left,$right) = ($v->[1],$v->[2]);
	if (defined $hydroset{$left} and defined $hydroset{$right})
	  {
	    die " mol2 file contains bond between hydrogen atoms!  this is implausible\n";
	  }
	else
	  {
	    my ($bonded,$the_hid) = (-1,-1); 
	    if (defined $hydroset{$left})  { $bonded = $right; $the_hid = $left }
	    if (defined $hydroset{$right}) { $bonded = $left; $the_hid = $right }
	    if ($bonded != -1)
	      {
		$bonded_to{$the_hid} = $bonded;
		push @{$hydrogens{$bonded}},$the_hid;
	      }
	  }
      }
    my (%newname, %exists);
    # prepare rename table
    for my $j (@hydrogens)
      {
	my $k = $bonded_to{$j};
	if (! defined $k )
	  {
	    print "That's odd; H number $j isn't bonded at all!\n";
	  }
	my $kn = $atom_names{$k}; 
	my @hlist = @{$hydrogens{$k}}; # the list of hydrogens bonded to K
        # make up name from name they are bonded to.
        if (($#hlist != 0) && length($kn) > 2) { # use 2nd and 3rd characters
          $kn = substr($kn,1,2); 
        }
        elsif (length($kn) > 3) {
          $kn = substr($kn,0,3);
        }
        $kn = "H".$kn; 
        $kn = $kn."A" if ($#hlist != 0);
        # now check to see whether this name has already been given to a hydrogen
        my $iloop = 0;
        while ($exists{$kn}) {  # name exists
           print "debug $kn already exists\n" if ($debug==1);
           chop($kn);
           $iloop++;
           die "ERROR in making up name for hydrogen atom bonded to ",$atom_names{$k}, 
               " all names like $kn occupied?\n" if ($iloop>25); 
           $kn .= chr(65+$iloop);
        }
        $exists{$kn} = 1;
	$newname{$j}=$kn;
        print "debug H bonded to atomname ",  $atom_names{$k}, " given new name ", $newname{$j}, "\n" if ($debug==1);
      }
    # do the renaming
    for my $j (@{$atx})
      {
	if (defined $newname{$j->[0]})
	  {
	    $j->[1] = $newname{$j->[0]};
	  }
      }
  }

    my $inhaled_mol2 = inhale_mol2($ARGV[0]);
    my $atx = untabifulate($inhaled_mol2->{"@<TRIPOS>ATOM"});
    my $bdx = untabifulate($inhaled_mol2->{"@<TRIPOS>BOND"});
  assign_hydrogen_names($atx,$bdx);
    $inhaled_mol2->{"@<TRIPOS>ATOM"} = tabifulate($atx);
    exhale_mol2($inhaled_mol2, $ARGV[1]);
