]> git.lizzy.rs Git - go-anidb.git/blob - misc/episodelist.go
7f7d0abd8e2edc752587cbb36919c6ad9885575a
[go-anidb.git] / misc / episodelist.go
1 package misc
2
3 import (
4         "fmt"
5         "sort"
6         "strings"
7 )
8
9 type EpisodeCount struct {
10         RegularCount int
11         SpecialCount int
12         CreditsCount int
13         OtherCount   int
14         TrailerCount int
15         ParodyCount  int
16 }
17
18 type EpisodeList []*EpisodeRange
19
20 func EpisodeToList(ep *Episode) EpisodeList {
21         return RangesToList(EpisodeToRange(ep))
22 }
23
24 func RangesToList(ranges ...*EpisodeRange) EpisodeList {
25         return EpisodeList(ranges)
26 }
27
28 // Converts the EpisodeList into the AniDB API list format.
29 func (el EpisodeList) String() string {
30         scales := map[EpisodeType]int{}
31
32         for _, er := range el {
33                 if er == nil {
34                         continue
35                 }
36
37                 s := er.scale()
38                 if s > scales[er.Type] {
39                         scales[er.Type] = s
40                 }
41         }
42
43         parts := make([]string, len(el))
44         for i, er := range el {
45                 parts[i] = er.Format(scales[er.Type])
46         }
47
48         return strings.Join(parts, ",")
49 }
50
51 // Formats the list according to the number of digits of
52 // the count for its type, given in the EpisodeCount.
53 func (el EpisodeList) FormatLog(ec EpisodeCount) string {
54         parts := make([]string, len(el))
55         for i, er := range el {
56                 switch er.Type {
57                 case EpisodeTypeRegular:
58                         parts[i] = er.FormatLog(ec.RegularCount)
59                 case EpisodeTypeSpecial:
60                         parts[i] = er.FormatLog(ec.SpecialCount)
61                 case EpisodeTypeCredits:
62                         parts[i] = er.FormatLog(ec.CreditsCount)
63                 case EpisodeTypeOther:
64                         parts[i] = er.FormatLog(ec.OtherCount)
65                 case EpisodeTypeTrailer:
66                         parts[i] = er.FormatLog(ec.TrailerCount)
67                 case EpisodeTypeParody:
68                         parts[i] = er.FormatLog(ec.ParodyCount)
69                 default:
70                         parts[i] = er.Format(er.scale())
71                 }
72         }
73
74         return strings.Join(parts, ",")
75 }
76
77 // Returns true if any of the contained EpisodeRanges contain the
78 // given EpisodeContainer.
79 func (el EpisodeList) ContainsEpisodes(ec EpisodeContainer) bool {
80         for _, i := range el {
81                 if i != nil && i.ContainsEpisodes(ec) {
82                         return true
83                 }
84         }
85         return false
86 }
87
88 // Parses a string in the AniDB API list format and converts into
89 // an EpisodeList.
90 //
91 //      ParseEpisodeList("01")       <=> EpisodeList{ParseEpisodeRange("01")}
92 //      ParseEpisodeList("S2-S3")    <=> EpisodeList{ParseEpisodeRange("S2-S3")}
93 //      ParseEpisodeList("T1,C1-C3") <=> EpisodeList{ParseEpisodeRange("T1"), ParseEpisodeRange("C1-C3")}
94 func ParseEpisodeList(s string) (el EpisodeList) {
95         parts := strings.Split(s, ",")
96
97         el = make(EpisodeList, len(parts))
98         for i := range parts {
99                 el[i] = ParseEpisodeRange(parts[i])
100         }
101
102         return el.Simplify()
103 }
104
105 // Returns a simplified version of the EpisodeList (removes nil ranges, merges mergeable ranges, sorts).
106 func (el EpisodeList) Simplify() EpisodeList {
107         nl := make(EpisodeList, 0, len(el))
108
109         // drop nil ranges
110         for _, er := range el {
111                 if er != nil {
112                         nl = append(nl, er)
113                 }
114         }
115
116         // merge ranges
117         for n, changed := 0, true; changed; n++ {
118                 tmp := EpisodeList{}
119                 used := map[int]bool{}
120                 changed = false
121
122                 for i, a := range nl {
123                         if used[i] {
124                                 continue
125                         }
126                         for j, b := range nl[i+1:] {
127                                 if c := a.Merge(b); c != nil {
128                                         changed = true
129                                         used[j+i+1] = true
130                                         a = c
131                                 }
132                         }
133                         tmp = append(tmp, a)
134                 }
135                 nl = tmp
136
137                 if n > len(el) {
138                         panic(fmt.Sprintf("Too many iterations (%d) when simplifing %s!", n, el))
139                 }
140         }
141         sort.Sort(nl)
142         return nl
143 }
144
145 func (el EpisodeList) CountEpisodes() (ec EpisodeCount) {
146         for _, er := range el {
147                 var c *int
148                 switch er.Type {
149                 case EpisodeTypeRegular:
150                         c = &ec.RegularCount
151                 case EpisodeTypeSpecial:
152                         c = &ec.SpecialCount
153                 case EpisodeTypeCredits:
154                         c = &ec.CreditsCount
155                 case EpisodeTypeOther:
156                         c = &ec.OtherCount
157                 case EpisodeTypeTrailer:
158                         c = &ec.TrailerCount
159                 case EpisodeTypeParody:
160                         c = &ec.ParodyCount
161                 default:
162                         continue
163                 }
164                 if *c < 0 {
165                         continue
166                 }
167                 if er.End == nil {
168                         *c = -1
169                         continue
170                 }
171                 *c += er.End.Number - er.Start.Number
172         }
173         return
174 }
175
176 func (el EpisodeList) Len() int {
177         return len(el)
178 }
179
180 func (el EpisodeList) Less(i, j int) bool {
181         switch {
182         case el[i] == nil:
183                 return true
184         case el[j] == nil:
185                 return false
186         case el[i].Type < el[j].Type:
187                 return true
188         case el[i].Type > el[j].Type:
189                 return false
190         case el[i].Start.Number < el[j].Start.Number:
191                 return true
192         }
193         return false
194 }
195
196 func (el EpisodeList) Swap(i, j int) {
197         el[i], el[j] = el[j], el[i]
198 }