
package SentenceParse;
use Parser;
use Production;
use PhraseStruct;
use Node;

sub new {
    my $class = shift;
    my $self = {};
    $self->{SENTENCE} = [];
   if(defined $_[0]){
	$self->{SENTENCE} = shift;
    }
    $self->{PARSER} = undef;
    if(defined $_[0]){
	$self->{PARSER} = shift;
    }
    $self->{PRODUCTION} = [];
    $self->{SOLUTIONS} = [];
    $self->{CURRENT} = -1;
    $self->{PARSE_NUM} = 0;
    bless $self=>$class;
    return $self;
}

#as per Earley Algorithm
sub build_productions(){
    my ($self) = @_;
    $self->{PRODUCTION}[0][0] = new Production($self->{PARSER}{GRAMMAR}{'#'}[0],0,0,0);
    $self->{CURRENT} = 0;
    #print (@sentence,"\n");
    while($self->{CURRENT}<=(scalar @{$self->{SENTENCE}})){
	#print "Current production table: $self->{CURRENT}\n";
	foreach my $product (@{$self->{PRODUCTION}[$self->{CURRENT}]}){
	    #print "product: $product\n";
	    #print "phrase_struct: $product->{PHRASE_STRUCT}\n";
	    #print "Curr = $product->{PHRASE_STRUCT}{PRODUCT}:";
	    #print "\t@{$product->{PHRASE_STRUCT}{CONSTITUENTS}}\n";
	    #print "progress: $product->{PROGRESS}\n";
	    
	    if(not defined $product->{PHRASE_STRUCT}
	       ->{CONSTITUENTS}->[$product->{PROGRESS}]){
		$self->complete($product);
	    }
	    elsif(defined $self->{PARSER}{GRAMMAR}{$product->{PHRASE_STRUCT}
				   ->{CONSTITUENTS}->[$product->{PROGRESS}]}){
		$self->predict($product);
	    }
	    elsif(defined $self->{PARSER}{LEXICON}{$product->{PHRASE_STRUCT}
				   {CONSTITUENTS}[$product->{PROGRESS}]}){
		$self->scan($product);
	    }
	}
	$self->{CURRENT}++;
    }
}

#predictor as per Earley Algorithm
sub predict(){
    my ($self,$product) = @_;
    foreach my $new_rule (@{$self->{PARSER}{GRAMMAR}{$product->{PHRASE_STRUCT}{CONSTITUENTS}[$product->{PROGRESS}]}}){
#every rule that results in
#the next-up phrase structure
	my $duplicate = 0;
	foreach (@{$self->{PRODUCTION}[$self->{CURRENT}]}){  #check to see if you've already
	    if($_->{PHRASE_STRUCT} eq $new_rule  #got a duplicate production
	       and $_->{PROGRESS} == 0
	       and $_->{LEFT} eq $product->{RIGHT}){
		$duplicate = 1;
	    }
	}
	unless($duplicate){  #if you didn't find a duplicate, add a new production
	    push(@{$self->{PRODUCTION}[$self->{CURRENT}]},
		 new Production($new_rule,0,$product->{RIGHT},
				$product->{RIGHT},[$product]));
	}
    }
}
#scanner as per Earley Algorithm
sub scan(){
    my($self,$product) = @_;
    my $next_word = ($self->{SENTENCE}[$product->{RIGHT}] or "NOMOREWORDSLEFT");
    my $goal_words = join(' ',@{$self->{PARSER}{LEXICON}{$product->{PHRASE_STRUCT}{CONSTITUENTS}[$product->{PROGRESS}]}->{CONSTITUENTS}});
#if the right word in the sentence fits the required lexical category
    if($goal_words =~ /\b$next_word\b/i or not $goal_words){
	#add a new production rule with the lexical item scanned
	my $new_product = new Production($product->{PHRASE_STRUCT},
					 $product->{PROGRESS}+1,$product->{LEFT},
					 $product->{RIGHT}+1,[$product]);
	$new_product->{WORD} = $self->{SENTENCE}[$product->{RIGHT}];
	$new_product->{CAUSE} = [$product];
	push(@{$self->{PRODUCTION}[$self->{CURRENT}+1]},$new_product);
    }
    
}

