#!/usr/bin/perl -w

use POSIX;

if($#ARGV!=0) {
  print "Usage: perl unshift_subs.pl <dir>\n";
  exit;
}
my $sourcedir=$ARGV[0];
my $shift_offset=177;
my $res_y=1080;
my $min1_y=0;
my $min2_y=0;
my $max1_height=0;
my $max2_height=0;
my $height_divider=0;
my $filmname;
my $lang;
my %positioncache=();

if($^O eq "MSWin32") {
  @filelist=glob("\"$sourcedir\\\*.xml\"");
} else {
  @filelist=glob("\"$sourcedir/\*.xml\"");
}
my $listsize=@filelist;
if($listsize==0) {
  print "Error: No XML files found in $sourcedir\n";
  exit;
}

sub shift_timecode {
  my $film=$_[0];
  my $in=$_[1];
  my $out=$_[2];
  my $is_native=$_[3];
  my @timein=split(/:/,$in);
  my @timeout=split(/:/,$out);
  if($timeout[0]>0) { return 0; }
# these subtitles are shifted for reasons other than onscreen text
  if($film eq "ESB") {
#    if($timein[1]==18 && $timein[2]>=46) { return 1; }
  }
# any subtitles during the titles and crawl text are shifted
#  if($timeout[1]==0 || $timeout[1]==1) { return 1; }
  if($is_native) { return 0; }
# burnt-in subtitles and neighboring dialogue are shifted for non-native subtitles
  if($film eq "SW") {
    if($timein[1]==49 && $timein[2]>=4 && $timein[2]<=59) { return 1; }
  } else {
    if($film eq "ROTJ") {
      if($timein[1]==9 && $timein[2]>=57) { return 1; }
      if($timein[1]==10 && $timein[2]<=17) { return 1; }
      if($timein[1]==14 && $timein[2]>=13 && $timein[2]<=19) { return 1; }
      if($timein[1]==14 && $timein[2]>=24 && $timein[2]<=30) { return 1; }
      if($timein[1]==14 && $timein[2]>=55 && $timein[2]<=57) { return 1; }
      if($timein[1]==15 && $timein[2]>=37 && $timein[2]<=47) { return 1; }
      if($timein[1]==19 && $timein[2]>=58) { return 1; }
      if($timein[1]==20 && $timein[2]<=9) { return 1; }
      if($timein[1]==20 && $timein[2]>=17 && $timein[2]<=30) { return 1; }
      if($timein[1]==20 && $timein[2]>=38 && $timein[2]<=41) { return 1; }
      if($timein[1]==23 && $timein[2]>=14 && $timein[2]<=47) { return 1; }
      if($timein[1]==24 && $timein[2]>=5 && $timein[2]<=14) { return 1; }
      if($timein[1]==27 && $timein[2]>=33 && $timein[2]<=43) { return 1; }
      if($timein[1]==29 && $timein[2]>=56) { return 1; }
      if($timein[1]==31 && $timein[2]>=22 && $timein[2]<=27) { return 1; }
      if($timein[1]==31 && $timein[2]>=51 && $timein[2]<=53) { return 1; }
    }
  }
  return 0;
}

sub round {
  $_[0] > 0 ? int($_[0] + .5) : -int(-$_[0] + .5)
}

