structs.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // SPDX-FileCopyrightText: Adam Evyčędo
  2. //
  3. // SPDX-License-Identifier: AGPL-3.0-or-later
  4. package traffic
  5. import (
  6. "fmt"
  7. "strings"
  8. "time"
  9. "github.com/dhconnelly/rtreego"
  10. "golang.org/x/text/language"
  11. )
  12. type DeparturesType uint8
  13. const (
  14. DEPARTURES_HYBRID DeparturesType = iota
  15. DEPARTURES_FULL
  16. )
  17. func LuaAlertToAlert(luaAlert AlertLua) (Alert, error) {
  18. resultAlert := Alert{
  19. TimeRanges: make([][2]time.Time, len(luaAlert.TimeRanges)),
  20. Headers: map[language.Tag]string{},
  21. Descriptions: map[language.Tag]string{},
  22. URLs: map[language.Tag]string{},
  23. Cause: AlertCause(luaAlert.Cause),
  24. Effect: AlertEffect(luaAlert.Effect),
  25. }
  26. for i, r := range luaAlert.TimeRanges {
  27. start, err := time.Parse("2006-01-02T15:04:05.999Z07:00", r.StartDate)
  28. if err != nil {
  29. return Alert{}, fmt.Errorf("error parsing time for range %s: %w", r.StartDate, err)
  30. }
  31. end, err := time.Parse("2006-01-02T15:04:05.999Z07:00", r.EndDate)
  32. if err != nil {
  33. return Alert{}, fmt.Errorf("error parsing time for range %s: %w", r.EndDate, err)
  34. }
  35. resultAlert.TimeRanges[i] = [2]time.Time{start, end}
  36. }
  37. for l, header := range luaAlert.Headers {
  38. tag, err := language.Parse(l)
  39. if err != nil {
  40. return Alert{}, fmt.Errorf("error parsing tag %s: %w", l, err)
  41. }
  42. resultAlert.Headers[tag] = header
  43. }
  44. for l, description := range luaAlert.Descriptions {
  45. tag, err := language.Parse(l)
  46. if err != nil {
  47. return Alert{}, fmt.Errorf("error parsing tag %s: %w", l, err)
  48. }
  49. resultAlert.Descriptions[tag] = description
  50. }
  51. for l, url := range luaAlert.Urls {
  52. tag, err := language.Parse(l)
  53. if err != nil {
  54. return Alert{}, fmt.Errorf("error parsing tag %s: %w", l, err)
  55. }
  56. resultAlert.URLs[tag] = url
  57. }
  58. return resultAlert, nil
  59. }
  60. func (v VehicleStatus) Location() Position {
  61. return Position{
  62. Lat: v.Latitude,
  63. Lon: v.Longitude,
  64. }
  65. }
  66. func (k LineType) Value() uint {
  67. return uint(k)
  68. }
  69. func (d Direction) Value() uint {
  70. return uint(d)
  71. }
  72. type DepartureRealtime struct {
  73. Time time.Time
  74. Departure Departure
  75. Headsign string
  76. LineID string
  77. Order StopOrder
  78. Update Update
  79. Alerts []SpecificAlert
  80. }
  81. func (d DepartureRealtime) WithUpdate(update Update) DepartureRealtime {
  82. d.Update = update
  83. return d
  84. }
  85. func (d DepartureRealtime) WithAlerts(alerts []Alert, languages []language.Tag) DepartureRealtime {
  86. d.Alerts = selectSpecificAlerts(alerts, languages)
  87. return d
  88. }
  89. func selectSpecificAlerts(alerts []Alert, languages []language.Tag) []SpecificAlert {
  90. now := time.Now()
  91. validAlerts := []SpecificAlert{}
  92. for _, alert := range alerts {
  93. timeValid := len(alert.TimeRanges) == 0
  94. for _, timeRange := range alert.TimeRanges {
  95. if now.After(timeRange[0]) && now.Before(timeRange[1]) {
  96. timeValid = true
  97. break
  98. }
  99. }
  100. if !timeValid {
  101. continue
  102. }
  103. headerLanguages := make([]language.Tag, len(alert.Headers))
  104. i := 0
  105. for l := range alert.Headers {
  106. headerLanguages[i] = l
  107. i++
  108. }
  109. headerMatcher := language.NewMatcher(headerLanguages)
  110. ht, _, _ := headerMatcher.Match(languages...)
  111. descriptionLanguages := make([]language.Tag, len(alert.Descriptions))
  112. i = 0
  113. for l := range alert.Descriptions {
  114. descriptionLanguages[i] = l
  115. i++
  116. }
  117. descriptionMatcher := language.NewMatcher(descriptionLanguages)
  118. dt, _, _ := descriptionMatcher.Match(languages...)
  119. URLLanguages := make([]language.Tag, len(alert.URLs))
  120. i = 0
  121. for l := range alert.URLs {
  122. URLLanguages[i] = l
  123. i++
  124. }
  125. URLMatcher := language.NewMatcher(URLLanguages)
  126. ut, _, _ := URLMatcher.Match(languages...)
  127. validAlerts = append(validAlerts, SpecificAlert{
  128. Header: alert.Headers[ht],
  129. Description: alert.Descriptions[dt],
  130. URL: alert.URLs[ut],
  131. Cause: alert.Cause,
  132. Effect: alert.Effect,
  133. })
  134. }
  135. return validAlerts
  136. }
  137. func (g LineGraph) LastNodes() []int {
  138. lastNodes := []int{}
  139. for i, nextNodes := range g.NextNodes {
  140. for _, node := range nextNodes {
  141. if node == -1 {
  142. lastNodes = append(lastNodes, i)
  143. break
  144. }
  145. }
  146. }
  147. return lastNodes
  148. }
  149. type LineStub struct {
  150. Name string
  151. Colour string
  152. Type string
  153. }
  154. func (l Line) DisplayName() string {
  155. return l.Name
  156. }
  157. func (l Line) IsItem() {}
  158. type Shape struct { // todo(BAF11)
  159. Points []Position
  160. }
  161. type Queryable interface {
  162. IsItem()
  163. DisplayName() string
  164. }
  165. type Locatable interface {
  166. Location() Position
  167. }
  168. func (s Stop) DisplayName() string {
  169. return s.Name
  170. }
  171. func (s Stop) Location() Position {
  172. return s.Position
  173. }
  174. func (s Stop) Bounds() *rtreego.Rect {
  175. rect, err := rtreego.NewRectFromPoints(
  176. rtreego.Point{s.Position.Lat, s.Position.Lon},
  177. rtreego.Point{s.Position.Lat, s.Position.Lon},
  178. )
  179. if err != nil {
  180. panic(err.Error())
  181. }
  182. return rect
  183. }
  184. func (s Stop) IsItem() {}
  185. type TimedStopStub struct {
  186. StopStub
  187. Time uint
  188. }
  189. type StopStub struct {
  190. Code string
  191. Name string
  192. NodeName string
  193. Zone string
  194. OnDemand bool
  195. }
  196. type Validity string // 20060102_20060102
  197. func (v Validity) Start() string {
  198. return strings.Split(string(v), "_")[0]
  199. }
  200. func (v Validity) End() string {
  201. return strings.Split(string(v), "_")[1]
  202. }
  203. type FeedCodeIndex map[Validity]CodeIndex
  204. type GlobalCodeIndex map[string]FeedCodeIndex
  205. type NameIndex []NameOffset
  206. type FeedNameIndex map[Validity]NameIndex
  207. type GlobalNameIndex map[string]FeedNameIndex
  208. func (ix NameIndex) String(i int) string {
  209. return ix[i].Name
  210. }
  211. func (ix NameIndex) Len() int {
  212. return len(ix)
  213. }
  214. type FeedCalendar map[Validity][]Schedule
  215. type GlobalCalendar map[string]FeedCalendar
  216. type Vehicles map[string]Vehicle
  217. type FeedVehicles map[Validity]Vehicles
  218. type GlobalVehicles map[string]FeedVehicles
  219. type FeedPositionIndex map[Validity]*rtreego.Rtree
  220. type GlobalPositionIndex map[string]FeedPositionIndex
  221. type Version struct {
  222. Link string
  223. ValidFrom time.Time
  224. ValidTill time.Time
  225. }
  226. func (v Version) String() string {
  227. return v.ValidFrom.Format(ValidityFormat) + "_" + v.ValidTill.Format(ValidityFormat)
  228. }
  229. type GlobalVersions map[string][]Version
  230. var DateFormat string = "2006-01-02"
  231. var DateTimeFormat string = "2006-01-02T15:04:05-07:00"
  232. var ValidityFormat string = "20060102"
  233. var ValidityFormatExtended string = "20060102150405"
  234. type Traffic struct {
  235. CodeIndexes GlobalCodeIndex
  236. NameIndexes GlobalNameIndex
  237. LineIdIndexes GlobalCodeIndex
  238. LineIndexes GlobalNameIndex
  239. TripIndexes GlobalNameIndex
  240. PositionIndexes GlobalPositionIndex
  241. Versions GlobalVersions
  242. Calendars GlobalCalendar
  243. Vehicles GlobalVehicles
  244. Feeds map[string]Feed
  245. FeedInfos map[Validity]map[string]FeedInfo
  246. }
  247. type Context struct {
  248. DataHome string
  249. FeedID string
  250. Version Validity
  251. }