using NadekoBot.Extensions; using NadekoBot.Modules.Music.Common.Exceptions; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using NadekoBot.Common; namespace NadekoBot.Modules.Music.Common { public class MusicQueue : IDisposable { private LinkedList Songs { get; set; } = new LinkedList(); private int _currentIndex = 0; public int CurrentIndex { get { return _currentIndex; } set { lock (locker) { if (Songs.Count == 0) _currentIndex = 0; else _currentIndex = value %= Songs.Count; } } } public (int Index, SongInfo Song) Current { get { var cur = CurrentIndex; return (cur, Songs.ElementAtOrDefault(cur)); } } private readonly object locker = new object(); private TaskCompletionSource nextSource { get; } = new TaskCompletionSource(); public int Count { get { lock (locker) { return Songs.Count; } } } private uint _maxQueueSize; public uint MaxQueueSize { get => _maxQueueSize; set { if (value < 0) throw new ArgumentOutOfRangeException(nameof(value)); lock (locker) { _maxQueueSize = value; } } } public void Add(SongInfo song) { song.ThrowIfNull(nameof(song)); lock (locker) { if(MaxQueueSize != 0 && Songs.Count >= MaxQueueSize) throw new QueueFullException(); Songs.AddLast(song); } } public int AddNext(SongInfo song) { song.ThrowIfNull(nameof(song)); lock (locker) { if (MaxQueueSize != 0 && Songs.Count >= MaxQueueSize) throw new QueueFullException(); var curSong = Current.Song; if (curSong == null) { Songs.AddLast(song); return Songs.Count; } var songlist = Songs.ToList(); songlist.Insert(CurrentIndex + 1, song); Songs = new LinkedList(songlist); return CurrentIndex + 1; } } public void Next(int skipCount = 1) { lock(locker) CurrentIndex += skipCount; } public void Dispose() { Clear(); } public SongInfo RemoveAt(int index) { lock (locker) { if (index < 0 || index >= Songs.Count) throw new ArgumentOutOfRangeException(nameof(index)); var current = Songs.First.Value; for (int i = 0; i < Songs.Count; i++) { if (i == index) { current = Songs.ElementAt(index); Songs.Remove(current); if (CurrentIndex != 0) { if (CurrentIndex >= index) { --CurrentIndex; } } break; } } return current; } } public void Clear() { lock (locker) { Songs.Clear(); CurrentIndex = 0; } } public (int CurrentIndex, SongInfo[] Songs) ToArray() { lock (locker) { return (CurrentIndex, Songs.ToArray()); } } public void ResetCurrent() { lock (locker) { CurrentIndex = 0; } } public void Random() { lock (locker) { CurrentIndex = new NadekoRandom().Next(Songs.Count); } } public SongInfo MoveSong(int n1, int n2) { lock (locker) { var currentSong = Current.Song; var playlist = Songs.ToList(); if (n1 >= playlist.Count || n2 >= playlist.Count || n1 == n2) return null; var s = playlist[n1]; playlist.RemoveAt(n1); playlist.Insert(n2, s); Songs = new LinkedList(playlist); if (currentSong != null) CurrentIndex = playlist.IndexOf(currentSong); return s; } } public void RemoveSong(SongInfo song) { lock (locker) { Songs.Remove(song); } } public bool IsLast() { lock (locker) return CurrentIndex == Songs.Count - 1; } } } //O O [O] O O O O // // 3