var backend = require("./databaseBackendSequelize"); var listeners = require("./listeners"); var routing = require("./routing"); var utils = require("./utils"); var underscore = require("underscore"); var stream = require("stream"); var Promise = require("promise"); var DEFAULT_TYPES = [ { name: "Marker", type: "marker", fields: [ { name: "Description", type: "textarea" } ] }, { name: "Line", type: "line", fields: [ { name: "Description", type: "textarea" } ] } ]; function padIdExists(padId) { return backend.padIdExists(padId); } function getPadData(padId) { return backend.getPadDataByWriteId(padId).then(function(data) { if(data != null) return utils.extend(JSON.parse(JSON.stringify(data)), { writable: true }); return backend.getPadData(padId).then(function(data) { if(data != null) return utils.extend(JSON.parse(JSON.stringify(data)), { writable: false, writeId: null }); throw "This pad does not exist."; }); }); } function createPad(data) { return Promise.resolve().then(function() { if(!data.id || data.id.length == 0) throw "Invalid read-only ID"; if(!data.writeId || data.writeId.length == 0) throw "Invalid write-only ID"; if(data.id == data.writeId) throw "Read-only and write-only ID cannot be the same."; return Promise.all([ padIdExists(data.id).then(function(exists) { if(exists) throw "ID '" + data.id + "' is already taken."; }), padIdExists(data.writeId).then(function(exists) { if(exists) throw "ID '" + data.writeId + "' is already taken."; }) ]) }).then(function() { return backend.createPad(data); }).then(function(newData) { data = newData; return Promise.all(DEFAULT_TYPES.map(function(it) { return backend.createType(data.id, it); })); }).then(function() { return utils.extend(JSON.parse(JSON.stringify(data)), { writable: true }); }); } function updatePadData(padId, data) { return Promise.resolve().then(function() { if(data.id != null && data.id != padId && data.id.length == 0) throw "Invalid read-only ID"; var existsPromises = [ ]; if(data.id != null && data.id != padId) { existsPromises.push(padIdExists(data.id).then(function(exists) { if(exists) throw "ID '" + data.id + "' is already taken."; })); } if(data.writeId != null) { existsPromises.push(backend.getPadData(padId).then(function(padData) { if(data.writeId != padData.writeId) { if(data.writeId.length == 0) throw "Invalid write-only ID"; if(data.writeId == (data.id != null ? data.id : padId)) throw "Read-only and write-only ID cannot be the same."; return padIdExists(data.writeId).then(function(exists) { if(exists) throw "ID '" + data.writeId + "' is already taken."; }); } })); } return Promise.all(existsPromises); }).then(function() { return backend.updatePadData(padId, data); }).then(function(newData) { listeners.notifyPadListeners(padId, "padData", function(listener) { var dataClone = JSON.parse(JSON.stringify(newData)); if(!listener.writable) dataClone.writeId = null; return dataClone; }); if(data.id != null && data.id != padId) listeners.changePadId(padId, data.id); return data; }); } function getViews(padId) { return backend.getViews(padId); } function createView(padId, data) { return Promise.resolve().then(function() { if(data.name == null || data.name.trim().length == 0) throw "No name provided."; return backend.createView(padId, data); }).then(function(data) { listeners.notifyPadListeners(data.padId, "view", data); return data; }); } function updateView(viewId, data) { return Promise.resolve().then(function() { if(data.name == null || data.name.trim().length == 0) throw "No name provided."; return backend.updateView(viewId, data); }).then(function(data) { listeners.notifyPadListeners(data.padId, "view", data); return data; }); } function deleteView(viewId) { return backend.deleteView(viewId).then(function(data) { listeners.notifyPadListeners(data.padId, "deleteView", { id: data.id }); return data; }); } function getTypes(padId) { return backend.getTypes(padId); } function createType(padId, data) { return Promise.resolve().then(function() { if(data.name == null || data.name.trim().length == 0) throw "No name provided."; return backend.createType(padId, data); }).then(function(data) { listeners.notifyPadListeners(data.padId, "type", data); return data; }); } function updateType(typeId, data) { return Promise.resolve().then(function() { if(data.name == null || data.name.trim().length == 0) throw "No name provided."; return backend.updateType(typeId, data); }).then(function(data) { listeners.notifyPadListeners(data.padId, "type", data); return _updateObjectStyles(data.type == "line" ? backend.getPadLinesByType(data.padId, typeId) : backend.getPadMarkersByType(data.padId, typeId), data.type == "line").then(function() { return data; }); }); } function _optionsToObj(options, idx) { var ret = { }; if(options) { for(var i=0; i 0 && object.id) // Objects from getLineTemplate() do not have an ID return (isLine ? _updateLine : _updateMarker)(object.id, update); else return Promise.resolve(); } }); })); }); }); } function getPadLines(padId) { return backend.getPadLines(padId); } function getPadLinesWithPoints(padId, bboxWithZoom) { return utils.filterStreamPromise(backend.getPadLines(padId), function(data) { return _getLinePoints(data.id, bboxWithZoom).then(function(trackPoints) { data.trackPoints = trackPoints; return data; }); }); } function getLineTemplate(data) { return backend.getLineTemplate(data).then(function(line) { return _updateObjectStyles(line, true).then(function() { return line; }); }); } function createLine(padId, data) { var calculateRoutingP = _calculateRouting(data); var createLineP = calculateRoutingP.then(function() { return _createLine(padId, data); }); var setLinePointsP = Promise.all([ calculateRoutingP, createLineP ]).then(function(res) { return _setLinePoints(padId, res[1].id, res[0]); }); var updateLineStyleP = createLineP.then(function(lineData) { return _updateObjectStyles(lineData, true); }); return Promise.all([ calculateRoutingP, createLineP, setLinePointsP, updateLineStyleP ]).then(function(res) { return res[1]; }); } function updateLine(lineId, data) { var originalLineP = backend.getLine(lineId); var calculateRoutingP = originalLineP.then(function(originalLine) { if(data.routePoints == null) data.routePoints = originalLine.routePoints; if(data.mode == null) data.mode = originalLine.mode || ""; if((data.mode == "track" && data.trackPoints) || !underscore.isEqual(data.routePoints, originalLine.routePoints) || data.mode != originalLine.mode) return _calculateRouting(data); // Also sets data.distance and data.time }); var updateLineP = calculateRoutingP.then(function() { return _updateLine(lineId, data); }); var updateLineStyleP = updateLineP.then(function(newLine) { return _updateObjectStyles(newLine, true); // Modifies res.updateLine }); var setLinePointsP = Promise.all([ originalLineP, calculateRoutingP ]).then(function(res) { if(res[1]) return _setLinePoints(res[0].padId, lineId, res[1]); }); return Promise.all([ originalLineP, calculateRoutingP, updateLineP, updateLineStyleP, setLinePointsP ]).then(function(res) { return res[2]; }); } function _createLine(padId, data) { var dataCopy = utils.extend({ }, data); delete dataCopy.trackPoints; // They came if mode is track return backend.createLine(padId, dataCopy).then(function(newData) { listeners.notifyPadListeners(newData.padId, "line", newData); return newData; }); } function _updateLine(lineId, data) { var dataCopy = utils.extend({ }, data); delete dataCopy.trackPoints; // They came if mode is track return backend.updateLine(lineId, dataCopy).then(function(newData) { listeners.notifyPadListeners(newData.padId, "line", newData); return newData; }); } function _setLinePoints(padId, lineId, trackPoints) { return backend.setLinePoints(lineId, trackPoints).then(function() { listeners.notifyPadListeners(padId, "linePoints", function(listener) { return { reset: true, id: lineId, trackPoints : (listener && listener.bbox ? routing.prepareForBoundingBox(trackPoints, listener.bbox) : [ ]) }; }); }); } function deleteLine(lineId) { return backend.deleteLine(lineId).then(function(data) { return backend.setLinePoints(lineId, [ ]).then(function() { return data; }); }).then(function(data) { listeners.notifyPadListeners(data.padId, "deleteLine", { id: data.id }); return data; }); } function getLinePoints(padId, bboxWithZoom) { return utils.filterStreamPromise(backend.getPadLines(padId, "id"), function(data) { return _getLinePoints(data.id, bboxWithZoom).then(function(trackPoints) { if(trackPoints.length >= 2) return { id: data.id, trackPoints: trackPoints }; }); }); } /*function copyPad(fromPadId, toPadId, callback) { function _handleStream(stream, next, cb) { stream.on("data", function(data) { stream.pause(); cb(data, function() { stream.resume(); }); }); stream.on("error", next); stream.on("end", next); } async.auto({ fromPadData : function(next) { backend.getPadData(fromPadId, next); }, toPadData : function(next) { getPadData(toPadId, next); }, padsExist : [ "fromPadData", "toPadData", function(r, next) { if(!r.fromPadData) return next(new Error("Pad "+fromPadId+" does not exist.")); if(!r.toPadData.writable) return next(new Error("Destination pad is read-only.")); toPadId = r.toPadData.id; next(); }], copyMarkers : [ "padsExist", function(r, next) { _handleStream(getPadMarkers(fromPadId, null), next, function(marker, cb) { createMarker(toPadId, marker, cb); }); }], copyLines : [ "padsExist", function(r, next) { _handleStream(getPadLines(fromPadId), next, function(line, cb) { async.auto({ createLine : function(next) { _createLine(toPadId, line, next); }, getLinePoints : function(next) { backend.getLinePoints(line.id, next); }, setLinePoints : [ "createLine", "getLinePoints", function(r, next) { _setLinePoints(toPadId, r.createLine.id, r.getLinePoints, next); } ] }, cb); }); }], copyViews : [ "padsExist", function(r, next) { _handleStream(getViews(fromPadId), next, function(view, cb) { createView(toPadId, view, function(err, newView) { if(err) return cb(err); if(r.fromPadData.defaultView && r.fromPadData.defaultView.id == view.id && r.toPadData.defaultView == null) updatePadData(toPadId, { defaultView: newView.id }, cb); else cb(); }); }); }] }, callback); }*/ function _calculateRouting(line) { if(line.mode == "track" && line.trackPoints && line.trackPoints.length >= 2) { line.distance = utils.calculateDistance(line.trackPoints); line.time = null; routing._calculateZoomLevels(line.trackPoints); for(var i=0; i= 2 && line.mode && line.mode != "track") { return routing.calculateRouting(line.routePoints, line.mode).then(function(routeData) { line.distance = routeData.distance; line.time = routeData.time; for(var i=0; i