Partially working draft
This commit is contained in:
parent
afb73b70ff
commit
534bc70f0f
27
datasources/mtr/bus/BusStop.go
Normal file
27
datasources/mtr/bus/BusStop.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package bus
|
||||||
|
|
||||||
|
type BusStop struct {
|
||||||
|
RouteId string
|
||||||
|
Direction string
|
||||||
|
StationSeq int
|
||||||
|
StationId string
|
||||||
|
Latitude float64
|
||||||
|
Longtitude float64
|
||||||
|
|
||||||
|
Name *map[string] string
|
||||||
|
RouteStops *map[int] *BusStop
|
||||||
|
}
|
||||||
|
|
||||||
|
func ( busStop BusStop ) PrevStop() *BusStop {
|
||||||
|
if v, hasKey := (*busStop.RouteStops)[ busStop.StationSeq - 1 ]; hasKey {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ( busStop BusStop ) NextStop() *BusStop {
|
||||||
|
if v, hasKey := (*busStop.RouteStops)[ busStop.StationSeq + 1 ]; hasKey {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
48
datasources/mtr/bus/QueryResult.go
Normal file
48
datasources/mtr/bus/QueryResult.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package bus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type QueryResult struct {
|
||||||
|
Schedules *map[BusStop] *BusStopBuses
|
||||||
|
Lang string
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
func ( result QueryResult ) Message() string {
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return fmt.Sprintf( "%s", result.Error )
|
||||||
|
}
|
||||||
|
|
||||||
|
sb := strings.Builder{}
|
||||||
|
|
||||||
|
for busStop, buses := range *result.Schedules {
|
||||||
|
|
||||||
|
if busStop.PrevStop() != nil {
|
||||||
|
sb.WriteString( (*busStop.PrevStop().Name)[ result.Lang ] )
|
||||||
|
sb.WriteString( " > *" )
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.WriteString( (*busStop.Name)[ result.Lang ] )
|
||||||
|
sb.WriteString( "*" )
|
||||||
|
|
||||||
|
if busStop.NextStop() != nil {
|
||||||
|
sb.WriteString( " > " )
|
||||||
|
sb.WriteString( (*busStop.NextStop().Name)[ result.Lang ] )
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.WriteString( "\n" )
|
||||||
|
for _, bus := range buses.Buses {
|
||||||
|
sb.WriteString( " * " )
|
||||||
|
sb.WriteString( bus.ETAText )
|
||||||
|
sb.WriteString( "\n" )
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.WriteString( "\n" )
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
@ -27,14 +27,15 @@ type Bus struct {
|
|||||||
LineRef string `json:"lineRef"`
|
LineRef string `json:"lineRef"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BusStopSchedules struct {
|
type BusStopBuses struct {
|
||||||
Buses [] Bus `json:"bus"`
|
Buses [] Bus `json:"bus"`
|
||||||
|
BusStopId string `json:"busStopId"`
|
||||||
Suspended string `json:"isSuspended"`
|
Suspended string `json:"isSuspended"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BusSchedule struct {
|
type BusSchedule struct {
|
||||||
RefreshTime int `json:"appRefreshTimeInSecond,string"`
|
RefreshTime int `json:"appRefreshTimeInSecond,string"`
|
||||||
BusStops [] BusStopSchedules `json:"busStop"`
|
BusStops [] BusStopBuses `json:"busStop"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSchedule( lang string, routeName string ) ( *BusSchedule, error ) {
|
func getSchedule( lang string, routeName string ) ( *BusSchedule, error ) {
|
||||||
|
@ -12,19 +12,6 @@ import (
|
|||||||
"github.com/tgckpg/golifehk/utils"
|
"github.com/tgckpg/golifehk/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BusStop struct {
|
|
||||||
RouteId string
|
|
||||||
Direction string
|
|
||||||
StationSeq string
|
|
||||||
StationId string
|
|
||||||
Latitude float64
|
|
||||||
Longtitude float64
|
|
||||||
Name_zhant string
|
|
||||||
Name_en string
|
|
||||||
}
|
|
||||||
|
|
||||||
var mBusStops *map[string]BusStop
|
|
||||||
|
|
||||||
var CSV_BUSSTOPS string = filepath.Join( utils.WORKDIR, "mtr_bus_stops.csv" )
|
var CSV_BUSSTOPS string = filepath.Join( utils.WORKDIR, "mtr_bus_stops.csv" )
|
||||||
|
|
||||||
func readBusStopData( r io.Reader ) ( *map[string]BusStop, error ) {
|
func readBusStopData( r io.Reader ) ( *map[string]BusStop, error ) {
|
||||||
@ -36,6 +23,8 @@ func readBusStopData( r io.Reader ) ( *map[string]BusStop, error ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
busStops := map[string]BusStop{}
|
busStops := map[string]BusStop{}
|
||||||
|
routeStops := map[string] map[string] map[int] *BusStop{}
|
||||||
|
|
||||||
var headers []string
|
var headers []string
|
||||||
for i, line := range entries {
|
for i, line := range entries {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
@ -45,6 +34,8 @@ func readBusStopData( r io.Reader ) ( *map[string]BusStop, error ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var entry BusStop
|
var entry BusStop
|
||||||
|
i18n_Name := map[string] string{}
|
||||||
|
|
||||||
for j, value := range line {
|
for j, value := range line {
|
||||||
switch headers[j] {
|
switch headers[j] {
|
||||||
case "ROUTE_ID":
|
case "ROUTE_ID":
|
||||||
@ -52,7 +43,8 @@ func readBusStopData( r io.Reader ) ( *map[string]BusStop, error ) {
|
|||||||
case "DIRECTION":
|
case "DIRECTION":
|
||||||
entry.Direction = value
|
entry.Direction = value
|
||||||
case "STATION_SEQNO":
|
case "STATION_SEQNO":
|
||||||
entry.StationSeq = value
|
v, _ := strconv.Atoi( value )
|
||||||
|
entry.StationSeq = v
|
||||||
case "STATION_ID":
|
case "STATION_ID":
|
||||||
entry.StationId = value
|
entry.StationId = value
|
||||||
case "STATION_LATITUDE":
|
case "STATION_LATITUDE":
|
||||||
@ -62,9 +54,9 @@ func readBusStopData( r io.Reader ) ( *map[string]BusStop, error ) {
|
|||||||
v, _ := strconv.ParseFloat( value, 64 )
|
v, _ := strconv.ParseFloat( value, 64 )
|
||||||
entry.Longtitude = v
|
entry.Longtitude = v
|
||||||
case "STATION_NAME_CHI":
|
case "STATION_NAME_CHI":
|
||||||
entry.Name_zhant = value
|
i18n_Name["zh"] = value
|
||||||
case "STATION_NAME_ENG":
|
case "STATION_NAME_ENG":
|
||||||
entry.Name_en = value
|
i18n_Name["en"] = value
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf( "Unknown header \"%s\"", headers[j] )
|
return nil, fmt.Errorf( "Unknown header \"%s\"", headers[j] )
|
||||||
}
|
}
|
||||||
@ -74,6 +66,26 @@ func readBusStopData( r io.Reader ) ( *map[string]BusStop, error ) {
|
|||||||
return nil, fmt.Errorf( "Duplicated entry %+v", entry )
|
return nil, fmt.Errorf( "Duplicated entry %+v", entry )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
routeDir, hasKey := routeStops[ entry.RouteId ]
|
||||||
|
if !hasKey {
|
||||||
|
routeStops[ entry.RouteId ] = map[string] map[int] *BusStop{}
|
||||||
|
routeDir = routeStops[ entry.RouteId ]
|
||||||
|
}
|
||||||
|
|
||||||
|
route, hasKey := routeDir[ entry.Direction ]
|
||||||
|
if !hasKey {
|
||||||
|
routeDir[ entry.Direction ] = map[int] *BusStop{}
|
||||||
|
route = routeDir[ entry.Direction ]
|
||||||
|
}
|
||||||
|
|
||||||
|
_, hasKey = route[ entry.StationSeq ]
|
||||||
|
if !hasKey {
|
||||||
|
route[ entry.StationSeq ] = &entry
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Name = &i18n_Name
|
||||||
|
entry.RouteStops = &route
|
||||||
|
|
||||||
busStops[ entry.StationId ] = entry
|
busStops[ entry.StationId ] = entry
|
||||||
}
|
}
|
||||||
return &busStops, nil
|
return &busStops, nil
|
||||||
|
@ -1,41 +1,68 @@
|
|||||||
package bus
|
package bus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"github.com/tgckpg/golifehk/utils"
|
"github.com/tgckpg/golifehk/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type QueryObject struct {
|
type queryObj struct {
|
||||||
Route string
|
Route string
|
||||||
BusStops *[]BusStop
|
BusStops *[]BusStop
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueryResult struct {
|
type qTerm struct {
|
||||||
BusStops []BusStop
|
|
||||||
err string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Term struct {
|
|
||||||
Value string
|
Value string
|
||||||
ProblyRoute bool
|
ProblyRoute bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func Query( message string ) *QueryResult {
|
func Query( lang string, message string ) *QueryResult {
|
||||||
return &QueryResult{ err: "No Result" }
|
|
||||||
|
qo, err := parse( message )
|
||||||
|
if err != nil {
|
||||||
|
return &QueryResult{ Error: err }
|
||||||
|
}
|
||||||
|
|
||||||
|
if qo.Route != "" {
|
||||||
|
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" ) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func test( entry BusStop, val string ) bool {
|
func test( entry BusStop, val string ) bool {
|
||||||
switch true {
|
switch true {
|
||||||
case strings.Contains( entry.Name_zhant, val ):
|
case strings.Contains( (*entry.Name)["zh"], val ):
|
||||||
fallthrough
|
fallthrough
|
||||||
case strings.Contains( entry.Name_en, val ):
|
case strings.Contains( (*entry.Name)["en"], val ):
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func parse( line string ) ( *QueryObject, error ) {
|
func parse( line string ) ( *queryObj, error ) {
|
||||||
busStops, err := getBusStops()
|
busStops, err := getBusStops()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -47,10 +74,10 @@ func parse( line string ) ( *QueryObject, error ) {
|
|||||||
matches := []BusStop{}
|
matches := []BusStop{}
|
||||||
|
|
||||||
// Sanitize and assume properties for each of the keywords
|
// Sanitize and assume properties for each of the keywords
|
||||||
terms := []Term{}
|
terms := []qTerm{}
|
||||||
for _, val := range strings.Split( line, " " ) {
|
for _, val := range strings.Split( line, " " ) {
|
||||||
val = strings.ToUpper( strings.Trim( val, " " ) )
|
val = strings.ToUpper( strings.Trim( val, " " ) )
|
||||||
term := Term{
|
term := qTerm{
|
||||||
Value: val,
|
Value: val,
|
||||||
ProblyRoute: strings.ContainsAny( val, utils.ROUTE_CHARS ),
|
ProblyRoute: strings.ContainsAny( val, utils.ROUTE_CHARS ),
|
||||||
}
|
}
|
||||||
@ -99,5 +126,5 @@ func parse( line string ) ( *QueryObject, error ) {
|
|||||||
matches = matches_in
|
matches = matches_in
|
||||||
}
|
}
|
||||||
|
|
||||||
return &QueryObject{ Route: route, BusStops: &matches }, err
|
return &queryObj{ Route: route, BusStops: &matches }, err
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestQuerySchedule(t *testing.T) {
|
func TestQuerySchedule( t *testing.T ) {
|
||||||
qo, err := parse( "K74 天瑞" )
|
qo := Query( "zh", "K73 池" )
|
||||||
if err != nil {
|
|
||||||
t.Error( err )
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf( "%+v", qo )
|
fmt.Print( qo.Message() )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user