//! {"category": "libraries"} class DatabaseList { constructor(name) { this._name = name; } _getList() { let self = this; return database.get(this._name).then(function(node) { return JSON.parse(node); }).catch(function(error) { return self._emptyNode(); }); } _randomKey() { let kAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; let kBytes = 32; let result = ""; for (let i = 0; i < kBytes; i++) { result += kAlphabet.charAt(Math.floor(Math.random() * kAlphabet.length)); } return this._name + "_" + result; } _emptyNode() { return {next: null, previous: null}; } _getNode() { var self = this; var key = self._randomKey(); return database.get(key).then(function(found) { if (!found) { return key; } else { return self._getNode(); } }); } _getRelative(node, next, count) { } _insertEnd(item, after) { let self = this; return this._getList().then(function(listNode) { let readPromises = [self._getNode()]; readPromises.push(listNode.previous ? database.get(listNode.previous).then(JSON.parse) : null); readPromises.push(listNode.next ? database.get(listNode.next).then(JSON.parse) : null); return Promise.all(readPromises).then(function(results) { let newNodeName = results[0]; let previousNode = results[1]; let nextNode = results[2]; let newNode = self._emptyNode(); let oldPrevious = listNode.previous; let oldNext = listNode.next; newNode.value = item; newNode.previous = listNode.previous || newNodeName; newNode.next = listNode.next || newNodeName; if (after) { listNode.previous = newNodeName; listNode.next = listNode.next || newNodeName; } else { listNode.next = newNodeName; listNode.previous = listNode.previous || newNodeName; } let writePromises = [ database.set(self._name, JSON.stringify(listNode)), database.set(newNodeName, JSON.stringify(newNode)), ]; if (oldPrevious && oldPrevious == oldNext) { previousNode.next = newNodeName; previousNode.previous = newNodeName; writePromises.push(database.set(oldPrevious, JSON.stringify(previousNode))); } else { if (previousNode) { previousNode.next = newNodeName; writePromises.push(database.set(oldPrevious, JSON.stringify(previousNode))); } if (nextNode) { nextNode.previous = newNodeName; writePromises.push(database.set(oldNext, JSON.stringify(nextNode))); } } return Promise.all(writePromises); }); }); } _removeEnd(after) { let self = this; return this._getList().then(function(listNode) { if (listNode.next) { if (listNode.next == listNode.previous) { return database.get(listNode.next).then(JSON.parse).then(function(removedNode) { let removedName = listNode.next; listNode.next = null; listNode.previous = null; return Promise.all([ database.remove(removedName), database.set(self._name, JSON.stringify(listNode)), ]).then(function() { return removedNode.value; }); }); } else { let name1 = listNode.previous; let name2 = listNode.next; return Promise.all([ database.get(listNode.previous), database.get(listNode.next), ]).then(function(nodes) { var node1 = JSON.parse(nodes[0]); var node2 = JSON.parse(nodes[1]); if (after) { let name0 = node1.previous; return database.get(name0).then(JSON.parse).then(function(node0) { node0.next = name2; node2.previous = name0; listNode.previous = name0; return Promise.all([ database.set(name0, JSON.stringify(node0)), database.remove(name1), database.set(name2, JSON.stringify(node2)), database.set(self._name, JSON.stringify(listNode)), ]) }).then(function() { return node1.value; }); } else { let name3 = node2.next; return database.get(name3).then(JSON.parse).then(function(node3) { node1.next = name3; node3.previous = name1; listNode.next = name3; terminal.print(name1, " ", name2, " ", name3, " ", self._name); terminal.print(JSON.stringify(listNode)); return Promise.all([ database.set(name1, JSON.stringify(node1)), database.remove(name2), database.set(name3, JSON.stringify(node3)), database.set(self._name, JSON.stringify(listNode)), ]) }).then(function() { return node2.value; }); } }); } } }); } push(item) { return this._insertEnd(item, true); } pop() { return this._removeEnd(true); } shift() { return this._removeEnd(false); } unshift(item) { return this._insertEnd(item, false); } _sliceInternal(head, count, next, end, result) { let self = this; if (head[next] == end && count > 0) { result.push(head.value); return new Promise(function(resolve, reject) { resolve(result); }); } else { if (count > 0) { return database.get(head[next]).then(JSON.parse).then(function(retrieved) { return self._sliceInternal(retrieved, count - 1, next, end, result).then(function(result) { result.push(head.value); return result; }); }); } else { return new Promise(function(resolve, reject) { resolve(result); }); } } } get(count) { let self = this; return self._getList().then(function(listNode) { if (listNode.next) { return database.get(count > 0 ? listNode.next : listNode.previous).then(JSON.parse).then(function(head) { if (head) { return self._sliceInternal( head, Math.abs(count), count > 0 ? "next" : "previous", count > 0 ? listNode.next : listNode.previous, []).then(function(result) { result.reverse(); return result; }); } else { return null; } }); } }); } } function wipeDatabase() { let promises = []; return database.getAll().then(function(list) { for (let i = 0; i < list.length; i++) { promises.push(database.remove(list[i])); } }); return Promise.all(promises); } function dumpDatabase() { return database.getAll().then(function(list) { let promises = []; for (let i = 0; i < list.length; i++) { promises.push(database.get(list[i])); } return Promise.all(promises).then(function(values) { for (let i = 0; i < list.length; i++) { terminal.print(list[i], " ", values[i]); } }); }).catch(function(error) { terminal.print(error); }); } if (imports.terminal) { x = new DatabaseList("list"); core.register("onInput", function(input) { if (input == "clear") { wipeDatabase().then(function() { terminal.print("Database is now empty."); }); } else if (input.substring(0, "push ".length) == "push ") { x.push(input.substring("push ".length)).then(dumpDatabase).catch(terminal.print); } else if (input.substring(0, "unshift ".length) == "unshift ") { x.unshift(input.substring("unshift ".length)).then(dumpDatabase).catch(terminal.print); } else if (input == "pop") { x.pop().then(function(out) { terminal.print("POPPED: ", out); }).then(dumpDatabase).catch(terminal.print); } else if (input == "shift") { x.shift().then(function(out) { terminal.print("SHIFTED: ", out); }).then(dumpDatabase).catch(terminal.print); } else if (input.substring(0, "get ".length) == "get ") { let parts = input.split(" "); x.get(parseInt(parts[1])).then(function(result) { terminal.print(JSON.stringify(result)) }).catch(terminal.print); } else { dumpDatabase(); } }); }