#! /usr/bin/perl -w

########################################################################
#### file          : ctm2srt.pl
#### date          : april 22 1998
#### author        : Cedric Auzanne for NIST
#### description   : parses ctm and ndx files to create srt file
####
########################################################################
#### usage         : ctm2srt.pl [-s] ctmfile_full_path
#### ndx file MUST be in the same directory as the specified ctm file
####
#### using the -s flag turns on the save mode :
#### words out of boundaries will be outputed as comments, see next section.
####
#### see also      : srt2ctm.pl does reverse operation
####
########################################################################
#### comments      : with the -s switch, words that are out of bouds
####                 (not included in a section)
####                 are printed as comments like the following
#### <Comment> Out of boundary word : WATERS, S=33.76, E=34.12 </Comment>
#### where WATERS is the word, S is start time and E end time
####
#### words are considered out of boundaries if start time AND end time
#### are not in the same section or one of these is not in a section.
#### words from nonspeech are out of boundaries
####
#### marking out of boundaries words as comments permits a complete reconstruction
#### of the ctm file.
####
########################################################################
#### Formats :
#### see man ctm for the specs of the ctm format
####
#### srt format
#### this srt format follows the 1997 SDR srt specs :
#### the <Episode> and <Section> tags are kept as in the ltt format
#### comments are written between <Comment> and </Comment> tags
#### words are written between <Word> tags like :
#### <Word S_time=37.94 E_time=38.36> LAND </Word>
####
#### where LAND is the word (always in uppercase)
#### S_time is the beginning time of the word
#### E_time is the end time of the word.
#### these times are computed from the start time and duration
#### available in the ctm format.
####
########################################################################
#### update : may 26 1998
#### fix bug : problem if no words in a section (ep970812)
########################################################################
#### update : july 1 1998
#### fix bug : implement more error checking
########################################################################


########################################################################
#### global variables
@tag_list    = ();         # array of array, list of all sections
#                          # contains type, ID, start time and end time for each entry                         
$i           = 0;          # int, current section (entry in tag_list)
$current     = 0;          # int, current entry in ctm line list
$save        = "F";        # "T" if save mode enabled
$openedS     = "F";        # "T" if a section is currently opened
$ctmfilename = "";
$ndxfilename = "";
$srtfilename = "";


