use strict;
use WordNet::QueryData;

my $verbose = 0;

my $filepath = "h:\\itaproj\\code\\meetme-conf-rec-8000-1234462646.22.txt";
my $csvfileout = "h:\\itaproj\\code\\meetme-conf-rec-8000-1234462646.22_simplified_lesk.csv";
open F1, $filepath;
open F2, ">$csvfileout";

my $wn = WordNet::QueryData->new;
print F2 "Word,Sense,Overlap Score,Overlap SD,SensesSD\n";
while(my $tempText = <F1>)
{
    $tempText =~ m/p\d:\s*(.*)/i;
    my $sentence;

    if($1)
    {
        print "Processing sentence : $1\n";    
        $sentence = $1;
        print F2 "$sentence\n";
        my $tempHash = getWSDScores($sentence, $wn);
        foreach my $word (keys %{$tempHash})
        {
            my @temp1 = split(/:/, $tempHash->{$word});
            print F2 "$word,$temp1[0],$temp1[1],$temp1[2],$temp1[3]\n";
        }
    }
}

close(F2);
close(F1);

#print F2 "Word,Sense,Score,OverlapsSD,SensesSD\n";
#my %word_counts = ();
#my %word_scores = ();
#my %word_sensesSD = ();

#while(my $tempText = <F1>)
#{
#    $tempText =~ m/p\d:\s*(.*)/i;
#    my $sentence;
#
#    if($1)
#    {
#        print "Processing sentence : $1\n";
#        
#        $sentence = $1;
#        my $tempHash = getWSDScores($sentence, $wn);
#        my $total = keys %{$tempHash};
#        foreach my $word (keys %{$tempHash})
#        {
#            my @temp1 = split(/:/, $tempHash->{$word});
#            
#            if($word_counts{$word})
#            {
#                $word_counts{$word} ++;    
#            }
#            else
#            {
#                $word_counts{$word} = 1;
#            }
#            
#            if($word_scores{$word})
#            {
#                $word_scores{$word} = $temp1[1]/$total;    
#            }
#            else
#            {
#                $word_scores{$word} += $temp1[1]/$total;
#            }
#            
#            $word_sensesSD{$word} = $temp1[3];
#            #print F2 "$word,$temp1[0]," . $temp1[1]/$total . ",$temp1[2],$temp1[3]\n";
#        }
#    }
#}
#
#open F2, ">$csvfileout";
#print F2 "Word,AvgScore,SensesSD\n";
#foreach my $word (keys %word_scores)
#{
#    print F2 "$word," . $word_scores{$word}/$word_counts{$word} . ",$word_sensesSD{$word}\n";
#}
#close(F2);
#close(F1);

#Returns a score based on simplified Lesk's WSD algorithm.
#Inputs are:
#the sentence.
#WordNet::QueryData object to work on.
#Output is a reference to hash of form (Word, Selected Sense:Score:OverlapSD:FreqSD).

sub getWSDScores
{
    print "Inside getWSDScores ...\n" if($verbose);
    
    my $sentence = shift;
    my $wordnet = shift;
    my %word_sense_map = ();
    
    my $sentence_map = getWordCountHash($sentence);
    my $totalwords = keys %{$sentence_map};
    foreach my $word (keys %{$sentence_map})
    {
        print "Processing word : $word ...\n" if($verbose);
        
        my ($sense, $overlap, $sdoverlaps) = getBestSense($word,$sentence_map,$wordnet);
        my $sensesSD = getSensesSD($word,$wordnet);
        $word_sense_map{$word} = "$sense:" . $overlap/$totalwords . ":$sdoverlaps:$sensesSD" if($sense);
    
        print "Selected sense is : $sense ...\n" if($verbose);
    }
    return \%word_sense_map;
}

