"use strict";
var EXPORTED_SYMBOLS = ["PinnedEngine"];
var {Engine: Engine} = require("engines");
var {SyncComponent: SyncComponent} = require("component");
var {Utils: Utils} = require("utils");
var {Auth: Auth} = require("auth");
var {STORAGE_QUERIES: STORAGE_QUERIES} = require("./modules/sql");
var {PinnedModel: PinnedModel} = require("./modules/model");
function PinnedEngine() {
Engine.call(this,"Pinned",STORAGE_QUERIES);
}

PinnedEngine.prototype = {
__proto__: Engine.prototype,
init: function PinnedEngine_init() {
this._logger.debug("init");
this._pendingEntries = Object.create(null);
this._deletedEntries = Object.create(null);
this._model = new PinnedModel();
this._componentNotify = Utils.throttle(this._componentNotify.bind(this),2000);
this.set = Utils.throttle(this.set.bind(this),500);
this.emit("init");
this.update((function () {
this.emit("init","finish");
}
).bind(this));
}
,
finalize: function PinnedEngine_finalize() {
this._logger.debug("finalize");
this._pendingEntries = null;
this._deletedEntries = null;
this._model = null;
this.emit("finalize");
}
,
setListData: function PinnedEngine_setListData(list) {
if (! list)
return;
var needNotify = false;
list = list.filter((function (data) {
var storageEntry = this._storage.findEntry({
id_string: data.id_string});
if (storageEntry && storageEntry.version >= data.version)
return false;
if (data.deleted && this._deletedEntries[data.key] >= data.version)
{
return false;
}

if (this._isExternalMod(data))
{
this._logger.debug("isExternalMod " + JSON.stringify(data) + " | " + JSON.stringify(this._pendingEntries));
needNotify = true;
}

return true;
}
).bind(this));
if (! list.length)
return;
Engine.prototype.setListData.call(this,list);
if (this._unprocessedSnapshot)
{
this.set(this._unprocessedSnapshot);
return;
}

if (needNotify)
{
this._logger.debug("notify " + this.name);
this._componentNotify();
}

if (! this._hasSomePendings && this._needRecalculate)
this._recalculateAndSync();
}
,
setData: function PinnedEngine_setData(data) {
if (! this.enabled)
throw new Error("Trying setData on disabled engine");
var entry = this._model.get(data);
if (! entry)
return;
this._storage.updateEntry(entry);
if (entry.deleted)
{
this._deletedEntries[entry.key] = entry.version;
}

this._removeFromPending(entry.key);
}
,
get: function PinnedEngine_get() {
var data = {
};
this._storage.getAllEntries().forEach(function ({key: key, value: value, folder: folder}) {
if (key && ! folder)
data[key] = value;
}
);
return data;
}
,
set: function PinnedEngine_set(snapshot, dontCheckOnDelete) {
if (this._hasSomePendings)
{
this._needRecalculate = true;
return;
}

this._unprocessedSnapshot = null;
if (! this._storage.rootId)
{
this._unprocessedSnapshot = snapshot;
return null;
}

var [toAdd, toDelete] = this._subtract(snapshot,! ! dontCheckOnDelete);
if (! toAdd.length && ! toDelete.length)
return true;
try {
this._insertRecords({
add: toAdd,
remove: toDelete});
this._addToPending(toAdd);
this._addToPending(toDelete);
}
catch (ex) {
this._logger.error("Can not insert records in database.");
this._logger.debug(ex);
return false;
}

this.sync();
return true;
}
,
_recalculateAndSync: function PinnedEngine__recalculateAndSync() {
this.emit("init","finish");
this._needRecalculate = false;
}
,
_subtract: function PinnedEngine__subtract(data, dontCheckOnDelete) {
var storageData = {
};
this._storage.getAllEntries().forEach(function (entry) {
if (entry.key && ! entry.folder)
storageData[entry.key] = entry;
}
);
var rootId = this._storage.rootId;
var toAdd = [];
for(let [key, value] in Iterator(data)) {
let storageEntry = storageData[key];
if (storageEntry)
{
if (storageEntry.value === value)
continue;
let entry = {
id_string: storageEntry.id_string,
parent_id_string: rootId,
version: storageEntry.version || 0,
key: key,
value: value};
toAdd.push(entry);
}
 else
{
let entry = {
id_string: Utils.generateUUIDString(),
parent_id_string: rootId,
version: 0,
key: key,
value: value};
toAdd.push(entry);
}

}

var toDelete = [];
if (! dontCheckOnDelete)
{
for(let [key, value] in Iterator(storageData)) {
if (! (key in data))
{
toDelete.push(value);
}

}

}

return [toAdd, toDelete];
}
,
_entryIsPending: function PinnedEngine__entryIsPending(key) {
if (! key)
return false;
return ! ! this._pendingEntries[key];
}
,
_addToPending: function PinnedEngine__addToPending(data) {
if (! data || ! data.length)
return;
for (let i = 0, length = data.length;i < length;i++) {
let key = data[i].key;
if (this._pendingEntries[key])
{
this._pendingEntries[key]++;
}
 else
{
this._pendingEntries[key] = 1;
}

this._logger.debug("_addToPending " + key + " | " + JSON.stringify(this._pendingEntries));
}

}
,
_removeFromPending: function PinnedEngine__removeFromPending(key) {
if (! key)
return;
this._logger.debug("_removeFromPending " + key + " | " + JSON.stringify(this._pendingEntries));
if (this._pendingEntries[key])
this._pendingEntries[key]--;
}
,
_componentNotify: function PinnedEngine__componentNotify() {
SyncComponent.notify(this.name,"data",this.get());
}
,
_isExternalMod: function PinnedEngine__isExternalMod(entry) {
if (! entry)
return false;
if (entry.folder)
return false;
if (entry.deleted && this._deletedEntries[entry.key] >= entry.version)
{
return false;
}

return ! this._pendingEntries[entry.key];
}
,
get _hasSomePendings() {
for(let [key, value] in Iterator(this._pendingEntries)) {
if (value)
return true;
}

return false;
}
,
_unprocessedSnapshot: null,
_pendingEntries: null,
_deletedEntries: null,
_needRecalculate: false,
_PROTO_ID: 195560};
