123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- // SPDX-FileCopyrightText: Adam Evyčędo
- //
- // SPDX-License-Identifier: AGPL-3.0-or-later
- package traffic
- import (
- "fmt"
- "strings"
- "time"
- "github.com/dhconnelly/rtreego"
- "golang.org/x/text/language"
- )
- type DeparturesType uint8
- const (
- DEPARTURES_HYBRID DeparturesType = iota
- DEPARTURES_FULL
- )
- const ZWJ = "\u200d"
- func LuaAlertToAlert(luaAlert AlertLua) (Alert, error) {
- resultAlert := Alert{
- TimeRanges: make([][2]time.Time, len(luaAlert.TimeRanges)),
- Headers: map[language.Tag]string{},
- Descriptions: map[language.Tag]string{},
- URLs: map[language.Tag]string{},
- Cause: AlertCause(luaAlert.Cause),
- Effect: AlertEffect(luaAlert.Effect),
- }
- for i, r := range luaAlert.TimeRanges {
- start, err := time.Parse("2006-01-02T15:04:05.999Z07:00", r.StartDate)
- if err != nil {
- return Alert{}, fmt.Errorf("error parsing time for range %s: %w", r.StartDate, err)
- }
- end, err := time.Parse("2006-01-02T15:04:05.999Z07:00", r.EndDate)
- if err != nil {
- return Alert{}, fmt.Errorf("error parsing time for range %s: %w", r.EndDate, err)
- }
- resultAlert.TimeRanges[i] = [2]time.Time{start, end}
- }
- for l, header := range luaAlert.Headers {
- tag, err := language.Parse(l)
- if err != nil {
- return Alert{}, fmt.Errorf("error parsing tag %s: %w", l, err)
- }
- resultAlert.Headers[tag] = header
- }
- for l, description := range luaAlert.Descriptions {
- tag, err := language.Parse(l)
- if err != nil {
- return Alert{}, fmt.Errorf("error parsing tag %s: %w", l, err)
- }
- resultAlert.Descriptions[tag] = description
- }
- for l, url := range luaAlert.Urls {
- tag, err := language.Parse(l)
- if err != nil {
- return Alert{}, fmt.Errorf("error parsing tag %s: %w", l, err)
- }
- resultAlert.URLs[tag] = url
- }
- return resultAlert, nil
- }
- func (v VehicleStatus) Location() Position {
- return Position{
- Lat: v.Latitude,
- Lon: v.Longitude,
- }
- }
- func (k LineType) Value() uint {
- return uint(k)
- }
- func (d Direction) Value() uint {
- return uint(d)
- }
- type DepartureRealtime struct {
- Time time.Time
- Departure Departure
- Headsign string
- LineID string
- Order StopOrder
- Update Update
- Alerts []SpecificAlert
- }
- func (d DepartureRealtime) WithUpdate(update Update) DepartureRealtime {
- d.Update = update
- return d
- }
- func (d DepartureRealtime) WithAlerts(alerts []Alert, languages []language.Tag) DepartureRealtime {
- d.Alerts = selectSpecificAlerts(alerts, languages)
- return d
- }
- func selectSpecificAlerts(alerts []Alert, languages []language.Tag) []SpecificAlert {
- now := time.Now()
- validAlerts := []SpecificAlert{}
- for _, alert := range alerts {
- timeValid := len(alert.TimeRanges) == 0
- for _, timeRange := range alert.TimeRanges {
- if now.After(timeRange[0]) && now.Before(timeRange[1]) {
- timeValid = true
- break
- }
- }
- if !timeValid {
- continue
- }
- headerLanguages := make([]language.Tag, len(alert.Headers))
- i := 0
- for l := range alert.Headers {
- headerLanguages[i] = l
- i++
- }
- headerMatcher := language.NewMatcher(headerLanguages)
- ht, _, _ := headerMatcher.Match(languages...)
- descriptionLanguages := make([]language.Tag, len(alert.Descriptions))
- i = 0
- for l := range alert.Descriptions {
- descriptionLanguages[i] = l
- i++
- }
- descriptionMatcher := language.NewMatcher(descriptionLanguages)
- dt, _, _ := descriptionMatcher.Match(languages...)
- URLLanguages := make([]language.Tag, len(alert.URLs))
- i = 0
- for l := range alert.URLs {
- URLLanguages[i] = l
- i++
- }
- URLMatcher := language.NewMatcher(URLLanguages)
- ut, _, _ := URLMatcher.Match(languages...)
- validAlerts = append(validAlerts, SpecificAlert{
- Header: alert.Headers[ht],
- Description: alert.Descriptions[dt],
- URL: alert.URLs[ut],
- Cause: alert.Cause,
- Effect: alert.Effect,
- })
- }
- return validAlerts
- }
- func (g LineGraph) LastNodes() []int {
- lastNodes := []int{}
- for i, nextNodes := range g.NextNodes {
- for _, node := range nextNodes {
- if node == -1 {
- lastNodes = append(lastNodes, i)
- break
- }
- }
- }
- return lastNodes
- }
- type LineStub struct {
- Name string
- Colour string
- Type string
- }
- func (l Line) DisplayName() string {
- return l.Name
- }
- func (l Line) IsItem() {}
- type Shape struct { // todo(BAF11)
- Points []Position
- }
- type Queryable interface {
- IsItem()
- DisplayName() string
- }
- type Locatable interface {
- Location() Position
- }
- func (s Stop) DisplayName() string {
- return s.Name
- }
- func (s Stop) Location() Position {
- return s.Position
- }
- func (s Stop) Bounds() *rtreego.Rect {
- rect, err := rtreego.NewRectFromPoints(
- rtreego.Point{s.Position.Lat, s.Position.Lon},
- rtreego.Point{s.Position.Lat, s.Position.Lon},
- )
- if err != nil {
- panic(err.Error())
- }
- return rect
- }
- func (s Stop) IsItem() {}
- type TimedStopStub struct {
- StopStub
- Time uint
- }
- type StopStub struct {
- Code string
- Name string
- NodeName string
- Zone string
- OnDemand bool
- }
- type Validity string // 20060102_20060102
- func (v Validity) Start() string {
- return strings.Split(string(v), "_")[0]
- }
- func (v Validity) End() string {
- return strings.Split(string(v), "_")[1]
- }
- type FeedCodeIndex map[Validity]CodeIndex
- type GlobalCodeIndex map[string]FeedCodeIndex
- type NameIndex []NameOffset
- type FeedNameIndex map[Validity]NameIndex
- type GlobalNameIndex map[string]FeedNameIndex
- func (ix NameIndex) String(i int) string {
- return ix[i].Name
- }
- func (ix NameIndex) Len() int {
- return len(ix)
- }
- type FeedCalendar map[Validity][]Schedule
- type GlobalCalendar map[string]FeedCalendar
- type Vehicles map[string]Vehicle
- type FeedVehicles map[Validity]Vehicles
- type GlobalVehicles map[string]FeedVehicles
- type FeedPositionIndex map[Validity]*rtreego.Rtree
- type GlobalPositionIndex map[string]FeedPositionIndex
- type Version struct {
- Link string
- ValidFrom time.Time
- ValidTill time.Time
- }
- func (v Version) String() string {
- return v.ValidFrom.Format(ValidityFormat) + "_" + v.ValidTill.Format(ValidityFormat)
- }
- type GlobalVersions map[string][]Version
- var DateFormat string = "2006-01-02"
- var DateTimeFormat string = "2006-01-02T15:04:05-07:00"
- var ValidityFormat string = "20060102"
- var ValidityFormatExtended string = "20060102150405"
- type Traffic struct {
- CodeIndexes GlobalCodeIndex
- NameIndexes GlobalNameIndex
- LineIdIndexes GlobalCodeIndex
- LineIndexes GlobalNameIndex
- TripIndexes GlobalNameIndex
- PositionIndexes GlobalPositionIndex
- Versions GlobalVersions
- Calendars GlobalCalendar
- Vehicles GlobalVehicles
- Feeds map[string]Feed
- FeedInfos map[Validity]map[string]FeedInfo
- }
- type Context struct {
- DataHome string
- FeedID string
- Version Validity
- }
|