]> git.lizzy.rs Git - go-anidb.git/blob - misc/episode.go
misc: Fix Episode<->Episode comparison
[go-anidb.git] / misc / episode.go
1 package misc
2
3 import (
4         "fmt"
5         "math"
6         "strconv"
7 )
8
9 type EpisodeContainer interface {
10         // Returns true if this EpisodeContainer is equivalent or a superset of the given EpisodeContainer
11         ContainsEpisodes(EpisodeContainer) bool
12 }
13
14 type Formatter interface {
15         // Returns a string where the number portion is 0-padded to fit 'width' digits
16         Format(width int) string
17 }
18
19 type EpisodeType int
20
21 const (
22         EpisodeTypeRegular = EpisodeType(1 + iota)
23         EpisodeTypeSpecial // "S" episode
24         EpisodeTypeCredits // "C" episode
25         EpisodeTypeTrailer // "T" episode
26         EpisodeTypeParody  // "P" episode
27         EpisodeTypeOther   // "O" episode
28 )
29
30 func parseEpisodeType(typ string) EpisodeType {
31         switch typ {
32         case "":
33                 return EpisodeTypeRegular
34         case "S":
35                 return EpisodeTypeSpecial
36         case "C":
37                 return EpisodeTypeCredits
38         case "T":
39                 return EpisodeTypeTrailer
40         case "P":
41                 return EpisodeTypeParody
42         case "O":
43                 return EpisodeTypeOther
44         }
45         return 0
46 }
47
48 func (et EpisodeType) String() string {
49         switch et {
50         case EpisodeTypeRegular:
51                 return ""
52         case EpisodeTypeSpecial:
53                 return "S"
54         case EpisodeTypeCredits:
55                 return "C"
56         case EpisodeTypeTrailer:
57                 return "T"
58         case EpisodeTypeParody:
59                 return "P"
60         case EpisodeTypeOther:
61                 return "O"
62         default:
63                 return "!"
64         }
65 }
66
67 // An episode (duh).
68 type Episode struct {
69         Type   EpisodeType
70         Number int
71 }
72
73 // Converts the Episode into AniDB API episode format.
74 func (ep *Episode) String() string {
75         return ep.Format(1)
76 }
77
78 // returns how many digits are needed to represent this episode
79 func (ep *Episode) scale() int {
80         if ep == nil {
81                 return 1
82         }
83         return 1 + int(math.Floor(math.Log10(float64(ep.Number))))
84 }
85
86 // Returns true if ec is an Episode and is identical to this episode,
87 // or if ec is a single episode EpisodeRange / EpisodeList that
88 // contain only this episode.
89 func (ep *Episode) ContainsEpisodes(ec EpisodeContainer) bool {
90         switch e := ec.(type) {
91         case *Episode:
92                 return ep != nil && ep.Type == e.Type && ep.Number == e.Number
93         case *EpisodeRange:
94         case *EpisodeList:
95                 return EpisodeList{&EpisodeRange{Type: ep.Type, Start: ep, End: ep}}.ContainsEpisodes(ep)
96         default:
97         }
98         return false
99 }
100
101 func (ep *Episode) Format(width int) string {
102         return fmt.Sprintf("%s%0"+strconv.Itoa(width)+"d", ep.Type, ep.Number)
103 }
104
105 // Parses a string in the usual AniDB API episode format and converts into
106 // an Episode.
107 func ParseEpisode(s string) *Episode {
108         if no, err := strconv.ParseInt(s, 10, 32); err == nil {
109                 return &Episode{Type: EpisodeTypeRegular, Number: int(no)}
110         } else if len(s) < 1 {
111                 // s too short
112         } else if no, err = strconv.ParseInt(s[1:], 10, 30); err == nil {
113                 return &Episode{Type: parseEpisodeType(s[:1]), Number: int(no)}
114         }
115         return nil
116 }