golifehk/datasources/mtr/bus/query.go

140 lines
3.5 KiB
Go
Raw Normal View History

2022-09-14 09:12:48 +00:00
package bus
2022-09-13 13:42:51 +00:00
import (
2022-09-14 13:21:39 +00:00
"errors"
2022-09-13 13:42:51 +00:00
"fmt"
"strings"
"github.com/tgckpg/golifehk/utils"
)
2022-09-14 13:21:39 +00:00
type queryObj struct {
2022-09-13 13:42:51 +00:00
Route string
2022-09-14 09:12:48 +00:00
BusStops *[]BusStop
2022-09-14 14:54:51 +00:00
Search string
2022-09-14 09:12:48 +00:00
}
2022-09-14 13:21:39 +00:00
type qTerm struct {
2022-09-13 13:42:51 +00:00
Value string
ProblyRoute bool
}
2022-09-14 13:21:39 +00:00
func Query( lang string, message string ) *QueryResult {
qo, err := parse( message )
if err != nil {
return &QueryResult{ Error: err }
}
if qo.Route != "" {
2022-09-14 14:54:51 +00:00
if len( *qo.BusStops ) == 0 {
return &QueryResult{ Error: errors.New( "Result not found" ) }
}
2022-09-14 13:21:39 +00:00
schedules, err := getSchedule( lang, qo.Route )
if err != nil {
return &QueryResult{ Error: err }
}
if len( schedules.BusStops ) == 0 {
return &QueryResult{ Error: errors.New( "Schedules are empty. Maybe outside service time?" ) }
}
matches := map[BusStop] *BusStopBuses{}
for _, busStop := range *qo.BusStops {
for _, busStopSch := range schedules.BusStops {
if busStopSch.BusStopId == busStop.StationId {
matches[busStop] = &busStopSch
break
}
}
}
return &QueryResult{ Lang: lang, Schedules: &matches }
}
return &QueryResult{ Error: errors.New( "No Result" ) }
2022-09-14 09:12:48 +00:00
}
2022-09-13 13:42:51 +00:00
func test( entry BusStop, val string ) bool {
switch true {
2022-09-14 14:54:51 +00:00
case strings.Contains( strings.ToUpper( (*entry.Name)["zh"] ), val ):
2022-09-13 13:42:51 +00:00
fallthrough
2022-09-14 14:54:51 +00:00
case strings.Contains( strings.ToUpper( (*entry.Name)["en"] ), val ):
2022-09-13 13:42:51 +00:00
return true
}
return false
}
2022-09-14 13:21:39 +00:00
func parse( line string ) ( *queryObj, error ) {
2022-09-13 13:42:51 +00:00
busStops, err := getBusStops()
if err != nil {
return nil, err
}
var route string = ""
var searches = []string{}
matches := []BusStop{}
2022-09-14 09:12:48 +00:00
// Sanitize and assume properties for each of the keywords
2022-09-14 13:21:39 +00:00
terms := []qTerm{}
2022-09-13 13:42:51 +00:00
for _, val := range strings.Split( line, " " ) {
val = strings.ToUpper( strings.Trim( val, " " ) )
2022-09-14 13:21:39 +00:00
term := qTerm{
2022-09-13 13:42:51 +00:00
Value: val,
ProblyRoute: strings.ContainsAny( val, utils.ROUTE_CHARS ),
}
terms = append( terms, term )
}
2022-09-14 09:12:48 +00:00
// Search for route name first, otherwise search in other props
2022-09-13 13:42:51 +00:00
for _, entry := range *busStops {
// Search for RouteId
for _, term := range terms {
if term.ProblyRoute && term.Value == entry.RouteId {
if route != "" && route != term.Value {
return nil, fmt.Errorf( "Cannot %s & %s", route, term.Value )
}
matches = append( matches, entry )
route = entry.RouteId
break
}
searches = append( searches, term.Value )
if test( entry, term.Value ) {
matches = append( matches, entry )
break
}
}
}
2022-09-14 09:12:48 +00:00
// If route found, filter out all other route
// then search within that route
2022-09-14 14:54:51 +00:00
if route != "" {
if 0 < len( searches ) {
matches_in := []BusStop{}
for _, entry := range matches {
if entry.RouteId != route {
continue
}
2022-09-13 13:42:51 +00:00
2022-09-14 14:54:51 +00:00
for _, val := range searches {
if test( entry, val ) {
matches_in = append( matches_in, entry )
break
}
2022-09-13 13:42:51 +00:00
}
}
2022-09-14 14:54:51 +00:00
matches = matches_in
} else {
2022-09-13 13:42:51 +00:00
}
}
2022-09-14 13:21:39 +00:00
return &queryObj{ Route: route, BusStops: &matches }, err
2022-09-13 13:42:51 +00:00
}