#!/usr/local/bin/perl
use strict;
use warnings;
use LWP;
use Getopt::Long;

### TODO
# XML Parsing instead of regexes

my $USERNAME;
my $PASSWORD;
my $VERBOSE;
my $REMOTEFILE;
my $LOCALFILE;
my $MESSAGE;

GetOptions(
           "username=s"   => \$USERNAME,
           "password=s"   => \$PASSWORD,
           "verbose|v"    => \$VERBOSE,
           "remotefile=s" => \$REMOTEFILE,
           "localfile=s"  => \$LOCALFILE,
           "message|m=s"  => \$MESSAGE,
           );

&useage if ((!$USERNAME) or (!$PASSWORD) or (!$REMOTEFILE) or (!$LOCALFILE) or (!$MESSAGE));

if(!-f $LOCALFILE) {
  print "$LOCALFILE is not a valid localfile!\n";
  exit;
}

{
  package SubversionClient;
  our @ISA = qw(LWP::UserAgent);
  sub get_basic_credentials {
    return $USERNAME, $PASSWORD;
  }
}

my $ua = SubversionClient->new;
$ua->agent("deltavputfile 0.1");
my $UUID = $^T . "." . $$;

$REMOTEFILE =~ m|(http.?//.*?)(/.*)/([^/]+)$|;
my $servername = $1;
my $directory = $2;
my $file      = "/$3";

#OPTIONS
my $options_pass_in = qq|<?xml version="1.0" encoding="utf-8"?><D:options xmlns:D="DAV:"><D:activity-collection-set/></D:options>|;
my $options = DeltaV(type => "OPTIONS", url => $servername . $directory, xml => $options_pass_in, ec => 200);
$options->content =~ m|<D:activity-collection-set><D:href>([^<]+?)</D:href></D:activity-collection-set>|;
my $actset = $1;

$actset =~ m|([^!]+)!|;
my $repo = $1;

#MKACTIVITY
my $mkactivity = DeltaV(type => "MKACTIVITY", url => $servername . $actset . $UUID, ec => 201);

#PROPFIND
my $vcc = propfind(
  xml => qq|<?xml version="1.0" encoding="utf-8"?><propfind xmlns="DAV:"><prop><version-controlled-configuration xmlns="DAV:"/></prop></propfind>|,
  url => $servername . $directory,
  ec  => 207,
  re  => qr|<lp1:version-controlled-configuration><D:href>([^<]+?)</D:href></lp1:version-controlled-configuration>|,
);

#PROPFIND
my $checkedin = propfind(
  url => $servername . $vcc,
  ec  => 207,
  re  => qr|<lp1:checked-in><D:href>([^<]+?)</D:href></lp1:checked-in>|,
);

#CHECKOUT
my $checkout_xml_in = qq|<?xml version="1.0" encoding="utf-8"?><D:checkout xmlns:D="DAV:"><D:activity-set><D:href>$servername$actset$UUID</D:href></D:activity-set></D:checkout>|;
my $checkout = DeltaV(type => "CHECKOUT", url => $servername . $checkedin, xml => $checkout_xml_in, ec => 201);
$checkout->content =~ m|<p>Checked-out resource (.+?) has been created\.</p>|;
my $activityset = $1;

#PROPPATCH
my $message_xml_format = <<END;
<?xml version="1.0" encoding="utf-8" ?>
<D:propertyupdate xmlns:D="DAV:"><D:set><D:prop><log xmlns="http://subversion.tigris.org/xmlns/svn/">$MESSAGE</log></D:prop></D:set>
</D:propertyupdate>
END
my $proppatch = DeltaV(type => "PROPPATCH", url => $servername . $activityset, xml => $message_xml_format, ec => 207);
my $proppatch_xml = $proppatch->content; # do we do anything with this?

#PROPFIND
my $checkedinb = propfind(
  xml => qq|<?xml version="1.0" encoding="utf-8"?><propfind xmlns="DAV:"><prop><checked-in xmlns="DAV:"/></prop></propfind>|,
  url => $servername . $directory,
  ec  => 207,
  re  => qr|<lp1:checked-in><D:href>([^<]+?)</D:href></lp1:checked-in>|,
);

#CHECKOUT
my $checkout_xml_ina = qq|<?xml version="1.0" encoding="utf-8"?><D:checkout xmlns:D="DAV:"><D:activity-set><D:href>$servername$actset$UUID</D:href></D:activity-set></D:checkout>|;
my $checkouta = DeltaV(type => "CHECKOUT", url => $servername . $checkedinb . $file, xml => $checkout_xml_ina, ec => 201);
$checkouta->content =~ m|<p>Checked-out resource (.+?) has been created\.</p>|;
my $workingfile = $1;

#PUT
open(FILE, "<$LOCALFILE") or die "Can't open $LOCALFILE for reading: $!\n";
my $filecontent = join("", <FILE>);
close(FILE);
my $put = DeltaV(type => "PUT", url => $servername . $workingfile, xml => $filecontent, ec => 204);

#MERGE
my $merge_xml = qq|<?xml version="1.0" encoding="utf-8"?><D:merge xmlns:D="DAV:"><D:source><D:href>$servername$actset$UUID</D:href></D:source><D:no-auto-merge/><D:no-checkout/><D:prop><D:checked-in/><D:version-name/><D:resourcetype/><D:creationdate/><D:creator-displayname/></D:prop></D:merge>|;
my $merge = DeltaV(type => "MERGE", url => $servername . $directory, xml => $merge_xml, ec => 200);

#DELETE
my $delete = DeltaV(type => "DELETE", url => $servername . $actset. $UUID, ec => 204);

sub propfind {
  my %opts = @_;
  my $xml = $opts{xml} || "";
  my $url = $opts{url};
  my $ec  = $opts{ec};
  my $re  = $opts{re};
  my $propfind = DeltaV(type => "PROPFIND", url => $url, xml => $xml, ec => $ec, depth => 0);
  $propfind->content =~ m/$re/;
  my $returnvar = $1;
  return $returnvar;
}

sub DeltaV {
  my %opts  = @_;
  my $type  = $opts{type};
  my $url   = $opts{url};
  my $xml   = $opts{xml};
  my $ec    = $opts{ec};
  my $depth = $opts{depth};
  my $dv = HTTP::Request->new($type => $url);
     $dv->authorization_basic(SubversionClient->get_basic_credentials);
     $dv->content($xml) if ($xml);
     $dv->header(depth => $depth) if (defined($depth));
  my $dv_response = $ua->request($dv);
  if (($VERBOSE) or ($dv_response->code != $ec)) {
    print "#SENT###########################################################################\n";
    print $dv->as_string, "\n";
    print "#GOT############################################################################\n";
    print $dv_response->as_string(), "\n";
    print "################################################################################\n";
  }
  if ($dv_response->code != $ec) {
    die "Error";
  }
  return $dv_response;
}
sub useage {
  print <<END;
  --username   <USERNAME>
  --password   <PASSWORD>
  --message    <MESSAGE>
  --remotefile <REMOTEFILE> (http://server/path/to/file.txt)
  --localfile  <LOCALFILE>
END
  exit;
}


