#! /usr/bin/perl -w
# -- PB User Script Info --
# %%%{PBXName=Place Superclass Method Skeletons on Clipboard}%%%
# %%%{PBXInput=AllText}%%%
# %%%{PBXOutput=Pasteboard}%%%
# %%%{PBXKeyEquivalent=~s}%%%
#

use strict;
sub trim($);

$/=undef; #I need the whole blob of the file at once, not a line at a time.

my $fullText = <>; #Grab the source file
$/="\n";
my @lines = split("\n",$fullText); #Now get things a line at a time
my $selstart = %%%{PBXSelectionStart}%%%;
my $sellen = %%%{PBXSelectionLength}%%%;
#print "Start: " . $selstart . "\n";
#print "Len: " . $sellen . "\n";
my $selection = trim(substr($fullText,$selstart,$sellen));
#print "Selection: " . $selection . "\n";
my $stidx=-1; #Where does the class start
my $endidx=-1; #Where does the class end
my $x=-1; #Loop control variable. Need the indicies, so can't foreach '
my $isint = 0; #Is this an interface or implementation?
chomp($selection); #Get rid of a newline if there is one
for($x=0;$x<@lines;$x++) { #Look at every line. Find the start and end of the class
    if(index($lines[$x],$selection) >= 0) { #If this has the selection...
      if(index($lines[$x],'@implementation') >= 0) { #and is a @implementation line...
        $isint = 0;
        $stidx=$x;
      }
      if(index($lines[$x],'@interface') >= 0) { #or a @interface line...
        $isint = 1;
        $stidx=$x;
      }
    }
    if($stidx != -1 && index($lines[$x],'@end') >= 0) {
      $endidx=$x;
      last; #Break out of the loop, we've got what we need.
    }
}

if($endidx == -1 || $stidx == -1) { #If the user picked something not in a class setup
  exit;
}
my $semi=";";
#The next few lines get the class name for the comment that is inserted
my @selbreak = split(" +",$lines[$stidx]);
my $classname = $selbreak[1];

for($x=$stidx+1;$x<$endidx;$x++) { #For each line in the class...
  $lines[$x] = trim($lines[$x]);
  if(substr($lines[$x],0,1) ne "-" && #cycle if this isn't a method signature
     substr($lines[$x],0,1) ne "+") {  
    next;
  }
  my @signaturetok = split("\Q(\E.*?\Q)\E",$lines[$x]); #I hate perl regexs. So much.
  #That regex is to split on anything between parentheses (). This should be all data types, including multi-word types like unsigned int
  my $funcname = trim($signaturetok[1]); #Grab the function name for printing
  $funcname =~ s/[;: ]//g; #More with the regexs, this strips other chars from the name
  splice(@signaturetok,0,1); #Get rid of the - or +
  my $call = join("",@signaturetok); #Make a string that resembles a method call
  if(substr($call,-1,1) eq ';') { #I'm sure there's a better way to deal with this.
    $call = substr($call,0,-1);
  }
  $call =~ s/: /:/g; #Not needed, but looks nicer
  $call = trim($call);
  my $replace=" {\n  //Override " . $classname . " method " . $funcname . " here.\n  return [super " . $call . "];\n}"; #Not that pretty, this is a comment that will go in the skeleton body
  #This block tries to get rid of a semicolon or turnstile, and replace it with body
  if($isint == 1) { #Interface, .h file
    $lines[$x] =~ s/$semi/$replace/;
    print $lines[$x] . "\n";
  } else { #Implementation, .m file
    if(index($lines[$x],"{") >= 0) {
      $lines[$x] =~ s/"{"/$replace/;
    } else {
      print $lines[$x] . $replace . "\n";
    }
  }
}

sub trim($) { #Convenience function, trims start and end of string
  my $string = shift;
  $string =~ s/^\s+//;
  $string =~ s/\s+$//;
  return $string;
}

