var backend = require("./databaseBackendSequelize"); var listeners = require("./listeners"); var routing = require("./routing"); var utils = require("./utils"); var async = require("async"); var underscore = require("underscore"); var stream = require("stream"); var DEFAULT_TYPES = [ { name: "Marker", type: "marker", fields: [ { name: "Description", type: "textarea" } ] }, { name: "Line", type: "line", fields: [ { name: "Description", type: "textarea" } ] } ]; function getPadData(padId, callback) { backend.getPadDataByWriteId(padId, function(err, data) { if(err) return callback(err); else if(data != null) return callback(null, utils.extend(JSON.parse(JSON.stringify(data)), { writable: true, writeId: null })); backend.getPadData(padId, function(err, data) { if(err || data != null) return callback(err, utils.extend(JSON.parse(JSON.stringify(data)), { writable: false, writeId: null })); backend.createPad(utils.generateRandomId(10), padId, function(err, data) { if(err) return callback(err); async.each(DEFAULT_TYPES, function(it, next) { backend.createType(data.id, it, next); }, function(err) { callback(err, utils.extend(JSON.parse(JSON.stringify(data)), { writable: true, writeId: null })); }); }); }); }); } 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.padId, "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.padId, "view", data); callback(null, data); }); } function deleteView(viewId, callback) { backend.deleteView(viewId, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(data.padId, "deleteView", { id: data.id }); callback(null, data); }); } function getTypes(padId) { return backend.getTypes(padId); } function createType(padId, data, callback) { if(data.name == null || data.name.trim().length == 0) return callback("No name provided."); backend.createType(padId, data, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(data.padId, "type", data); callback(null, data); }); } function updateType(typeId, data, callback) { if(data.name == null || data.name.trim().length == 0) return callback("No name provided."); backend.updateType(typeId, data, function(err, data) { if(err) return callback(err); listeners.notifyPadListeners(data.padId, "type", data); _updateObjectStyles(data.type == "line" ? backend.getPadLinesByType(data.padId, typeId) : backend.getPadMarkersByType(data.padId, typeId), data.type == "line", function(err) { callback(err, 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, next); else return next(); } next(); }, next); } ], next); }, callback); } function getPadLines(padId) { return backend.getPadLines(padId); } function getPadLinesWithPoints(padId, bboxWithZoom) { return utils.filterStreamAsync(backend.getPadLines(padId), function(data, next) { _getLinePoints(data.id, bboxWithZoom, function(err, trackPoints) { if(err) return next(err); data.trackPoints = trackPoints; next(null, data); }); }); } function getLineTemplate(data, callback) { backend.getLineTemplate(data, function(err, line) { if(err) return callback(err); _updateObjectStyles(line, true, function(err) { return callback(err, line); }); }); } function createLine(padId, data, callback) { async.auto({ calculateRouting : function(next) { _calculateRouting(data, next); // Also sets data.distance and data.time }, createLine : [ "calculateRouting", function(res, next) { _createLine(padId, data, next); } ], setLinePoints : [ "createLine", "calculateRouting", function(res, next) { _setLinePoints(padId, res.createLine.id, res.calculateRouting, next); } ], updateLineStyle : [ "createLine", function(res, next) { _updateObjectStyles(res.createLine, true, next); // Modifies res.createLine } ] }, function(err, res) { return callback(err, res.createLine); }); } function updateLine(lineId, data, callback) { async.auto({ originalLine : backend.getLine.bind(backend, lineId), calculateRouting : [ "originalLine", function(res, next) { if(data.routePoints == null) data.routePoints = res.originalLine.routePoints; if(data.mode == null) data.mode = res.originalLine.mode || ""; if(underscore.isEqual(data.routePoints, res.originalLine.routePoints) && data.mode == res.originalLine.mode) return next(); _calculateRouting(data, next); // Also sets data.distance and data.time } ], updateLine : [ "calculateRouting", function(res, next) { _updateLine(lineId, data, next); } ], updateLineStyle : [ "updateLine", function(res, next) { _updateObjectStyles(res.updateLine, true, next); // Modifies res.updateLine } ], setLinePoints : [ "originalLine", "calculateRouting", function(res, next) { if(!res.calculateRouting) return next(); _setLinePoints(res.originalLine.padId, 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.padId, "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.padId, "line", data); callback(null, data); }); } function _setLinePoints(padId, lineId, trackPoints, callback) { backend.setLinePoints(lineId, trackPoints, function(err) { if(err) return callback(err); listeners.notifyPadListeners(padId, "linePoints", function(bboxWithZoom) { return { reset: true, id: lineId, trackPoints : (bboxWithZoom ? routing.prepareForBoundingBox(trackPoints, 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.padId, "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, trackPoints) { if(err) return next(err); if(trackPoints.length >= 2) next(null, { id: data.id, trackPoints: trackPoints }); 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(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, callback) { if(line.routePoints && line.routePoints.length >= 2 && line.mode) { routing.calculateRouting(line.routePoints, line.mode, function(err, routeData) { if(err) return callback(err); line.distance = routeData.distance; line.time = routeData.time; for(var i=0; i