diff --git a/msp/errors.go b/msp/errors.go new file mode 100644 index 0000000..ff500f7 --- /dev/null +++ b/msp/errors.go @@ -0,0 +1,12 @@ +package msp + +import ( + "errors" +) + +var ( + // ErrEndAfterStart occurs when a period given has an end time after its start time + ErrEndAfterStart = errors.New("error: start time is after end time") + // ErrNoValidPeriods occurs when an empty set of periods is passed or when ll periods are invalid + ErrNoValidPeriods = errors.New("error: no valid periods available") +) diff --git a/msp/msp.go b/msp/msp.go index 409bd44..12dc73f 100644 --- a/msp/msp.go +++ b/msp/msp.go @@ -1,10 +1,69 @@ package msp -var () +import ( + "sort" + "time" +) -func init() { +func MostSpecificPeriod(ts time.Time, periods ...Period) (id string, err error) { + // Filter to get only valid periods here + periods = ValidTimePeriods(ts, periods...) + if len(periods) == 0 { + return "", ErrNoValidPeriods + } + // find the shortest duration + d, err := GetDuration(periods[0].StartTime, periods[0].EndTime) + for _, x := range periods { + p, err := GetDuration(x.StartTime, x.EndTime) + if err == nil && p < d { + d = p + } + } + // find all periods with this shortest duration + var matchingDurations []Period + for _, x := range periods { + p, err := GetDuration(x.StartTime, x.EndTime) + if err == nil && p == d { + matchingDurations = append(matchingDurations, x) + } + } + // Find the newest time a period starts + newest := matchingDurations[0].StartTime + for _, x := range matchingDurations { + if x.StartTime.After(newest) { + newest = x.StartTime + } + } + // Determine whichever of these periods have the same start time in addtion to duration + var matchingDurationsAndStartTimes []Period + for _, x := range matchingDurations { + if x.StartTime == newest { + matchingDurationsAndStartTimes = append(matchingDurationsAndStartTimes, x) + } + } + // Finally, return the period with the 'last' name lexicographically + var identifiers []string + for _, x := range matchingDurationsAndStartTimes { + identifiers = append(identifiers, x.Identifier) + } + sort.Strings(identifiers) + return identifiers[len(identifiers)-1], nil } -func MostSpecificPeriod(periods ...Period) (id string, err error) { - return +func GetDuration(start time.Time, end time.Time) (dur time.Duration, err error) { + if start.After(end) { + err = ErrEndAfterStart + } + dur = end.Sub(start) + return dur, err +} + +func ValidTimePeriods(ts time.Time, periods ...Period) []Period { + var valid []Period + for _, p := range periods { + if p.StartTime.Before(ts) && p.EndTime.After(ts) { + valid = append(valid, p) + } + } + return valid } diff --git a/msp/msp_test.go b/msp/msp_test.go index cccf3a6..3eff177 100644 --- a/msp/msp_test.go +++ b/msp/msp_test.go @@ -1,9 +1,20 @@ package msp import ( + "fmt" "testing" ) //(periods ...Period) (id string, err error) { func TestMostSpecificPeriod(t *testing.T) { + testCases := []struct { + testID string + result string + Periods []Period + }{{testID: "test"}} + for _, tc := range testCases { + t.Run(fmt.Sprintf("%s", tc.testID), func(t *testing.T) { + + }) + } }