Skip to content
Snippets Groups Projects
MinervaPluginProxy.js 16.5 KiB
Newer Older
var Annotation = require('../map/data/Annotation');
Piotr Gawron's avatar
Piotr Gawron committed
var IdentifiedElement = require('../map/data/IdentifiedElement');
var UserDbOverlay = require('../map/overlay/UserDbOverlay');
var Configuration = require('../Configuration');
var logger = require('../logger');
var Promise = require("bluebird");

Piotr Gawron's avatar
Piotr Gawron committed
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()
        });
Piotr Gawron's avatar
Piotr Gawron committed
    }
  };
}

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 = [];

Piotr Gawron's avatar
Piotr Gawron committed
  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);
Piotr Gawron's avatar
Piotr Gawron committed
    },
    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;
    },
Piotr Gawron's avatar
Piotr Gawron committed
    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();
    },
Piotr Gawron's avatar
Piotr Gawron committed
    fitBounds: function (params) {
      var submap = map.getSubmapById(params.modelId);
Piotr Gawron's avatar
Piotr Gawron committed
      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);
Piotr Gawron's avatar
Piotr Gawron committed
    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) {
Piotr Gawron's avatar
Piotr Gawron committed
  return {
    data: createProjectData(options),
    map: createProjectMap(options)
  };
}

function createConfiguration(options) {
Piotr Gawron's avatar
Piotr Gawron committed
  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;