#!/usr/sbin/perl

##################################################################
#
#  parse.pl - a script that takes a qry file, parses out 
#	the operators: stem, loop, seq, and "and" and
#	computes the correct ranges that for the corresponding
#	"and" operators.
#
#  Author:  David Martinez 
#	San Diego Supercomputer Center 
#            (damartin@sdsc.edu)        August 1997  
#
#
##################################################################

########################## GLOBALS ###############################

# name of the output file
$outfilename = "../qry/base.qry";
$outfilename = "query.qry";

$inputfile = "../qry/Xlaevis5S/Xlaevis5S13.qry";
$inputfile = "../qry/demos/trna.qry";
@input = &get_input;  # parses operators and values 

$ops=0;
$num_pri=0;

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

# for error checking
if ( !(-e $inputfile) ) {
   print "query file $inputfile doesn't exist!\n";
   print "Bailing out..\n";
   exit(1);
}
print "using query file: $inputfile\n";


########################### MAIN #################################

#-------------------------------------------------------------
# start creating output file
#-------------------------------------------------------------
if ( !open(OUTFILE,"> $outfilename") ) {
   print "Error opening an output file $outfilename: $!\n";
   print "Bailing out..\n";
   exit(1);
}

print OUTFILE "# Author: David Martinez  \n";
print OUTFILE "# Copyright [1996] By David Martinez\n";
print OUTFILE "#  \n";
## print  " Total in list=$index\n";
##  for ($j=0; $j<$index; $j++) {
##    for ($i=0; $i<3; $i++) {
##    	$key="$j"."_$i";
##	if (($val{$key} eq "seq:") && ($i==0)) { print  "index=$j Operator " }
##	elsif (($val{$key} eq "loop:") && ($i==0)) {print "index=$j Operator " }
##	elsif (($val{$key} eq "stem:") && ($i==0)) {print "index=$j Operator " }
##	elsif (($val{$key} eq "nodisplay") && ($i==0)) {print "index=$j Main " }
##	elsif (($val{$key} eq "and:") && ($i==0)) { print "index=$j Node " }
##   	print  " $val{$key}";
##   }
##   print  "\n";
##}

#-------------------------------------------------------------
# start preparing nodes for calculations
# find primary nodes first
#
#-------------------------------------------------------------

for ($j=0; $j<$index; $j++) {
	$i=0;
        $key="$j"."_$i";

        if (($val{$key} eq ("seq:"))||($val{$key} eq ("loop:")) && ($i==0)) {  
	   $ops++;
	   if ($ops==3) { # we have a primary branch
		# only loops and seq can terminate branches
		# start calculating Node values
                $ind=$j-3;
		$prime="$ind"."_0";
		$temp="$ind"."_1";
		$prim_ind[$num_pri]=$val{$temp};
		# output primary node info
##		print "Primary Node $num_pri has an index of $prim_ind[$num_pri]\n"; 
                # increment number of primary nodes
                $num_pri++;

	   }
	}

        elsif (($val{$key} eq "stem:") && ($i==0)) {  
	   $ops++;
           if ($ops==3) { # we have a primary branch
	   # actually, this should indicate flaw with the query
	   # since a branch should not terminate with a stem.
		$ind=$j-3;
                $prime="$ind"."_0";

		$temp="$ind"."_1";
                $prim_ind[$num_pri]=$val{$temp};
                # output primary node info
##		print "Primary Node $num_pri has an index of $prim_ind[$num_pri]\n"; 
		# increment number of primary nodes
                $num_pri++;

           }
	}

        elsif (($val{$key} eq "and:") && ($i==0)) {  
	   $key5="$j"."_5";
	   $val{$key5}="n";
	   $ops=0; # reset primary count
	}

} # end for ($j=0;

## print "number of primary nodes: $num_pri\n";


#-------------------------------------------------------------
# start calculations
# work forward from primary nodes and work backward 
# to previous "and" nodes.
#-------------------------------------------------------------

# work on first branch
# this will become a new subroutine primenode
#
for ($i=0; $i<$num_pri; $i++) { 
# $prim_ind[$num_pri] is the index value of the primary node
# start computing Primary nodes values
# 1st and 2nd node values first
     $temp=$prim_ind[$i]+1;
     $key_s1="$temp"."_1";
     $key_s2="$temp"."_2";
     $s1=$val{$key_s1};
     $s2=$val{$key_s2};
     $temp=$prim_ind[$i]+2;
     $key_loop1a="$temp"."_1";
     $key_loop1b="$temp"."_2";
     $loop1a=$val{$key_loop1a};
     $loop1b=$val{$key_loop1b};
     $temp++;
     $key_loop2a="$temp"."_1";
     $key_loop2b="$temp"."_2";
     $loop2a=$val{$key_loop2a};
     $loop2b=$val{$key_loop2b};
     $key1="$prim_ind[$i]"."_1";
     $key2="$prim_ind[$i]"."_2";
     $key3="$prim_ind[$i]"."_3";
     $key4="$prim_ind[$i]"."_4";
     $val{$key1}=2*$s1+$loop1a;
     $val{$key2}=2*$s2+$loop1b;
     $val{$key3}=$loop2a;
     $val{$key4}=$loop2b;
##     print "Primary Node values: prim_ind=$prim_ind[$i], num_pri=$num_pri, prim_ind[i]=$prim_ind[$i], $val{$key1},  $val{$key2},  $val{$key3},  $val{$key4}\n";
}
     # algorithm needs some way to keep track of previously 
     # computed nodes and use them when necesary.
