Partially working draft
This commit is contained in:
		
							
								
								
									
										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() )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user