# ALIGN2HTML
# Author: Jerome Ajot
#
# This software was developed at the National Institute of Standards and Technology by 
# employees of the Federal Government in the course of their official duties. Pursuant
# to title 17 Section 105 of the United States Code this software is not subject to
# copyright protection and is in the public domain. ALIGN2HTML is an experimental system.
# NIST assumes no responsibility whatsoever for its use by other parties, and makes no
# guarantees, expressed or implied, about its quality, reliability, or any other
# characteristic. We would appreciate acknowledgement if the software is used.
#
# THIS SOFTWARE IS PROVIDED "AS IS."  With regard to this software, NIST MAKES NO EXPRESS
# OR IMPLIED WARRANTY AS TO ANY MATTER WHATSOEVER, INCLUDING MERCHANTABILITY,
# OR FITNESS FOR A PARTICULAR PURPOSE.

package Segment;
use strict;
use Data::Dumper;

use Token;

sub new
{
    my $class = shift;
    my $self = {};

	$self->{ID} = shift;
	$self->{SPKRID} = shift;
	$self->{TOKENS} = {};
	$self->{MINX} = 10000000;
	$self->{MAXX} = 0;
	$self->{HEIGHT} = 0;
	$self->{HASFAKETIME} = 0;
	
    bless $self;
    return $self;
}

sub AddToken
{
	my ($self, $tkn) = @_;
	$self->{TOKENS}{$tkn->{ID}} = $tkn;
}

sub SetY
{
	my ($self, $ypos) = @_;
		
	foreach my $tknid(sort keys %{ $self->{TOKENS} })
	{
		$self->{TOKENS}{$tknid}->SetYPos($ypos);
	}
}

sub isTokenInSegment
{
	my ($self, $tokenid) = @_;
	
	foreach my $tknid(sort keys %{ $self->{TOKENS} })
	{
		return 1 if($tknid == $tokenid);
	}
	
	return 0;
}

sub CalculateMinMaxX
{
	my ($self) = @_;
	
	foreach my $tknid(sort keys %{ $self->{TOKENS} })
	{
		next if( ($self->{TOKENS}{$tknid}->{XSTARTPOS} == 0) && ($self->{TOKENS}{$tknid}->{XENDPOS} == 0) && ($self->{TOKENS}{$tknid}->{TEXT} eq "") );
		$self->{MINX} = $self->{TOKENS}{$tknid}->{XSTARTPOS} if($self->{MINX} > $self->{TOKENS}{$tknid}->{XSTARTPOS});
		$self->{MAXX} = $self->{TOKENS}{$tknid}->{XENDPOS}   if($self->{MAXX} < $self->{TOKENS}{$tknid}->{XENDPOS});
	}
}

sub HasOnlyOneFakeToken
{
    my ($self) = @_;
    
    foreach my $tknid(sort keys %{ $self->{TOKENS} })
	{
		return 0 if( !( ($self->{TOKENS}{$tknid}->{XSTARTPOS} == 0) && ($self->{TOKENS}{$tknid}->{XENDPOS} == 0) && ($self->{TOKENS}{$tknid}->{TEXT} eq "") ) );
	}
	
	return 1;
}

sub CleanSegmentPrevNext
{
	my ($self) = @_;
	
	foreach my $tknid(sort keys %{ $self->{TOKENS} })
	{
		my $myToken = $self->{TOKENS}{$tknid};
		
		for(my $i=0; $i< @{ $myToken->{PREVTKNID} }; $i++)
		{
			delete $myToken->{PREVTKNID}[$i] if(!$self->isTokenInSegment($myToken->{PREVTKNID}[$i]));
		}
		
		for(my $i=0; $i< @{ $myToken->{NEXTTKNID} }; $i++)
		{
			delete $myToken->{NEXTTKNID}[$i] if(!$self->isTokenInSegment($myToken->{NEXTTKNID}[$i]));
		}
		
		$myToken->{NUMPREV} = scalar( @{ $myToken->{PREVTKNID} } );
		$myToken->{NUMNEXT} = scalar( @{ $myToken->{NEXTTKNID} } );
	}
}

