#!/usr/bin/env perl

# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

use warnings;
use strict;

use WebService::UrbanDictionary;
use Getopt::Long qw(GetOptionsFromString);

Getopt::Long::Configure ("bundling");

my $getopt_error;
local $SIG{__WARN__} = sub {
  $getopt_error = shift;
  chomp $getopt_error;
};

my $usage = "Usage: udict [-m <show definition matching this regex>] [-n <entry number>] [-s <up/down (sort by thumbs up/down)>] <phrase>\n";

my ($entry, $sort, $match, $show_all);
my $arguments = join(' ', @ARGV);

$arguments =~ s/'/\\'/g;

my ($ret, $args) = GetOptionsFromString($arguments,
  'a'   => \$show_all,
  'm=s' => \$match,
  'n=i' => \$entry,
  's=s' => \$sort);

print "$getopt_error -- $usage"  and exit if defined $getopt_error;
print "Missing phrase -- $usage" and exit if @$args == 0 and not $match and not $entry;


if (@$args == 0) {
  open my $fh, "<", "udict.last";
  if ($fh) {
    $args = <$fh>;
    chomp $args;
    close $fh;
  } else {
    $args = "wtf";
  }
} else {
  $args = join(' ', @$args);
  open my $fh, ">", "udict.last";
  print $fh "$args\n";
  close $fh;
}

my $ud = WebService::UrbanDictionary->new;
my $results = $ud->request($args);

sub sort_entries {
  if (defined $sort) {
    if (lc $sort eq 'down' or lc $sort eq 'd') {
      return $a->{'thumbs_up'} <=> $b->{'thumbs_up'};
    } else {
      return $b->{'thumbs_up'} <=> $a->{'thumbs_up'};
    }
  } else {
    return $b->{'thumbs_up'} <=> $a->{'thumbs_up'};
  }
}

my @entries;
if (defined $sort) {
  @entries = sort sort_entries @{ $results->definitions };
} else {
  @entries = @{ $results->definitions };
}
my $num_entries = @entries;

if ($num_entries == 0) {
  print "$args: no definition found.\n";
  exit;
}

if (defined $entry) {
  if ($entry < 1 or $entry > $num_entries) {
    if ($num_entries == 1) {
      print "There is only one entry for $args.\n";
    } else {
      print "$args: no such entry. There are $num_entries entries.\n";
    }
    exit;
  }
  $entry--;
}

sub show_definition {
  my $entry = shift;
  my $num = shift;

  $num = 1 if not defined $num;

  if ($num_entries > 1) {
    print "$num/$num_entries: ";
  }

  $entry->{'definition'} =~ s/\[(.*?)\]/$1/g;
  $entry->{'example'} =~ s/\[(.*?)\]/$1/g if $entry->{'example'};

  print "(+$entry->{'thumbs_up'}/-$entry->{'thumbs_down'}) $entry->{'definition'}\n";
  print "«$entry->{'example'}»\n" if $entry->{'example'};
}

if (defined $show_all or defined $match) {
  my $shown;
  eval {
    my $n = 0;
    for my $each (@entries) {
      $n++;
      if (defined $match) {
        my $def = $each->{'definition'} . "\n";
        $def .= "«$each->{'example'}»" if $each->{'example'};
        next if $def !~ m/$match/im;
      }
      show_definition($each, $n);
      print "\n";
      $shown++;
    }
  };

  if ($@) {
    my $err = $@;
    $err =~ s/; marked by <-- HERE.*/: $match/;
    print "Oops, $err\n";
    exit;
  }

  if (not $shown) {
    print "$args: no definition matching '$match' found.\n";
  }
} else {
  show_definition($entries[$entry], $entry + 1);
}
