github.com/martinohmann/rfoutlet@v1.2.1-0.20220707195255-8a66aa411105/internal/schedule/schedule.go (about) 1 // Package schedule provides types to define time switch schedule intervals for 2 // outlets. 3 package schedule 4 5 import ( 6 "encoding/json" 7 "fmt" 8 "sync" 9 "time" 10 11 uuid "github.com/satori/go.uuid" 12 ) 13 14 // Schedule is a collection of intervals. 15 type Schedule struct { 16 sync.RWMutex 17 intervals []Interval 18 } 19 20 // New creates a new empty *Schedule. 21 func New() *Schedule { 22 return NewWithIntervals(make([]Interval, 0)) 23 } 24 25 // NewWithIntervals create a new *Schedule with intervals. 26 func NewWithIntervals(intervals []Interval) *Schedule { 27 return &Schedule{ 28 intervals: intervals, 29 } 30 } 31 32 // Enabled returns true if any of the intervals is enabled. 33 func (s *Schedule) Enabled() bool { 34 if s == nil { 35 return false 36 } 37 38 s.RLock() 39 intervals := s.intervals 40 s.RUnlock() 41 42 for _, i := range intervals { 43 if i.Enabled { 44 return true 45 } 46 } 47 48 return false 49 } 50 51 // Contains returns true if any of the intervals contains t. 52 func (s *Schedule) Contains(t time.Time) bool { 53 if s == nil { 54 return false 55 } 56 57 s.RLock() 58 intervals := s.intervals 59 s.RUnlock() 60 61 for _, i := range intervals { 62 if i.Contains(t) { 63 return true 64 } 65 } 66 67 return false 68 } 69 70 // AddInterval adds an interval to the schedule of an outlet. 71 func (s *Schedule) AddInterval(interval Interval) error { 72 if interval.ID == "" { 73 interval.ID = uuid.NewV4().String() 74 } 75 76 s.Lock() 77 defer s.Unlock() 78 79 for _, i := range s.intervals { 80 if i.ID == interval.ID { 81 return fmt.Errorf("interval %q already exists", interval.ID) 82 } 83 } 84 85 s.intervals = append(s.intervals, interval) 86 87 return nil 88 } 89 90 // UpdateInterval updates an interval of the schedule of an outlet. Will return 91 // an error if the interval does not exist. 92 func (s *Schedule) UpdateInterval(interval Interval) error { 93 s.Lock() 94 defer s.Unlock() 95 96 for j, i := range s.intervals { 97 if i.ID == interval.ID { 98 s.intervals[j] = interval 99 return nil 100 } 101 } 102 103 return fmt.Errorf("interval %q does not exist", interval.ID) 104 } 105 106 // DeleteInterval deletes an interval of the schedule of an outlet. Will return 107 // an error if the interval does not exist. 108 func (s *Schedule) DeleteInterval(interval Interval) error { 109 s.Lock() 110 defer s.Unlock() 111 112 for j, i := range s.intervals { 113 if i.ID == interval.ID { 114 s.intervals = append(s.intervals[:j], s.intervals[j+1:]...) 115 return nil 116 } 117 } 118 119 return fmt.Errorf("interval %q does not exist", interval.ID) 120 } 121 122 // UnmarshalJSON implements the json.Unmarshaler interface. 123 // 124 // This ensures that the json bytes are correctly unmarshalled into the 125 // internal slice of Interval values. 126 func (s *Schedule) UnmarshalJSON(b []byte) error { 127 return json.Unmarshal(b, &s.intervals) 128 } 129 130 // MarshalJSON implements the json.Marshaler interface. 131 // 132 // This hides that fact that *Schedule wraps a slice of Interval in the 133 // marshalled json. 134 func (s *Schedule) MarshalJSON() ([]byte, error) { 135 return json.Marshal(s.intervals) 136 }