#Returns the best sense for a given word based on MAX overlap method.
#Inputs are:
#word to disambiguate.
#reference to hash containing (word,count). This is the context or the sentence in which the word appears.
#WordNet::QueryData object to work on.
#Outputs are:
#The best sense of form : word#POS#sensenumber.
#The number of overlaps for best sense.
#The SD of overlaps of all the senses.
sub getBestSense
{
    print "Inside getBestSense ...\n" if ($verbose);
    
    my $word = shift;
    my $wchash = shift;
    my $wordnet = shift;
    
    my @overlaps;
    
    my $bestOverlap = 0;
    my $bestSense = "";

    my @pos = $wordnet->querySense($word);
    
    foreach my $tempPos (@pos)
    {
        print "Processing for POS ==> $tempPos\n" if ($verbose);
        
        my @senses = $wordnet->querySense($tempPos);
        foreach my $tempSense (@senses)
        {
            print "Processing for sense ==> $tempSense\n" if ($verbose);
            
            my @glos = $wordnet->querySense($tempSense,"glos");
            my $gloswc = getWordCountHash($glos[0]);
            my $numcommon = getOverlap($gloswc, $wchash);
            push(@overlaps, $numcommon);
            
            if($numcommon > $bestOverlap)
            {
                $bestOverlap = $numcommon;
                $bestSense = $tempSense;
            }
        }
    }
    
    my $sdOverlaps = 0;
    $sdOverlaps = getSD(\@overlaps) if(@overlaps);
    return ($bestSense, $bestOverlap, $sdOverlaps);
}

#Converts the given sentence to a data structure used for internal purposes.
#Input is the sentence.
#Output is a reference to hash containing (word,count).
sub getWordCountHash
{
    print "Inside getWordCountHash ...\n" if($verbose);
    
    my $sentence = shift;
    my @words = split(/[^A-Za-z0-9]/, $sentence);
    my %wchash = ();
    
    foreach my $temp (@words)
    {
        print "Current Term = $temp ...\n" if ($verbose);
        my $key = lc($temp);
        
        if($key eq "")
        {
            next;            
        }
        
        if($wchash{$key})
        {
            $wchash{$key} += 1;
        }
        else
        {
            $wchash{$key} = 1;
        }
    }
    return \%wchash;
}

#Finds the number of word overlaps between 2 sentences.
#Inputs are references to hashes containing the 2 sentences in the form (term,count).
#Usually, sentence1 is the given sentence.
#Output is the no. of overlaps between the 2 sentences.

sub getOverlap
{
    print "Inside getOverlap ...\n" if($verbose);
    
    my $sentence1 = shift;
    my $sentence2 = shift;
    
    my $overlap = 0;
    
    foreach my $tempWord (keys %{$sentence1})
    {
        print "Processing Term = $tempWord ...\n" if ($verbose);
        
        if($sentence2->{$tempWord})
        {
            print "Found common ...\n" if ($verbose);
            
            $overlap ++;
        }
    }   
    print "Overlap = $overlap ...\n" if ($verbose);
    
    return $overlap;
}

#Calculate the standard deviation for a list of numbers.
sub getSD
{
  my $ar = shift;
  my $elements = scalar @$ar;
  my $sum = 0;
  my $sumsq = 0;

  foreach (@$ar)
  {
    $sum += $_;
    $sumsq += ($_ **2);
  }
  
  return sqrt( $sumsq/$elements - (($sum/$elements) ** 2));
}

#Calculate the standard deviation for frequencies of different senses of a given word.
#Inputs are:
#The word.
#WordNet::QueryData object to work on.
#Output is the required standard deviation.
sub getSensesSD
{
    print "Inside getSensesSD ...\n" if($verbose);
    
    my $word = shift;
    my $wordnet = shift;
    my @sensefreqs;
    
    my @pos = $wordnet->querySense($word);
    foreach my $tempPos (@pos)
    {
        print "Processing for POS ==> $tempPos\n" if ($verbose);
        
        my @senses = $wordnet->querySense($tempPos);
        foreach my $tempSense (@senses)
        {
            my $tempFreq = 1 + $wordnet->frequency($tempSense);
            push(@sensefreqs, $tempFreq);
            
            print "Sense ==> $tempSense ... Freq ==> $tempFreq\n" if ($verbose);
        }
    }
    my $sdfreqs = 0;
    $sdfreqs = getSD(\@sensefreqs) if(@sensefreqs);
    return $sdfreqs;
}