use Net::IRC;
use Finance::Quote;
use Geo::Weather;
use strict;
use HTML::Strip;
use LWP::UserAgent;
use XML::Simple;
use Time::HiRes qw( usleep );

my $version = "18";
my $botnick = "StockBot_";
my @channel_list = ("#wipples");
my @server_list = ("irc.desync.com", "irc.blessed.net", "irc.foxlink.net");
my $passwd = "XXXXXXXX";

my $q = Finance::Quote->new;
$q->timeout(60);
my $irc = new Net::IRC;

my $q = Finance::Quote->new;
$q->timeout(60);

my $w = new Geo::Weather;

my $hs = HTML::Strip->new();

my $ua = LWP::UserAgent->new;
$ua->timeout(30);
$ua->env_proxy;

my $server = select_server();
my $conn = $irc->newconn(Server   => $server,
			 Port     => 6667,
			 Nick     => $botnick,
			 Ircname  => 'StockBot',
			 Username => 'StockBot');


$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('part',   \&on_part);
$conn->add_handler('cdcc',   \&on_dcc);
$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);

$irc->start;


sub on_ping {
}

sub on_ping_reply {
}

sub on_msg {
    my ($self, $event) = @_;
    my ($arg, $nick) = ($event->args, $event->nick);
    my @args = split(/ /, $arg);
    if ($nick == "_aa_") {
	if ($arg =~ /^join/i) {
	    $self->join($args[1]);
	}
	if ($arg =~ /^part/i) {
	    $self->part($args[1]);
	}
	if ($arg =~ /^nick/i) {
	    $self->nick($args[1]);
	}
	if ($arg =~ /^quit/i) {
	    quit();
	}
    }
    if ($arg =~ /^op/i) {
	if ($args[2] eq $passwd) {
	    $self->mode($args[1], "+o $nick");
	}
	else {
	    $self->notice($nick, "Incorrect passwERd, you CRAZY HAcKER!");
	}
    }
    if ($arg =~ /^help/i) {
	help($self, $nick);
    }
    if ($arg =~ /^quote/i) {
	my ($exchange, $verbosity, $subarg, $symbol, @symbols);
	my @args = split(/ /, $arg);
	($exchange, $verbosity, @symbols) = process_args(@args);
	foreach $symbol (@symbols) {
	    quote($self, $nick, $nick, $symbol, $exchange, $verbosity);
	}
    }
}

sub on_chat {
}

sub on_public {
    my ($self, $event) = @_;
    my ($arg, $target, $nick, $mynick) = ($event->args, $event->to, $event->nick, $self->nick);
    my @args = split(/ /, $arg);
    foreach my $word (@args) {
	if ($word =~ /^http:\/\/.*\..*/i or $word =~ /^www.*\..*/i or $word =~ /^ftp:\/\/.*\..*/i) {
	    add_url($nick, $word);
	}
    }
    if ($arg =~ /^quote/i) {
	my ($exchange, $verbosity, @symbols) = process_args(@args);
	foreach my $symbol (@symbols) {
	    quote($self, $nick, $target, $symbol, $exchange, $verbosity);
	}
    }
    if ($arg =~ /^weather/i) {
	weather($self, $target, $nick, $args[1]);
    }
    if ($arg =~ /^forecast/i) {
	forecast($self, $target, $nick, $args[1]);
    }
    if ($arg =~ /^e2/i) {
	my $e2_args = $arg;
	$e2_args =~ s/e2\ //i;
	e2($self, $target, $nick, $e2_args);
    }
    if ($arg =~ /^help/i) {
	help($self, $nick);
    }
}
sub forecast {
    my ($self, $target, $nick, $zip) = @_;
    if ($zip > 10000 and $zip <= 99999) {
        my $c = $w->get_weather($zip);
	my $raw_forecast = $w->report_forecast();
	my $forecast_string = $hs->parse($raw_forecast);
	$hs->eof;
	my @forecast = split(/\n/, $forecast_string);
	foreach my $line (@forecast) {
	    if ($line ne "\n") {
		$line =~ s/\n//g;
		print "$line";
	    }
	}
    }
}

