"use strict"; var Annotation = require('../map/data/Annotation'); var IdentifiedElement = require('../map/data/IdentifiedElement'); var UserDbOverlay = require('../map/overlay/UserDbOverlay'); var Configuration = require('../Configuration'); var logger = require('../logger'); var Promise = require("bluebird"); function getOverlayByName(customMap, dbOverlayName) { var dbOverlay = customMap.getOverlayByName(dbOverlayName); if (dbOverlay === null) { var validOverlays = ""; var overlays = customMap.getDbOverlays(); for (var overlay in overlays) { if (overlays.hasOwnProperty(overlay)) { validOverlays += overlay.getName() + ", "; } } throw new Error("Invalid DbOverlay: " + dbOverlayName + ". Valid DbOverlays: " + validOverlays); } else { return dbOverlay; } } function getFullElements(customMap, identifiedElements) { var result = []; return Promise.each( identifiedElements, function (item) { if (item.length === undefined) { return customMap.getSubmapById(item.getModelId()).getModel().getByIdentifiedElement(item, true).then( function (fullElement) { result.push(fullElement); }); } else { return getFullElements(customMap, item).then(function (resultRow) { result.push(resultRow); }); } }).then(function () { return result; }); } function getElements(elementIdentifiers, customMap) { var identifiedElements = []; var elementsByModelId = []; for (var i = 0; i < elementIdentifiers.length; i++) { var identifiedElement = new IdentifiedElement(elementIdentifiers[i]); if (elementsByModelId[identifiedElement.getModelId()] === undefined) { elementsByModelId[identifiedElement.getModelId()] = []; } elementsByModelId[identifiedElement.getModelId()].push(identifiedElement); identifiedElements.push(identifiedElement); } var modelScopePromises = []; for (var key in elementsByModelId) { if (elementsByModelId.hasOwnProperty(key)) { var model = customMap.getModel().getSubmodelById(parseInt(key)); modelScopePromises.push(model.getByIdentifiedElements(elementsByModelId[key], true)); } } // first promise fetch all data return Promise.all(modelScopePromises).then(function () { // this promise return result in the right order var elementPromises = []; for (var i = 0; i < identifiedElements.length; i++) { var element = identifiedElements[i]; var model = customMap.getModel().getSubmodelById(element.getModelId()); var promise = model.getByIdentifiedElement(element, true); elementPromises.push(promise); } return Promise.all(elementPromises); }); } function createProjectData(options) { var map = options.map; return { getBioEntityById: function (param) { var isArray = true; if (param.length === undefined) { param = [param]; isArray = false; } return getElements(param, map).then(function (result) { if (!isArray) { return result[0]; } else { return result; } }); }, getAllBioEntities: function () { var models = [map.getModel()]; var result = []; var i; for (i = 0; i < map.getModel().getSubmodels().length; i++) { models.push(map.getModel().getSubmodels()[i]); } var promises = []; for (i = 0; i < models.length; i++) { promises.push(models[i].getAliases({ type: map.getConfiguration().getSimpleElementTypeNames(), complete: true })); } return Promise.all(promises).then(function (aliasesByModel) { var promises = []; for (var i = 0; i < models.length; i++) { promises.push(models[i].getReactionsForElements(aliasesByModel[i], true)); for (var j = 0; j < aliasesByModel[i].length; j++) { result.push(aliasesByModel[i][j]); } } return Promise.all(promises); }).then(function (reactionsByModel) { for (var i = 0; i < models.length; i++) { for (var j = 0; j < reactionsByModel[i].length; j++) { result.push(reactionsByModel[i][j]); } } return result; }); }, getReactionsWithElement: function (param) { if (param.length === undefined) { param = [param]; } return getReactionsForElements(param, map); }, getProjectId: function () { return map.getProject().getProjectId(); }, getName: function () { return map.getProject().getName(); }, getVersion: function () { return map.getProject().getVersion(); }, getDisease: function () { if (map.getProject().getDisease() !== undefined) { return new Annotation(map.getProject().getDisease()); } else { return null; } }, getOrganism: function () { if (map.getProject().getOrganism() !== undefined) { return new Annotation(map.getProject().getOrganism()); } else { return null; } }, getModels: function () { var result = [{modelId: map.getId()}]; for (var i = 0; i < map.getSubmaps().length; i++) { var subModel = map.getSubmaps()[i].getModel(); result.push({ modelId: subModel.getId(), name: subModel.getName(), width: subModel.getWidth(), height: subModel.getHeight() }); } return result; } }; } function getReactionsForElements(elementIdentifiers, customMap) { var elementsByModelId = []; for (var i = 0; i < elementIdentifiers.length; i++) { var identifiedElement = new IdentifiedElement(elementIdentifiers[i]); if (elementsByModelId[identifiedElement.getModelId()] === undefined) { elementsByModelId[identifiedElement.getModelId()] = []; } elementsByModelId[identifiedElement.getModelId()].push(identifiedElement); } var modelScopePromises = []; for (var key in elementsByModelId) { if (elementsByModelId.hasOwnProperty(key)) { var model = customMap.getModel().getSubmodelById(parseInt(key)); var promise = model.getReactionsForElements(elementsByModelId[key], true); modelScopePromises.push(promise); } } // first promise fetch all data return Promise.all(modelScopePromises).then(function (reactionResult) { var result = []; for (var i = 0; i < reactionResult.length; i++) { result = result.concat(reactionResult[i]); } return result; }); } function createMarkerElements(options) { var params = options.params; var filteredType = options.filteredType; var isDefault = options.isDefault; var markerElements = []; if (params.length === undefined) { params = [params]; } for (var i = 0; i < params.length; i++) { var elementParam = params[i]; if (elementParam.type === undefined && isDefault) { markerElements.push({ element: elementParam.element }); } else if (elementParam.type === filteredType) { markerElements.push({ element: elementParam.element, options: elementParam.options }); } else if (elementParam.type !== "ICON" && elementParam.type !== "SURFACE") { throw new Error("Unknown type:" + elementParam.type); } } return markerElements; } function createProjectMap(options) { var map = options.map; var pluginId = options.pluginId; map.registerDbOverlay(new UserDbOverlay({name: pluginId, map: map})); var listenersData = []; return { getVisibleDataOverlays: function () { return map.getVisibleDataOverlays(); }, addListener: function (param) { var object = null; var listenerWrapper = null; var listenerType = param.type; if (param.dbOverlayName !== undefined) { object = getOverlayByName(map, param.dbOverlayName); listenerWrapper = function (e) { return getFullElements(map, e.arg.identifiedElements).then(function (result) { return param.callback(result); }); }; } else if (param.object === "plugin") { object = options.plugin; listenerWrapper = function () { return param.callback(); }; } else if (param.object === "overlay") { object = map; if (param.type === "onShow") { listenerType = "onShowOverlay"; } else if (param.type === "onHide") { listenerType = "onHideOverlay"; } else { throw new Error("Unknown listener type: " + param.type); } listenerWrapper = function (e) { return param.callback(e.arg); }; } else if (param.object === "map") { object = map; if (param.type !== "onZoomChanged" && param.type !== "onCenterChanged") { throw new Error("Unknown listener type: " + param.type); } listenerWrapper = function (e) { return param.callback({modelId: e.object.getId(), zoom: e.arg}); }; } else { throw new Error("Invalid argument"); } object.addListener(listenerType, listenerWrapper); listenersData.push({listener: param.callback, wrapper: listenerWrapper, object: object, type: listenerType}); if (object === map) { var submaps = map.getSubmaps(); for (var i = 0; i < submaps.length; i++) { var submap = submaps[i]; submap.addListener(listenerType, listenerWrapper); listenersData.push({listener: param.callback, wrapper: listenerWrapper, object: submap, type: listenerType}); } } }, removeListener: function (param) { var dbOverlay = getOverlayByName(map, param.dbOverlayName); var indexToBeRemoved = -1; for (var i = 0; i < listenersData.length; i++) { var listenerData = listenersData[i]; if (listenerData.listener === param.callback && listenerData.object === dbOverlay && listenerData.type === param.type) { indexToBeRemoved = i; } } if (indexToBeRemoved === -1) { throw new Error("Listener doesn't exist"); } var listenerWrapper = listenersData[indexToBeRemoved].wrapper; dbOverlay.removeListener(param.type, listenerWrapper); listenersData.splice(indexToBeRemoved, 1); }, removeAllListeners: function () { var removedListeners = []; for (var i = 0; i < listenersData.length; i++) { var listenerData = listenersData[i]; var listenerWrapper = listenersData[i].wrapper; listenerData.object.removeListener(listenerData.type, listenerWrapper); removedListeners.push(listenerData.listener); } return removedListeners; }, getHighlightedBioEntities: function (dbOverlayName) { if (dbOverlayName === undefined) { dbOverlayName = pluginId; } var dbOverlay = getOverlayByName(map, dbOverlayName); var identifiedElements; return dbOverlay.getIdentifiedElements().then(function (result) { identifiedElements = result; return getFullElements(map, identifiedElements); }).then(function (fullElements) { var result = []; for (var i = 0; i < identifiedElements.length; i++) { var type; if (identifiedElements[i].getIcon() !== undefined) { type = "ICON"; } else { type = "SURFACE"; } var row = { element: fullElements[i], type: type, options: { icon: identifiedElements[i].getIcon(), color: identifiedElements[i].getColor(), opacity: identifiedElements[i].getOpacity() } }; result.push(row); } return result; }); }, showBioEntity: function (params) { var iconElements = createMarkerElements({ params: params, filteredType: "ICON", isDefault: true }); var surfaceElements = createMarkerElements({ params: params, filteredType: "SURFACE", isDefault: false }); var promise = Promise.resolve(); if (iconElements.length > 0) { promise = map.getOverlayByName(pluginId).addMarker(iconElements); } return promise.then(function () { if (surfaceElements.length > 0) { return map.getOverlayByName(pluginId).addSurface(surfaceElements); } else { return Promise.resolve(); } }); }, hideBioEntity: function (params) { var iconElements = createMarkerElements({ params: params, filteredType: "ICON", isDefault: true }); var surfaceElements = createMarkerElements({ params: params, filteredType: "SURFACE", isDefault: false }); return map.getOverlayByName(pluginId).removeMarker(iconElements).then(function () { return map.getOverlayByName(pluginId).removeSurface(surfaceElements); }); }, setCenter: function (params) { var submap = map.getSubmapById(params.modelId); if (submap === null) { throw new Error("Unknown modelId: " + params.modelId); } return submap.setCenter(new google.maps.Point(params.x, params.y)); }, getCenter: function (params) { var submap = map.getSubmapById(params.modelId); if (submap === null) { throw new Error("Unknown modelId: " + params.modelId); } return submap.getCenter(); }, fitBounds: function (params) { var submap = map.getSubmapById(params.modelId); if (submap === null) { throw new Error("Unknown modelId: " + params.modelId); } var p1 = new google.maps.Point(params.x1, params.y1); var p2 = new google.maps.Point(params.x2, params.y2); var latLng1 = submap.fromPointToLatLng(p1); var latLng2 = submap.fromPointToLatLng(p2); var bounds = new google.maps.LatLngBounds(); bounds.extend(latLng1); bounds.extend(latLng2); return submap.getGoogleMap().fitBounds(bounds); }, setZoom: function (params) { var submap = map.getSubmapById(params.modelId); if (submap === null) { throw new Error("Unknown modelId: " + params.modelId); } return submap.setZoom(params.zoom); }, getZoom: function (params) { var submap = map.getSubmapById(params.modelId); if (submap === null) { throw new Error("Unknown modelId: " + params.modelId); } return submap.getZoom(); }, openMap: function (params) { return map.openSubmap(params.id); } } } function createProject(options) { return { data: createProjectData(options), map: createProjectMap(options) }; } function createConfiguration(options) { var configuration = new Configuration(options.configuration); return { options: configuration.getOptions(), overlayTypes: configuration.getOverlayTypes(), imageConverters: configuration.getImageConverters(), modelConverters: configuration.getModelConverters(), elementTypes: configuration.getElementTypes(), reactionTypes: configuration.getReactionTypes(), miriamTypes: configuration.getMiriamTypes(), mapTypes: configuration.getMapTypes(), modificationStateTypes: configuration.getModificationStateTypes(), privilegeTypes: configuration.getPrivilegeTypes(), annotators: configuration.getAnnotators() }; } function createPluginData(options) { return { setGlobalParam: function (key, value) { return ServerConnector.setPluginGlobalParam({hash: options.hash, key: key, value: value}); }, getGlobalParam: function (key) { return ServerConnector.getPluginGlobalParam({hash: options.hash, key: key}); }, setUserParam: function (key, value) { return ServerConnector.setPluginUserParam({hash: options.hash, key: key, value: value}); }, getUserParam: function (key) { return ServerConnector.getPluginUserParam({hash: options.hash, key: key}); } }; } function MinervaPluginProxy(options) { return { pluginId: options.pluginId, element: options.element, project: createProject(options), configuration: createConfiguration(options), pluginData: createPluginData(options) }; } module.exports = MinervaPluginProxy;