penguin/golifehk

@golifehk bot in Telegram

datasources/kmb/routestops.go

raw ยท 4077 bytes

package kmb

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "path/filepath"
    // "strings"

    query "github.com/tgckpg/golifehk/query"
    "github.com/tgckpg/golifehk/utils"
)

var JSON_ROUTESTOPS string = filepath.Join( utils.WORKDIR, "kmb-routestops.json" )
var JSON_BUSSTOPS string = filepath.Join( utils.WORKDIR, "kmb-busstops.json" )

func readRouteStopsData( busStops *map[string] *BusStop, buff *bytes.Buffer ) ( *[] *RouteStop, error ) {

    routeStopsData := RouteStops{}
    err := json.Unmarshal( buff.Bytes(), &routeStopsData )
    if err != nil {
        return nil, err
    }

    // routeStops[ Route ][ ServiceType ][ Direction ][ Seq ] = RouteStop
    routeStops := map[string] *map[string] *map[ string ] *map[ int ] *RouteStop{}
    allRouteStops := [] *RouteStop{}

    for _, entry := range routeStopsData.RouteStops {

        busStop := (*busStops)[ entry.StationId ]
        if busStop == nil {
            busStop = &BusStop {
                BusStopId: entry.StationId,
                Name_en: "???", Name_tc: "???", Name_sc: "???",
            }
            busStop.Reload()

            (*busStops)[ entry.StationId ] = busStop
        }

        if busStop.Routes == nil {
            busStopRoutes := [] *RouteStop{}
            busStop.Routes = &busStopRoutes
        }

        (*busStop.Routes) = append( (*busStop.Routes), entry )
        entry.BusStop = busStop

        route := routeStops[ entry.RouteId ]
        if route == nil {
            route = &map[string] *map[ string ] *map[ int ] *RouteStop{} 
            routeStops[ entry.RouteId ] = route
        }

        service := (*route)[ entry.ServiceType ]
        if service == nil {
            service = &map[ string ] *map[ int ] *RouteStop{}
            (*route)[ entry.ServiceType ] = service
        }

        direction := (*service)[ entry.Direction ]
        if direction == nil {
            direction = &map[ int ] *RouteStop{}
            (*service)[ entry.Direction ] = direction
        }
        entry.RouteStops = direction

        seq := (*direction)[ entry.StationSeq ]
        if seq == nil {
            (*direction)[ entry.StationSeq ] = entry
        }
        allRouteStops = append( allRouteStops, entry )
    }

    return &allRouteStops, nil
}

func readBusStopsData( buff *bytes.Buffer ) ( *map[string]*BusStop, error ) {
    busStopsData := BusStops{}
    err := json.Unmarshal( buff.Bytes(), &busStopsData )
    if err != nil {
        return nil, err
    }

    busStopMap := map[string] *BusStop{}
    for _, entry := range busStopsData.BusStops {

        entry.Reload()

        if _, ok := busStopMap[ entry.BusStopId ]; ok {
            return nil, fmt.Errorf( "Duplicated BusStop: %s", entry.BusStopId )
        }

        busStopMap[ entry.BusStopId ] = entry
    }
    return &busStopMap, nil
}

func getRouteStops() (*[] query.ISearchable, error) {

    QUERY_FUNC := func() ( io.ReadCloser, error ) {
        resp, err := http.Get( "https://data.etabus.gov.hk/v1/transport/kmb/stop" )
        if err != nil {
            return nil, err
        }
        return resp.Body, nil
    }

    buff, err := utils.CacheStream( JSON_BUSSTOPS, QUERY_FUNC, 7 * 24 * 3600 )
    if err != nil {
        return nil, err
    }

    busStopMap, err := readBusStopsData( buff )
    if err != nil {
        return nil, err
    }

    QUERY_FUNC = func() ( io.ReadCloser, error ) {
        resp, err := http.Get( "https://data.etabus.gov.hk/v1/transport/kmb/route-stop" )
        if err != nil {
            return nil, err
        }
        return resp.Body, nil
    }

    buff, err = utils.CacheStream( JSON_ROUTESTOPS, QUERY_FUNC, 7 * 24 * 3600 )
    if err != nil {
        return nil, err
    }

    routeStops, err := readRouteStopsData( busStopMap, buff )
    if err != nil {
        return nil, err
    }

    searchables := [] query.ISearchable{}
    for _, routeStop := range *routeStops {
        searchables = append( searchables, routeStop )
        routeStop.Reload()
    }

    return &searchables, nil
}