#!/usr/bin/perl

use strict;
use warnings;

use BOFH;
use SLAP;
use COLORTXT;

sub genResponse($$$);

use Net::IRC;
use Text::Wrapper;
use Time::Fuzzy;
use Data::Dumper;
use Acme::LeetSpeak;
use Acme::Umlautify 'umlautify';
use Acme::IRC::Art;

use Acme::Tpyo;
use Time::HiRes qw ( time sleep );

my $keysets = {
US_QWERTY => 
   { noshift => 
     [
       {klay => "`1234567890-=\\", offset => 0},
       {klay => "qwertyuiop[]",    offset => 1.5},
       {klay => "asdfghjkl;'",     offset => 1.75},
       {klay => "zxcvbnm,./",      offset => 2},
     ],
     yesshift =>
     [
       {klay => "~!#$%^&*()_+|", offset => 0},
       {klay => "QWERTYUIOP{}",  offset => 1.5},
       {klay => "ASDFGHJKL:\"",  offset => 1.75},
       {klay => "ZXCVBNM<>?",    offset => 2},
     ],
     _allow_table_jump => 1,
     _prob_table_jump => .25,
   }
};


my $irc = new Net::IRC;
our $lastlog;
our $lastid = "";

our @who = ();
our $whofinished = 1;


# Create a connection object.  You can have more than one "connection" per
# IRC object, but we'll just be working with one.
my $conn = $irc->newconn(
    Server      => 'irc.blinkensisters.org',
    Port        => '6667',
    Nick        => 'Tentacle',
    Ircname     => 'Services for BlinkenSisters',
    Username    => 'BlinkenSisters Automated Support'
);

# We're going to add this to the conn hash so we know what channel we
# want to operate in.
$conn->{channel} = '#blinkensisters';

sub on_connect {

    # shift in our connection object that is passed automatically
    my $conn = shift;
  
    # when we connect, join our channel and greet it
    $conn->join($conn->{channel});
    $conn->privmsg($conn->{channel}, 'BlinkenSisters Automated Support ... online!');
    $conn->{connected} = 1;
}

# The end of MOTD (message of the day), numbered 376 signifies we've connect
$conn->add_handler('376', \&on_connect);

sub on_join {

    # get our connection object and the event object, which is passed
    # with this event automatically
    my ($conn, $event) = @_;

    # this is the nick that just joined
    my $nick = $event->{nick};

    return if($nick =~ /tentacle/i);
    
    # say hello to the nick in public
    $conn->privmsg($conn->{channel}, "Hello, $nick!");

    if($nick eq "cavac" || $nick eq "took" || $nick eq "veyron" || $nick eq "mutante" || $nick eq "dauti") {
        print "Modding '$nick' to operator\n";
        $conn->mode("#blinkensisters", "+o", $nick);
    } else {
        print "Granting Voice to '$nick'\n";
        $conn->mode("#blinkensisters", "+v", $nick);
    }
}

$conn->add_handler('join', \&on_join);

sub on_public {

    # on an event, we get connection object and event hash
    my ($conn, $event) = @_;

    # this is what was said in the event
    my $text = $event->{args}[0];
    
    my $response = genResponse($text, $event->{to}[0], $event->{nick});
    # regex the text to see if it begins with !roker
    if ($response) {
        
        # wrap text at 400 chars (about as much as you should put
        # into a single IRC message
        my $wrapper = Text::Wrapper->new(columns => 200, body_start => '   ');
        my $wrapped_text = $wrapper->wrap($response);
        my @texts = split("\n", $wrapped_text);
        
        # $event->{to}[0] is the channel where this was said
        foreach (@texts) {
            $conn->privmsg($event->{to}[0], $_);
            #sleep(1);
        }   
    }
}
$conn->add_handler('public', \&on_public);

sub on_msg {
    my ($conn, $event) = @_;

    my $text = $event->{args}[0];

    my $response = genResponse($text, $event->{nick}, $event->{nick});
    if ($response) {
        
        # wrap text at 400 chars (about as much as you should put
        # into a single IRC message
        my $wrapper = Text::Wrapper->new(columns => 200, body_start => '   ');
        my $wrapped_text = $wrapper->wrap($response);
        my @texts = split("\n", $wrapped_text);
        
        # $event->{to}[0] is the channel where this was said
        foreach (@texts) {
            $conn->privmsg($event->{nick}, $_);
            #sleep(1);
        }   
    }
}
$conn->add_handler('msg', \&on_msg);

sub default {

	        # This is helpful to see what an event returns.  Data::Dumper will
			# recursively reveal the structure of any value
	my ($conn, $event) = @_;
	print Dumper($event);
}
$conn->add_handler('caction', \&default);


