-
Notifications
You must be signed in to change notification settings - Fork 0
/
schedule.go
168 lines (150 loc) · 5.51 KB
/
schedule.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package humphrey
import (
"encoding/xml"
"fmt"
"net/url"
"strconv"
"time"
)
// WEEKDAY, SATURDAY, SUNDAY, TODAY, and NOW are all valid dates to pass to GetRouteSchedule
const (
WEEKDAY = "wd"
SATURDAY = "sd"
SUNDAY = "su"
TODAY = "today"
NOW = "now"
)
// A RouteSchedule represents the BART XML document that starts with a <root>
type RouteSchedule struct {
XMLName xml.Name `xml:"root"`
Number int `xml:"sched_num"`
Trains []TrainSchedule `xml:"route>train"`
Message string `xml:"message>special_schedule"`
}
// A Schedule represents the schedule entry passed from the BART `scheds` command.
type Schedule struct {
EffectiveDate time.Time
Number int
}
type intermediateSchedule struct {
XMLName xml.Name `xml:"schedule"`
EffectiveDate string `xml:"effectivedate,attr"`
Number int `xml:"id,attr"`
}
// a bartSched represents the BART `scheds` command XML response
type bartSchedDocument struct {
XMLName xml.Name `xml:"root"`
Schedules []Schedule `xml:"schedules>schedule"`
}
type stationScheduleResponse struct {
XMLName xml.Name `xml:"root"`
Trains []Train `xml:"station>item"`
}
// Train represents the train items in the response from `stnsched`
type Train struct {
Line string
Origin Station
Time time.Time
DestinationTime time.Time
Index int
BikeFlag int
}
type intermediateTrain struct {
XMLName xml.Name `xml:"item"`
Line string `xml:"line,attr"`
Origin string `xml:"trainHeadStation,attr"`
Time string `xml:"origTime,attr"`
DestinationTime string `xml:"destTime,attr"`
Index int `xml:"trainIdx,attr"`
BikeFlag int `xml:"bikeflag,attr"`
}
// A TrainSchedule represents the BART XML <train>
type TrainSchedule struct {
XMLName xml.Name `xml:"train"`
Index int `xml:"index,attr"`
Stops []ScheduledStop `xml:"stop"`
}
// A ScheduledStop represents the BART XML <stop>
type ScheduledStop struct {
XMLName xml.Name `xml:"stop"`
Station string `xml:"station,attr"`
Time string `xml:"origTime,attr"`
BikeFlag int `xml:"bikeFlag,attr"`
}
const (
effectiveTimeFormat = "01/02/2006 03:04 PM"
originTimeFormat = "3:04 PM"
destinationTimeFormat = "3:04 PM"
)
// UnmarshalXML unmarshals the Schedule by way of an intermediate struct
func (s *Schedule) UnmarshalXML(xmlDecoder *xml.Decoder, startEl xml.StartElement) error {
var i intermediateSchedule
err := xmlDecoder.DecodeElement(&i, &startEl)
if err != nil {
return err
}
s.Number = i.Number
s.EffectiveDate, err = time.Parse(effectiveTimeFormat, i.EffectiveDate)
if err != nil {
return fmt.Errorf("parsing <effectiveDate> %v: %v", i.EffectiveDate, err)
}
return nil
}
// UnmarshalXML unmarshals the Train by way of an intermediate struct
func (t *Train) UnmarshalXML(xmlDecoder *xml.Decoder, startEl xml.StartElement) error {
var i intermediateTrain
err := xmlDecoder.DecodeElement(&i, &startEl)
if err != nil {
return err
}
t.Time, err = time.Parse(originTimeFormat, i.Time)
if err != nil {
return fmt.Errorf("parsing origTime %v: %v", i.Time, err)
}
t.DestinationTime, err = time.Parse(originTimeFormat, i.DestinationTime)
if err != nil {
return fmt.Errorf("parsing destTime %v: %v", i.DestinationTime, err)
}
t.Line, t.Index, t.BikeFlag = i.Line, i.Index, i.BikeFlag
t.Origin = Station{Abbreviation: i.Origin}
return nil
}
// GetRouteScheduleByDate requests a route schedule by route number and date, which can be formatted
// either as a "MM/DD/YYYY" string or passed as one of the constants WEEKDAY, SATURDAY, SUNDAY, TODAY, or NOW.
func (c *Client) GetRouteScheduleByDate(routeNumber int, date string) (RouteSchedule, error) {
var routeSchedule RouteSchedule
params := url.Values{"route": []string{strconv.Itoa(routeNumber)}, "date": []string{date}, "cmd": []string{"routesched"}}
err := c.MakeRequest("sched", "routesched", params, &routeSchedule)
if err != nil {
return RouteSchedule{}, fmt.Errorf("making 'routesched' request for %d on %v: %v", routeNumber, date, err)
}
return routeSchedule, nil
}
// GetRouteScheduleBySchedule requests a route schedule by route number and schedule number.
func (c *Client) GetRouteScheduleBySchedule(routeNumber int, scheduleNumber int) (RouteSchedule, error) {
var routeSchedule RouteSchedule
params := url.Values{"route": []string{strconv.Itoa(routeNumber)}, "sched": []string{strconv.Itoa(scheduleNumber)}, "cmd": []string{"routesched"}}
err := c.MakeRequest("sched", "routesched", params, &routeSchedule)
if err != nil {
return RouteSchedule{}, fmt.Errorf("making 'routesched' request for %d on schedule #%d: %v", routeNumber, scheduleNumber, err)
}
return routeSchedule, nil
}
// GetCurrentSchedules requests the information about currently relevant schedules.
func (c *Client) GetCurrentSchedules() ([]Schedule, error) {
var schedResponse bartSchedDocument
err := c.MakeRequest("sched", "scheds", url.Values{}, &schedResponse)
if err != nil {
return nil, fmt.Errorf("making 'scheds' request: %v", err)
}
return schedResponse.Schedules, nil
}
// GetStationSchedule returns a slice of TrainSchedules for the given station
func (c *Client) GetStationSchedule(station Station) ([]Train, error) {
var response stationScheduleResponse
err := c.MakeRequest("sched", "stnsched", url.Values{"orig": []string{station.Abbreviation}}, &response)
if err != nil {
return nil, fmt.Errorf("making 'stnsched' request for %s: %v", station.Abbreviation, err)
}
return response.Trains, nil
}