#!/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("Startup");

 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 wakeup";
      $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);
}

