#! /usr/bin/perl -w


# Author : HqD
# Version : 0.0.1

use strict;
#use Switch;
use POSIX qw(ceil floor);
use List::Util qw[min max];

&main();

sub main() {
	my $flag = 0;
	my $file_name = "roudier";
	foreach my $arg (@ARGV){
		if ($arg =~ /^-[f]/) {$flag = 1; next;}
		if ($flag==1) {$file_name = $arg;next;}
	}
	hamming_distance($file_name, $file_name.".hamming");
}

sub hamming_distance {
	my $in_file = $_[0];
	my $out_file = $_[1];
	my @motifs = undef; my @freqs = undef;
	open(IN, $in_file ) or die "$!\n";
	my $N = 0;
	while (<IN>) {
		chomp;
		my @line=split /\s+/,$_;
		$motifs[$N] = $line[0];
		$freqs[$N] = convert($line[1]);
		$N++;
	}
	close(IN);	
	my @hamming_dist = undef;
	for (my $i=0; $i<$N; $i++) {
		my @temp = undef;
		for (my $j=0; $j<$N; $j++) {
			$temp[$j] = 0;
		}
		$hamming_dist[$i] = [ @temp ];
	}

	for (my $i=0; $i<$N-1; $i++) {
		if ($i % 1000 ==0) {print $i, "...\n";}
		for (my $j=$i+1; $j<$N; $j++) {
			my $temp_dist = 0;
			if (index($motifs[$i], "N")>=0 || index($motifs[$j], "N")>=0) {
				my $temp1 = "";
				for (my $k=0; $k<length($motifs[$i]); $k++) {
					if (substr($motifs[$i], $k, 1) eq "N") {
						$temp1 = $temp1.substr($motifs[$j], $k, 1);
					}
				}
				my $temp2 = "";
				for (my $k=0; $k<length($motifs[$j]); $k++) {
					if (substr($motifs[$j], $k, 1) eq "N") {
						$temp2 = $temp2.substr($motifs[$i], $k, 1);
					}
				}
				$temp_dist = hd($temp1, $temp2);
				$hamming_dist[$i][$j] = $temp_dist;
				$hamming_dist[$j][$i] = $temp_dist;
			}
			else {
				$temp_dist = hd($motifs[$i], $motifs[$j]);
				$hamming_dist[$i][$j] = $temp_dist;
				$hamming_dist[$j][$i] = $temp_dist;
			}
		}
	}
	
	print $out_file, "\n";

	open(OUT, ">$out_file") or die "$out_file: $!\n";
	for (my $i=0; $i<$N; $i++) {
		for (my $j=0; $j<$N; $j++) {
			print OUT $hamming_dist[$i][$j], "\t";
		}
		print OUT "\n";
	}
	close(OUT);
}

sub hd {
    return ($_[0] ^ $_[1]) =~ tr/\001-\255//;
}

sub convert {
	my $strNumber = $_[0];
	$strNumber = sprintf("%04d", $strNumber);
	my $number = $strNumber + 1 - 1;
	return $number;
}