########################################################################
#### check parameters
die "\nUsage : ctm2srt.pl [-s] ctm_fullpath\n" if (($#ARGV < 0) || ($#ARGV > 1));
die "\nERROR : wrong argument : $ARGV[0]\n" if (($#ARGV == 1) && ($ARGV[0] ne "-s"));


if ($#ARGV == 1)
{
    $save = "T" if ($ARGV[0] eq "-s");
    $ctmfilename      = $ARGV[1];
}
else
{
    $ctmfilename      = $ARGV[0];
}

# check ctm file existance
die "\nERROR : ctm file $ctmfilename not found\n" if (! -f $ctmfilename);

# comute ndx filename and check existance
$ndxfilename      = "$1.ndx" if ($ctmfilename =~ /(.*?).ctm/);
die "\nERROR : ndx file $ndxfilename not found\n" if (! -f $ndxfilename);

# compute srt filename
$srtfilename      = "$1.srt" if ($ctmfilename =~ /(.*?).ctm/);

print "Processing file $ctmfilename, with $ndxfilename, to $srtfilename :\n";


########################################################################
#### open output file, print comments

open OFD, ">$srtfilename" or die "\nERROR : can't open output file $srtfilename\n";

print OFD "<Comment>\n";
print OFD "\tThis file was generated by ctm2srt.pl\n";
print OFD "\tdate      : ", scalar localtime, "\n";
print OFD "\tctm file  : $ctmfilename\n";
print OFD "\tdtt2 file : $ndxfilename\n";
print OFD "\tsave mode : on\n" if ($save eq "T");
print OFD "\tsave mode : off\n" if ($save eq "F");
print OFD "</Comment>\n\n";



########################################################################
#### open ndx file and load data

open NDXFD, "<$ndxfilename" or die "\nERROR : can't open ndx file $ndxfilename\n";
@content = <NDXFD>;
chomp @content;
close NDXFD;


print "\tLoading Episode tag\n";

# get <Episode> tag and print it out
foreach $val (@content)
{
    do
    {
	my $filename  = "";
	my $program   = "";
	my $scribe    = "";
	my $date      = "";
	my $version   = -1;
	my $version_d = "";

	$filename  = $1 if ($val =~ /Filename=(.*?)\s+/);
	$program   = $1 if ($val =~ /Program="(.*?)"\s+/);
	$scribe    = $1 if ($val =~ /Scribe="(.*?)"\s+/);
	$date      = $1 if ($val =~ /Date="(.*?)"\s+/);
	$version   = $1 if ($val =~ /Version=(\d+)\s+/);
	$version_d = $1 if ($val =~ /Version_Date=(.*?)[\s|>]/);

	print "\tWARNING : empty filename field in $val\n" if ($filename eq "");
	print "\tWARNING : empty program field in $val\n" if ($program eq "");
#	print "\tWARNING : empty scribe field in $val\n" if ($scribe eq "");
#	print "\tWARNING : empty date field in $val\n" if ($date eq "");
	print "\tWARNING : empty version field in $val\n" if ($version == -1);
	print "\tWARNING : empty version date field in $val\n" if ($version_d eq "");

	print OFD "<Episode Filename=$filename Program=\"$program\" Scribe=\"$scribe\" Date=\"$date\" Version=$version Date=$version_d >\n\n";
	last;
    } if ($val =~ /<Episode/);
}

# create array of sections from the ndx, do all possible checks
my $previousendtime = 0;
print "\tLoading sections\n";

# create dummy entry :
my @tmp = ("dummy", -1, -1 , "0.0");
push @tag_list, [@tmp];

foreach $val (@content)
{
    do
    {
	my $starttime = 0;
	my $endtime   = 0;
	my $type      = "";
	my $ID        = "";

	$starttime = $1 if ($val =~ /S_time=(\d+\.\d+)/);
	$endtime   = $1 if ($val =~ /E_time=(\d+\.\d+)/);
	$type      = $1 if ($val =~ /Type=(\w+)/);
	$ID        = $1 if ($val =~ /ID=(\w+\.\d+)/);

	print "\tWARNING : empty S_time in $val\n" if ($starttime == 0);
	print "\tWARNING : empty E_time in $val\n" if ($endtime ==0);
	print "\tWARNING : empty type in $val\n" if ($type eq "");
	print "\tWARNING : empty ID in $val\n" if ($ID eq "");
	print "\tWARNING : section time overlap in $val\n" if ($starttime < $previousendtime);

	$previousendtime = $endtime;
	my @tmp = ($type, $starttime, $endtime, $ID);
	push @tag_list, [@tmp];
    } if ($val =~ /<Section/);
}

die "\tERROR : no section tags loaded\n", if ($#tag_list < 0);
print "\tFound ", $#tag_list, " section tags\n";



########################################################################
########################################################################
########################################################################
#### start processing

# read each line in ctm file and process

@content = ();
$current = 0;
open CTMFD, "<$ctmfilename" or die "ERROR : can't open ctm file $ctmfilename\n";
@content = <CTMFD>;
chomp @content;
close CTMFD;

$previousendtime = -1;
while ($current <= $#content)
{
    my $line = "";
    $line = $content[$current];
    print "\tERROR : line is uninitialized\n" if ($line eq "");

    print "\tProcessing ctm line $current\r";
    # line is comment, lose it
    if ($line =~ /^\s*?;/)
    {
	$current++;
	next;
    }

    my $show      = "";
    my $channel   = "";
    my $starttime = -1;
    my $duration  = -1;
    my $endtime   = 0;
    my $word      = "";
    my $remainder = "";
    
    # parse line and check for error
    ($show, $channel, $starttime, $duration, $word, $remainder) = split (/\s+/, $line);

    print "\n\tWARNING : format error in ctm line $line\n"
	if (($show eq "") || ($channel eq "") || ($starttime == -1) || ($duration == -1) || ($word eq "") || (! $remainder eq ""));
        # if remainder is NOT empty the split didn't work out

    print "\n\tWARNING : word time overlap in ctm, word $word at time $starttime\n" if ($starttime < $previousendtime);
    $previousendtime = $starttime;
    $endtime = $starttime + $duration;

    

    ############################################################
    ############################################################
    ############################################################

    ### words starts before current section but ends inside section
    if ($starttime < $tag_list[$i][1])
    {
	print OFD "<Comment> Out of boundary word : $word, S=$starttime, E=$endtime Before next section </Comment>\n"
	    if ($save eq "T");
	print "\nWARNING : OBW 1 : $word, S=$starttime, E=$endtime, SS=$tag_list[$i][1], SE=$tag_list[$i][2]\n";
	$current++;
	next;
    }


    ############################################################
    #### word falls inside current section
    # implied $starttime >= start of section
    if ($endtime <= ($tag_list[$i][2] + 0.0000001))
    {
	print OFD "<Word S_time=$starttime E_time=$endtime> $word </Word>\n";
	$current++;
	next;
    }
    
#    printf "WARNING : %s, %e, %e, %e, %e\n", $word, $starttime, $endtime, $tag_list[$i][1], $tag_list[$i][2];


    ############################################################
    #### at this point word ends AFTER end of current section, so is out 
    # implied $starttime >= start of section
    # implied $endtime > end of section

    # close current section if needed
    if (($openedS eq "T") && ($i !=0))
    {
	print OFD "</Section>\n\n";
	$openedS = "F";
    }


    #### word is across end of section boundary
    if ($starttime < $tag_list[$i][2])
    {
	print OFD "<Comment> Out of boundary word : $word, S=$starttime, E=$endtime Word is across end of section boundary </Comment>\n"
	    if ($save eq "T");
	printf "WARNING : OBW 2 : %s, %e, %e, %e, %e\n", $word, $starttime, $endtime, $tag_list[$i][1], $tag_list[$i][2];
	$current++;
	next;
    }


    # implied $starttime > end of session
    # implied $endtime   > end of section
    # check with next session

    # check if more sections are available
    if (($i+1) <= $#tag_list)
    {

	### words starts before next section
	if ($starttime < $tag_list[$i+1][1])
	{
	    print OFD "<Comment> Out of boundary word : $word, S=$starttime, E=$endtime Before next section </Comment>\n"
		if ($save eq "T");
	    print "\nWARNING : OBW 3 : $word, S=$starttime, E=$endtime, SS=$tag_list[$i][1], SE=$tag_list[$i][2]\n";
	    $current++;
	    next;
	}

	#### word is inside next session, open session and print word
	# implied $starttime >= start of next session
	if ($endtime <= $tag_list[$i+1][2])
	{
            $i++;
            print OFD "<Section Type=$tag_list[$i][0] S_time=$tag_list[$i][1] E_time=$tag_list[$i][2] ID=$tag_list[$i][3] >\n";
            $openedS = "T";
	    print OFD "<Word S_time=$starttime E_time=$endtime> $word </Word>\n";
	    $current++;
	    next;
	}

	# implied $starttime >= start of next session
	# implied $endtime   >  end of next session
	$i++;
	print OFD "<Section Type=$tag_list[$i][0] S_time=$tag_list[$i][1] E_time=$tag_list[$i][2] ID=$tag_list[$i][3] >\n";
	print OFD "<Comment> Empty section </Comment>\n";
 	print OFD "</Section>\n\n";
	print "\n\tWARNING : empty section\n";
	next;
  	

    } # if more section
    
    #### word is after last section
    print OFD "<Comment> Out of boundary word, after last section : $word, S=$starttime, E=$endtime word after last section </Comment>\n"
	if ($save eq "T");
    print "\nWARNING : OBW 4 : $word, S=$starttime, E=$endtime, SS=$tag_list[$i][1], SE=$tag_list[$i][2]\n";
    $current++;

} # while


# finish processing
if (($openedS eq "T") && ($i !=0))
{
    print OFD "</Section>\n\n";
    $openedS = "F";
}

print OFD "</Episode>";
close OFD;

print "\n\tDone.\n\n";
