use strict;
use Irssi;
use vars qw($VERSION %IRSSI);
use DBI;
use Time::Piece;
use POSIX qw(strftime);

$VERSION = "2.30";
%IRSSI = (
	authors     => "planb, RootBear",
	contact     => "RootBear\@IRCnet",
	name        => "ss.pl",
	description => "Seen script using DBI, searches and displays both on public command (if enabled) and when user was kicked.",
	license     => "Public Domain, EVVKTVH",
	url         => "http://www.ironsunrise.com/",
	changed     => "2009-07-13 15:56",
	bugs        => "Slightly fewer, this time around."
);

our $dbhost          = "localhost";
our $db              = "irssi";
our $table           = "seenscript";
our $dbuser          = "makkara";
our $dbpass          = "password";
our $public          = "true";
our $private         = "true";
our $resource_hog    = "true";
our $allowedchannels = "#raapr";
our $querychannels   = "#ham.fi #another_channel";

our $information     = "information_schema";

my $db_start;
my $db_rows;

#Open Connections
our $dbh = DBI->connect( "dbi:mysql:database=$db:host=$dbhost", "$dbuser", "$dbpass" )
	or Irssi::print("\cC4Failed to connect to database $db: $DBI::errstr", MSGLEVEL_CLIENTCRAP+MSGLEVEL_NEVER);

our $dbin = DBI->connect( "dbi:mysql:database=$information:host=$dbhost", "$dbuser", "$dbpass" )
        or Irssi::print("\cC4Failed to connect to database $information: $DBI::errstr", MSGLEVEL_CLIENTCRAP+MSGLEVEL_NEVER);

sub update_db {
	my ($nick, $host, $channel, $action, $message) = @_;

	$channel = lc($channel);

	if ($channel eq $allowedchannels) {

        my $date = strftime("%F %H:%M:%Sz", gmtime);

	if ($message eq '') {
		$message=' ';
	}

	if (! utf8::is_utf8($message)) {
	  utf8::encode($message);
	}

		#SELECT on $host
		my $sth = $dbh->prepare("SELECT * FROM $table WHERE host = ?");
		$sth->execute($host);
		
		#No results? Make a new row.
		if ($sth->rows() == 0) {
			my $insert_handle = $dbh->prepare("INSERT INTO $table VALUES (?, ?, ?, ?, ?, ?)");
			$insert_handle->execute($nick, $host, $channel, $action, $message, $date);
			$db_rows = $db_rows + 1;
		}
		else {
			my $update_handle = $dbh->prepare("UPDATE $table SET nick = ?, host = ?, channel = ?, action = ?, message = ?, date = ? WHERE host = ?");
			$update_handle->execute($nick, $host, $channel, $action, $message, $date, $host);
		}
		$sth->finish();
	}
}

sub join_check_db {
	my ($server, $channel, $nick, $host) = @_;

	#Find window
	my $window = Irssi::window_item_find($channel);

	#Search db for $host (user@host)
	my $sth = $dbh->prepare("SELECT * FROM $table WHERE host LIKE ? ORDER BY date DESC");
	$sth->execute($host);

	#If user@host is not found, try %@host
	if ($sth->rows() == 0) {
		$host =~ s/.*\@/\%\@/;
		$sth->execute($host);
	}

	#If user@host is not found, try $nick
	if ($sth->rows() == 0) {
		$sth = $dbh->prepare("SELECT * FROM $table WHERE nick = ? ORDER BY date DESC");
		$sth->execute($nick);
	}

	#Echo output if found
	if ($sth->rows() >= 1) {
		my @row = $sth->fetchrow_array();
		#Now this was a whore to get working right... fucking dirty nasty hack to make it print _after_ the join message.
		Irssi::timeout_add_once(10, sub {
			my $time = strftime("%H:%M:%S", localtime);
			Irssi::Windowitem::print($window, 
						"$time \cC14.\cC15.\cC0. \cC5Last seen as: $row[0] ($row[1]) $row[3] $row[2] on $row[5]", 
						MSGLEVEL_CLIENTCRAP+MSGLEVEL_NEVER
			);
		}, []);
		#Time to remove eyes with fork. BBL.
	}
	$sth->finish();
}

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

	my $allowed = index($querychannels,lc($target));

	if (($allowed >= 0) && ($msg =~ /^!seen ([^ ]+)/)) {
		my $query = $1;
#		$query =~ s/\*/%/;
	
		if ($query eq '') {
			$query = $nick;
		}

		my $accuracy = '';

		my $sth = $dbh->prepare("SELECT * FROM $table WHERE nick LIKE ? ORDER BY date DESC");
		$sth->execute($query);

                if ($sth->rows() == 0) {
                        $sth = $dbh->prepare("SELECT * FROM $table WHERE nick REGEXP ? ORDER BY date DESC");
                        $sth->execute($query);
                        $accuracy = '[regexp] ';
                }

                if (($sth->rows() == 0) || ($sth->rows() > 2)) {
                        $sth = $dbh->prepare("SELECT * FROM $table WHERE nick SOUNDS LIKE ? ORDER BY date DESC");
                        $sth->execute($query);
			$accuracy = '[guess] ';
                }

		if (($sth->rows() >= 1) && ($sth->rows() < 3)) {
                        my @row = $sth->fetchrow_array();
                        Irssi::timeout_add_once(10, sub {
                                my $window = Irssi::window_item_find($target);
                                Irssi::Windowitem::command($window, "/ $accuracy"."$row[0] ($row[1]) last seen $row[3] $row[2] ($row[4]) on $row[5]");
			}, []);
		} else {
                        Irssi::timeout_add_once(10, sub {
                                my $window = Irssi::window_item_find($target);
				Irssi::Windowitem::command($window, "/ I have no information about $query. RootBear\'s Seen Script v $VERSION. Database created $db_start, $db_rows nicks registered.");
                        }, []);
		}
	
		$sth->finish();
	}
}