sub weather {
    my ($self, $target, $nick, $zip) = @_;
    my $temp_color;
    if ($zip > 10000 and $zip <= 99999) { 
	my $c = $w->get_weather($zip);
	my ($city, $state, $temp, $cond, $wind, $humi) = ($c->{city}, $c->{state}, $c->{temp}, $c->{cond}, $c->{wind}, $c->{humi});
	$wind =~ s/&nbsp\;//ig;
	$wind =~ s/<\/td>//ig;
	if ($temp > 32) {
	    $temp_color = 4;
	}
	if ($temp <= 32) {
	    $temp_color = 12;
	}
	$self->privmsg($target, "Current Conditions for $city, $state: Temp(\003$temp_color\002$temp\002\003) Condition(\002$cond\002) Wind(\002$wind\002) Humidity(\002$humi\002\%)");
    }
    else {
	$self->privmsg($target, "Invalid Zipper Code, Foo!");
    }
}

sub e2 {
    my ($self, $target, $nick, $node) = @_;
    my $count = 1;
    $node =~ s/ /\%20/g;
    my $url = "http://everything2.com/index.pl?displaytype=xmltrue&node=" . $node;
    
    my $response = $ua->get($url);
    if ($response->is_success) {
	my $data = $response->content;
	my $data_hash = XMLin($data);

	if (ref($data_hash->{writeup}) eq 'ARRAY') {
	    foreach my $writeup (@{$data_hash->{writeup}}) {
		my $doctext = $hs->parse($writeup->{doctext}); $hs->eof;
		$doctext = e2_parse_doc($doctext);
		my $writeups = @{$data_hash->{writeup}};
		$self->privmsg($nick, "$count of $writeups writeups:");
		e2_display($self, $nick, $writeup->{author}->{content}, $writeup->{createtime}, $writeup->{title}, $doctext, $writeup->{node_id}, "1_000_000");
		$count++;
	    }
	}
	elsif ($data_hash->{writeup}) {
	    foreach my $writeup ($data_hash->{writeup}) {
		my $doctext = $hs->parse($writeup->{doctext}); $hs->eof;
		$doctext = e2_parse_doc($doctext);
		e2_display($self, $target, $writeup->{author}->{content}, $writeup->{createtime}, $writeup->{title}, $doctext, $writeup->{node_id}, "4_000_000");
	    }
	}
	else {
	    $node =~ s/\%20/ /g;
	    $self->privmsg($target, "Nothing found for \002$node\002.");
	}
    }
    else {
	$self->privmsg($target, $response->status_line);
    }
}

sub e2_parse_doc {
    my $doc = shift;
    $doc =~ s/\ ,/,/g;
    $doc =~ s/\ \./\./g;
    $doc =~ s/\ \ /\ /g;
    $doc =~ s/\n\n/\n/gi;
    $doc =~ s/\&nbsp\;/\ /g;
    $doc =~ s/\&copy\;/\(c\)/gi;
    $doc =~ s/\&\#91\;/\[/g;
    $doc =~ s/\&\#93\;/\]/g;
    $doc =~ s/\ \'s/\'s/gi;
    return $doc;
}

sub e2_display {
    my ($self, $target, $author, $createtime, $title, $doctext, $node_id, $delay) = @_;
    my $display_lines = 5;
    my @lines = split(/\n/, $doctext);
    my $c = 0;
    $self->privmsg($target, "\002$title\002 by \002$author\002 on $createtime \003" . "12http://everything2.com/?node_id=$node_id\003");
    while ($c < $display_lines) {
	$self->privmsg($target, "$lines[$c]");
	$c++;
	usleep ($delay);
    }
}

sub on_action {
}

sub on_join {
}

sub on_part {
}

sub on_dcc {
}

sub on_topic {
}

sub on_init {
}

sub on_connect {
    my $self = shift;
    foreach my $channel (@channel_list) {
	$self->join($channel);
    }
}

sub on_diconnect {
    sleep 10;
}

sub on_nick_taken {
}

sub on_names {
}

sub quit {
    exit 0;
}

