package misc
import (
+ "encoding/json"
"fmt"
"sort"
"strings"
type EpisodeList []*EpisodeRange
+func EpisodeToList(ep *Episode) EpisodeList {
+ return RangesToList(EpisodeToRange(ep))
+}
+
+func RangesToList(ranges ...*EpisodeRange) EpisodeList {
+ return EpisodeList(ranges)
+}
+
+func ContainerToList(ec EpisodeContainer) EpisodeList {
+ switch v := ec.(type) {
+ case *Episode:
+ return EpisodeToList(v)
+ case *EpisodeRange:
+ return RangesToList(v)
+ case EpisodeList:
+ return v
+ default:
+ panic("unimplemented")
+ }
+}
+
// Converts the EpisodeList into the AniDB API list format.
func (el EpisodeList) String() string {
scales := map[EpisodeType]int{}
return strings.Join(parts, ",")
}
+func (el EpisodeList) Infinite() bool {
+ for i := range el {
+ if el[i].Infinite() {
+ return true
+ }
+ }
+ return false
+}
+
+// Returns a channel that can be used to iterate using for/range.
+//
+// If the EpisodeList is infinite, then the channel is also infinite.
+// The caller is allowed to close the channel in such case.
+//
+// NOTE: Not thread safe.
+func (el EpisodeList) Episodes() chan Episode {
+ ch := make(chan Episode, 1)
+
+ go func() {
+ abort := false
+
+ if el.Infinite() {
+ defer func() { recover(); abort = true }()
+ } else {
+ defer close(ch)
+ }
+
+ for _, er := range el {
+ for ep := range er.Episodes() {
+ ch <- ep
+
+ if abort {
+ return
+ }
+ }
+ }
+ }()
+ return ch
+}
+
// Returns true if any of the contained EpisodeRanges contain the
// given EpisodeContainer.
func (el EpisodeList) ContainsEpisodes(ec EpisodeContainer) bool {
return nl
}
+func (el EpisodeList) CountEpisodes() (ec EpisodeCount) {
+ for _, er := range el {
+ var c *int
+ switch er.Type {
+ case EpisodeTypeRegular:
+ c = &ec.RegularCount
+ case EpisodeTypeSpecial:
+ c = &ec.SpecialCount
+ case EpisodeTypeCredits:
+ c = &ec.CreditsCount
+ case EpisodeTypeOther:
+ c = &ec.OtherCount
+ case EpisodeTypeTrailer:
+ c = &ec.TrailerCount
+ case EpisodeTypeParody:
+ c = &ec.ParodyCount
+ default:
+ continue
+ }
+ if *c < 0 {
+ continue
+ }
+ if er.End == nil {
+ *c = -1
+ continue
+ }
+ *c += er.End.Number - er.Start.Number
+ }
+ return
+}
+
func (el EpisodeList) Len() int {
return len(el)
}
func (el EpisodeList) Swap(i, j int) {
el[i], el[j] = el[j], el[i]
}
+
+func (el *EpisodeList) Add(ec EpisodeContainer) {
+ *el = append(*el, ContainerToList(ec)...)
+ *el = el.Simplify()
+}
+
+func (el *EpisodeList) Sub(ec EpisodeContainer) {
+ el2 := make(EpisodeList, 0, len(*el)*2)
+ switch e, ok := ec.(canInfinite); {
+ case ok:
+ if e.Infinite() {
+ eCh := e.Episodes()
+ ep := <-eCh
+ close(eCh)
+
+ for _, r := range *el {
+ el2 = append(el2, r.Split(&ep)[0])
+ }
+ break
+ }
+ fallthrough
+ default:
+ for ep := range ec.Episodes() {
+ for _, r := range *el {
+ el2 = append(el2, r.Split(&ep)...)
+ }
+ el2 = el2.Simplify()
+ }
+ }
+ *el = append(*el, el2.Simplify()...)
+}
+
+// Equivalent to marshaling el.String()
+func (el EpisodeList) MarshalJSON() ([]byte, error) {
+ return json.Marshal(el.String())
+}
+
+// NOTE: Since the String() representation doesn't include them,
+// it's not exactly reversible if the user has set .Parts in any
+// of the contained episodes.
+func (el EpisodeList) UnmarshalJSON(b []byte) error {
+ var v string
+ if err := json.Unmarshal(b, &v); err != nil {
+ return err
+ }
+
+ l := ParseEpisodeList(v)
+ for k := range l {
+ el[k] = l[k]
+ }
+ return nil
+}