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