commit 89770c0864fc1644c17df3573049bc44adc85881
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2022-09-15T12:00:49Z |
| subject | Support route listing & search |
commit 89770c0864fc1644c17df3573049bc44adc85881
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2022-09-15T12:00:49Z
Support route listing & search
---
datasources/mtr/bus/QueryResult.go | 84 ++++++++++++++++------
datasources/mtr/bus/query.go | 143 ++++++++++++++++++++++++++++---------
datasources/mtr/bus/query_test.go | 2 +-
3 files changed, 173 insertions(+), 56 deletions(-)
diff --git a/datasources/mtr/bus/QueryResult.go b/datasources/mtr/bus/QueryResult.go
index fd45f6f..a6286d5 100644
--- a/datasources/mtr/bus/QueryResult.go
+++ b/datasources/mtr/bus/QueryResult.go
@@ -2,6 +2,7 @@ package bus
import (
"fmt"
+ "sort"
"strings"
)
@@ -9,8 +10,33 @@ type QueryResult struct {
Schedules *map[BusStop] *BusStopBuses
Lang string
Error error
+ Query *QueryObject
}
+func writeShortRoute( lang *string, sb *strings.Builder, b *BusStop ) {
+ if b.PrevStop() != nil {
+ sb.WriteString( (*b.PrevStop().Name)[ *lang ] )
+ sb.WriteString( " > " )
+ }
+
+ sb.WriteString( "**" )
+ sb.WriteString( (*b.Name)[ *lang ] )
+ sb.WriteString( "**" )
+
+ if b.NextStop() != nil {
+ sb.WriteString( " > " )
+ sb.WriteString( (*b.NextStop().Name)[ *lang ] )
+ }
+
+ sb.WriteString( "\n" )
+}
+
+type ByRouteId []BusStop
+
+func (a ByRouteId) Len() int { return len(a) }
+func (a ByRouteId) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a ByRouteId) Less(i, j int) bool { return a[i].RouteId < a[j].RouteId }
+
func ( result QueryResult ) Message() string {
if result.Error != nil {
@@ -19,33 +45,51 @@ func ( result QueryResult ) Message() string {
sb := strings.Builder{}
- for busStop, buses := range *result.Schedules {
+ if result.Schedules == nil {
- if busStop.PrevStop() != nil {
- sb.WriteString( (*busStop.PrevStop().Name)[ result.Lang ] )
- sb.WriteString( " > *" )
- }
+ query := *result.Query
+ if query.Route == "" {
+ sort.Sort( ByRouteId( *query.BusStops ) )
+ for _, busStop := range *query.BusStops {
+ sb.WriteString( busStop.RouteId )
+ sb.WriteString( " " )
+ writeShortRoute( &result.Lang, &sb, &busStop )
+ }
+ } else if query.BusStops == nil && query.RouteStarts != nil {
+ for d, b := range *query.RouteStarts {
+ sb.WriteString( query.Route )
+ sb.WriteString( "-" )
+ sb.WriteString( d )
+ sb.WriteString( "\n " )
- sb.WriteString( (*busStop.Name)[ result.Lang ] )
- sb.WriteString( "*" )
+ for {
+ sb.WriteString( (*b.Name)[ result.Lang ] )
+ b = b.NextStop()
+ if b == nil {
+ break
+ }
- if busStop.NextStop() != nil {
- sb.WriteString( " > " )
- sb.WriteString( (*busStop.NextStop().Name)[ result.Lang ] )
+ sb.WriteString( " > " )
+ }
+ sb.WriteString( "\n" )
+ }
+ } else {
+ sb.WriteString( "Unreachable condition occured!?" )
}
-
- sb.WriteString( "\n" )
- for _, bus := range buses.Buses {
- sb.WriteString( " * " )
- if bus.ETAText == "" {
- sb.WriteString( bus.ETDText )
- } else {
- sb.WriteString( bus.ETAText )
+ } else {
+ for busStop, buses := range *result.Schedules {
+ writeShortRoute( &result.Lang, &sb, &busStop )
+ for _, bus := range buses.Buses {
+ sb.WriteString( " * " )
+ if bus.ETAText == "" {
+ sb.WriteString( bus.ETDText )
+ } else {
+ sb.WriteString( bus.ETAText )
+ }
+ sb.WriteString( "\n" )
}
sb.WriteString( "\n" )
}
-
- sb.WriteString( "\n" )
}
return sb.String()
diff --git a/datasources/mtr/bus/query.go b/datasources/mtr/bus/query.go
index a3a7a8b..ccb4941 100644
--- a/datasources/mtr/bus/query.go
+++ b/datasources/mtr/bus/query.go
@@ -7,37 +7,66 @@ import (
"github.com/tgckpg/golifehk/utils"
)
-type queryObj struct {
+type qTerm struct {
+ Org string
+ Value string
+ ProblyRoute bool
+}
+
+type QueryObject struct {
Route string
BusStops *[]BusStop
- Search string
+ RouteStarts *map[string] *BusStop
+ SearchTerms *[] *qTerm
}
-type qTerm struct {
- Value string
- ProblyRoute bool
+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 {
+ qr := QueryResult{ Lang: lang }
+
qo, err := parse( message )
if err != nil {
- return &QueryResult{ Error: err }
+ qr.Error = err
+ return &qr
}
+ qr.Query = qo
+
if qo.Route != "" {
+ if qo.BusStops == nil {
+ return &qr
+ }
+
if len( *qo.BusStops ) == 0 {
- return &QueryResult{ Error: errors.New( "Result not found" ) }
+ qr.Error = errors.New( NotFound( qo.SearchTerms ) )
+ return &qr
}
schedules, err := getSchedule( lang, qo.Route )
if err != nil {
- return &QueryResult{ Error: err }
+ qr.Error = err
+ return &qr
}
if len( schedules.BusStops ) == 0 {
- return &QueryResult{ Error: errors.New( "Schedules are empty. Maybe outside service time?" ) }
+ qr.Error = errors.New( "Schedules are empty...perhaps Out of Service Time?" )
+ return &qr
}
matches := map[BusStop] *BusStopBuses{}
@@ -52,10 +81,16 @@ func Query( lang string, message string ) *QueryResult {
}
- return &QueryResult{ Lang: lang, Schedules: &matches }
+ qr.Schedules = &matches
+ return &qr
+ } else {
+ if len( *qo.BusStops ) == 0 {
+ return &QueryResult{ Error: errors.New( NotFound( qo.SearchTerms ) ) }
+ }
+
+ return &qr
}
- return &QueryResult{ Error: errors.New( "No Result" ) }
}
func test( entry BusStop, val string ) bool {
@@ -68,7 +103,7 @@ func test( entry BusStop, val string ) bool {
return false
}
-func parse( line string ) ( *queryObj, error ) {
+func parse( line string ) ( *QueryObject, error ) {
busStops, err := getBusStops()
if err != nil {
@@ -76,18 +111,22 @@ func parse( line string ) ( *queryObj, error ) {
}
var route string = ""
- var searches = []string{}
matches := []BusStop{}
// Sanitize and assume properties for each of the keywords
- terms := []qTerm{}
+ terms := [] *qTerm{}
for _, val := range strings.Split( line, " " ) {
- val = strings.ToUpper( strings.Trim( val, " " ) )
+
+ if val == "" {
+ continue
+ }
+
term := qTerm{
- Value: val,
+ Org: val,
+ Value: strings.ToUpper( strings.Trim( val, " " ) ),
ProblyRoute: strings.ContainsAny( val, utils.ROUTE_CHARS ),
}
- terms = append( terms, term )
+ terms = append( terms, &term )
}
// Search for route name first, otherwise search in other props
@@ -105,7 +144,6 @@ func parse( line string ) ( *queryObj, error ) {
break
}
- searches = append( searches, term.Value )
if test( entry, term.Value ) {
matches = append( matches, entry )
break
@@ -113,27 +151,62 @@ func parse( line string ) ( *queryObj, error ) {
}
}
- // If route found, filter out all other route
- // then search within that route
- if route != "" {
- if 0 < len( searches ) {
- matches_in := []BusStop{}
- for _, entry := range matches {
- if entry.RouteId != route {
- continue
- }
+ searchTerms := [] *qTerm{}
+ matches_in := []BusStop{}
+
+ for _, term := range terms {
+ if term.ProblyRoute {
+ continue
+ }
+ searchTerms = append( searchTerms, term )
+ }
- for _, val := range searches {
- if test( entry, val ) {
- matches_in = append( matches_in, entry )
- break
- }
+ 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
- } else {
}
+
+ 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 &queryObj{ Route: route, BusStops: &matches }, err
+ return nil, fmt.Errorf( "Cannot parse: %s", line )
}
diff --git a/datasources/mtr/bus/query_test.go b/datasources/mtr/bus/query_test.go
index cbea0d1..b1decb2 100644
--- a/datasources/mtr/bus/query_test.go
+++ b/datasources/mtr/bus/query_test.go
@@ -6,7 +6,7 @@ import (
)
func TestQuerySchedule( t *testing.T ) {
- qo := Query( "zh", "K73 池" )
+ qo := Query( "zh", "水" )
fmt.Print( qo.Message() )
}