#!/usr/bin/perl -w
use strict;

use Net::IRC;
use Net::IRC::Connection qw(schedule);
use Getopt::Std;
use XML::RSS;
use LWP;

# some globals
my %rss_feeds;
my $ua = new LWP::UserAgent;
my %opts;

getopts('c:',\%opts);
die "Need config\n" if !defined $opts{c};
open F, $opts{c} or die "Cant open $opts{c} :- $!\n";
my %conf;
while (<F>) {
	my ($option,$value) = $_ =~ /(^\w*)\s*(.*)/;
	next if (!defined $option || !defined $value); # ignore any non config lines
	chomp $value if (defined $value && $value =~ (/\n$/));
    $conf{$option} = $value if (defined $value && $value !~ /^\s*$/);
}
close F;

die "Missing essential config\n" if (!defined $conf{nick} || !defined $conf{server} || !defined$conf{port} || !defined $conf{ircname});
print "Connecting to $conf{server}.......\n";

my $irc = new Net::IRC;
my $conn = $irc->newconn(Server   => $conf{server},
             Port     => $conf{port},
             Nick     => $conf{nick},
             Ircname  => $conf{ircname},
             Username => $conf{user})
    or die "irctest: Can't connect to IRC server.\n";

# What to do when the bot successfully connects.
sub on_connect {
    my $self = shift;

    print "Joining $conf{chan}...\n";
    $self->join($conf{chan});
}

# Handles some messages you get when you connect
sub on_init {
    my ($self, $event) = @_;
    my (@args) = ($event->args);
    shift (@args);
    print "*** @args\n";
}

# What to do when someone leaves a channel the bot is on.
sub on_part {
    my ($self, $event) = @_;
    my ($channel) = ($event->to)[0];

    printf "*** %s has left channel %s\n", $event->nick, $channel;
}

# What to do when someone joins a channel the bot is on.
sub on_join {
    my ($self, $event) = @_;
    my ($channel) = ($event->to)[0];

    printf "*** %s (%s) has joined channel %s\n",
    $event->nick, $event->userhost, $channel;

#    if ($event->userhost =~ /^corbeau\@.*execpc\.com/) {  # Auto-ops anyone who
#    $self->mode("#IRC.pm", "+o", $event->nick);      # matches hostmask.
#    }
}

# What to do when we receive a private PRIVMSG.
sub on_msg {
    my ($self, $event) = @_;
    my ($nick) = $event->nick;

    print "*$nick*  ", ($event->args), "\n";
#    $self->privmsg($nick, &pickrandom());   # Say a Zippy quote.
}

# What to do when we receive channel text.
sub on_public {
    my ($self, $event) = @_;
    my @to = $event->to;
    my ($nick, $mynick) = ($event->nick, $self->nick);
    my ($arg) = ($event->args);

    # Note that $event->to() returns a list (or arrayref, in scalar
    # context) of the message's recipients, since there can easily be
    # more than one.

	my $greeting = "hello";
	if ($arg =~ /$mynick/i && $arg =~ /$greeting/) {
		my $response = "Hi";
		$self->privmsg([ @to ], $response);
	}

	if ($arg =~ /$mynick/i && $arg =~ /rss stop/) {
		my ($url,$timeout) = $arg =~ /.*rss stop\s+(.+)\s+(\d+)/;
		&stop_watching_rss_feed($self,$event,$url) if (defined $rss_feeds{$url});
		$self->privmsg([ @to ], "No longer watching feed $url\n") if defined $rss_feeds{$url};
	}

	if ($arg =~ /$mynick/i && $arg =~ /rss watch/) {
		my ($url,$timeout) = $arg =~ /.*rss watch\s+(.+)\s+(\d+)/;
		&create_rss_feed($self,$event,$url,$timeout);
	}

    if ($arg =~ /Go away/i) {       # Tell him to leave, and he does.
    	$self->quit("BAH!!");
    	exit 0;
    }

}

sub on_umode {
    my ($self, $event) = @_;
    my @to = $event->to;
    my ($nick, $mynick) = ($event->nick, $self->nick);
    my ($arg) = ($event->args);

    # Note that $event->to() returns a list (or arrayref, in scalar
    # context) of the message's recipients, since there can easily be
    # more than one.

    print "<$nick> $arg\n";
    #if ($arg =~ /$mynick/i) {                   # Say a Zippy quote if our nick
    #	$self->privmsg([ @to ], &pickrandom()); # appears in the message.
    #}

    if ($arg =~ /Go away/i) {       # Tell him to leave, and he does.
    	$self->quit("Yow!!");
    	exit 0;
    }

}
# What to do when we receive a message via DCC CHAT.
sub on_chat {
    #my ($self, $event) = @_;
    #my ($sock) = ($event->to)[0];

    #print '*' . $event->nick . '* ' . join(' ', $event->args), "\n";
    #$self->privmsg($sock, &pickrandom());   # Say a Zippy quote.
}

# Prints the names of people in a channel when we enter.
sub on_names {
    my ($self, $event) = @_;
    my (@list, $channel) = ($event->args);    # eat yer heart out, mjd!

    # splice() only works on real arrays. Sigh.
    ($channel, @list) = splice @list, 2;

    print "Users on $channel: @list\n";
}

# What to do when we receive a DCC SEND or CHAT request.
#sub on_dcc {
    #my ($self, $event) = @_;
    #my $type = ($event->args)[1];
#}

