#
#  This file is common to a number of the files in the TightKnot directory. It includes utility functions for parsing filenames, generating TeX, and so forth.
#

sub parsefilename {

  my $filename = @_[0];
  my @fnparts;

  my @summands;
  my @sumtags;

  my $totalcr = 0;
  my $totalcomp = 1;

  my $cr;
  my $comp;
  my $ind;

  my $tag = "";

  $filename =~ s/\.vect//g;
  $filename =~ s/\.\/vects\/kl\_//g;

#  print "filename: $filename \n";

  @fnparts = split(/\_/,$filename);

  print "fnparts: @fnparts \n";

  my $i;
  my @summand_texkeys;
  my $treeTag;

  for ($i=0;$i<=$#fnparts;$i++) { 

#   print "Now checking $fnparts[$i] $fnparts[$i+1] ... \n";

    if ($fnparts[$i] =~ /^\d+$/ && $fnparts[$i+1] =~ /^\d+$/) {

      if ($fnparts[$i+2] =~ /^\d+$/ || $fnparts[$i+2] =~ /^(r|m|mr|rm)$/) {  # We have a link or an (m/r) tag

	if ($fnparts[$i+2] =~ /^\d+$/) {

	  $cr = $fnparts[$i]; $comp = $fnparts[$i+1]; $ind = $fnparts[$i+2];
	  $totalcr += $cr; $totalcomp += $comp - 1;
	  push (@summand_texkeys,"$cr^{$comp}_{$ind}");

#	  print "so far, texkeys = @summand_texkeys\n";

	} else {

	  $cr = $fnparts[$i]; $comp = 1; $ind = $fnparts[$i+1];
	  $totalcr += $cr; $totalcomp += $comp - 1;

	  # We have an r/m tag, which should appear in the tex key 

	  $fnparts[$i+2] =~ s/mr/{mr}/g;
	  $fnparts[$i+2] =~ s/rm/{rm}/g;

	  push (@summand_texkeys,$cr."_{$ind}".$fnparts[$i+2]);

#	  print "r/m tag: $cr  $ind  $fnparts[$i+2] texkeys = @summand_texkeys\n";

	}

#	print "\tpushing ".$fnparts[$i]."_".$fnparts[$i+1]."_".$fnparts[$i+2]."\n";

	push(@summands,$fnparts[$i]."_".$fnparts[$i+1]."_".$fnparts[$i+2]);
	$i += 2; # skip to the next part

      } else {

	$cr = $fnparts[$i]; $comp = 1; $ind = $fnparts[$i+1];
	$totalcr += $cr; $totalcomp += $comp - 1;

	push (@summand_texkeys,$cr."_{$ind}");
#	print "\tpushing ".$fnparts[$i]."_".$fnparts[$i+1]."\n";

	push(@summands,$fnparts[$i]."_".$fnparts[$i+1]); # A standard link
	$i += 1; # skip ahead by 2 fragments

      }

      if ($totalcomp > 1 && $#summands > 0) { # Composite link.

	  if ($i == $#fnparts-2) { # we have a treetag

	      $treeTag = $fnparts[$i+1];
	      $tag = $fnparts[$i+2];
	      $i += 2;
	      
	  } elsif ($i == $#fnparts-1) { # no treetag
	      
	      $tag = $fnparts[$i+1];
	      $i++;

	  }
	  
	  } elsif ($i == $#fnparts-1) { # We have a tag, and we're not a composite link

	      $tag = $fnparts[$i+1];
	      $i++;
       
	  }

    }
   
  }

  print "summands: @summands \n";
  
  my $knottype = join("_#_",@summands);
  
  if (defined $treeTag) {

      $knottype = $knottype."_$treeTag";

  }

  my %retstuff;

  @{$retstuff{summands}} = @summands;
  $retstuff{tag} = $tag;
  $retstuff{knottype} = $knottype;

  $retstuff{cr} = $totalcr;
  $retstuff{comp} = $totalcomp;
  
  if (scalar @summands > 1) { $retstuff{index} = 1; }
  else { $retstuff{index} = $ind; }

  $retstuff{tex} = join(" \\# ",@summand_texkeys);

  return %retstuff;

}

