1
# Ruby API towards Trafikanten, with a builtin web server
2
# Run this file and point your browser to http://localhost:4567/. Enter the name of a station, select, and view realtime departures
3
# from the station
4
%w(rubygems open-uri cgi hpricot yaml).each{|dep|require dep}
5
# Seems easier
6
class String
7
  def url_encode;CGI.escape(self);end
8
  def url_decode;CGI.unescape(self);end
9
end
10
11
class Station
12
  attr_accessor :station_id, :name, :district, :x, :y
13
  def initialize(options={})
14
    options.each{|k,v|send("#{k}=",v)}
15
  end
16
  
17
  def self.find_by_name(a_name)
18
    uri = "http://www8.trafikanten.no/txml?type=1&stopname=#{a_name.url_encode}"
19
    data = open(uri).read
20
    result = []
21
    doc = Hpricot(data)
22
    (doc/"//stopmatch").each do |match|
23
      id = (match/"fromid").inner_html.to_i
24
      name = (match/"stopname").inner_html
25
      district = (match/"district").inner_html
26
      x = (match/"xcoordinate").inner_html
27
      y = (match/"ycoordinate").inner_html
28
      result << new(:x => x, :y => y, :station_id => id, :name => name, :district => district)
29
    end
30
    result
31
  end
32
  
33
  # There seem to be different data sources for subway stations and the other stations.
34
  def subway_station?
35
    ["03011930","03012220","03011030","03012365","02190070","02190080","02190090","03010011","03010020","03010031","03010200","03010360","03010370","03010600","03010610","03010770","03010780","03010950","03011010","03011020","03011110","03011120","03011130","03011140","03011200","03011210","03011220","03011310","03011320","03011330","03011400","03011410","03011430","03011440","03011450","03011510","03011520","03011530","03011540","03011610","03011620","03011630","03011710","03011720","03011730","03011810","03011910","03011920","03011940","03012000","03012010","03012020","03012030","03012040","03012100","03012120","03012130","03012210","03012230","03012240","03012260","03012270","03012280","03012305","03012310","03012315","03012320","03012325","03012330","03012340","03012345","03012350","03012355","03012360","03012370","03012375","03012380","03012385","03012390","03012410","03012420","03012430","03012450","03012460","03012560","03012565","03012572","03012630"].include?(station_id.to_s)    
36
  end
37
  
38
  def realtime_url
39
    subway_station? ?  "http://www.sis.trafikanten.no:8088/xmlrtpi/dis/request?DISID=SN$#{station_id}" : "http://www.sis.trafikanten.no/xmlrtpi/dis/request?DISID=SN$#{station_id}"
40
  end
41
  
42
  def realtime_departures
43
    result = []
44
    doc = Hpricot(open(realtime_url).read)
45
    (doc/"disdeviation").each do |m|
46
      trip_status = (m/"trip_status").inner_html      
47
      departure_field =  (trip_status == "real") ? "expecteddisdeparturetime" : "scheduleddisdeparturetime"
48
      scheduled_departure = (m/departure_field).inner_html
49
      destination = (m/"destinationstop").inner_html
50
      line = (m/"lineid").inner_html
51
      result << Departure.new(:status => trip_status, :departure => Time.parse(scheduled_departure), :destination => destination, :line => line, :from => name)
52
    end
53
    return result
54
  end
55
  
56
end
57
58
class Departure
59
  attr_accessor :status, :departure, :destination, :line, :from
60
  def initialize(options={})
61
    options.each{|k,v|send("#{k}=",v)}
62
  end
63
  
64
  def to_s
65
    "Linje #{line} fra #{from} til #{destination} klokka #{departure.strftime('%H:%M (%d/%m)')}"
66
  end
67
end
68
69
# Just to play nice, let's embed a webserver
70
# if __FILE__ == $0
71
  require 'sinatra'
72
73
  get '/' do
74
    '<h1>Velg stoppested</h1><form method="get" action="/locations"><input name="q" type="text" /><input type="submit"/></form>'
75
  end
76
77
78
  get '/locations' do
79
    result = []
80
    result << '<h1>Velg stasjon</h1><ul>'
81
    matches = Station.find_by_name(params[:q])
82
    matches.each do |m|
83
      result << "<li><a href='/departures/#{m.station_id}/#{m.name}'>#{m.name}</a></li>"
84
    end
85
    result << "</ul>"
86
    result.join("\n")
87
  end
88
89
  get '/departures/:station_id/:station_name' do
90
    result = []
91
    station = Station.new(:station_id => params[:station_id], :name => params[:station_name].url_decode)
92
    result << "<h1>Avganger fra #{station.name}</h1>"
93
    result << "<ul>"
94
    station.realtime_departures.sort{|a,b|a.departure<=>b.departure}.each do |dep|
95
      result << "<li>#{dep.to_s}</li>"
96
    end
97
    result << "</ul>"
98
    result.join("\n")
99
  end
100
# end