penguin/golifehk

@golifehk bot in Telegram

datasources/mtr/bus/query.go

raw ยท 2523 bytes

package bus

import (
    "fmt"
    "strings"
    "github.com/tgckpg/golifehk/utils"
)

type QueryObject struct {
    Route string
    BusStops *[]BusStop
}

type QueryResult struct {
    BusStops []BusStop
    err string
}

type Term struct {
    Value string
    ProblyRoute bool
}

func Query( message string ) *QueryResult {
    return &QueryResult{ err: "No Result" }
}

func test( entry BusStop, val string ) bool {
    switch true {
    case strings.Contains( entry.Name_zhant, val ):
        fallthrough
    case strings.Contains( 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 = ""
    var searches = []string{}
    matches := []BusStop{}

    // Sanitize and assume properties for each of the keywords
    terms := []Term{}
    for _, val := range strings.Split( line, " " ) {
        val = strings.ToUpper( strings.Trim( val, " " ) )
        term := Term{
            Value: 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 
            }

            searches = append( searches, term.Value )
            if test( entry, term.Value ) {
                matches = append( matches, entry )
                break
            }
        }
    }

    // If route found, filter out all other route
    // then search within that route
    if route != "" && 0 < len( searches ) {
        matches_in := []BusStop{}
        for _, entry := range matches {
            if entry.RouteId != route {
                continue
            }

            for _, val := range searches {
                if test( entry, val ) {
                    matches_in = append( matches_in, entry )
                    break
                }
            }
        }
        matches = matches_in
    }

    return &QueryObject{ Route: route, BusStops: &matches }, err
}