1package songlist 2 3import ( 4 "fmt" 5 "reflect" 6 "time" 7) 8 9// Collection holds a set of songlists, and keeps track of movement between different lists. 10type Collection struct { 11 lists []Songlist 12 index int 13 last Songlist 14 current Songlist 15 updated time.Time 16} 17 18// NewCollection returns Collection. 19func NewCollection() *Collection { 20 return &Collection{ 21 lists: make([]Songlist, 0), 22 } 23} 24 25// Activate activates the specified songlist. The songlist is not added to the 26// collection. If the songlist is found in the collection, the index of that 27// songlist is activated. 28func (c *Collection) Activate(s Songlist) { 29 c.index = -1 30 for i, stored := range c.lists { 31 if stored == s { 32 c.index = i 33 break 34 } 35 } 36 c.last = c.current 37 c.current = s 38 c.SetUpdated() 39} 40 41// ActivateIndex activates the songlist pointed to by the specified index. 42func (c *Collection) ActivateIndex(i int) error { 43 list, err := c.Songlist(i) 44 if err != nil { 45 return err 46 } 47 c.Activate(list) 48 return nil 49} 50 51// Add appends a songlist to the collection. 52func (c *Collection) Add(s Songlist) { 53 c.lists = append(c.lists, s) 54} 55 56// Current returns the active songlist. 57func (c *Collection) Current() Songlist { 58 return c.current 59} 60 61// Index returns the current list cursor. 62func (c *Collection) Index() (int, error) { 63 if !c.ValidIndex(c.index) { 64 return 0, fmt.Errorf("Songlist index is out of range") 65 } 66 return c.index, nil 67} 68 69// Last returns the last used songlist. 70func (c *Collection) Last() Songlist { 71 return c.last 72} 73 74// Len returns the songlists count. 75func (c *Collection) Len() int { 76 return len(c.lists) 77} 78 79// Remove removes a songlist from the collection. 80func (c *Collection) Remove(index int) error { 81 if err := c.ValidateIndex(index); err != nil { 82 return err 83 } 84 if index+1 == c.Len() { 85 c.lists = c.lists[:index] 86 } else { 87 c.lists = append(c.lists[:index], c.lists[index+1:]...) 88 } 89 return nil 90} 91 92// Replace replaces an existing songlist with its new version. Checking 93// is done on a type-level, so this function should not be used for lists where 94// several of the same type is contained within the collection. 95func (c *Collection) Replace(s Songlist) { 96 for i := range c.lists { 97 if reflect.TypeOf(c.lists[i]) != reflect.TypeOf(s) { 98 continue 99 } 100 //console.Log("Songlist UI: replacing songlist of type %T at %p with new list at %p", s, c.lists[i], s) 101 //console.Log("Songlist UI: comparing %p %p", c.lists[i], c.Songlist()) 102 103 active := c.lists[i] == c.Current() 104 c.lists[i] = s 105 106 if active { 107 //console.Log("Songlist UI: replaced songlist is currently active, switching to new songlist.") 108 c.Activate(s) 109 } 110 return 111 } 112 113 //console.Log("Songlist UI: adding songlist of type %T at address %p since no similar exists", s, s) 114 c.Add(s) 115} 116 117func (c *Collection) Songlist(index int) (Songlist, error) { 118 if err := c.ValidateIndex(index); err != nil { 119 return nil, err 120 } 121 return c.lists[index], nil 122} 123 124func (c *Collection) ValidIndex(i int) bool { 125 return i >= 0 && i < c.Len() 126} 127 128func (c *Collection) ValidateIndex(i int) error { 129 if !c.ValidIndex(i) { 130 return fmt.Errorf("Index %d is out of bounds (try between 1 and %d)", i+1, c.Len()) 131 } 132 return nil 133} 134 135// Updated returns the timestamp of when this collection was last updated. 136func (c *Collection) Updated() time.Time { 137 return c.updated 138} 139 140// SetUpdated sets the update timestamp of the collection. 141func (c *Collection) SetUpdated() { 142 c.updated = time.Now() 143} 144