# Yells about incoming CTCP PINGs.
sub on_ping {
    my ($self, $event) = @_;
    my $nick = $event->nick;

    $self->ctcp_reply($nick, join (' ', ($event->args)));
    print "*** CTCP PING request from $nick received\n";
}

# Gives lag results for outgoing PINGs.
sub on_ping_reply {
    my ($self, $event) = @_;
    my ($args) = ($event->args)[1];
    my ($nick) = $event->nick;

    $args = time - $args;
    print "*** CTCP PING reply from $nick: $args sec.\n";
}

# Change our nick if someone stole it.
sub on_nick_taken {
    my ($self) = shift;

    $self->nick(substr($self->nick, -1) . substr($self->nick, 0, 8));
}

# Display formatted CTCP ACTIONs.
sub on_action {
    my ($self, $event) = @_;
    my ($nick, @args) = ($event->nick, $event->args);

    print "* $nick @args\n";
}

# Reconnect to the server when we die.
sub on_disconnect {
    my ($self, $event) = @_;

    print "Disconnected from ", $event->from(), " (",
          ($event->args())[0], "). Attempting to reconnect...\n";
    $self->connect();
}

# Look at the topic for a channel you join.
sub on_topic {
    my ($self, $event) = @_;
    my @args = $event->args();

    # Note the use of the same handler sub for different events.

    if ($event->type() eq 'notopic') {
        print "No topic set for $args[1].\n";
    	# If it's being done _to_ the channel, it's a topic change.
    } 
	elsif ($event->type() eq 'topic' and $event->to()) {
        print "Topic change for ", $event->to(), ": $args[0]\n";

    } 
	else {
        print "The topic for $args[1] is \"$args[2]\".\n";
    }
}

sub create_rss_feed {
	my ($self,$event,$url,$timer) = @_;
	my $response = "Feed is already being watched" if defined $rss_feeds{$url};
	return $response if defined $response;
	print "Scheduling a new rss feed watch $url every $timer seconds\n";	
	my %feed_data;
	$feed_data{url} = $url;
	$feed_data{timer} = $timer;
	$feed_data{event} = \$event;
	# need to initially populate the % of seen articles.
	my $rss = new XML::RSS();
    my $req = HTTP::Request->new(GET => $feed_data{url});
    my $res = $ua->request($req);
    $rss->parse($res->content);
	my %items;
	foreach my $item (@{$rss->{'items'}}) {
		my %hash;
		$hash{title} = $item->{'title'};
        $items{ $item->{'title'} } = \%hash;
 
	}
	$feed_data{items} = \%items;
	$rss_feeds{$url} = \%feed_data;
	my @to = $event->to();
	print $self->privmsg( [@to ], "Watching feed $url every $timer seconds\n");
	$conn->schedule($timer,\&watch_rss_feed,$self,$event,$url,$timer);
}

sub watch_rss_feed {
	my (undef,$self,$event,$url,$timer) = @_;
	my (%feed,%items);
	%feed =	%{$rss_feeds{$url}} if defined %{$rss_feeds{$url}};
	%items = %{$feed{items}} if defined %{$feed{items}};
	my $stop = $feed{stop};
	next if (defined $stop && $stop == 1);
	my $rss = new XML::RSS();
	my $req = HTTP::Request->new(GET => $feed{url});
	my $res = $ua->request($req);
	$rss->parse($res->content);
	my @to = $event->to();
	
	foreach my $item (@{$rss->{'items'}}) {
        my $title = $item->{'title'};
		my %gotme = %{$items{$title}} if defined %{$items{$title}};
		next if %gotme;	
		my %hash;
		$hash{title} = $title;
		$hash{link} = $item->{'link'};
		$hash{description} = $item->{'description'};
		$items{$title} = \%hash; # remember we have seen this.
		$self->privmsg([ @to ], $item->{link});	
		for my $line ($item->{description}) {
			$line =~ s/<br\s>//;
			$self->privmsg([ @to ], $line);
			sleep 1;
		}
		sleep 2;
	}
	$feed{items} = \%items;
	$rss_feeds{$url} = \%feed;
	$conn->schedule($timer,\&watch_rss_feed,$self,$event,$url,$timer);
}

sub stop_watching_rss_feed {
	my ($self,$event,$url) = @_;
	my %feed = %{$rss_feeds{$url}};
	$feed{stop} = 1;
	$rss_feeds{$url} = \%feed;	
}

sub blah {
  my ($self, $event) = @_;

  print "Got event of type: " . $event->type . "\n";
}

print "Installing handler routines...";

#$conn->add_default_handler(\&blah);

$conn->add_handler('cping',  \&on_ping);
$conn->add_handler('crping', \&on_ping_reply);
$conn->add_handler('msg',    \&on_msg);
$conn->add_handler('chat',   \&on_chat);
$conn->add_handler('public', \&on_public);
$conn->add_handler('caction', \&on_action);
$conn->add_handler('join',   \&on_join);
$conn->add_handler('umode',   \&on_umode);
$conn->add_handler('part',   \&on_part);
$conn->add_handler('topic',   \&on_topic);
$conn->add_handler('notopic',   \&on_topic);

$conn->add_global_handler([ 251,252,253,254,302,255 ], \&on_init);
$conn->add_global_handler('disconnect', \&on_disconnect);
$conn->add_global_handler(376, \&on_connect);
$conn->add_global_handler(433, \&on_nick_taken);
$conn->add_global_handler(353, \&on_names);

print " done.\n";
print "starting...\n";
$irc->start;

