package vstp import ( "encoding/json" "fmt" "strconv" "strings" "time" "git.fjla.uk/owlboard/go-types/pkg/database" "git.fjla.uk/owlboard/go-types/pkg/upstreamApi" "git.fjla.uk/owlboard/timetable-mgr/helpers" "git.fjla.uk/owlboard/timetable-mgr/log" ) // Unmarshals the JSON data and runs it through the formatData() function and returns the data in a DB ready Struct func unmarshalData(jsonData string) database.Service { var schedule upstreamApi.MsgData err := json.Unmarshal([]byte(jsonData), &schedule) if err != nil { log.Msg.Error("Unable to unmarshal message body: " + err.Error()) //return err } log.Msg.Debug("Unmarshalling Complete") if schedule.Data.CIFMsg.ScheduleSegment == nil { log.Msg.Warn("ScheduleSegment is nil") } else if len(schedule.Data.CIFMsg.ScheduleSegment) == 0 { log.Msg.Warn("ScheduleSegment is empty") } return formatData(&schedule.Data.CIFMsg) } // Transforms the upstreamApi.Schedule type into a database.Service type func formatData(dataInput *upstreamApi.Schedule) database.Service { log.Msg.Debug("ScheduleSegment length: " + fmt.Sprint(len(dataInput.ScheduleSegment))) log.Msg.Debug("Printing dataInput to console:") var operator, headcode, powerType string var planSpeed int32 var stops []database.Stop // Check that the ScheduleSegment contains data, 'Delete' messages have no ScheduleSegment if len(dataInput.ScheduleSegment) > 0 { operator = dataInput.ScheduleSegment[0].ATOCCode headcode = dataInput.ScheduleSegment[0].SignallingID powerType = dataInput.ScheduleSegment[0].CIFPowerType planSpeed = parseSpeed(dataInput.ScheduleSegment[0].CIFSpeed) stops = parseStops(dataInput.ScheduleSegment[0].ScheduleLocation) } if operator == "" { operator = "UK" } service := database.Service{ TransactionType: dataInput.TransactionType, StpIndicator: dataInput.CIFSTPIndicator, Vstp: true, Operator: operator, TrainUid: dataInput.CIFTrainUID, Headcode: headcode, PowerType: powerType, PlanSpeed: planSpeed, ScheduleStartDate: parseDate(dataInput.ScheduleStartDate, false), ScheduleEndDate: parseDate(dataInput.ScheduleEndDate, true), DaysRun: parseDaysRun(dataInput.ScheduleDaysRun), Stops: stops, } return service } // Uses the map provided in 'helpers' to translate incorrect CIF speeds to their correct equivalent func parseSpeed(CIFSpeed string) int32 { log.Msg.Debug("CIFSpeed Input: '" + CIFSpeed + "'") if CIFSpeed == "" { log.Msg.Debug("Speed data not provided") return int32(0) } actualSpeed, exists := helpers.SpeedMap[CIFSpeed] if !exists { actualSpeed = CIFSpeed } log.Msg.Debug("Corrected Speed: " + actualSpeed) speed, err := strconv.ParseInt(actualSpeed, 10, 32) if err != nil { log.Msg.Warn("Unable to parse speed: " + CIFSpeed + ", returning 0") return int32(0) } return int32(speed) } // Converts the date string provided from the upstream API into a proper Date type and adds a time func parseDate(dateString string, end bool) time.Time { log.Msg.Debug("Date Input: " + dateString) date, err := time.Parse("2006-01-02", dateString) if err != nil { log.Msg.Error("Unable to parse date: " + dateString) return time.Time{} } var hour, minute, second, nanosecond int location := time.UTC if end { hour, minute, second, nanosecond = 23, 59, 59, 0 } else { hour, minute, second, nanosecond = 0, 0, 0, 0 } dateWithTime := time.Date(date.Year(), date.Month(), date.Day(), hour, minute, second, nanosecond, location) log.Msg.Debug("Parsed date: " + dateWithTime.String()) return dateWithTime } // Converts the binary stype 'daysRun' field into an array of short days func parseDaysRun(daysBinary string) []string { log.Msg.Debug("daysRun Input: " + daysBinary) shortDays := []string{"m", "t", "w", "th", "f", "s", "su"} var result []string for i, digit := range daysBinary { if digit == '1' { result = append(result, shortDays[i]) } } return result } // Converts an array if upstreamApi.ScheduleLocation types to an array of database.Stop types func parseStops(inputStops []upstreamApi.ScheduleLocation) []database.Stop { var stops []database.Stop for _, loc := range inputStops { stop := database.Stop{ PublicDeparture: parseTimeStrings(loc.PublicDepartureTime), WttDeparture: parseTimeStrings(loc.ScheduledDepartureTime), PublicArrival: parseTimeStrings(loc.PublicArrivalTime), WttArrival: parseTimeStrings(loc.ScheduledArrivalTime), IsPublic: strings.TrimSpace(loc.PublicDepartureTime) != "" || strings.TrimSpace(loc.PublicArrivalTime) != "", Tiploc: loc.Tiploc.Tiploc.TiplocId, } stops = append(stops, stop) } return stops } func parseTimeStrings(t string) string { if t == "" { return t } strippedT := strings.TrimSpace(t) if strippedT == "" { return "" } else { return strippedT[:4] } }