#
#  Copyright (c) 2002-2007 Nieko Maatjes
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  See http://www.gnu.org/licenses/gpl.txt
#
#  Credits:
#  commands/tools.pl:distance()
#   Eli Bendersky (http://www.merriampark.com/ldperl.htm)
#  commands/slogan.pl
#   Eike Dehling
#  commands/smoes.pl
#   Sander Ruitenbeek
#  Borkifier
#   Dark Horse Consulting, http://www.darkhorse.to/bork.php
#  Miscellaneous
#   Remko Bijker, Ronald Teune
#
# Furbie's first incarnation was born on Nov 19th, 2002
#
# TODO, some day:
# - DCC, so you can send faster to people on IRC
#   Can only be done when identification is on userhost basis.
#   Is now (20070527) busy :) Is `nick` still necessary later, or
#    only temporary when running the script? Identification is then
#    on server + userhost basis. Nick may be necessary for waarschuw.
#    (Will this work with Jabber and MSN on the same server? That
#    is then BitlBee's responsibility :)
#   - Key in MySQL on server+userhost, not server+nick
# - Call to script in irssi as thread?
#   - Done 2008-10-26.
#   - Made irssi crash, we need something else... Perhaps we can
#     start a new thread, which puts output in a buffer, which is
#     read by some Irssi function? Use closures for this?
# - Ban users on userhost?


use DBI;                            # Database
use utf8;                           # Yay! Unicode!
use Irssi;                          # Chat client
use strict;                         # Declare vars, etc.
use Date::Parse;                    # Parse date to timestamp

our @commands = ();