sub ss_join {
	my ($server, $channel, $nick, $address) = @_;

	join_check_db($server, $channel, $nick, $address);
	update_db($nick, $address, $channel, "joining", "");
}

sub ss_part {
	my ($server, $channel, $nick, $address, $reason) = @_;

	update_db($nick, $address, $channel, "leaving", $reason);
}

sub ss_quit {
	my ($server, $nick, $address, $reason) = @_;
                         
        update_db($nick, $address, "IRC", "quitting", $reason);
}

sub ss_kick {
	my ($server, $channel, $nick, $kicker, $address, $reason) = @_;

	my $chanrec = $server->channel_find($channel);
	my $nickrec = $chanrec->nick_find($nick);
	my $uhost = $nickrec->{'host'};

	update_db($nick, $uhost, $channel, "getting kicked by $kicker from", $reason);
}

sub ss_nick {
	my ($server, $newnick, $oldnick, $address) = @_;

	update_db($oldnick, $address, "", "changing nick to $newnick", "");
}

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

	update_db($nick, $address, $target, "speaking on", $msg);
}

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

        if ($msg =~ /^!seen ([^ ]+)/) {
                my $query = $1;
                $query =~ s/\*/%/;
		
		my $rivit;
                my $sth = $dbh->prepare("SELECT * FROM $table WHERE nick LIKE ? ORDER BY date DESC");
                $sth->execute($query);

		$rivit = $sth->rows();

                if ($rivit == 0) {
                        $sth = $dbh->prepare("SELECT * FROM $table WHERE nick SOUNDS LIKE ? ORDER BY date DESC");
                        $sth->execute($query);
			$rivit = $sth->rows();
		}

                if ($rivit == 0) {
                        $sth = $dbh->prepare("SELECT * FROM $table WHERE nick REGEXP ? ORDER BY date DESC");
                        $sth->execute($query);
                        $rivit = $sth->rows();

                }

                if (($rivit >= 1) && ($rivit < 3)) {
                        my @row = $sth->fetchrow_array();
                        Irssi::timeout_add_once(10, sub {
		 	$server->command("MSG $nick $row[0] ($row[1]) last seen $row[3] $row[2] ($row[4]) on $row[5]");
                        }, []);
                } 
                $sth->finish();
         } 
}


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

	update_db($nick, $address, $target, "speaking on", $msg);
}

#Irssi::signal_add_last('message join', 'ss_join' );
#Irssi::signal_add_last('message part', 'ss_part' );
#Irssi::signal_add_last('message quit', 'ss_quit' );
Irssi::signal_add_last('message kick', 'ss_kick' );
#Irssi::signal_add_last('message nick', 'ss_nick' );

if ($resource_hog eq "true") {
	Irssi::signal_add_last('message public', 'ss_public' );
	Irssi::signal_add_last('message irc action', 'ss_act' );
}

if ($public eq "true") {
	Irssi::signal_add_last('message public', 'ss_query' );
}

if ($private eq "true") {
	Irssi::signal_add_last('message private', 'ss_private' );
}

$db_start = "unknown";
$db_rows  = "unknown";

my $stin = $dbin->prepare("SELECT CREATE_TIME,UPDATE_TIME,TABLE_ROWS FROM tables WHERE TABLE_NAME='$table'");
$stin->execute();

if ($stin->rows() >= 1) {
	my @rown = $stin->fetchrow_array();
        $db_start = $rown[0];
	$db_rows = $rown[2];
} 
$stin->finish();
my $now = localtime;

Irssi::print "Seen Script version $VERSION by RootBear. Start time ".$now->ymd." ".$now->hms.". Database creation time $db_start, $db_rows rows.";


