/* ullist.js Description: Defines ULList, which represents a doubly linked list in which each item has a unique identifier stored in the `uid` field. */ function ULList() { this.first = null; this.last = null; this.length = 0; } /* Add an item to the beginning of the list */ ULList.prototype.prepend = function(item) { if(this.first !== null) { item.next = this.first; this.first.prev = item; } else { this.last = item; } this.first = item; this.first.prev = null; this.length++; return true; } /* Add an item to the end of the list */ ULList.prototype.append = function(item) { if(this.last !== null) { item.prev = this.last; this.last.next = item; } else { this.first = item; } this.last = item; this.last.next = null; this.length++; return true; } /* Insert an item after one which has a specified UID */ ULList.prototype.insertAfter = function(item, uid) { var after = this.find(uid); if(!after) return false; // Update links item.next = after.next; if(item.next) item.next.prev = item; item.prev = after; after.next = item; // New end of list if(after == this.last) this.last = item; this.length++; return true; } /* Insert an item before one that has a specified UID */ ULList.prototype.insertBefore = function(item, uid) { var before = this.find(uid); if(!before) return false; // Update links item.next = before; item.prev = before.prev; if(item.prev) item.prev.next = item; before.prev = item; // New beginning of list if(before == this.first) this.first = item; this.length++; return true; } /* Remove an item from the list */ ULList.prototype.remove = function(uid) { var item = this.find(uid); if(!item) return false; // Boundary conditions if(item == this.first) this.first = item.next; if(item == this.last) this.last = item.prev; // General case if(item.prev) item.prev.next = item.next; if(item.next) item.next.prev = item.prev; this.length--; return true; } /* Find an element in the list, return false if specified UID not found */ ULList.prototype.find = function(uid) { // Can't possibly find it in an empty list if(this.first === null) return false; var item = this.first; var iter = this.first; while(iter !== null && item.uid != uid) { item = iter; iter = iter.next; } if(item && item.uid == uid) return item; return false; } /* Clear all elements from the list */ ULList.prototype.clear = function() { this.first = null; this.last = null; this.length = 0; } /* Dump the contents of the list into an array */ ULList.prototype.toArray = function(pack) { var arr = new Array(this.length); var item = this.first; var i = 0; while(item !== null) { if(pack !== false && typeof item.pack == "function") arr[i++] = item.pack(); else arr[i++] = item; item = item.next; } return arr; } /* iterate across the playlist */ ULList.prototype.forEach = function (fn) { var item = this.first; while(item !== null) { fn(item); item = item.next; } }; /* find a media with the given video id */ ULList.prototype.findVideoId = function (id) { var item = this.first; while(item !== null) { if(item.media && item.media.id === id) return item; item = item.next; } return false; }; ULList.prototype.findAll = function(fn) { var result = []; this.forEach(function(item) { if( fn(item) ) { result.push(item); } }); return result; } module.exports = ULList;