#---------------------------------------------------------------------#
# function ReadScoringMatrixFromFile:                                 #
#    reads a scoring matrix for sequence alignment from a file and    #
#    stores it in a hash of hashes; the file must be given in         #
#    the BLAST scoring matrix format                                  #
#    the functions return 0 upon success and a non-zero value if an   #
#    error has occurred                                               #
#---------------------------------------------------------------------#

sub ReadScoringMatrixFromFile
{
    my ($filename, $mhash) = @_;

    return 1 unless (open(INPUT, "< $filename")); # file could not be opened

    my $init = 1;
    my @keylist;
    my %keyhash;
    my $num = 0;

    while (my $line = <INPUT>) # read line by line
    {
        chomp $line;

	$line =~ /([^\#]*)/; # strip comments
	$line = $1;

	if ($line =~ /\S/) # line contains something
	{
	    if ($init) # treat first line differently
	    {
	        # parse header line

	        return 2 if ($line =~ /[^A-IK-NP-Z\*\s]/);

	        @keylist = ($line =~ /[A-IK-NP-Z\*]/g);

		$num = @keylist;

		return 2 if ($num <= 1); # syntax error

		$keyhash{$_} = 1 foreach (@keylist); # build up index

		$init = 0;
	    }
	    else
	    {
	        if ($line =~ /([\w\*])\W(.*)/) # extract first charachter
		{
		    my $linechar = $1;

		    return 2 unless (exists($keyhash{$linechar})); # sy. error

		    my @entries = ($2 =~ /([+-]?\d+)/g); # split rest of line

		    return 2 if (@entries != $num); # syntax error

		    for (my $i = 0; $i < $num; $i++)
		    {
		        $mhash->{$linechar}{$keylist[$i]} = $entries[$i];
		    }
		}
		else # syntax error
		{
		    return 2;
		}
	    }
	}
    }

    return 2 if ($num != keys(%$mhash)); # syntax error: matrix incomplete

    # check symmetry

    foreach my $key1 (keys(%$mhash))
    {
        foreach my $key2 (keys(%$mhash))
	{
	    return 3 if ($mhash->{$key1}{$key2} != $mhash->{$key2}{$key1});
	}
    }

    return 0;
}
