#!/usr/bin/env ruby 
require 'SVG/Graph/TimeSeries'
require 'time'
require 'net/http'
require 'rubygems'
require 'mongrel'

#Thu Feb  1 15:44:59 PST 2007
#Keith Fahlgren

# see http://kfahlgren.com:4117/graphs/rails_cookbook.svg for an example
# and , for the scrape 

class Puller
  def self.data_from_url(url)
    begin
      data = nil
      uri = URI.parse(url)
      http = Net::HTTP.new(uri.host, uri.port)
      if url =~ /^https|:443\// # hmm this looks brittle
        http.use_ssl = true 
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      end  
      http.start{|h|
        query = uri.query ? "?" + uri.query : ""
        h.get2(uri.path + query, {"Accept" => 'text/xml'}) {|resp|
          puts resp.body if $DEBUG
          data = resp.body
        }
      }
    rescue => e
      raise ArgumentError.new("Url (#{url}) error! [#{e}]")
    end
    return data
  end
  def self.rexml_from_url(url)
    return REXML::Document.new(data_from_url(url))
  end  
end # of class Puller


class ScrapeGrapher < Mongrel::HttpHandler
  PORT = 4117
  SERVER = "0.0.0.0"
  AMAZON_SCRAPE = "http://www.tupleshop.com/sales-rank.html"
  BOOK_TITLE = "Rails Cookbook"
  MAX_ITEMS = 100

  def process(request, response)
    begin
      raw_data = Puller.data_from_url(AMAZON_SCRAPE).sub(/^<h1>#{BOOK_TITLE} - Amazon Sales Rank<\/h1>\n\n/, '').split("<br />\n")
      ranks = []
      # was map then flatten! but that won't scale
      raw_data.each_with_index {|x,i|
        # slow
        if (i % (raw_data.length / MAX_ITEMS)) == 0
          ranks << x.sub(/ - .+$/, '')
          ranks << x.sub(/^.+ - /, '').sub(/,/, '').to_i
        end  
      }  

      title = "Sales Rank (lower better)"
      graph = SVG::Graph::TimeSeries.new({
                                          :width => 1200,
                                          :height => 600,
                                          :graph_title => title,
                                          :show_graph_title => true,
                                          :no_css => true,
                                          :key => false,
                                          :scale_x_integers => true,
                                          :scale_y_integers => false,
                                          :min_x_value => ranks.first,
                                          :min_y_value => 1,
                                          :show_data_labels => true,
                                          :show_data_values => false,
                                          :show_x_guidelines => true,
                                          :show_x_title => true,
                                          :x_title => "Time",
                                          :show_y_title => true,
                                          :y_title => "Amazon Ranking",
                                          :y_title_text_direction => :bt,
                                          :stagger_x_labels => true,
                                          :x_label_format => "%m/%d/%y:%I%p",
                                          })

      graph.add_data({
                      :data => ranks,
                      :title => 'Amazon Sales Rank',
                     })

      response.start(200) {|head, out|
        head["Content-Type"] = "image/svg+xml"
        return out.write(graph.burn)
      }  
    rescue => e
      puts "Server error (#{e}) [#{e.backtrace.inspect}]"
    end
  end
end

h = Mongrel::HttpServer.new(ScrapeGrapher::SERVER, ScrapeGrapher::PORT)
h.register("/graphs/rails_cookbook.svg", ScrapeGrapher.new)
trap("INT"){ h.stop }
h.run.join