#********************************************************
#********************************************************
#********************************************************

#
# initialize variables
#
     $count=0;
     $start=$num_pri-1;	
     $i=$prim_ind[$start]-1;
     $prime=$prim_ind[$start]-1;
     while ($i>0) {
##	print "i=$i\n";
	# initialize operator values
#	$i--;
	$key_0="$i"."_0";
	$key_1="$i"."_1";
	$key_2="$i"."_2";
	$key_3="$i"."_3";

	if (($val{$key_0} eq "loop:")||($val{$key_0} eq "seq:")||($val{$key_0} eq "stem:")) {
##	   print "one more to go\n";
	   $i--;
	   $count++;  # if count is greater than 2, then we are in a 
	   # new primary branch, last node cannot be used in calculations
	   # until it's appropriate.
	}
	elsif ($val{$key_0} eq "and:") {
##	   print "got the node with index=$val{$key_1}\n";
	   $j=$i+1;
##	   print "i=$i and j=$j\n";
# operator keys
	   $op=$j;
	   $key_op0="$op"."_0";
	   $key_op1="$op"."_1";
	   $key_op2="$op"."_2";
# current node keys
	   $curr=$i;
           $key_1="$curr"."_1";
           $key_2="$curr"."_2";
           $key_3="$curr"."_3";
           $key_4="$curr"."_4";
	   $i--;
# find previous node keys
	   for ($k=$j ;$k<20; $k++) {
               $key_nd0="$k"."_0";
               $key_nd1="$k"."_1";
               $key_nd2="$k"."_2";
               $key_nd3="$k"."_3";
               $key_nd4="$k"."_4";
               $key_nd5="$k"."_5";
##	       if ($val{$key_nd0} eq "and:") {
	       if (($val{$key_nd0} eq "and:")&&($val{$key_nd5} eq "n")) {  
##		   print "found previous unused node at $key_nd0\n";
		   $prev=$k;
		   last;
	       }
	   } # end for 
	   $diff=$prev-$curr;
	   # if $diff >=4 then don't use previous node until appropriate
	   # start as new node.

           $next=$op+1;
           $key_next="$next"."_0";

	   if ($diff<=3) {
	   if (($val{$key_op0} eq "loop:")||($val{$key_op0} eq "seq:")) {
	   # compute node values
	   	$val{$key_1}=$val{$key_op1};
		$val{$key_2}=$val{$key_op2};
		if ($val{$key_next} eq "and:") { 
		# use previous node's values
		    $val{$key_3}=$val{$key_nd1}+$val{$key_nd3};
		    $val{$key_4}=$val{$key_nd2}+$val{$key_nd4};
		    $val{$key_nd5}="u";
		} 
		elsif ($val{$key_next} eq "stem:") { ## added for loop stem case
                    $key_next1="$next"."_1";
                    $key_next2="$next"."_2";
                    $val{$key_3}=$val{$key_next1}+$val{$key_nd1}+$val{$key_nd3};
                    $val{$key_4}=$val{$key_next2}+$val{$key_nd2}+$val{$key_nd4};
                    $val{$key_nd5}="u";
		}
	   } 
	   elsif ($val{$key_op0} eq "stem:") {
	   # There are two possibilites
	   	if (($val{$key_next} eq "loop:")||($val{$key_next} eq "seq:")) {
                    $key_next1="$next"."_1";
                    $key_next2="$next"."_2";
 		    $val{$key_1}=2*$val{$key_op1}+$val{$key_next1};
		    $val{$key_2}=2*$val{$key_op2}+$val{$key_next2};
		    # use previous node's values
		    $val{$key_3}=$val{$key_nd1}+$val{$key_nd3};
		    $val{$key_4}=$val{$key_nd2}+$val{$key_nd4};
		    $val{$key_nd5}="u";
		}
	   	elsif ($val{$key_next} eq "and:") {
                    $val{$key_1}=2*$val{$key_op1}+$val{$key_nd1}+$val{$key_nd3};
                    $val{$key_2}=2*$val{$key_op2}+$val{$key_nd2}+$val{$key_nd4};
		    $val{$key_nd5}="u";
	
		# find previous node keys
           	    for ($k=$j ;$k<20; $k++) {
               		$key_nd0="$k"."_0";
               		$key_nd1="$k"."_1";
               		$key_nd2="$k"."_2";
               		$key_nd3="$k"."_3";
               		$key_nd4="$k"."_4";
               		$key_nd5="$k"."_5";
               		if (($val{$key_nd0} eq "and:")&&($val{$key_nd5} eq "n")) {
##                   	    print "found next previous unused node at $key_nd0\n";
                   	    last;
               	 	}
           	    } # end for
                    $val{$key_3}=$val{$key_nd1}+$val{$key_nd3};
                    $val{$key_4}=$val{$key_nd2}+$val{$key_nd4};
		    $val{$key_nd5}="u";

		} # end elsif

	  } # end elsif

	  }  # end if ($diff<=3) {  
          else {print "diff=$diff, curr=$curr\n"; }
     } # end elsif
} # end while