FILELOOP: for $sourcefile (@filelist) {
  my $in_timecode;
  my $out_timecode;
  my $graphic=0;
  my $x=0;
  my $y=0;
  my $height;
  my $token1="";
  my $token2="";
  my @arr;
  my @height_array=();
  my @y_array=();
  my $native=0;
  if($^O eq "MSWin32") {
    @arr=split(/\\/,$sourcefile);
  } else {
    @arr=split(/\//,$sourcefile);
  }
  my $fname=$arr[-1];
  print "Processing ".$fname."...\n";
  open(OLDXML, "<".$sourcefile);
  @arr=split(/-/,$fname);
  my $filmname=$arr[0];
  my $lang=$arr[1];
  if (index($fname,"-native") != -1 || index($fname,"-match-") != -1 || index($fname,"-nocrawl") != -1) {
    $native=1;
  }
  for(my $i=2; (($i < $#arr) && ($i <= 3)); $i++) {
    if(length($arr[$i])>4 || $arr[$i] eq "full" || $arr[$i] eq "mono") {
      last;
    } else {
      $lang=$lang."-".$arr[$i];
    }
  }
  foreach my $line (<OLDXML>) {
    if (index($line, '<Event ') != -1) {
      if (index($line, "InTC=") != -1) {
        @arr=split(/InTC="/,$line);
        $in_timecode=$arr[1];
        @arr=split(/"/,$in_timecode);
        $in_timecode=$arr[0];
      }
      if (index($line, "OutTC=") != -1) {
        @arr=split(/OutTC="/,$line);
        $out_timecode=$arr[1];
        @arr=split(/"/,$out_timecode);
        $out_timecode=$arr[0];
      }
    }
    if (index($line, '<Graphic') != -1) {
      $graphic=1;
    }
    if($graphic==1) {
      if (index($line, "Y=") != -1) {
        @arr=split(/Y="/,$line);
        $y=$arr[1];
        @arr=split(/"/,$y);
        $y=$arr[0];
        @arr=split(/Height="/,$line);
        $height=$arr[1];
        @arr=split(/"/,$height);
        $height=$arr[0];
        if($y>$res_y/2) {
          push(@y_array,$y);
        }
        push(@height_array,$height);
      }
    }
  }
  close(OLDXML);
  @arr=sort { $b <=> $a } @height_array;
  $max2_height=$arr[0];
  $height_divider=floor($max2_height*3/5);
  $max1_height=$arr[0];
  $x=1;
  while($max1_height>$height_divider && $x<$#arr) {
    $max1_height=$arr[$x];
    if($max1_height>$height_divider) {
      $x=$x+1;
    }
  }
  if($x>$#arr) {
    $max1_height=$max2_height;
  }
  if($#y_array>10) {
    @arr=sort { $b <=> $a } @y_array;
    $min2_y=$arr[-1];
    $min1_y=$arr[-1];
    $x=-1;
    while($min1_y<($min2_y+$max2_height-$max1_height) && (0-$x)<$#arr) {
      $min1_y=$arr[$x];
      if($min1_y<($min2_y+$max2_height-$max1_height)) {
        $x=$x-1;
      }
    }
    if((0-$x)>$#arr) {
      $min1_y=$min2_y;
    }
  } else {
    if(!(exists $positioncache{$filmname."-".$lang})) {
      print "Warning: Titles subtitles without corresponding full subtitles will have less accurate unshifted positioning.\n";
      open(OLDXML, "<".$sourcefile);
      $graphic=0;
      foreach my $line (<OLDXML>) {
        if (index($line, '<Graphic') != -1) {
          $graphic=1;
        }
        if($graphic==1) {
          if (index($line, "Y=") != -1) {
            @arr=split(/Y="/,$line);
            $y=$arr[1];
            @arr=split(/"/,$y);
            $y=$arr[0];
            @arr=split(/Height="/,$line);
            $height=$arr[1];
            @arr=split(/"/,$height);
            $height=$arr[0];
            if($y<$res_y/2) {
              if($height>$height_divider) {
                push(@y_height_array2,$y+$height);
              } else {
                push(@y_height_array1,$y+$height);
              }
            }
          }
        }
      }
      @arr=sort { $b <=> $a } @y_height_array2;
      $max_y2=$arr[0];
      @arr=sort { $b <=> $a } @y_height_array1;
      $max_y1=$arr[0];
      close(OLDXML);
    }
  }
  open(OLDXML, "<".$sourcefile);
  if($^O eq "MSWin32") {
    open(NEWXML, '>' . $sourcedir . '\\_' . $fname);
  } else {
    open(NEWXML, '>' . $sourcedir . '/_' . $fname);
  }
  $graphic=0;
  foreach my $line (<OLDXML>) {
    if (index($line, '<Event ') != -1) {
      if (index($line, "InTC=") != -1) {
        @arr=split(/InTC="/,$line);
        $in_timecode=$arr[1];
        @arr=split(/"/,$in_timecode);
        $in_timecode=$arr[0];
      }
      if (index($line, "OutTC=") != -1) {
        @arr=split(/OutTC="/,$line);
        $out_timecode=$arr[1];
        @arr=split(/"/,$out_timecode);
        $out_timecode=$arr[0];
      }
    }
    if (index($line, '<Graphic') != -1) {
      $graphic=1;
    }
    if($graphic==1) {
      if (index($line, "Y=") != -1) {
        @arr=split(/Y="/,$line);
        $y=$arr[1];
        @arr=split(/"/,$y);
        $y=$arr[0];
        if($y<$res_y/2) {
          if(shift_timecode($filmname,$in_timecode,$out_timecode,$native)) {
            @arr=split(/Height="/,$line);
            $height=$arr[1];
            @arr=split(/"/,$height);
            $height=$arr[0];
            $token1="Y=\"".$y;
            if($#y_array>10) {
              if($height>$height_divider) {
                $x=$y+$min2_y-$shift_offset;
              } else {
                $x=$y+$min1_y-$shift_offset;
              }
              if(exists $positioncache{$filmname."-".$lang}) {
                $positioncache{$filmname."-".$lang}{$in_timecode}=$x;
              } else {
                $positioncache{$filmname."-".$lang}={$in_timecode => $x};
              }
            } else {
              if(exists $positioncache{$filmname."-".$lang}{$in_timecode}) {
                $x=$positioncache{$filmname."-".$lang}{$in_timecode};
              } else {
# fallback positioning
                $res_offset=3*$res_y/1080;
                if($height>$height_divider) {
                  $line_offset=$max_y2-$y-$height;
                  $x=$res_y-$shift_offset-$height-$line_offset+$res_offset;
                } else {
                  $line_offset=$max_y1-$y-$height;
                  $x=$res_y-$shift_offset-$height-$line_offset+$res_offset;
                }
              }
            }
            $token2="Y=\"".$x;
            $line=~s/$token1/$token2/;
          }
        }
      }
      print NEWXML $line;
    } else {
      if (index($line, "VideoFormat") != -1) {
        if (index($line, "1080p") != -1) {
          $res_y=1080;
          $shift_offset=177;
        }
        if (index($line, "720p") != -1) {
          $res_y=720;
          $shift_offset=118;
        }
      }
      print NEWXML $line;
    }
  }
  close(OLDXML);
  close(NEWXML);
  if($^O eq "MSWin32") {
    rename($sourcedir . '\\_' . $fname,$sourcedir . '\\' . $fname);
  } else {
    rename($sourcedir . '/_' . $fname,$sourcedir . '/' . $fname);
  }
}

print "Process complete. Subtitles in $sourcedir have been unshifted.\n";
