Added kmb and refactored query.Parse

This commit is contained in:
2022-09-17 04:33:47 +08:00
parent 292665c49b
commit 3376d9eb96
21 changed files with 762 additions and 241 deletions

View File

@@ -1,76 +1,44 @@
package bus
import (
"errors"
"fmt"
"strings"
"github.com/tgckpg/golifehk/utils"
query "github.com/tgckpg/golifehk/query"
)
type qTerm struct {
Org string
Value string
ProblyRoute bool
}
func Query( lang string, message string ) query.IQueryResult {
type QueryObject struct {
Route string
BusStops *[]BusStop
RouteStarts *map[string] *BusStop
SearchTerms *[] *qTerm
}
func NotFound ( terms *[] *qTerm ) string {
sb := strings.Builder{}
sb.WriteString( "Not Found" )
if 0 < len( *terms ) {
sb.WriteString( ":" )
for _, term := range *terms {
sb.WriteString( " \"" )
sb.WriteString( term.Org )
sb.WriteString( "\"" )
}
}
return sb.String()
}
func Query( lang string, message string ) *QueryResult {
var qBusStops *query.QueryObject
var err error
qr := QueryResult{ Lang: lang }
qo, err := parse( message )
busStops, err := getBusStops()
if err != nil {
qr.Error = err
return &qr
goto qrReturn
}
qr.Query = qo
qBusStops, err = query.Parse( strings.ToUpper( message ), busStops )
if err != nil {
qr.Error = err
goto qrReturn
}
if qo.Route != "" {
if qo.BusStops == nil {
return &qr
}
if len( *qo.BusStops ) == 0 {
qr.Error = errors.New( NotFound( qo.SearchTerms ) )
return &qr
}
schedules, err := getSchedule( lang, qo.Route )
qr.Query = qBusStops
if 0 < len( *qBusStops.Results ) && 1 < len( *qBusStops.SearchTerms ) {
schedules, err := getSchedule( lang, qBusStops.Key )
if err != nil {
qr.Error = err
return &qr
goto qrReturn
}
if len( schedules.BusStops ) == 0 {
qr.Schedules = &map[BusStop] *BusStopBuses{}
return &qr
qr.Schedules = &map[*BusStop] *BusStopBuses{}
goto qrReturn
}
matches := map[BusStop] *BusStopBuses{}
for _, busStop := range *qo.BusStops {
matches := map[*BusStop] *BusStopBuses{}
for _, entry := range *qBusStops.Results {
busStop := any( entry ).( *BusStop )
for _, busStopSch := range schedules.BusStops {
if busStopSch.BusStopId == busStop.StationId {
@@ -82,131 +50,10 @@ func Query( lang string, message string ) *QueryResult {
}
qr.Schedules = &matches
return &qr
} else {
if len( *qo.BusStops ) == 0 {
return &QueryResult{ Error: errors.New( NotFound( qo.SearchTerms ) ) }
}
return &qr
}
}
func test( entry BusStop, val string ) bool {
switch true {
case strings.Contains( strings.ToUpper( (*entry.Name)["zh"] ), val ):
fallthrough
case strings.Contains( strings.ToUpper( (*entry.Name)["en"] ), val ):
return true
}
return false
}
func parse( line string ) ( *QueryObject, error ) {
busStops, err := getBusStops()
if err != nil {
return nil, err
}
var route string = ""
matches := []BusStop{}
// Sanitize and assume properties for each of the keywords
terms := [] *qTerm{}
for _, val := range strings.Split( line, " " ) {
if val == "" {
continue
}
term := qTerm{
Org: val,
Value: strings.ToUpper( strings.Trim( val, " " ) ),
ProblyRoute: strings.ContainsAny( val, utils.ROUTE_CHARS ),
}
terms = append( terms, &term )
}
// Search for route name first, otherwise search in other props
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
}
if test( entry, term.Value ) {
matches = append( matches, entry )
break
}
}
}
searchTerms := [] *qTerm{}
matches_in := []BusStop{}
for _, term := range terms {
if term.ProblyRoute {
continue
}
searchTerms = append( searchTerms, term )
}
if 0 < len( searchTerms ) {
// If route found, filter out all other route
// then search the terms within that route
for _, entry := range matches {
if route != "" && entry.RouteId != route {
continue
}
for _, term := range searchTerms {
if test( entry, term.Value ) {
matches_in = append( matches_in, entry )
break
}
}
}
matches = matches_in
return &QueryObject{
Route: route,
BusStops: &matches,
SearchTerms: &searchTerms,
}, err
} else if route != "" {
// Route listing
st := map[string] *BusStop{}
for _, entry := range *busStops {
if entry.RouteId != route {
continue
}
if _, ok := st[ entry.Direction ]; ok {
continue
}
st[ entry.Direction ] = &entry
for st[ entry.Direction ].PrevStop() != nil {
st[ entry.Direction ] = st[ entry.Direction ].PrevStop()
}
}
return &QueryObject{ Route: route, RouteStarts: &st, BusStops: nil }, nil
}
return nil, fmt.Errorf( "Cannot parse: %s", line )
qrReturn:
var iqr query.IQueryResult
iqr = &qr
return iqr
}