#!/usr/bin/env ruby

require 'socket'
require 'net/http'
require 'uri'
require 'rss'

module PhidgetApplication
  class PhidgetBiff
    
    def initialize(ip = "127.0.0.1", port = 4321, interval = 10, url_file = "url.txt")
      main(ip, port, interval, url_file)
    end
    
    def main(ip, port, interval, url_file)
      uris = load_uri(url_file)
      modified_times = init_modified_time(uris)      
      
      socket = TCPSocket.new(ip, port)
      init_pin(socket)
      biff_loop(socket, uris, modified_times, interval)
      
      while line = socket.gets
        pin, data = parse(line)
        if data != nil   && data == 1
          set_pin(socket, pin, 0)
          open_url(uris[pin])
        end
      end
      socket.close
    end
    
    ##########################################################
    
    def load_uri(url_file)
      uris = Array.new
      File.open(url_file)  do |f|
        f.each do |line|
          if(line !~ /^#/)
            line.chomp!
            puts line
            uris.push(URI.parse(line))
            break if uris.length > 8
          end
        end
      end
      uris
    end
  
    def init_pin(socket)
      for i in 0..8
        set_pin(socket, i, 0)
      end
    end

    def init_modified_time(uris)
      modified_times = Hash.new
        uris.each do |uri|
          time  = get_modified_time(uri)
          modified_times[uri] = time
      end
      modified_times
    end
  
    def parse(line)
      args = line.split(",")
      if args[0] == "In" and
        args[1] == "InterfaceKit" and
        args[2] == "Digital"
        port = args[3].to_i
        data = args[4].to_i
      end
      return port, data
    end

    def open_url(uri)
      url = uri.to_s
      if(uri.path =~ /[.]rdf$/)
        url = parse_rss(uri)
      end
      system "cygstart #{url}" 
    end
  
    def parse_rss(uri)
      url = nil
      Net::HTTP.start(uri.host) do |http|
        begin 
          response = http.get(uri.path)
          rss = RSS::Parser.parse(response.body)
          url = rss.channel.link.to_s
        rescue 
        end
      end
      url
    end

    ##########################################################
    
    def biff_loop(socket, uris, modified_times, sleep_time = 10)
      Thread.start do
        while true
          uris.each do |uri|
            time  = get_modified_time(uri)
            puts uri.to_s
            puts "  " + time.to_s
            if(time != nil && modified_times[uri] < time)
              set_pin(socket, uris.index(uri), 1)
              modified_times[uri] = time
            end
          end
          sleep(sleep_time)  
        end
      end
    end
    
    def get_modified_time (uri, timeout = 2)
      return nil unless /^http/ =~ uri.to_s
      time = nil
      dead = Time.at(0)
      begin
        uri_const = URI.parse(uri.to_s)
        http = http_connect(uri_const, timeout)
        response = http.head(uri.to_s)
        if response.code.to_i != 200
          time = dead
        elsif response['last-modified']
          time = Time.httpdate(response['last-modified']) 
        else
          time = Time.now 
        end
      rescue Net::ProtoFatalError => e  # 404
        time = dead
      rescue 
        time = dead # timeout? 
      end
      time
    end
    
    def http_connect(uri, timeout)
      http =  Net::HTTP.new(uri.host, uri.port)
      http.open_timeout = timeout
      http.read_timeout = timeout
      http
    end
    
    def set_pin(socket, pin, state = 0, delimiter = "\r\n")
      str = "Out,InterfaceKit,#{pin},#{state}" + delimiter
      socket.print str
    end
    
    def PhidgetBiff.print_usage
      puts "Usage:"
      puts " % PhidgetBiff [ip] [port] [interval] [url_file]"
      puts " % PhidgetBiff [ip] [port] [interval]"
      puts " % PhidgetBiff [interval]"
      puts " % PhidgetBiff "
    end
  end

  #############################################
  #プログラム開始
  #############################################
  case ARGV.length
    when 0:
      PhidgetBiff.print_usage
      PhidgetBiff.new()
    when 1:
      PhidgetBiff.new("127.0.0.1", 4321, ARGV[0].to_i)  
    when 2:
      PhidgetBiff.new(ARGV[0], ARGV[1].to_i)
    when 3:
      PhidgetBiff.new(ARGV[0], ARGV[1].to_i, ARGV[2].to_i)
    when 4:
      PhidgetBiff.new(ARGV[0], ARGV[1].to_i, ARGV[2].to_i, ARGV[3])      
    else
      PhidgetBiff.print_usage
      exit(0)
  end  
  
end