sub standardknottype {

  my $knottype = @_[0];
  my @parts;

  @parts = split(/\_/,$knottype);

  if (@parts[$#parts] =~ /^(r|m|mr|rm)/) {

    return $parts[0]."_".$parts[1];

  }

  return $knottype;

}

sub crossing_number { 
   
    my %knots = %{@_[0]};
    my $key = @_[1];
    my $cr;

    if (defined $knots{$key}{summands}) {

	$cr = 0;
	
	foreach ($knots{$key}{summands}) {

	    if ($_ =~ /^(\d+)_.+/) {

		$cr += $1;

	    } else {

		die("crossing_number: Couldn't parse summand $_ \n");

	    }

	}

    } else {

	if ($key =~ /(\d+)_.+/) {

	    $cr = $1;

	} else {

	    die("crossing_number: Couldn't parse $key. \n");

	}

    }

    return $cr;

}

sub prime_summands { 

    my %knots = %{@_[0]};
    my $key = @_[1];

    if (defined $knots{$key}{summands}) {

	return scalar @{$knots{$key}{summands}};

    } else {

	return 1;

    }

}

sub stored_writhe { 

  my %knots = %{@_[0]};
  my $knottype = @_[1];
  my $raw_writhe;

  $raw_writhe = $knots{standardknottype($knottype)}{writhe};

  if ($knottype =~ /m/) {

    $raw_writhe *= -1.0;

  } 

  return $raw_writhe;

}



sub compare_summands {

  my %symorder = ( 'e' => 1, 'r' => 2, 'm' => 3, 'rm' => 4, 'mr' => 4 );

  my %knots = %{@_[0]};
  my $a = @_[1];
  my $b = @_[2];

  #print "a = $a, b = $b\n";

  unless (defined $knots{$a}{summands}) {

    return $knots{$a}{index} <=> $knots{$b}{index};

  } 
	
  my @A = @{$knots{$a}{summands}};
  my @B = @{$knots{$b}{summands}};
 
  #print "A = @A\n";
  #print "B = @B\n";
 
  my $i;
  
  if ((scalar @A <=> scalar @B) ne 0) { 
    
    #print "Different number of summands"; 
    return (scalar @A <=> scalar @B); 
    
  }
  
  foreach $i (0..(scalar @A - 1)) {
    
    #print $i;
    #$i = (scalar @A - 1) - $i;
    #print $i;
    
    my @aparts,@bparts;
    
    #print "a[i] $A[$i] \n";
    #print "b[i] $B[$i] \n";
    
    @aparts = split(/_/,$A[$i]);
    @bparts = split(/_/,$B[$i]);
    
    
    if ($aparts[0] <=> $bparts[0] or $aparts[1] <=> $bparts[1]) {
      
      return ($aparts[0] <=> $bparts[0] or $aparts[1] <=> $bparts[1]);
      
    }
    
  }
  
  foreach $i (0..(scalar @A - 1)) {
    
    #print $i;
    #$i = (scalar @A - 1) - $i;
    #print $i;
    
    my @aparts,@bparts;
    
    #print "a[i] $A[$i] \n";
    #print "b[i] $B[$i] \n";
    
    @aparts = split(/_/,$A[$i]);
    @bparts = split(/_/,$B[$i]);
    
    #print "aparts: @aparts\n";
    #print "bparts: @bparts\n";
    
    unless (defined($aparts[2])) {
      
      $aparts[2] = 'e';
      
    } 
    
    unless (defined($bparts[2])) {
      
      $bparts[2] = 'e';
      
    }
    
    my $j;
    
    #print "aparts: @aparts\n";
    #print "bparts: @bparts\n";
    
    
    if ($aparts[0] <=> $bparts[0] or $aparts[1] <=> $bparts[1] or $symorder{$aparts[2]} <=> $symorder{$bparts[2]}) {
      
      return ($aparts[0] <=> $bparts[0] or $aparts[1] <=> $bparts[1] or $symorder{$aparts[2]} <=> $symorder{$bparts[2]});
      
    }
    
  }
  
  
  return 0; # We ran out of summands
  
}


sub sorted_knot_types { 

    my %knots = %{@_[0]};
    my $composites = @_[1];
    my @keys; 
    my %fastknots;

    foreach $_ ( keys ( %knots )) {

	unless ( $_ =~ /vect/) {

	    print "Considering $_, ps = ".prime_summands(\%knots,$_)."\n";

	    if ($composites =~ /composites/ || prime_summands(\%knots,$_) == 1) {

		push(@keys,$_);
		$fastknots{$_} = $knots{$_};

	    }

	}

    }

    print "Sorting ".scalar @keys." knot types...\n";
    
    my @sortkeys = sort{ 
	    
	($fastknots{$a}{cr} <=> $fastknots{$b}{cr}) or
	    
	(prime_summands(\%fastknots,$a) <=> prime_summands(\%fastknots,$b)) or
		
	$fastknots{$a}{comp} <=> $fastknots{$b}{comp} or 

	compare_summands(\%fastknots,$a,$b)
				
    } @keys ;

    return @sortkeys;

}

1;