sub MultiGraphXY
{
	my ($self) = @_;
	
	my $maxheigh = 0;
	
	if(scalar(keys %{ $self->{TOKENS} }) != 0)
	{
		my %tokenPositions;
		my @listTokenID;
		my $currentlevel = 0;
		my $maxlengh = 0;
	
		foreach my $tknid(sort {$a <=> $b} keys %{ $self->{TOKENS} })
		{
			$tokenPositions{$tknid}{XB} = 0;
			$tokenPositions{$tknid}{XE} = 1;
			$tokenPositions{$tknid}{Y} = 0;
			$tokenPositions{$tknid}{TEXT} = $self->{TOKENS}{$tknid}->{TEXT};
			
			push(@listTokenID, $tknid);
			
			if( scalar(@{ $self->{TOKENS}{$tknid}->{PREVTKNID} }) == 0 )
			{
				$tokenPositions{$tknid}{Y} = $currentlevel;
				$currentlevel++;
			}
		}
			
		for(my $i=0; $i<@listTokenID; $i++)
		{
			my $tokenid = $listTokenID[$i];
			my $token = $self->{TOKENS}{$tokenid};
			my @prevtkn = @{ $token->{PREVTKNID} };
			my @nexttkn = @{ $token->{NEXTTKNID} };
			
			my $tokenBegin = $tokenPositions{$tokenid}{XB};
			my $tokenEnd = $tokenPositions{$tokenid}{XE};
			my $tokenY = $tokenPositions{$tokenid}{Y};
			
			for(my $j=0; $j<@nexttkn; $j++)
			{
				my $nexttokenid = $nexttkn[$j];
				
				my $nexttokenBegin = $tokenPositions{$nexttokenid}{XB};
				my $nexttokenEnd = $tokenPositions{$nexttokenid}{XE};
				my $nextTokenY = $tokenPositions{$nexttokenid}{Y};
				
				if( $nexttokenBegin < $tokenEnd)
				{
					$tokenPositions{$nexttokenid}{XB} = $tokenEnd;
					$tokenPositions{$nexttokenid}{XE} = $tokenPositions{$nexttokenid}{XB} + 1;
					$i = -1;
				}
				
				my $nbrprev = scalar( @{ $self->{TOKENS}{$nexttokenid}->{PREVTKNID} } ) - 1;
				
				if($nextTokenY < ($tokenY + $j - $nbrprev))
				{
					$tokenPositions{$nexttokenid}{Y} = $tokenY + $j - $nbrprev;
					$i = -1;
				}
			}
			
			for(my $j=0; $j<@prevtkn; $j++)
			{
				my $prevtokenid = $prevtkn[$j];
				
				my $prevtokenBegin = $tokenPositions{$prevtokenid}{XB};
				my $prevtokenEnd = $tokenPositions{$prevtokenid}{XE};
				
				if( $prevtokenEnd != $tokenBegin)
				{
					$tokenPositions{$prevtokenid}{XE} = $tokenBegin;
					$i = -1;
				}
			}
		}
		
		foreach my $tken (sort {$a <=> $b} keys %tokenPositions)
		{
			$maxheigh = $tokenPositions{$tken}{Y} if($tokenPositions{$tken}{Y} > $maxheigh);
			$maxlengh = $tokenPositions{$tken}{XE} if($tokenPositions{$tken}{XE} > $maxlengh);
		}
		
		foreach my $tknid(sort keys %{ $self->{TOKENS} })
		{
			my $updown = 1;
			my $base = 0;
			
			if($self->{TOKENS}{$tknid}->{REFORSYS} eq "REF")
			{
				$updown = -1;
				$base = $maxheigh;
			}
		
			if($self->{TOKENS}{$tknid}->{REALTIME} == 0)
			{
				$self->{TOKENS}{$tknid}->MakeFakeTime($tokenPositions{$tknid}{XB}, $tokenPositions{$tknid}{XE}, $maxlengh);
				$self->{HASFAKETIME} = 1;
			}
			
			$self->{TOKENS}{$tknid}->{YPOS} += $base*30 + $updown*30*$tokenPositions{$tknid}{Y};
		}
	}
	
	$self->{HEIGHT} = ($maxheigh+1)*30;
}

sub Compute
{
	my ($self) = @_;
	
	# Calculate Min and Max X
	$self->CalculateMinMaxX();
	
	# Clean up the previous and Next of Tokens
	$self->CleanSegmentPrevNext();

	# Assign X and Y for graph
	$self->MultiGraphXY();	
}

