#!/usr/bin/perl

use warnings;
use strict;

use URI;

use Data::Dumper;

# there's got to be a better way... embed the tables?
my (%Vocal) = %{loadTable("vocal-table.csv")};
my (%Instrument) = %{loadTable("instrument-table.csv")};
my (%Orchestra) = %{loadTable("orchestra-table.csv")};
my (%Type) = %{loadTable("relationship-type-table.csv")};

# the list of edits we are about to commit
my (@edits);

# until the heat death of the universe
while (1) {
  # read in a stanza
  my @lines;
  my $nonblank = 0;
  while(<>) {
    chomp;
    last if /^$/ && $nonblank;
    next if /^#/;
    $nonblank = 1;
    push @lines, $_;
  }
  
  # if we are out of stanzas, exit
  last if $#lines == -1;
  
  # parse first and second entity
  my ($type0, @id0) = parseEntityLine(shift @lines);
  my ($type1, @id1) = parseEntityLine(shift @lines);

  #print join ",",$type0, $type1; print "\n";
  #print join ",",@id0; print "\n";
  #print join ",",@id1; print "\n";

  # Parse remaining lines, extract relationship parameters
  my (%param) = map {
    lc $1 => $_ if (s/^\s*(\w+)\s*[:=]?(?:\s*|$)//);
  } @lines;
  
  # --- canonicalize parameters ---
  #print Dumper(\%param);
  
  # Type
  die "(Relationship) Type not specified" unless exists $param{type};
  foreach (keys %Type) {
    $param{type} = $Type{$_} if exists $param{$_};
    delete $param{$_};
  }
  $param{type} = $Type{$param{type}} 
    if exists $Type{$param{type}};

  # Guest, Additional, Minor
  foreach (qw(guest additional minor)) {
    if (exists $param{$_}) {
      if ($param{$_} =~ m/1|Y(es)?|^$/i) {
        $param{$_} = 1;
      } else {
        $param{$_} = 0;
      }
    }
  }
  
  # Vocal
  foreach (keys %Vocal) {
    $param{vocal} = $Vocal{$_} if exists $param{$_};
    delete $param{$_};
  }
  $param{vocal} = $Vocal{$param{vocal}} 
    if exists $param{vocal} && exists $Vocal{$param{vocal}};

  # Instrument
  foreach (keys %Instrument) {
    $param{instrument} = $Instrument{$_} if exists $param{$_};
    delete $param{$_};
  }
  $param{instrument} = $Instrument{$param{instrument}}
    if exists $param{instrument} && exists $Instrument{$param{instrument}};

  # Orchestra
  foreach (keys %Orchestra) {
    $param{orchestra} = $Orchestra{$_} if exists $param{$_};
    delete $param{$_};
  }
  $param{orchestra} = $Orchestra{$param{instrument}}
    if exists $param{orchestra} && exists $Orchestra{$param{orchestra}};

  # BeginDate -- YYYY-MM-DD
  if (exists $param{begindate}) {
    my ($date) = $param{begindate};
    delete $param{begindate};
    if ($date =~ m/(\d+)-(\d+)-(\d+)/) {
      $param{begindate_y} = $1;
      $param{begindate_m} = $2;
      $param{begindate_d} = $3;
    }
  }
  
  # EndDate
  if (exists $param{enddate}) {
    my ($date) = $param{enddate};
    delete $param{enddate};
    if ($date =~ m/(\d+)-(\d+)-(\d+)/) {
      $param{enddate_y} = $1;
      $param{enddate_m} = $2;
      $param{enddate_d} = $3;
    }
  }

  #print Dumper(\%param);

  # construct url...

  # type -> linktypeid
  if ($param{type} =~ m/^\d+$/) {
    $param{linktypeid} = $param{type};
    delete $param{type};
  } else {
    die "(Relationship) Type unknown";
  }
  
  # additional -> attr_additional_0
  if (exists $param{additional}) {
    $param{attr_additional_0} = $param{additional};
    delete $param{additional};
  }

  # guest -> attr_guest_0
  if (exists $param{guest}) {
    $param{attr_guest_0} = $param{guest};
    delete $param{guest};
  }

  # minor -> attr_minor_0
  if (exists $param{minor}) {
    $param{attr_minor_0} = $param{minor};
    delete $param{minor};
  }
  
  # instrument -> attr_instrument_0
  if (exists $param{instrument}) {
    $param{attr_instrument_0} = $param{instrument};
    delete $param{instrument};
  }
  
  # vocal -> attr_vocal_0
  if (exists $param{vocal}) {
    $param{attr_vocal_0} = $param{vocal};
    delete $param{vocal};
  }

  # note -> notetext
  if (exists $param{note}) {
    $param{notetext} = $param{note};
    delete $param{note};
  }
  
  print Dumper(\%param);
  
  # Foreach (Entity1, Entity2) pair
  foreach my $id0 (@id0) { foreach my $id1 (@id1) {
    my (%edit) = (
      link0 => $type0 . "=" . $id0,
      link1 => $type1 . "=" . $id1,
    );
    foreach (keys %param) {
      $edit{$_} = $param{$_};
    }
    push @edits, \%edit;
  }}
}

foreach my $edit (@edits) {
  my $uri = new URI "http://musicbrainz.org/edit/relationship/add.html";
  
  $uri->query_form($edit);
  
  print "firefox --new-tab ", $uri, "\n";
  
  # open a new tab in browser...
  system "firefox", "--new-tab", $uri->as_string;

  # Delay a few seconds to reduce load.
  sleep 3 + rand(4);
}

sub parseEntityLine {
  my ($line) = @_;
  
  #print $line;
  
  # extract entity type from line
  die "Could not find entity type" 
    unless $line =~ s/^\s*(artist|release|track)(?::|\s)\s*//i;
  
  my ($type) = lc $1;

  # extract entities from line
  my (@ids) = split /(?:,|\s)\s*/, $line; # )()
  
  die "No entities specified" if $#ids == -1;

  # Convert entityid(TrackID, etc...) to entity number (cache this data
  # within an invocation)
  #@ids = artistIDsToNumbers @ids if $type == "artist";
  
  return $type, @ids;
}

# load a CSV table of the form name, ID
sub loadTable {
  my ($file) = @_;
  open IN, $file;
  my (%table);
  while(<IN>) {
    chomp;
    $table{lc $1} = $2 if m/^([^,]*),(\d+)/;
  }
  close IN;
  return \%table;
}