#!/usr/bin/perl
###########################################
# gtkticker
# Mike Schilli, 2004 (m@perlmeister.com)
###########################################
use warnings;
use strict;

my $YHOO_URL = "http://quote.yahoo.com/d?".
               "f=sl1c1&s=";
my $RCFILE   = "$ENV{HOME}/.gtkticker";
my @LABELS       = ();
my $UPD_INTERVAL = 60;
my @SYMBOLS;

use Gtk;
use POE qw(Component::Client::HTTP);
use HTTP::Request;
use Log::Log4perl qw(:easy);
use Data::Dumper;

Log::Log4perl->easy_init($DEBUG);

    # Read config file
open FILE, "<$RCFILE" or
    die "Cannot open $RCFILE";
while(<FILE>) {
    next if /^\s*#/;
    push @SYMBOLS, $_ for /(\S+)/g;
}
close FILE;

POE::Session->create(
   inline_states => {
       _start         => \&start,
       _stop    => sub { INFO "Shutdown" },
       yhoo_response  => \&resp_handler,
       wake_up        => \&wake_up_handler,
   }
);

my $STATUS;

$poe_kernel->post("ticker", "wake_up");
$poe_kernel->run();

###########################################
sub start {
###########################################

  DEBUG "Starting up";

  $poe_kernel->alias_set( 'ticker' );

  my_gtk_init();

  $STATUS->set("Starting up");

  POE::Component::Client::HTTP->spawn(
    Agent     => 'gtkticker/0.01',
    Alias     => 'useragent',
    Timeout   => 60,
  );
}

###########################################
sub upd_quotes {
###########################################

    my $request = HTTP::Request->new(
        GET => $YHOO_URL . 
               join ",", @SYMBOLS);

    $STATUS->set("Fetching quotes");

    $poe_kernel->post('useragent', 
      'request', 'yhoo_response', 
      $request);
}

#########################################
sub my_gtk_init {
#########################################

    my $w = Gtk::Window->new();
    $w->set_default_size(150,200);

        # Create Menu
    my $accel = Gtk::AccelGroup->new();
    $accel->attach($w);
    my $factory = Gtk::ItemFactory->new(
       'Gtk::MenuBar', "<main>", $accel);

    $factory->create_items(
      { path =>  '/_File',
        type =>  '<Branch>',
      },
      { path        =>  '/_File/_Quit',
        accelerator =>  '<control>Q',
        callback    =>  
                  [sub { Gtk->exit(0) }],
      });

    my $vb   = Gtk::VBox->new(0, 0);
    my $upd  = Gtk::Button->new(
                              'Update');

    $vb->pack_start($factory->get_widget(
                    '<main>'), 0, 0, 0);

        # Button at bottom
    $vb->pack_end($upd,  0, 0, 0);

        # Status line on top of buttons
    $STATUS = Gtk::Label->new();
    $STATUS->set_alignment(0.5, 0.5);
    $vb->pack_end($STATUS, 0, 0, 0);

    my $table = Gtk::Table->new(
                     scalar @SYMBOLS, 3);
    $vb->pack_start($table, 1, 1, 0);

    for my $row (0..@SYMBOLS-1) {

      for my $col (0..2) {

        my $label = Gtk::Label->new();
        $label->set_alignment(0.0, 0.5);
        push @{$LABELS[$row]}, $label;

        $table->attach_defaults($label, 
            $col, $col+1, $row, $row+1);
      }

    }
          
    $w->add($vb);

        # Destroying window
    $w->signal_connect('destroy',
        sub {Gtk->exit(0)});

        # Pressing update button
    $upd->signal_connect('clicked', 
        sub { DEBUG "Sending wake_up";
              $poe_kernel->post(
                'ticker', 'wake_up')} );
    $w->show_all();
}

###########################################
sub resp_handler {
###########################################
    my ($req, $resp) = 
            map { $_->[0] } @_[ARG0, ARG1];

    if($resp->is_error()) {
        ERROR $resp->message();
        $STATUS->set($resp->message());
        return 1;
    }

    DEBUG "Response: ", $resp->content();

    my $count = 0;

    for(split /\n/, $resp->content()) {
        my($symbol, $price, $change) = 
                           split /,/, $_;
        chop $change;
        $change = "" if $change =~ /^0/;
        $symbol =~ s/"//g;
        $LABELS[$count][0]->set($symbol);
        $LABELS[$count][1]->set($price);
        $LABELS[$count][2]->set($change);
        $count++;
    }

    $STATUS->set("");

    1;
}

###########################################
sub wake_up_handler {
###########################################
    DEBUG("waking up");

        # Initiate update
    upd_quotes();

        # Re-enable timer
    $poe_kernel->delay('wake_up', 
                   $UPD_INTERVAL);
}