sub GetDraw
{
	my ($self, $minx) = @_;
	my $output2 = "";
	
	my @listfirsts;
	my @listlasts;
	
	foreach my $tknid(sort keys %{ $self->{TOKENS} })
	{
		my @prevtkn = @{ $self->{TOKENS}{$tknid}->{PREVTKNID} };
		my @nexttkn = @{ $self->{TOKENS}{$tknid}->{NEXTTKNID} };
		
		if(scalar(@prevtkn) > 1)
		{
			for(my $i=1; $i<@prevtkn; $i++)
			{
				my $end1x = $self->{TOKENS}{$prevtkn[$i-1]}->{XENDPOS} - $minx;
				my $end1y = $self->{TOKENS}{$prevtkn[$i-1]}->{YPOS};
				my $end2x = $self->{TOKENS}{$prevtkn[$i]}->{XENDPOS} - $minx;
				my $end2y = $self->{TOKENS}{$prevtkn[$i]}->{YPOS};
				
				$output2 .= sprintf("jg.drawLine(scale*%.0f, %.0f, scale*%.0f, %.0f);\n", $end1x, $end1y, $end2x, $end2y);
			}
		}
		
		push(@listfirsts, $tknid) if(scalar(@prevtkn) == 0);
		
		if(scalar(@nexttkn) > 1)
		{
			for(my $i=1; $i<@nexttkn; $i++)
			{
				my $begin1x = $self->{TOKENS}{$nexttkn[$i-1]}->{XSTARTPOS} - $minx;
				my $begin1y = $self->{TOKENS}{$nexttkn[$i-1]}->{YPOS};
				my $begin2x = $self->{TOKENS}{$nexttkn[$i]}->{XSTARTPOS} - $minx;
				my $begin2y = $self->{TOKENS}{$nexttkn[$i]}->{YPOS};
				
				$output2 .= sprintf("jg.drawLine(scale*%.0f, %.0f, scale*%.0f, %.0f);\n", $begin1x, $begin1y, $begin2x, $begin2y);
			}			
		}
		
		push(@listlasts, $tknid) if(scalar(@nexttkn) == 0);
	}
	
	if(scalar(@listfirsts) > 1)
	{
		for(my $i=1; $i<@listfirsts; $i++)
		{
			my $begin1x = $self->{TOKENS}{$listfirsts[$i-1]}->{XSTARTPOS} - $minx;
			my $begin1y = $self->{TOKENS}{$listfirsts[$i-1]}->{YPOS};
			my $begin2x = $self->{TOKENS}{$listfirsts[$i]}->{XSTARTPOS} - $minx;
			my $begin2y = $self->{TOKENS}{$listfirsts[$i]}->{YPOS};
			
			$output2 .= sprintf("jg.drawLine(scale*%.0f, %.0f, scale*%.0f, %.0f);\n", $begin1x, $begin1y, $begin2x, $begin2y);
		}			
	}
	
	if(scalar(@listlasts) > 1)
	{
		for(my $i=1; $i<@listlasts; $i++)
		{
			my $end1x = $self->{TOKENS}{$listlasts[$i-1]}->{XENDPOS} - $minx;
			my $end1y = $self->{TOKENS}{$listlasts[$i-1]}->{YPOS};
			my $end2x = $self->{TOKENS}{$listlasts[$i]}->{XENDPOS} - $minx;
			my $end2y = $self->{TOKENS}{$listlasts[$i]}->{YPOS};
			
			$output2 .= sprintf("jg.drawLine(scale*%.0f, %.0f, scale*%.0f, %.0f);\n", $end1x, $end1y, $end2x, $end2y);
		}			
	}
	
	my $output = "";
	
	if($output2 ne "")
	{
		$output .= sprintf("jg.setColor(\"grey\");\n");
		$output .= sprintf("jg.setStroke(Stroke.DOTTED);\n");
		$output .= $output2;
	}
	
	foreach my $tknid(sort keys %{ $self->{TOKENS} })
	{		
		$output .= $self->{TOKENS}{$tknid}->GetDraw($minx);
	}
	
	return $output;
}

1;