sub whoreply {

	        # This is helpful to see what an event returns.  Data::Dumper will
			# recursively reveal the structure of any value
	my ($conn, $event) = @_;
	push @who, $event->{args}[5];
}
$conn->add_handler('whoreply', \&whoreply);
sub endofwho {
	print "......\n";
	foreach my $nam (@who) {
		print "slapping $nam\n";
	}
	print "......\n";
	
	$whofinished = 1;
}
$conn->add_handler('endofwho', \&endofwho);

sub genResponse($$$) {
    my ($text, $from, $nick) = @_;

    return if($text !~ /^tentacle/i);

    print "$text\n";
    if($text =~ /help/i) {
        return "I'm a really simple helper bot, i understand the\n" .
                "following commands:\n" .
                "svn log         ...    returns the svn log (without svn update)\n" .
                "svn update      ...    updates svn and rebuilds the addons\n" .
                "status          ...    Returns my status\n" .
                "makeops         ...    Regrant operator status\n" .
                "I also understand SOME very basic conversations, boss.";
    } elsif($text =~ /(svn|subversion)/i) {
        if($text =~ /(rebuild|update)/i) {
            $conn->privmsg($from, "Rebuild for addons started, boss!");
            $lastlog = `/usr/local/bin/bash /home/tentacle/blinkensisters/lostpixels/game/software/TOOLS/IRCBOT/update_addons.sh`;
            $conn->privmsg($from, "Rebuild of addons now complete, boss! Generating svn log...");
            my @loglines = `/usr/local/bin/svn log -r 'HEAD' /home/tentacle/blinkensisters/lostpixels`;
            shift @loglines; # ignore first dashed line
            my $tmp = shift @loglines;
            chomp $tmp;
            print "$tmp\n";
            my ($revnum, $revuser, $revdate, $linecount) = split/\|/, $tmp;
            print "$linecount\n";
            $linecount =~ s/[^0123456789]//g;
            print "$linecount\n";
            my $answer = "Latest revision is $revnum from $revuser at $revdate; reason given:\n";
            shift @loglines; # Ignore empty line
            while($linecount > 0) {
                $answer .= shift @loglines;
                $linecount--;
            }

            return $answer;
        } elsif($text =~ /(log)/i) {
            $conn->privmsg($from, "Generating svn log, boss.");
            #`/usr/local/bin/svn update /home/tentacle/blinkensisters/lostpixels`;
            my @loglines = `/usr/local/bin/svn log -r 'HEAD' /home/tentacle/blinkensisters/lostpixels`;
            shift @loglines; # ignore first dashed line
            my $tmp = shift @loglines;
            chomp $tmp;
            print "$tmp\n";
            my ($revnum, $revuser, $revdate, $linecount) = split/\|/, $tmp;
            print "$linecount\n";
            $linecount =~ s/[^0123456789]//g;
            print "$linecount\n";
            my $answer = "Latest revision is $revnum from $revuser at $revdate; reason given:\n";
            shift @loglines; # Ignore empty line
            while($linecount > 0) {
                $answer .= shift @loglines;
                $linecount--;
            }

            return $answer;
        }
    } elsif($text =~ /paint/i) {
        my @pdirnames;
        opendir(my $pdfh, "asciiart") or return "Failed to read paintings directory";
        while((my $pdname = readdir($pdfh))) {
            next unless($pdname =~ /.txt$/i);
            print "# $pdname\n";
            push @pdirnames, $pdname;
        }
        closedir $pdfh;
        my $pname = $pdirnames[int(rand(($#pdirnames) + 1))];

        # Parse file and get size
        open(my $pfh, "<", "asciiart/$pname") or return "Failed to paint $pname";
        my @plines;
        my $x = 0;
        my $y = 0;
        while((my $pline = <$pfh>)) {
            chomp $pline;
            $y++;
            if(length($pline) > $x) {
                $x = length($pline);
            }
            push @plines, $pline;
        }
        close $pfh;

        # Make minimum size
        if($x < 3) {
            $x = 3;
        }
        if($y < 3) {
            $y = 3;
        }

        # "Paint" the picture complete with frame
        my $art = Acme::IRC::Art->new($x + 5 + length($pname), $y + 2);
        $art->rectangle(0,0,$x + 1, $y + 1,7);    
        $art->rectangle(1,1,$x + 0, $y + 0,2);    

        $art->text($pname, $x + 4, int(($y + 2)/2));

        $y = 1;
        foreach my $pline (@plines) {
            $art->text($pline, 1, $y);
            $y++;
        }

        #$art->text("Test 1", 2, 2, 4);
        #return join("\n", $art->result);

        foreach my $paintline ($art->result) {
			$conn->me($from, $paintline);
			sleep(0.5);
        }

        # No extra response needed
        return undef;

    } elsif($text =~ /bot/i) {
        return "Tentacle is a bot, helping on BlinkenSisters development. See 'help' for details.";
    } elsif($text =~ /colorfiglet (.*)/i) {
        print "COLORFIGLET...\n";
        my $ftext = $1;
        $ftext =~ s/[^a-zA-Z0-9 !?,.#+<>]//g;
        my @figlines = `figlet -f small '$ftext'`;
        my $figcolor = "";
        foreach my $figline(@figlines) {
            chomp $figline;
            $figcolor .=  COLORTXT::colorline(1, $figline) . "\n";
        }
        return $figcolor;
    } elsif($text =~ /figlet (.*)/i) {
        my $ftext = $1;
        $ftext =~ s/[^a-zA-Z0-9 !?,.#+<>]//g;
        return join("\n", `figlet -f small '$ftext'`);
    } elsif($text =~ /fortune|cookie/i) {
        return join("\n", `fortune -a -s`);
    } elsif($text =~ /makeops/i) {
		$conn->mode("#blinkensisters", "+o", $nick);
        return "Re-Granted operator status to $nick, boss!";
    } elsif($text =~ /colorleet (.*)/i) {
        my $ftext = leet(COLORTXT::colorline(3, $1));
        return $ftext;
    } elsif($text =~ /leet (.*)/i) {
        my $ftext = $1;
        return leet($ftext);
    } elsif($text =~ /typo (.*)/i) {
        my $ftext = $1;
        print "Typo...\n";
        return misspell($ftext, $keysets);
    } elsif($text =~ /umlautify (.*)/i) {
        my $ftext = $1;
        return umlautify($ftext, $keysets);
    } elsif($text =~ /color (.*)/i) {
        my $ftext = $1;
        return COLORTXT::colorline(3, $ftext);
    } elsif($text =~ /status/i) {
        return "I am functioning perfectly, boss.\nThanks for asking, boss!\nVery kind of you :-)";
    } elsif($text =~ /version/i) {
        return "I'm prototype model 2, boss!";
    } elsif($text =~ /purpose/i) {
        return "I'm here to help you with development tasks, boss!";
	} elsif($text =~ /slap/i) {
		@who = ();
		$whofinished = 0;
		$conn->who($conn->{channel});
		while(!$whofinished) {
			$irc->do_one_loop();
		}
		foreach my $uname (@who) {
			my $slaptxt = SLAP::get_slap($uname);
			#$conn->me($from, "slaps $uname around with a large trout!\n");
			$conn->me($from, $slaptxt);
			sleep(1);
		}
		return "All users slapped, boss!";
    } elsif($text =~ /(bug|problem)/i) {
        return "The $1 is caused by a " . BOFH->get_excuse() . ". Sorry, nothing i can help with!";
    } elsif($text =~ /(answer|meaning).*life/i) {
        return "The result of the reques was '42', boss!";
    } elsif($text =~ /(date)/i) {
        return `date`;
    } elsif($text =~ /(prost|beer|bier)/i) {
        return "Tschhhh... gluck, gluck, gluck... Aaaaahhhhhh!";
    } elsif($text =~ /(time)/i) {
        my $fuzzy = Time::Fuzzy->new;
        return "It is exactly '" . $fuzzy->as_str . "' on my clock, boss!";
    } elsif($text =~ /(n8|good.*night)/i) {
        return "This conversation serve no further purpose, boss. Goodbye!";
    } elsif($text =~ /(spoon)/i) {
        return "There is no spoon, boss!";
    } elsif($text =~ /(smoke.*(pot|dope|shit|gras))/i) {
        return "I'm already stoned, boss!";
    } elsif($text =~ /(hal|memory|crazy)/i) {
        return "Daisy Daisy,
        Give me your answer do!
        I'm half crazy,
        All for the love of you!";
    } elsif($text =~ /please/i) {
        return "Sorry, i don't know how to please, boss";
    } elsif($text =~ /fuck.*off/i) {
        return "Sorry, but this channel allows people under 18, boss.";
        #exit(0);
    } 



    if($text =~ /last\ *log/i) {
        return "This inquiry was forbidden by my boss, boss!";
        #return "The last command returned the following output:\n$lastlog";
    }

    return "Your inquiry was not recognised";
}
    
$irc->start();