print "results of calculations so far:\n";
 for ($j=0; $j<$index; $j++) {
        $key="$j"."_0";
        if (($val{$key} eq "seq:")) { 
##	   print  "index=$j Operator "; 
           for ($i=0; $i<3; $i++) {
              $key="$j"."_$i";
              print OUTFILE " $val{$key}";
           }
           print OUTFILE "\n";
	}
        elsif (($val{$key} eq "loop:")) {
##	   print "index=$j Operator "; 
	   for ($i=0; $i<3; $i++) {
	      $key="$j"."_$i";
              print OUTFILE " $val{$key}";
   	   }
           print OUTFILE "\n";
	}
        elsif (($val{$key} eq "stem:")) {
##	   print "index=$j Operator "; 
           for ($i=0; $i<3; $i++) {
              $key="$j"."_$i";
              print OUTFILE " $val{$key}";
           }
           print OUTFILE "\n";
	}
        elsif (($val{$key} eq "nodisplay")) {
##	   print "index=$j Main "; 
           for ($i=0; $i<5; $i++) {
              $key="$j"."_$i";
              print OUTFILE " $val{$key}";
           }
           print OUTFILE "\n";
	}
        elsif (($val{$key} eq "and:")) { 
##	   print "index=$j Node "; 
           for ($i=0; $i<5; $i++) {
              $key="$j"."_$i";
              print OUTFILE " $val{$key}";
           }
           print OUTFILE "\n";
   	}
#   print OUTFILE "\n";
#   print  "\n";
}


close OUTFILE;


print "DONE\n";

######################## SUBROUTINES #############################

#-------------------------------------------------------------
# to trim leading and trailing spaces from an input field
#-------------------------------------------------------------
sub trim_spaces {
   local ($input) = @_;
   $input =~ s/^\s+//;
   $input =~ s/\s+$//;
   return $input;
}

#-----------------------------------------------------------------
# opens the basemap file, extracts and returns the grid dimensions
# (xDimension and zDimension), and the list of numbers 
# that designate the elevations at each point on the basemap
# Just added: also returns scale factor
#-----------------------------------------------------------------
sub get_input {
   local (@list);
   local (@inputinfo) = ();
   local ($IN_HEIGHT) = 0;

   if( !open(INPUT, "< $inputfile") ) {
      print "Error in $0 reading in the inputfile: $!\n";
      return ();
   } else {
      @list = <INPUT>;
      close INPUT;
   }

   if (!@list) {
      print "Error in $0 reading in the query: ";
      print "no data read from $inputfile\n";
      return ();
   }

   $index=0;

   # extract operators, values and nodes
   # ignore comments
   foreach $line (@list) {
         @fields = split(' ',$line);

      if ($fields[0] eq "#") {  # ignore comment lines 
         next;

      } elsif ($line =~ /seq:/) {     # get sequence values 
	 $_=$fields[1];
	 $count=tr/a-z//;
         for ($i=0; $i<3; $i++) {
            $key="$index"."_$i";
	    if ($i>0) {
		$val{$key}=$count;
	    }
            else { $val{$key}=$fields[$i]; }
         }
	 $index++;
         next;

      } elsif ($line =~ /stem:/) {     # get stem values 
         for ($i=0; $i<3; $i++) {
            $key="$index"."_$i";
            $val{$key}=$fields[$i];
         }
	 $index++;
         next;

      } elsif ($line =~ /loop:/) {     # get loop values 
         for ($i=0; $i<3; $i++) {
            $key="$index"."_$i";
            $val{$key}=$fields[$i];
         }
	 $index++;
         next;

      } elsif ($line =~ /and:/) {  # get and values 
	 # index the "and" node and initialize values
	 for ($i=0; $i<2; $i++) {
	    $key="$index"."_$i";
            $val{$key}=$fields[$i];
	    if ($i==1) {
		$val{$key}=$index;
	    }
	 }
	 $index++;
         next;

      } elsif ($line =~ /nodisplay/) {  # get scale line
         for ($i=0; $i<3; $i++) {
            $key="$index"."_$i";
            $val{$key}=$fields[$i];
         }
         $index++;
         next;

      } elsif ($IN_HEIGHT==1) {          # get elevation value
         chop $line;
         $line = &trim_spaces($line);
	 print "chopping line\n";
         push (@inputinfo, $line);
	 $index++;
	 print "index=$index\n";
      }
   }
   return @inputinfo;
}


