/**
* @tovvry
* DynamicList solve this problem:
* we push an item and return an index, the
* index is used in other place, but at some
* point, the item is deleted from this list(the
* item still exists and the index is needed);
* this will broken the index of all items that
* follow the deleted item
* performance: http://jsperf.com/array-test-slice-vs-delete
*/
function DynamicList () {
this.head = null;
this.tail = null;
this.index = 0;
this.size = 0;
}
DynamicList.prototype = {
constructor: DynamicList,
add: function (data, cb) {
var item = new Item(data);
item.index(this.index++);
if (this.tail) {
this.tail.next(item);
this.tail = item;
} else {
this.head = this.tail = item;
}
if (cb && typeof cb === 'function') {
cb(item, item.index());
}
this.size++;
return item.index();
},
remove: function (itemOrIndex, data) {
var item = this.find(itemOrIndex, data);
if (!item) {
return;
}
var prev = item.prev();
var next = item.next();
if (!prev) {
this.head = next;
this.head.prev(null);
} else {
prev.next(next);
next.prev(prev);
}
if (!next) {
this.tail = prev;
}
if (this.size >= 1) {
this.size--;
}
},
find: function (itemOrIndex, data) {
if (!this.head) {
return;
}
var index = typeof itemOrIndex === 'number' ? itemOrIndex : null;
var item = index === null ? itemOrIndex : null;
var start, dir = 0;
if (index) {
var diffA = index - this.head.index();
var diffB = this.tail.index() - index;
if (diffA <= diffB) {
start = this.head;
dir = 1;
} else {
start = this.tail;
}
} else {
start = this.head;
dir = 1;
}
var iter = start, counter = 0;
var found;
while (iter && counter <= this.size) {
if (data && iter.data() === data) {
found = iter;
}
else if (index && iter.index() === index) {
found = iter;
} else if (item && typeof item.index == 'function' && item.index() === iter) {
found = iter;
}
if (found) {
return found;
}
if (dir) {
iter = iter.next();
} else {
iter = iter.prev();
}
counter++;
}
return found;
},
length: function () {
return this.size;
},
isEmpty: function () {
return this.size === 0;
},
/**
* remove all stuff
*/
empty: function () {
}
}
function Item (data) {
this._index = -1;
this._prev = null;
this._next = null;
this._data = data;
}
Item.prototype = {
constructor: Item,
index: function (index) {
if (index) {
this._index = index;
} else {
return this._index;
}
},
prev: function (item) {
if (item) {
this._prev = item;
if (item.next() !== this) {
item.next(this);
}
} else {
return this._prev;
}
},
next: function (item) {
if (item) {
this._next = item;
if (item.prev() !== this) {
item.prev(this);
}
} else {
return this._next;
}
},
data: function (d) {
if (d) {
this._data = d;
}
else {
return this._data;
}
},
}