257 lines
5.7 KiB
Go
257 lines
5.7 KiB
Go
package kmb
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
i18n "github.com/tgckpg/golifehk/i18n"
|
|
query "github.com/tgckpg/golifehk/query"
|
|
utils "github.com/tgckpg/golifehk/utils"
|
|
)
|
|
|
|
type QueryResult struct {
|
|
Schedules *map[*RouteStop]*[]*Schedule
|
|
Lang string
|
|
Error error
|
|
Query *query.QueryObject
|
|
|
|
isConsumed bool
|
|
dataType string
|
|
tableData [][]query.TableCell
|
|
|
|
FallbackNearest int
|
|
NearestRange float64
|
|
}
|
|
|
|
func writeRouteHead(sb *strings.Builder, r *RouteStop) {
|
|
utils.WriteMDv2Text(sb, r.RouteId)
|
|
if r.Direction == "O" {
|
|
sb.WriteString("↑")
|
|
} else if r.Direction == "I" {
|
|
sb.WriteString("↓")
|
|
}
|
|
if r.ServiceType != "1" {
|
|
utils.WriteMDv2Text(sb, utils.ToPower(r.ServiceType))
|
|
}
|
|
}
|
|
|
|
func writeShortRoute(lang *string, sb *strings.Builder, r *RouteStop) {
|
|
|
|
if r.PrevStop() != nil {
|
|
utils.WriteMDv2Text(sb, (*(r.PrevStop().BusStop).Name)[*lang])
|
|
sb.WriteString(" \\> ")
|
|
}
|
|
|
|
sb.WriteString("*")
|
|
utils.WriteMDv2Text(sb, (*(r.BusStop).Name)[*lang])
|
|
sb.WriteString("*")
|
|
|
|
if r.NextStop() != nil {
|
|
sb.WriteString(" \\> ")
|
|
utils.WriteMDv2Text(sb, (*(r.NextStop().BusStop).Name)[*lang])
|
|
}
|
|
|
|
sb.WriteString("\n")
|
|
}
|
|
|
|
func (this QueryResult) DataType() string { return this.dataType }
|
|
func (this QueryResult) Consumed() bool { return this.isConsumed }
|
|
func (this QueryResult) GetTableData() [][]query.TableCell { return this.tableData }
|
|
|
|
func (this *QueryResult) Message() (string, error) {
|
|
|
|
this.dataType = "PlainText"
|
|
|
|
if this.Error != nil {
|
|
return "", this.Error
|
|
}
|
|
|
|
langPack, err := i18n.LoadKeys(this.Lang)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
sb := strings.Builder{}
|
|
|
|
if 0 < len(*this.Query.Results) {
|
|
|
|
// Print Stop Names, then print the list of routes
|
|
if this.Query.Key == "" {
|
|
loc := this.Query.Message.Location
|
|
if loc != nil {
|
|
|
|
this.dataType = "Table"
|
|
|
|
table := [][]query.TableCell{}
|
|
minDist := math.MaxFloat64
|
|
maxDist := -1.0
|
|
|
|
for _, item := range *this.Query.Results {
|
|
b := any(item).(*BusStop)
|
|
|
|
row := []query.TableCell{}
|
|
|
|
bDist := b.Dist(loc.Lat(), loc.Lon())
|
|
if bDist < minDist {
|
|
minDist = bDist
|
|
}
|
|
|
|
if maxDist < bDist {
|
|
maxDist = bDist
|
|
}
|
|
|
|
cell := query.TableCell{
|
|
Name: fmt.Sprintf("%s (%s)", (*b.Name)[this.Lang], i18n.FormatDistance(langPack, bDist)),
|
|
Value: fmt.Sprintf("%s", b.BusStopId),
|
|
}
|
|
row = append(row, cell)
|
|
|
|
for colIndex, r := range *b.Routes {
|
|
if colIndex%6 == 0 {
|
|
table = append(table, row)
|
|
row = []query.TableCell{}
|
|
}
|
|
sb_i := strings.Builder{}
|
|
writeRouteHead(&sb_i, r)
|
|
cell := query.TableCell{
|
|
Name: sb_i.String(),
|
|
Value: fmt.Sprintf("%s %s", r.RouteId, (*b.Name)[this.Lang]),
|
|
}
|
|
row = append(row, cell)
|
|
}
|
|
|
|
table = append(table, row)
|
|
}
|
|
this.tableData = table
|
|
|
|
rangeText := i18n.FormatDistance(langPack, this.NearestRange)
|
|
if maxDist < this.NearestRange {
|
|
utils.WriteMDv2Text(&sb, i18n.DS_KMB_NEAREST_STOPS.Text(langPack, rangeText))
|
|
} else if this.NearestRange < minDist {
|
|
utils.WriteMDv2Text(&sb, i18n.DS_KMB_NO_NEAREST_STOPS.Text(langPack, rangeText, this.FallbackNearest))
|
|
}
|
|
|
|
} else {
|
|
busStops := map[string]*BusStop{}
|
|
for _, item := range *this.Query.Results {
|
|
var r *RouteStop
|
|
r = any(item).(*RouteStop)
|
|
|
|
b := r.BusStop
|
|
if b.Routes == nil {
|
|
continue
|
|
}
|
|
|
|
busStops[b.BusStopId] = b
|
|
}
|
|
|
|
for _, b := range busStops {
|
|
utils.WriteMDv2Text(&sb, (*b.Name)[this.Lang])
|
|
sb.WriteString("\n ")
|
|
for _, route := range *b.Routes {
|
|
writeRouteHead(&sb, route)
|
|
sb.WriteString(" ")
|
|
}
|
|
sb.WriteString("\n")
|
|
}
|
|
}
|
|
|
|
// We got a route key
|
|
} else {
|
|
|
|
// We also got other search keys with 1 < Results
|
|
// Get the ETA for this stop
|
|
if 1 < len(*this.Query.SearchTerms) {
|
|
|
|
now := time.Now()
|
|
for _, item := range *this.Query.Results {
|
|
var r *RouteStop
|
|
r = any(item).(*RouteStop)
|
|
writeRouteHead(&sb, r)
|
|
sb.WriteString("\n")
|
|
writeShortRoute(&this.Lang, &sb, r)
|
|
|
|
noSchedules := true
|
|
|
|
for _, schedule := range *(*this.Schedules)[r] {
|
|
|
|
if !schedule.ETA.IsZero() {
|
|
|
|
_m := schedule.ETA.Sub(now).Minutes()
|
|
|
|
sb.WriteString(" \\* ")
|
|
|
|
eta := i18n.UNITS_MINUTE.Text(langPack, _m)
|
|
|
|
if _m < 0 {
|
|
utils.WriteMDv2Text(&sb, i18n.DS_KMB_ETA_DEPARTED.Text(langPack, eta))
|
|
} else {
|
|
utils.WriteMDv2Text(&sb, eta)
|
|
}
|
|
|
|
noSchedules = false
|
|
}
|
|
|
|
if schedule.Remarks_en != "" {
|
|
sb.WriteString(" \\*\\* ")
|
|
switch this.Lang {
|
|
case "en":
|
|
utils.WriteMDv2Text(&sb, schedule.Remarks_en)
|
|
case "zh-Hant":
|
|
utils.WriteMDv2Text(&sb, schedule.Remarks_tc)
|
|
}
|
|
}
|
|
|
|
sb.WriteString("\n")
|
|
}
|
|
|
|
if noSchedules {
|
|
utils.WriteMDv2Text(&sb, i18n.DS_KMB_NO_SCHEDULES.Text(langPack))
|
|
}
|
|
|
|
sb.WriteString("\n")
|
|
}
|
|
|
|
// We got only the route key, proceed to list the route stops
|
|
} else {
|
|
// Result contains all route stops, we only need the starting one
|
|
routes := []*RouteStop{}
|
|
|
|
for _, item := range *this.Query.Results {
|
|
var r *RouteStop
|
|
r = any(item).(*RouteStop)
|
|
if r.PrevStop() == nil {
|
|
routes = append(routes, r)
|
|
}
|
|
}
|
|
|
|
sort.Sort(ByRoute(routes))
|
|
|
|
for _, r := range routes {
|
|
writeRouteHead(&sb, r)
|
|
sb.WriteString("\n")
|
|
for {
|
|
b := *r.BusStop
|
|
utils.WriteMDv2Text(&sb, (*b.Name)[this.Lang])
|
|
r = r.NextStop()
|
|
if r == nil {
|
|
break
|
|
}
|
|
|
|
sb.WriteString(" \\> ")
|
|
}
|
|
sb.WriteString("\n")
|
|
}
|
|
|
|
}
|
|
}
|
|
} else {
|
|
return "", fmt.Errorf(i18n.NO_RESULTS.Text(langPack))
|
|
}
|
|
|
|
return sb.String(), nil
|
|
}
|