#!/usr/bin/perl

use strict;
use warnings;
use lib "/home/dabreegster/lab/hexedui";
use include;

if (@ARGV and shift() eq "--stfu") {
  open STDERR, ">>/var/log/bewarez" or die "can't open stderr log: $!\n";
  print STDERR "-" x 80, "\n";
}

#sub POE::Kernel::ASSERT_DEFAULT () { 1 }
use POE ("Component::Server::TCP");
use PoCoBewarez;
use HexedUI;
use Queue;
use Storable;

# Load up our old dlqueue.
my $restore = retrieve(".dlqueue") if -f ".dlqueue";
my $dlqueue = new Queue;
my $entry = forge_template(
  [qw(name percent sofar total speed eta)],
  name    => "-",
  percent => "%100.0",
  sofar   => "1024.42 MB",
  total   => "1024.42 MB",
  speed   => "42.0 K/s",
  eta     => "xx::yy::zz"
);

# Set up the interface.
my $ui = cast HexedUI Bewarez => {
  Title => {
    Type   => "Fixed",
    At     => [0, 0],
    Size   => [3, "100%"],
    Border => 1
  },
  Main => {
    Type   => "Menu",
    At     => [3, 0],
    Size   => ["100% - 3", "100%"],
    Border => 1,
    Pad    => 1,
    Queue  => $dlqueue,
    KeyHandler => sub {
      my (undef, $key) = @_;
      if ($key eq "p") {
        POE::Kernel->post("bewarez", "toggle");
      } elsif ($key eq "<KEY_DC>") {
        POE::Kernel->post("bewarez", "delete_dl");
      }
    },
    ShiftKeys => 1,
    DeleteKey => 0    # We want to do preprocessing on it ourselves
  },
  Shutdown => sub {
    POE::Kernel->call($_->{DL}{Alias}, "shutdown") foreach $dlqueue->all;
    POE::Kernel->call("server", "shutdown");
    savestate();
  }
};

# Set up the session to handle commands.
POE::Component::Server::TCP->new(
  Port        => 31008,
  Alias       => "server",
  ClientInput => sub {
    my ($cmd, $arg) = split(" ", $_[ARG0], 2);
    if ($cmd eq "add") {
      POE::Kernel->post("bewarez", "add_dl", $arg);
    } else {
      croak "I don't know the command $cmd!";
    }
  }
);

# Set up our session to manage the queue and everything else.
POE::Session->create(
  inline_states => {
    _start => sub {
      $_[KERNEL]->alias_set("bewarez");
      $dlqueue->{Alive} = 0;
      $ui->{Bewarez}{Title}->title(0, "Be Warez... I pwn your warez.");
      $ui->{Bewarez}{Title}->draw;

      $dlqueue->hook(sub {
        my $queue = shift;
        my $cmd = shift;

        if ($cmd eq "shift") {
          my ($oldid, $newid) = @_;
          # We only need to do something if the first queue spot has been tampered with.
          return unless $oldid == 0 or $newid == 0;
          # And preserve our status (if we're active or not).
          my $bewarez = $queue->{Heap}{Bewarez};
          my $status = $bewarez->{Alive};
          # Pause the old file if it was active.
          my $pauseme = $oldid || $newid;   # Pause the old '0'.
          POE::Kernel->call($bewarez->{Queue}[$pauseme]{DL}{Alias}, "pause") if $status;
          # And start up the new one unless we were already paused.
          POE::Kernel->post($bewarez->{Queue}[-1]{DL}{Alias}, "resume") if $status;
        }

        # Save the new state of the queue in case we exit abnormally.
        savestate() if $cmd eq "add" or $cmd eq "del" or $cmd eq "shift";
      }, Leecher => $dlqueue);
      if ($restore) {
        $_[KERNEL]->call("bewarez" => "add_dl", $_) foreach @$restore;
      }
    },
    add_dl => sub {
      my $url = $_[ARG0];
      return unless $url;

      debug("already in queue"), return if $dlqueue->get($url);
      $dlqueue->add($url, MenuFilter => $entry, DL => PoCoBewarez->new(
          URL      => $url,
          Alias    => "leecher_$url",
          UA_Alias => "leech_$url",
          Progress => sub {
            my $dl = shift;
            $dlqueue->set(0, foo => "bar");
          }
      ));

      # Do we start it now or not?
      if ($dlqueue->all == 1) {
        #$dlqueue->set($url, Menu => "Starting download: $url...");
        POE::Kernel->post($dlqueue->{Queue}[-1]{DL}{Alias}, "resume");
      } else {
        #$dlqueue->set($url, Menu => "Queued download: $url");
      }
    },
    toggle => sub {
      $_[KERNEL]->yield( $dlqueue->{Alive} ? "pause" : "resume" );
    },
    delete_dl => sub {
      my $queue = $_[HEAP]{Queue};
      my $dl = $queue->get($queue->active)->{DL};
      return unless my $opt = $ui->choose("Do you really want to delete $dl->{Name}?" =>
        "Just kidding.",
        "Cancel the download.",
        "Cancel the download and delete the file."
      );
      # Irregardless, remove the download from the queue.
      my $alive = $_[HEAP]{Alive};
      POE::Kernel->call("leecher", "pause") if $queue->active == 0;
      $queue->del($queue->active);
      POE::Kernel->call("leecher", "resume") if $alive;
      unlink($dl->{Name}) if $opt == 2; # Delete it, whatever...
    }
  }
);

$poe_kernel->run;
exit;

sub progress_bar {
  my ($name, $sofar, $total, $speed, $eta) = @_;
  my $entry = "$name: (" . sprintf("%.1f", $sofar / $total * 100) . "%) ";
  $entry .= sprintf("%.2f", $sofar / 1024 ** 2) . " MB of ";
  $entry .= sprintf("%.2f", $total / 1024 ** 2) . " MB";
  $entry .= sprintf(" [%.1fK/s] eta {%s}", $speed, $eta);
  return $entry;
}

# Serialize the download queue.
sub savestate {
  my @ls = map { $_->{DL}{GetURL} } $dlqueue->all;
  store(\@ls, ".dlqueue");
}