# Load the helpers and commands
chdir("/home/furbie/.irssi/scripts/");
foreach(<helpers/*.pl>)
{
    if (!(-x)) { next; }
    require $_; do $_;
}
foreach(<commands/*.pl>)
{
    if (!(-x)) { next; }
    require $_; do $_;
    s#^commands/(\w+)\.pl$#$1#;
    push @commands, $_;
}

# Redirect to main function
sub furbie_private
{
    my ($server, $msg, $nick, $address) = @_, my $mynick;
    $mynick = $server->{nick};
    furbie_channel($server, "$mynick: $msg", $nick, $address, $nick);
}

# Main function
sub furbie_channel
{
    # $server  Server object
    # $msg     Data sent by user
    # $nick    User's nick
    # $address User's e-mail address (BitlBee) / userhost
    # $target  Target channel/query for reply
    my ($server, $msg, $nick, $address, $target) = @_;

    # Thread will deal with command execution and output
    thread($server, $msg, $nick, $address, $target);
    #TODO#my $thread = threads->new(\&thread, $server, $msg, $nick, $address, $target);
    #TODO#$thread->detach;
}

sub thread {
    my ($server, $msg, $nick, $address, $target) = @_, my @results, my @commands = @commands;

    $address =~ s#^[~^!-]##; # Strip weird identification characters
    $address = lc $address;
    my ($usercommand, $result, $innerresult, $query, $dbh, $mynick, $output, $lastban);
    my $wait = 60;

    # Not connected
    if ($server !~ m/Irssi::Irc::Server=/)
    { return; }

    # Give user permission to add me
    if ($msg =~ m/ - New request:/
     && $nick eq 'root'
     && $server->{tag} eq 'localhost'
     && $target eq '&bitlbee')
    {
        $server->command("/msg &bitlbee yes");
        return;
    }

    # Useful variables
    $mynick = $server->{nick};

    # Strip quotes, my own name, etc.
    $msg =~ s/^['"]+(.*?)['"]+$/$1/;
    $msg =~ s/^[\s'"]*($mynick)[\s'"]*(:)[\s'"]*/$1$2 /i;

    # Message not meant for me
    if ($msg !~ s/^$mynick:\s*//i || $msg =~ /^($mynick:|$)\s*$/i)
    { return; }

    # Get user from database (TODO: dynamic programming)
    $dbh = mysqlconnect();
    ($result) = mysqlselect($dbh, sprintf('SELECT * FROM `gebruiker` WHERE `server`=%s AND `nick`=%s'
                                         ,$dbh->quote($server->{tag})
                                         ,$dbh->quote($nick)
                                         )
                           );

    # User doesn't exist
    if (!defined($result))
    {
        # Add user
        mysqldo($dbh, sprintf('INSERT INTO `gebruiker` VALUES(0, %s, %s, %s, NOW(), %s, %s)'
                             ,$dbh->quote($server->{tag})
                             ,$dbh->quote($nick)
                             ,$dbh->quote($address)
                             ,$dbh->quote('nee')
                             ,$dbh->quote('0000-00-00 00:00:00')
                             )
               );
        output(help('intro'), $server, $nick);
        # Don't say anything else in queries
        if ($target !~ m/#/)
        { $dbh->disconnect(); return; }
    }
    #TODO: keep track of userhosts
    if ($result->{"userhost"} eq '')
    {
        mysqldo($dbh, sprintf('UPDATE gebruiker SET `userhost`=%s WHERE server=%s AND nick=%s'
                             ,$dbh->quote($address)
                             ,$dbh->quote($server->{tag})
                             ,$dbh->quote($nick)
                             )
               );

        print "Setting `userhost` for user $nick ($server->{tag}): $address";
    }
    #TODO

    # Check if there are any messages waiting
    @results = mysqlselect($dbh, sprintf('SELECT * FROM bericht WHERE server=%s AND nick=%s'
                                        ,$dbh->quote($server->{tag})
                                        ,$dbh->quote($nick)
                                        )
                          );
    if (@results)
    {   # $result is used a bit further too
        foreach$innerresult(@results)
        {
            output($innerresult->{bericht}, $server, $nick);
            mysqldo($dbh, "DELETE FROM bericht WHERE id=$innerresult->{id}");
        }
        return;
    }

    # User is blocked (or temporarily, for 60 seconds)
    if ($result->{geblokt} eq 'ja' || str2time($result->{wanneer})+$wait > time)
    { return; }

    # Determine command
    ($usercommand, $msg) = split(/\s+/, $msg, 2);
    $msg =~ s/^\s*(.*?)\s*$/$1/; $msg =~ s/\s+/ /g;
    while($#commands > 0) # Until only $commands[0] is left
    {
        if (distance(lc $usercommand, lc $commands[0]) > distance(lc $usercommand, lc $commands[$#commands]))
        { shift @commands; }
        else
        { pop @commands; }
    }

    # I don't understand the command
    if (!defined($usercommand) || distance(lc $usercommand, lc $commands[0]) > length($usercommand) / 4)
    {
        if ($usercommand =~ m/\?$/ || $msg =~ m/\?$/)
        { $output = janee($msg); }
        else
        { $output = help('commands'); }
        output($output, $server, $target);
    }
    else
    {
        no strict 'refs';
        # `waarschuw` and `lijstje` need server
        if ($commands[0] eq 'waarschuw' || $commands[0] eq 'lijstje')
        { $msg = sprintf('%s %s %s', $server->{tag}, $nick, $msg); }

        # Maybe it's cached?
        ($innerresult) = mysqlselect($dbh, "SELECT * FROM cache WHERE commando=".$dbh->quote($commands[0].' '.$msg)." AND verloopt>NOW() AND bericht<>''");
        if (ref($innerresult) eq 'HASH')
        {
            $innerresult = $innerresult->{bericht};
            # These commands show fewer lines in channels
            if ($commands[0] =~ m/^(define|omschrijf|spel|vertaal|telefoon|films)$/ && index($target, '#') >= 0)
            {
                @results = split(/[\r\n]+/, $innerresult);
                if ($commands[0] eq 'vertaal') { $msg = pop(@results); } # Keep thesaurus
                else { $msg = ''; }
                while ($#results > 1) { pop @results; }
                $innerresult = join("\n", @results)."\n$msg";
            }
            $output = $innerresult;
        }
        else
        {
            eval
            {
                $output = &{$commands[0]}($msg, $dbh, index($target, '#') >= 0, $server);
            };
            if ($@)
            {
                $output = 'Dit commando is tijdelijk kapot. De beheerder is op de hoogte gesteld.';
                $server->command("/msg -ircnet Nieko Commando $commands[0] is kapot!");
                $server->command("/msg -ircnet Nieko $@");
            }
        }
        output($output, $server, $target);
    }
    $dbh->disconnect();
}

# Attach signals to this script
Irssi::signal_add('message public', 'furbie_channel');
Irssi::signal_add('message private', 'furbie_private');
Irssi::signal_add('message invite', 'furbie_invite' );
Irssi::signal_add('flood', 'furbie_blok');
#Irssi::signal_add('dcc chat message', 'furbie_dcc_message');
Irssi::command_bind('f_blok', 'furbie_blok');
Irssi::command_bind('f_unblok', 'furbie_unblok');
Irssi::command_bind('f_showblok', 'furbie_showblok');
Irssi::command_bind('f_ban', 'furbie_ban');
Irssi::command_bind('f_bericht', 'furbie_bericht');
Irssi::command_bind('f_showbericht', 'furbie_showbericht');
Irssi::command_bind('f_whois', 'furbie_whois');
Irssi::timeout_add(60000, 'waarschuwcron', undef);
Irssi::timeout_add(60000, 'cachecron', undef);
waarschuwcron();
cachecron();
