From 0875d0cbd4f3643928d307b6f1039aa34b224cbe Mon Sep 17 00:00:00 2001 From: "Diogo Franco (Kovensky)" Date: Wed, 17 Jul 2013 14:26:02 -0300 Subject: [PATCH] misc: (*EpisodeRange).Split(*Episode) -- Splits a range Also define Inc/IncNumber/Dec/DecNumber for episodes, used internally by Split. Includes test. --- misc/episode.go | 28 +++++++++ misc/episoderange.go | 126 ++++++++++++++++++++++++++++++++++++++ misc/episoderange_test.go | 29 +++++++++ 3 files changed, 183 insertions(+) diff --git a/misc/episode.go b/misc/episode.go index 72140d4..1dbd172 100644 --- a/misc/episode.go +++ b/misc/episode.go @@ -134,6 +134,34 @@ func (ep *Episode) FormatLog(max int) string { return ep.Format(scale(max)) } +func (ep *Episode) Inc() { + if ep.Parts > 0 && ep.Part == ep.Parts-1 { + ep.IncNumber() + } else { + ep.Part++ + } +} + +func (ep *Episode) IncNumber() { + ep.Part = -1 + ep.Parts = 0 + ep.Number++ +} + +func (ep *Episode) Dec() { + if ep.Part > 0 { + ep.Part-- + } else { + ep.DecNumber() + } +} + +func (ep *Episode) DecNumber() { + ep.Part = -1 + ep.Parts = 0 + ep.Number-- +} + // Parses a string in the usual AniDB API episode format and converts into // an Episode. func ParseEpisode(s string) *Episode { diff --git a/misc/episoderange.go b/misc/episoderange.go index fb91caa..729d2c8 100644 --- a/misc/episoderange.go +++ b/misc/episoderange.go @@ -144,6 +144,132 @@ func (a *EpisodeRange) Merge(b *EpisodeRange) (c *EpisodeRange) { return } +// Check if the given range is not nil, has a defined start +// and, if it has an end, that the end ends after the start. +func (er *EpisodeRange) Valid() bool { + switch { + case er == nil, er.Start == nil: + return false + case er.End == nil: + return true + case er.Start.Number < er.End.Number: + return true + case er.Start.Number > er.End.Number: + return false + case er.Start.Part <= er.End.Part: + return true + default: + return false + } +} + +// Simplifies the Start/End ranges if one contains the other. +// Sets the pointers to be identical if the range is modified. +// +// Modifies in-place, returns itself. +func (er *EpisodeRange) Simplify() *EpisodeRange { + switch { + case er.Start.ContainsEpisodes(er.End): + er.End = er.Start + case er.End != nil && er.End.ContainsEpisodes(er.Start): + er.Start = er.End + } + return er +} + +// Splits the range into one or two ranges, using the given +// Episode as the split point. The Episode is not included in +// the resulting ranges. +func (er *EpisodeRange) Split(ep *Episode) []*EpisodeRange { + if !er.ContainsEpisodes(ep) { // implies same type + return []*EpisodeRange{er} + } + if !er.Valid() { + return []*EpisodeRange{nil, nil} + } + + a := *er.Start + + inf := er.End == nil + b := Episode{} + if !inf { + b = *er.End + } + + end := &b + if inf { + end = nil + } + + switch { + case a.ContainsEpisodes(ep) && b.ContainsEpisodes(ep): + return []*EpisodeRange{nil, nil} + case a.ContainsEpisodes(ep): + if ep.Part >= 0 { + a.Inc() + } else { + a.IncNumber() + } + if a.Number == b.Number && b.Parts > 0 { + a.Parts = b.Parts + } + + r := &EpisodeRange{ + Type: er.Type, + Start: &a, + End: end, + } + return []*EpisodeRange{nil, r.Simplify()} + case b.ContainsEpisodes(ep): + if ep.Part >= 0 { + b.Dec() + } else { + b.DecNumber() + } + if b.Number == a.Number { + if a.Parts > 0 { + b.Parts = a.Parts + b.Part = a.Parts - 1 + } else if b.Part < 0 { + b.Part = a.Part + } + } + r := &EpisodeRange{ + Type: er.Type, + Start: &a, + End: &b, + } + return []*EpisodeRange{r.Simplify(), nil} + default: + ra := &EpisodeRange{ + Type: er.Type, + Start: &a, + End: ep, + } + rb := &EpisodeRange{ + Type: er.Type, + Start: ep, + End: end, + } + + ra = ra.Split(ep)[0] + rb = rb.Split(ep)[1] + + if ra.Valid() { + ra.Simplify() + } else { + ra = nil + } + if rb.Valid() { + rb.Simplify() + } else { + rb = nil + } + + return []*EpisodeRange{ra, rb} + } +} + // Returns true if both ranges are of the same type and // have identical start/end positions func (a *EpisodeRange) Equals(b *EpisodeRange) bool { diff --git a/misc/episoderange_test.go b/misc/episoderange_test.go index df67268..2402cdd 100644 --- a/misc/episoderange_test.go +++ b/misc/episoderange_test.go @@ -50,3 +50,32 @@ func ExampleEpisodeRange_PartialMerge() { // // 1-2.3 } + +func ExampleEpisodeRange_Split() { + a := misc.ParseEpisodeRange("1.0-1.3") + b := misc.ParseEpisode("1.2") + fmt.Println(a.Split(b)) + + b = misc.ParseEpisode("1") + fmt.Println(a.Split(b)) + + a = misc.ParseEpisodeRange("1.1-2") + fmt.Println(a.Split(b)) + + b = misc.ParseEpisode("2") + fmt.Println(a.Split(b)) + + a = misc.ParseEpisodeRange("1-10") + fmt.Println(a.Split(b)) + + b = misc.ParseEpisode("4") + fmt.Println(a.Split(b)) + + // Output: + // [1.0-1.1 1.3] + // [ ] + // [ 2] + // [1.1 ] + // [1 03-10] + // [1-3 05-10] +} -- 2.44.0