# paste.pl/Irssi/fahren@bochnia.pl
# /pastelast added and bits edited by dg

# target: [-ircnet] channel/nick
# num: x-y
# us. /paste [target] [num]
# ex. /paste 3-5
# prints third line to fifth line (starting from end) to current channel/query

# /pastelast [target] [lastlog options]

use strict;
use Irssi;
use Irssi::TextUI;

Irssi::command_bind("paste", \&cmd_paste);
Irssi::command_bind("pastelast", \&cmd_pastelast);
Irssi::settings_add_int('misc', 'paste_max_lines', 5);
Irssi::settings_add_bool('misc', 'paste_remove_date', 1);
Irssi::settings_add_bool('misc', 'paste_remove_colour', 0);

sub cmd_paste {
	my ($args, $server, $winit) = @_;

   my $target;
   ($args, $server, $target) = parse_args($args, $server, $winit);
   return if !$target;
         
   my(@out, $view, $line);
	$view = Irssi::active_win->view;
   $line = $view->{buffer}->{cur_line};

   if(!ref $line) {
      $winit->print("No lines in buffer");
      return;
   }

   my($min, $max) = 0;
   ($min) = $args =~ /(\d+)(-|$)/;
   ($max) = $args =~ /-(\d+)/;

   $min ||= 1;
   $max ||= $min;
   
   my $count = 0;

   while(ref $line) {
      $count++;
      if($count >= $min) {
         push @out, $line->get_text(1);
      }
      last if $count >= $max;
      $line = $line->prev;
   }

   if(@out > Irssi::settings_get_int('paste_max_lines') && $args !~ /-force/) {
      $winit->print("Cowardly refusing to output more lines than limit, use -force to paste them all");
      return;
   }

   if(!@out) {
      $winit->print("No lines found");
      return;
   }

   @out = reverse @out;
   paste_lines([@out], $server, $target);
}

# BUGS: doesn't work if lastlog format was changed

sub cmd_pastelast {
   my ($args, $server, $winit) = @_;

   my $target;
   ($args, $server, $target) = parse_args($args, $server, $winit || Irssi::active_win);
   return if !$target;
   
   $winit->command("lastlog $args");

   my(@out, $view, $line);
	$view = Irssi::active_win->view;
   $line = $view->{buffer}->{cur_line};

   if(!ref $line) {
      $winit->print("No lines in buffer");
      return;
   }

   if($line->get_text(0) !~ /^End of Lastlog/) {
      $winit->print("Error getting lastlog data: " . $line->get_text(1));
      return;
   }

   while(($line = $line->prev) && ref $line) {
      my $text = $line->get_text(1);
      last if $text =~ /^.{1,6}Lastlog/;
      push(@out, $text);
   }

   $winit->command("lastlog -clear");

   if(@out > Irssi::settings_get_int('paste_max_lines') && $args !~ /-force/) {
      $winit->print("Cowardly refusing to output more lines than limit, use -force to paste them all");
      return;
   }

   if(!@out) {
      $winit->print("No matching lines found");
      return;
   }

   @out = reverse @out;
   paste_lines([@out], $server, $target);
}

sub paste_lines {
   my($out, $server, $target) = @_;

   for my $text(@$out) {
      $text = irssi_colour($text, Irssi::settings_get_bool('paste_remove_colour'));
      $text =~ s/^\S+ // if Irssi::settings_get_bool('paste_remove_date');
      $server->command("msg $target $text");
   }
}

sub parse_args {
   my($args, $server, $winit) = @_;

   my $target;
   
   if($args =~ /^-/) {
      $args =~ s/^-(\S+) //;

      if(Irssi::server_find_tag($1)) {
         $server = Irssi::server_find_tag($1);
      }else{
         $args = "-$1 $args";
      }
   }

   if($args =~ s/^((?:[#!+&]|\w)\S*) //) {
      $target = $1;
   }

   if(!$target) {
      if($winit->{type} ne 'CHANNEL' && $winit->{type} ne 'QUERY') {
         $winit->print("No active channel or query in window");
         return;
      }
      $target = $winit->{name};
   }

   return($args, $server, $target);
}

# this kind of works, but the bold stuff doesn't seem to get sent correctly by irssi

# char codes 48 - 63
my $colours = '[' . join("", map(chr $_, 48 .. 63)) . ']';
my %colours;
@colours{split //, "?012'456>:3;9=87"} = 0 .. 15;
my $internal = '';

sub irssi_colour {
   my ($line, $action) = @_;

   if($action) { # remove
      $line =~ s{
                $internal
                (
                 [a-i]
                 |$colours / # fg
                 |/ $colours # bg
                )
             }{}xg;
   }else{
     $_ = $line;
     my $out = '';
     my %c;
     while(length) {
        if(s!^${internal}g!!) {
           if(defined $c{fg} || defined $c{bg}) {
              $out .= "" if defined $c{fg};
              $c{fg} = $c{bg} = undef;
           }elsif(defined $c{b}) {
              $out .= '';
              $c{b} = undef;
           }else{
              $out .= '';
              $c{b} = 1;
           }
        }elsif(s!^$internal/$colours!!) {
           $c{bg} = 1;
        }elsif(s!^$internal($colours)/!!) {
           $c{fg} = $1;
           $out .= "" . sprintf("%02d", $colours{$1});
        }else{
           s/^(.)//;
           $out .= $1;
        }
     }
     $line = $out;
   }
   return $line;
}

