package service import "strings" type MapPreviewView struct { Mode string `json:"mode"` BaseTiles *PreviewBaseTiles `json:"baseTiles,omitempty"` Viewport *PreviewViewport `json:"viewport,omitempty"` Variants []PreviewVariantView `json:"variants,omitempty"` SelectedVariantID *string `json:"selectedVariantId,omitempty"` } type PreviewBaseTiles struct { TileBaseURL string `json:"tileBaseUrl"` Zoom *int `json:"zoom,omitempty"` TileSize *int `json:"tileSize,omitempty"` } type PreviewViewport struct { Width *int `json:"width,omitempty"` Height *int `json:"height,omitempty"` MinLon *float64 `json:"minLon,omitempty"` MinLat *float64 `json:"minLat,omitempty"` MaxLon *float64 `json:"maxLon,omitempty"` MaxLat *float64 `json:"maxLat,omitempty"` } type PreviewVariantView struct { VariantID string `json:"variantId"` Name *string `json:"name,omitempty"` RouteCode *string `json:"routeCode,omitempty"` Controls []PreviewControlView `json:"controls,omitempty"` Legs []PreviewLegView `json:"legs,omitempty"` } type PreviewControlView struct { ID string `json:"id"` Kind *string `json:"kind,omitempty"` Lon *float64 `json:"lon,omitempty"` Lat *float64 `json:"lat,omitempty"` Label *string `json:"label,omitempty"` } type PreviewLegView struct { From string `json:"from"` To string `json:"to"` } func buildPreviewFromPayload(payloadJSON *string) (*MapPreviewView, error) { if payloadJSON == nil || strings.TrimSpace(*payloadJSON) == "" { return nil, nil } payload, err := decodeJSONObject(*payloadJSON) if err != nil { return nil, err } rawPreview, _ := payload["preview"].(map[string]any) if len(rawPreview) == 0 { return nil, nil } view := &MapPreviewView{} if mode := readStringField(rawPreview, "mode"); mode != nil { view.Mode = *mode } if view.Mode == "" { view.Mode = "readonly" } if rawBaseTiles, ok := rawPreview["baseTiles"].(map[string]any); ok && len(rawBaseTiles) > 0 { baseTiles := &PreviewBaseTiles{} if tileBaseURL := readStringField(rawBaseTiles, "tileBaseUrl"); tileBaseURL != nil { baseTiles.TileBaseURL = *tileBaseURL } baseTiles.Zoom = readIntField(rawBaseTiles, "zoom") baseTiles.TileSize = readIntField(rawBaseTiles, "tileSize") if strings.TrimSpace(baseTiles.TileBaseURL) != "" { view.BaseTiles = baseTiles } } if rawViewport, ok := rawPreview["viewport"].(map[string]any); ok && len(rawViewport) > 0 { viewport := &PreviewViewport{ Width: readIntField(rawViewport, "width"), Height: readIntField(rawViewport, "height"), MinLon: readFloatField(rawViewport, "minLon"), MinLat: readFloatField(rawViewport, "minLat"), MaxLon: readFloatField(rawViewport, "maxLon"), MaxLat: readFloatField(rawViewport, "maxLat"), } view.Viewport = viewport } if selectedVariantID := readStringField(rawPreview, "selectedVariantId"); selectedVariantID != nil { view.SelectedVariantID = selectedVariantID } rawVariants, _ := rawPreview["variants"].([]any) if len(rawVariants) > 0 { view.Variants = make([]PreviewVariantView, 0, len(rawVariants)) for _, raw := range rawVariants { item, ok := raw.(map[string]any) if !ok { continue } variantID := readStringField(item, "variantId") if variantID == nil || strings.TrimSpace(*variantID) == "" { variantID = readStringField(item, "id") } if variantID == nil || strings.TrimSpace(*variantID) == "" { continue } variant := PreviewVariantView{ VariantID: *variantID, Name: readStringField(item, "name"), RouteCode: readStringField(item, "routeCode"), } rawControls, _ := item["controls"].([]any) if len(rawControls) > 0 { variant.Controls = make([]PreviewControlView, 0, len(rawControls)) for _, rawControl := range rawControls { controlMap, ok := rawControl.(map[string]any) if !ok { continue } controlID := readStringField(controlMap, "id") if controlID == nil || strings.TrimSpace(*controlID) == "" { continue } variant.Controls = append(variant.Controls, PreviewControlView{ ID: *controlID, Kind: readStringField(controlMap, "kind"), Lon: readFloatField(controlMap, "lon"), Lat: readFloatField(controlMap, "lat"), Label: readStringField(controlMap, "label"), }) } } rawLegs, _ := item["legs"].([]any) if len(rawLegs) > 0 { variant.Legs = make([]PreviewLegView, 0, len(rawLegs)) for _, rawLeg := range rawLegs { legMap, ok := rawLeg.(map[string]any) if !ok { continue } from := readStringField(legMap, "from") to := readStringField(legMap, "to") if from == nil || to == nil || strings.TrimSpace(*from) == "" || strings.TrimSpace(*to) == "" { continue } variant.Legs = append(variant.Legs, PreviewLegView{ From: *from, To: *to, }) } } view.Variants = append(view.Variants, variant) } } if view.BaseTiles == nil && view.Viewport == nil && len(view.Variants) == 0 { return nil, nil } return view, nil } func readIntField(object map[string]any, key string) *int { if object == nil { return nil } value, ok := object[key] if !ok { return nil } switch v := value.(type) { case int: result := v return &result case int32: result := int(v) return &result case int64: result := int(v) return &result case float64: result := int(v) return &result default: return nil } } func readFloatField(object map[string]any, key string) *float64 { if object == nil { return nil } value, ok := object[key] if !ok { return nil } switch v := value.(type) { case float64: result := v return &result case float32: result := float64(v) return &result case int: result := float64(v) return &result case int32: result := float64(v) return &result case int64: result := float64(v) return &result default: return nil } }