var backend = require("./databaseBackendMongodb"); var listeners = require("./listeners"); var routing = require("./routing"); var utils = require("./utils"); var async = require("async"); var underscore = require("underscore"); function getPadData(padId, callback) { backend.getPadDataByWriteId(padId, function(err, data) { if(err || data != null) return callback(err, utils.extend(data, { writable: true })); backend.getPadData(padId, function(err, data) { if(err || data != null) return callback(err, utils.extend(data, { writable: false })); backend.createPad(utils.generateRandomId(10), padId, function(err, data) { callback(err, utils.extend(data, { writable: true })); }); }); }); } function updatePadData(padId, data, callback) { backend.updatePadData(padId, data, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(padId, "padData", data); callback(null, data); }); } function getViews(padId) { return backend.getViews(padId); } function createView(padId, data, callback) { if(data.name == null || data.name.trim().length == 0) return callback("No name provided."); backend.createView(padId, data, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(data._pad, "view", data); callback(null, data); }); } function updateView(viewId, data, callback) { if(data.name == null || data.name.trim().length == 0) return callback("No name provided."); backend.updateView(viewId, data, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(data._pad, "view", data); callback(null, data); }); } function deleteView(viewId, callback) { backend.deleteView(viewId, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(data._pad, "deleteView", { id: data.id }); callback(null, data); }); } function getPadMarkers(padId, bbox) { return backend.getPadMarkers(padId, bbox); } function createMarker(padId, data, callback) { backend.createMarker(padId, data, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(padId, "marker", _getMarkerDataFunc(data)); callback(null, data); }); } function updateMarker(markerId, data, callback) { backend.updateMarker(markerId, data, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(data._pad, "marker", _getMarkerDataFunc(data)); callback(null, data); }); } function deleteMarker(markerId, callback) { backend.deleteMarker(markerId, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(data._pad, "deleteMarker", { id: data.id }); callback(null, data); }); } function getPadLines(padId) { return backend.getPadLines(padId); } function createLine(padId, data, callback) { _calculateRouting(data, function(err, actualPoints) { // Also sets data.distance and data.time if(err) return callback(err); _createLine(padId, data, function(err, data) { if(err) return callback(err); _setLinePoints(padId, data.id, actualPoints, function(err) { callback(err, data); }); }); }); } function updateLine(lineId, data, callback) { async.auto({ originalLine : backend.getLine.bind(backend, lineId), calculateRouting : [ "originalLine", function(next, res) { if(data.points == null) data.points = res.originalLine.points; if(data.mode == null) data.mode = res.originalLine.mode || ""; if(underscore.isEqual(data.points, res.originalLine.points) && data.mode == res.originalLine.mode) return next(); _calculateRouting(data, next); // Also sets data.distance and data.time } ], updateLine : [ "calculateRouting", function(next) { _updateLine(lineId, data, next); } ], setLinePoints : [ "originalLine", "calculateRouting", function(next, res) { if(!res.calculateRouting) return next(); _setLinePoints(res.originalLine._pad, lineId, res.calculateRouting, next); } ] }, function(err, res) { callback(err, res.updateLine); }); } function _createLine(padId, data, callback) { backend.createLine(padId, data, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(data._pad, "line", data); callback(null, data); }); } function _updateLine(lineId, data, callback) { backend.updateLine(lineId, data, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(data._pad, "line", data); callback(null, data); }); } function _setLinePoints(padId, lineId, points, callback) { backend.setLinePoints(lineId, points, function(err) { if(err) return callback(err); listeners.notifyPadListeners(padId, "linePoints", function(bboxWithZoom) { return { reset: true, id: lineId, points : routing.prepareForBoundingBox(points, bboxWithZoom) }; }); callback(null); }); } function deleteLine(lineId, callback) { backend.deleteLine(lineId, function(err, data) { if(err) return callback(err); backend.setLinePoints(lineId, [ ], function(err) { if(err) return callback; listeners.notifyPadListeners(data._pad, "deleteLine", { id: data.id }); callback(null, data); }); }); } function getLinePoints(padId, bboxWithZoom) { return utils.filterStreamAsync(backend.getPadLines(padId, "id"), function(data, next) { _getLinePoints(data.id, bboxWithZoom, function(err, points) { if(err) return next(err); if(points.length >= 2) next(null, { id: data.id, points: points }); else next(null, null); }); }); } 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(next, r) { 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(next) { _handleStream(getPadMarkers(fromPadId, null), next, function(marker, cb) { createMarker(toPadId, marker, cb); }); }], copyLines : [ "padsExist", function(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(next, r) { _setLinePoints(toPadId, r.createLine.id, r.getLinePoints, next); } ] }, cb); }); }], copyViews : [ "padsExist", function(next, r) { _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, callback) { if(line.points && line.points.length >= 2 && line.mode) { routing.calculateRouting(line.points, line.mode, function(err, routeData) { if(err) return callback(err); line.distance = routeData.distance; line.time = routeData.time; for(var i=0; i