#completer as per Earley Algorithm
sub complete(){
    my ($self,$new_product) = @_;
    if($new_product->{PHRASE_STRUCT}{PRODUCT} eq "#" and $new_product->{LEFT} == 0 and $new_product->{RIGHT} == scalar(@{$self->{SENTENCE}})){
	#you got to the beginning
	#print "FOUND A SOLUTION!!\nBUILD THE TREE!!\n";
	push(@{$self->{SOLUTIONS}},$self->build_tree($new_product));
	#print "got it\n";
    }
    foreach my $old_product (@{$self->{PRODUCTION}[$new_product->{LEFT}]}){  
#each thing
	#that could have been waiting for this phrase structure
	if(($old_product->{PHRASE_STRUCT}{CONSTITUENTS}  #if it was looking for
	    [$old_product->{PROGRESS}] or 0)   # this phrase structure
	   eq $new_product->{PHRASE_STRUCT}{PRODUCT}){
	    #add a new production rule with the phrase structure completed
	     my $created_product = new Production($old_product->{PHRASE_STRUCT},
				$old_product->{PROGRESS}+1,$old_product->{LEFT},
				$new_product->{RIGHT},[$new_product]);
	     $created_product->{CAUSE} = [$new_product,$old_product];
	     push(@{$self->{PRODUCTION}[$self->{CURRENT}]},$created_product);
	 }
    }
}

#builds the tree for a given production and cause
sub build_tree(){
    my ($self,$product) = @_;
    #print "product: $product\n";
    #print "phrase_struct: @{$product->{PHRASE_STRUCT}{CONSTITUENTS}}\n";
   
    my $this_node = Node->new($product->{PHRASE_STRUCT}{CONSTITUENTS}[$product->{PROGRESS}-1]);
    #print "phrase: $this_node->{PHRASE}\n";
    if(($product->{LEFT} == 0)
       and ($product->{RIGHT} == 0)
       and ($product->{PROGRESS} < 1)){
	#print "FINISH!!\n";
	return ;
    }
    if($product->{PROGRESS} == 0){
	#unpredict
	#print "unpredictin\n";
	return ;
    }elsif(defined $self->{PARSER}{GRAMMAR}{$product->{PHRASE_STRUCT}
			    {CONSTITUENTS}[$product->{PROGRESS}-1]}){
	#uncomplete
	#print "uncompleting\n";
	unshift(@{$this_node->{CHILDREN}},$self->build_tree($product->{CAUSE}[0]));
	#print "new children of $this_node->{PHRASE}:\n";
	foreach (@{$this_node->{CHILDREN}}){
	    $_->{PARENT} = $this_node;
	    #print "$_->{PHRASE}\n";
	}
	if($product->{CAUSE}[0]->{PROGRESS}>0){
	    return ($self->build_tree($product->{CAUSE}[1]),$this_node);
	}else{return $this_node;}
    }elsif(defined $self->{PARSER}{LEXICON}{$product->{PHRASE_STRUCT}
			    {CONSTITUENTS}[$product->{PROGRESS}-1]}){
	#unscan
	#print "unscanning\n";
	$this_node->{CHILDREN} = [new Node($product->{WORD})];
	$this_node->{CHILDREN}[0]{PARENT} = $this_node;
	if($product->{PROGRESS}>1){
	    return ($self->build_tree($product->{CAUSE}[0]),$this_node);
	}else{ return $this_node;}
    }
    return $this_node;
}

#recursive print of the grammar tree from a particular node
#returns a string of form "[<node>[<child1>][<child2>].....[<lastchild>]]"
sub print_tree(){
    my ($self,$node) = @_;
    my $string = "";
    return "" unless(defined $node);
   
    $string .= '['  if(defined $node->{CHILDREN}[0]);
    $string .= " $node->{PHRASE} ";
    
    foreach (@{$node->{CHILDREN}}){
	#$string .= " ".(scalar @{$node->{CHILD}})." ";
	$string .= $self->print_tree($_);
    }
    $string .= ']' if(defined $node->{CHILDREN}[0]);
    return $string;
}
sub has_parse(){
    my ($self) = @_;
    return defined $self->{SOLUTIONS}[$self->{PARSE_NUM}];
}
sub get_parse(){
    my ($self) = @_;
    $self->{PARSE_NUM}++;
    return $self->print_tree($self->{SOLUTIONS}[$self->{PARSE_NUM}-1]);
}

sub get_tree(){
    my ($self) = @_;
    $self->{PARSE_NUM}++;
    return $self->{SOLUTIONS}[$self->{PARSE_NUM}-1];
}
1;