sub help {
    my ($self, $nick) = @_;
    $self->notice($nick, "Usage: /msg $botnick quote [-e exchange] [-v verbosity] SYMBOL[,SYMBOL2,...]");
    $self->notice($nick, "Exchanges: austrailia, dwsfunds, fidelity, tiaacref, troweprice, europe, canada, usa (default), nyse, nasdaq, uk_unit_trusts, vanguard, vwd");
    $self->notice($nick, "Indexes are prefixed with ^. See http://finance.yahoo.com/l?m=US&s=comp&t=I for available indexes");
}

sub usage {
    my ($self, $nick) = @_;
    $self->notice($nick, "StockBot Version: $version '/msg $botnick help' for more help");
    $self->notice($nick, "Usage: /msg $botnick quote [-e exchange] [-v verosity] SYMBOL[,SYMBOL2,...]");
}

sub quote {
    my ($self, $nick, $target, $symbol, $exchange, $verbosity) = @_;
    my $netcolor;
    $symbol = process_symbol($symbol);
    my %stock = $q->fetch($exchange,$symbol);
    if ($stock{$symbol,'success'} == 1) {
	if ($stock{$symbol,'net'} =~ /^-/i) {
	    $netcolor = 4;
	}
	elsif ($stock{$symbol,'net'} =~ /^\+/i) {
	    $netcolor = 3;
	}
	if ($verbosity >= 1) {
	    $self->privmsg($target, "$stock{$symbol,'name'} Price($stock{$symbol,'price'}) Change(\003" . "$netcolor" . "$stock{$symbol,'net'}\003) Volume($stock{$symbol,'volume'})");
	}
	if ($verbosity >= 2) {
	    $self->privmsg($target, "[$stock{$symbol,'name'}] 52 Week Range: $stock{$symbol,'year_range'} Today's Range: $stock{$symbol,'day_range'} Last Trade: $stock{$symbol,'date'} $stock{$symbol,'time'}");
	}
	if ($verbosity >= 3) {
	    $self->privmsg($target, "[$stock{$symbol,'name'}] P/E Ratio: $stock{$symbol,'pe'} Earnings Per Share: $stock{$symbol,'eps'} Net Asset Value: $stock{$symbol,'nav'}");
	}
	if ($verbosity >= 4) {
	    $self->privmsg($target, "[$stock{$symbol,'name'}] Debug Info: Method: $stock{$symbol,'method'} Exchange: $stock{$symbol,'exchange'}");
	}
    }
    else {
	$self->privmsg($target, "$symbol: $stock{$symbol,'errormsg'}");
    }
}

sub process_symbol {
    my $input_symbol = uc($_[0]);
    my $output_symbol;
    if ($input_symbol eq "NASDAQ") {
	$output_symbol = "^IXIC1";
    }
    elsif ($input_symbol eq "DJIA" or $input_symbol eq "DOWJONES" or $input_symbol eq "DOW") {
	$output_symbol = "^DJI";
    }
    elsif ($input_symbol eq "S&P") {
	$output_symbol = "^SPTSECP3";
    }
    else {
	$output_symbol = $input_symbol;
    }
    return $output_symbol;
}

sub process_args {
    my ($arg, $count, $param, $exchange, $verbosity, @symbols);
    $count = 0;
    foreach $arg (@_) {
	$param = $count + 1;
	if ($arg eq "-e") {
	    $exchange = $_[$param];
	}
	elsif ($arg eq "-v") {
	    $verbosity = $_[$param];
	    }
	$count = $count + 1;
    }
    my $arg_count = scalar(@_) - 1;
    @symbols = split(/,/, $_[$arg_count]);
    if (!$exchange) {
	$exchange = "usa";
    }
    if (!$verbosity) {
	$verbosity = 1;
    }
    return($exchange, $verbosity, @symbols);
}

sub select_server {
    return $server_list[int(rand(@server_list))];
}

sub add_url {
    my ($nick, $url) = @_;
    my $date = `date`;
    open(FILE, ">>urllog.dat");
    print FILE "$nick^^$url^^$date";
    close(FILE);
}