From b5612c1cf7cd762b418faac2ab61006ae9b86fb8 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Wed, 28 Mar 2018 19:01:52 +0200
Subject: [PATCH] data in model API doesn't include: submodels,
 centerLatLng,topLeftLatLng,bottomRightLatLng + models moved to project in JS

---
 frontend-js/package-lock.json                 |  54 +--
 frontend-js/src/main/js/ServerConnector.js    |   2 +-
 frontend-js/src/main/js/gui/CommentDialog.js  |   3 +-
 .../main/js/gui/export/AbstractExportPanel.js |   7 +-
 .../main/js/gui/export/ElementExportPanel.js  | 365 +++++++++---------
 .../main/js/gui/export/NetworkExportPanel.js  | 159 ++++----
 .../src/main/js/gui/leftPanel/SubmapPanel.js  |   6 +-
 .../src/main/js/map/AbstractCustomMap.js      |  25 +-
 frontend-js/src/main/js/map/CustomMap.js      |   6 +-
 frontend-js/src/main/js/map/Submap.js         |   2 +-
 frontend-js/src/main/js/map/data/MapModel.js  |  80 ----
 frontend-js/src/main/js/map/data/Project.js   |  28 +-
 .../src/main/js/map/surface/AliasSurface.js   |   2 +-
 frontend-js/src/main/js/minerva.js            |   6 +-
 .../src/main/js/plugin/MinervaPluginProxy.js  |  14 +-
 .../src/test/js/gui/MapContextMenu-test.js    |   4 +-
 .../test/js/gui/SelectionContextMenu-test.js  |   4 +-
 .../js/gui/leftPanel/OverlayPanel-test.js     |   2 +-
 frontend-js/src/test/js/helper.js             |  17 +-
 .../src/test/js/map/AbstractCustomMap-test.js |   4 +-
 frontend-js/src/test/js/map/CustomMap-test.js |   6 +-
 .../src/test/js/map/data/MapModel-test.js     |   2 +-
 .../js/map/overlay/SearchDbOverlay-test.js    |   4 +-
 frontend-js/src/test/js/minerva-test.js       |   7 +-
 .../test/js/plugin/MinervaPluginProxy-test.js |   6 +-
 .../lcsb/mapviewer/model/map/model/Model.java |   2 +-
 .../api/projects/models/ModelMetaData.java    | 110 ------
 .../api/projects/models/ModelRestImpl.java    |   7 +-
 28 files changed, 365 insertions(+), 569 deletions(-)

diff --git a/frontend-js/package-lock.json b/frontend-js/package-lock.json
index 29898ad842..378ebd3885 100644
--- a/frontend-js/package-lock.json
+++ b/frontend-js/package-lock.json
@@ -45,30 +45,38 @@
         "litemol": "github:dsehnal/LiteMol#a5419c696faa84530dd93acd55b747cf8136902b"
       },
       "dependencies": {
+        "ProtVista": {
+          "version": "git://github.com/davidhoksza/protvista.git#4e4bb737ba1e183291505bd25f8bae2e651ce21e",
+          "dev": true,
+          "requires": {
+            "d3": "3.5.17",
+            "file-saver": "1.3.3",
+            "jquery": "2.2.4",
+            "jszip": "3.1.4",
+            "underscore": "1.8.3"
+          },
+          "dependencies": {
+            "jquery": {
+              "version": "2.2.4",
+              "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.4.tgz",
+              "integrity": "sha1-LInWiJterFIqfuoywUUhVZxsvwI=",
+              "dev": true
+            }
+          }
+        },
         "jquery": {
           "version": "3.3.1",
           "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
           "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==",
           "dev": true
-        }
-      }
-    },
-    "ProtVista": {
-      "version": "git://github.com/davidhoksza/protvista.git#4e4bb737ba1e183291505bd25f8bae2e651ce21e",
-      "dev": true,
-      "requires": {
-        "d3": "3.5.17",
-        "file-saver": "1.3.3",
-        "jquery": "2.2.4",
-        "jszip": "3.1.4",
-        "underscore": "1.8.3"
-      },
-      "dependencies": {
-        "jquery": {
-          "version": "2.2.4",
-          "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.2.4.tgz",
-          "integrity": "sha1-LInWiJterFIqfuoywUUhVZxsvwI=",
-          "dev": true
+        },
+        "litemol": {
+          "version": "github:dsehnal/LiteMol#a5419c696faa84530dd93acd55b747cf8136902b",
+          "dev": true,
+          "requires": {
+            "@types/react": "15.6.14",
+            "@types/react-dom": "15.5.7"
+          }
         }
       }
     },
@@ -2050,14 +2058,6 @@
         "immediate": "3.0.6"
       }
     },
-    "litemol": {
-      "version": "github:dsehnal/LiteMol#a5419c696faa84530dd93acd55b747cf8136902b",
-      "dev": true,
-      "requires": {
-        "@types/react": "15.6.14",
-        "@types/react-dom": "15.5.7"
-      }
-    },
     "lodash": {
       "version": "4.17.4",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index 698bd803ef..48c374d88e 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -807,7 +807,7 @@ ServerConnector.getProject = function (projectId) {
       }
       project = self._projectsById[projectId];
       return self.getModels(projectId).then(function (models) {
-        project.setModel(models[0]);
+        project.setModels(models);
         return self.getOverlays({
           projectId: projectId,
           publicOverlay: true
diff --git a/frontend-js/src/main/js/gui/CommentDialog.js b/frontend-js/src/main/js/gui/CommentDialog.js
index 1974a06571..86148135a6 100644
--- a/frontend-js/src/main/js/gui/CommentDialog.js
+++ b/frontend-js/src/main/js/gui/CommentDialog.js
@@ -7,6 +7,7 @@ var Promise = require("bluebird");
 var AbstractGuiElement = require('./AbstractGuiElement');
 var Alias = require('../map/data/Alias');
 var Reaction = require('../map/data/Reaction');
+// noinspection JSUnusedLocalSymbols
 var logger = require('../logger');
 var Functions = require('../Functions');
 
@@ -18,7 +19,7 @@ function CommentDialog(params) {
     autoOpen : false,
     resizable : false,
     width : window.innerWidth / 2,
-    height : window.innerHeight / 2,
+    height : window.innerHeight / 2
   });
 }
 
diff --git a/frontend-js/src/main/js/gui/export/AbstractExportPanel.js b/frontend-js/src/main/js/gui/export/AbstractExportPanel.js
index 144896dd33..61eba919cc 100644
--- a/frontend-js/src/main/js/gui/export/AbstractExportPanel.js
+++ b/frontend-js/src/main/js/gui/export/AbstractExportPanel.js
@@ -253,12 +253,7 @@ AbstractExportPanel.prototype._getCompartmentNames = function () {
 };
 
 AbstractExportPanel.prototype.getModels = function () {
-  var self = this;
-  var models = [self.getProject().getModel()];
-  for (var i = 0; i < self.getProject().getModel().getSubmodels().length; i++) {
-    models.push(self.getProject().getModel().getSubmodels()[i]);
-  }
-  return models;
+  return this.getProject().getModels();
 };
 
 AbstractExportPanel.prototype._getAllCompartments = function () {
diff --git a/frontend-js/src/main/js/gui/export/ElementExportPanel.js b/frontend-js/src/main/js/gui/export/ElementExportPanel.js
index fc9f884e7e..e07f58e4ab 100644
--- a/frontend-js/src/main/js/gui/export/ElementExportPanel.js
+++ b/frontend-js/src/main/js/gui/export/ElementExportPanel.js
@@ -10,209 +10,206 @@ var logger = require('../../logger');
 var Promise = require("bluebird");
 
 function ElementExportPanel(params) {
-    params.panelName = "elementExport";
-    AbstractExportPanel.call(this, params);
+  params.panelName = "elementExport";
+  AbstractExportPanel.call(this, params);
 }
 
 ElementExportPanel.prototype = Object.create(AbstractExportPanel.prototype);
 ElementExportPanel.prototype.constructor = ElementExportPanel;
 
 ElementExportPanel.prototype.init = function () {
-    var self = this;
-    var element = self.getElement();
-    var configuration;
-    return ServerConnector.getConfiguration().then(function (result) {
-        configuration = result;
-        var typeDiv = self._createSelectTypeDiv(configuration.getElementTypes());
-        element.appendChild(typeDiv);
-        element.appendChild(self._createSelectColumnDiv(self.getAllColumns()));
-        return ServerConnector.getProjectStatistics(self.getProject().getProjectId());
-    }).then(function (statistics) {
-        return self._createMiriamTypeDiv(statistics.getElementAnnotations());
-    }).then(function (div) {
-        element.appendChild(div);
-        return self._createSelectIncludedCompartmentDiv();
-    }).then(function (div) {
-        element.appendChild(div);
-        return self._createSelectExcludedCompartmentDiv();
-    }).then(function (div) {
-        element.appendChild(div);
-        element.appendChild(self._createDownloadButton());
-    }).then(function () {
-        $(window).trigger('resize');
-    });
+  var self = this;
+  var element = self.getElement();
+  var configuration;
+  return ServerConnector.getConfiguration().then(function (result) {
+    configuration = result;
+    var typeDiv = self._createSelectTypeDiv(configuration.getElementTypes());
+    element.appendChild(typeDiv);
+    element.appendChild(self._createSelectColumnDiv(self.getAllColumns()));
+    return ServerConnector.getProjectStatistics(self.getProject().getProjectId());
+  }).then(function (statistics) {
+    return self._createMiriamTypeDiv(statistics.getElementAnnotations());
+  }).then(function (div) {
+    element.appendChild(div);
+    return self._createSelectIncludedCompartmentDiv();
+  }).then(function (div) {
+    element.appendChild(div);
+    return self._createSelectExcludedCompartmentDiv();
+  }).then(function (div) {
+    element.appendChild(div);
+    element.appendChild(self._createDownloadButton());
+  }).then(function () {
+    $(window).trigger('resize');
+  });
 };
 
 ElementExportPanel.prototype.createResponseString = function () {
-    var self = this;
-    var types, miriamTypes;
-    var includedCompartmentIds = [];
-    var excludedCompartmentIds = [];
-    var models = [self.getProject().getModel()];
-    for (var i = 0; i < self.getProject().getModel().getSubmodels().length; i++) {
-        models.push(self.getProject().getModel().getSubmodels()[i]);
+  var self = this;
+  var types, miriamTypes;
+  var includedCompartmentIds = [];
+  var excludedCompartmentIds = [];
+  var models = self.getProject().getModels();
+
+  var elements = [];
+  return self.getSelectedTypes().then(function (result) {
+    if (result.length === 0) {
+      return Promise.reject(new GuiMessageError("You must select at least one type"));
     }
-
-    var elements = [];
-    return self.getSelectedTypes().then(function (result) {
-        if (result.length === 0) {
-            return Promise.reject(new GuiMessageError("You must select at least one type"));
-        }
-        types = result;
-        return self.getSelectedIncludedCompartments();
-    }).then(function (result) {
-        result.forEach(function (compartment) {
-            includedCompartmentIds.push(compartment.getId());
-        });
-        return self.getSelectedExcludedCompartments();
-    }).then(function (result) {
-        result.forEach(function (compartment) {
-            excludedCompartmentIds.push(compartment.getId());
-        });
-
-        var promises = [];
-        for (var i = 0; i < models.length; i++) {
-            promises.push(models[i].getAliases({
-                type: types,
-                complete: true,
-                includedCompartmentIds: includedCompartmentIds,
-                excludedCompartmentIds: excludedCompartmentIds,
-            }));
-        }
-        return Promise.all(promises);
-    }).then(function (aliasesByModel) {
-        for (var i = 0; i < aliasesByModel.length; i++) {
-            for (var j = 0; j < aliasesByModel[i].length; j++) {
-                elements.push(aliasesByModel[i][j]);
-            }
-        }
-
-        return self.getSelectedMiriamTypes();
-    }).then(function (result) {
-        miriamTypes = result;
-        return self.getSelectedColumns();
-    }).then(function (selectedColumns) {
-        if (selectedColumns.length === 0) {
-            return Promise.reject(new GuiMessageError("You must select at least one column"));
-        }
-
-        var rows = [];
-        rows.push(self.createResponseHeader(selectedColumns, miriamTypes));
-        for (var i = 0; i < elements.length; i++) {
-            rows.push(self.createResponseRow(elements[i], selectedColumns, miriamTypes));
-        }
-        return rows.join("\n");
+    types = result;
+    return self.getSelectedIncludedCompartments();
+  }).then(function (result) {
+    result.forEach(function (compartment) {
+      includedCompartmentIds.push(compartment.getId());
+    });
+    return self.getSelectedExcludedCompartments();
+  }).then(function (result) {
+    result.forEach(function (compartment) {
+      excludedCompartmentIds.push(compartment.getId());
     });
+
+    var promises = [];
+    for (var i = 0; i < models.length; i++) {
+      promises.push(models[i].getAliases({
+        type: types,
+        complete: true,
+        includedCompartmentIds: includedCompartmentIds,
+        excludedCompartmentIds: excludedCompartmentIds,
+      }));
+    }
+    return Promise.all(promises);
+  }).then(function (aliasesByModel) {
+    for (var i = 0; i < aliasesByModel.length; i++) {
+      for (var j = 0; j < aliasesByModel[i].length; j++) {
+        elements.push(aliasesByModel[i][j]);
+      }
+    }
+
+    return self.getSelectedMiriamTypes();
+  }).then(function (result) {
+    miriamTypes = result;
+    return self.getSelectedColumns();
+  }).then(function (selectedColumns) {
+    if (selectedColumns.length === 0) {
+      return Promise.reject(new GuiMessageError("You must select at least one column"));
+    }
+
+    var rows = [];
+    rows.push(self.createResponseHeader(selectedColumns, miriamTypes));
+    for (var i = 0; i < elements.length; i++) {
+      rows.push(self.createResponseRow(elements[i], selectedColumns, miriamTypes));
+    }
+    return rows.join("\n");
+  });
 };
 
 ElementExportPanel.prototype.createResponseRow = function (alias, columns, miriamTypes) {
-    var stringBuilder = [];
-    var i, value;
-    for (i = 0; i < columns.length; i++) {
-        var column = columns[i];
-        value = alias[column.method]();
-        if (column.formatFunction !== undefined) {
-            value = column.formatFunction(value);
-        }
-        if (value instanceof String || typeof value === "string") {
-            value = value.replace(/[\n\r]/g, ' ');
-        }
-        stringBuilder.push(value);
+  var stringBuilder = [];
+  var i, value;
+  for (i = 0; i < columns.length; i++) {
+    var column = columns[i];
+    value = alias[column.method]();
+    if (column.formatFunction !== undefined) {
+      value = column.formatFunction(value);
+    }
+    if (value instanceof String || typeof value === "string") {
+      value = value.replace(/[\n\r]/g, ' ');
     }
-    for (i = 0; i < miriamTypes.length; i++) {
-        value = "";
-        var miriamType = miriamTypes[i];
-        var references = alias.getReferences();
-        for (var j = 0; j < references.length; j++) {
-            var reference = references[j];
-            if (reference.getType() === miriamType.getName()) {
-                value += reference.getResource() + ",";
-            }
-        }
-        stringBuilder.push(value);
+    stringBuilder.push(value);
+  }
+  for (i = 0; i < miriamTypes.length; i++) {
+    value = "";
+    var miriamType = miriamTypes[i];
+    var references = alias.getReferences();
+    for (var j = 0; j < references.length; j++) {
+      var reference = references[j];
+      if (reference.getType() === miriamType.getName()) {
+        value += reference.getResource() + ",";
+      }
     }
-    var result = stringBuilder.join("\t");
-    return result;
+    stringBuilder.push(value);
+  }
+  var result = stringBuilder.join("\t");
+  return result;
 };
 
 ElementExportPanel.prototype.getAllColumns = function () {
-    return [{
-        "columnName": "id",
-        "method": "getId",
-        "name": "Id",
-    }, {
-        "columnName": "name",
-        "method": "getName",
-        "name": "Name",
-    }, {
-        "columnName": "description",
-        "method": "getDescription",
-        "name": "Description",
-    }, {
-        "columnName": "modelId",
-        "method": "getModelId",
-        "name": "Model",
-    }, {
-        "columnName": "type",
-        "method": "getType",
-        "name": "Type",
-    }, {
-        "columnName": "complexId",
-        "method": "getComplexId",
-        "name": "Complex",
-    }, {
-        "columnName": "compartmentId",
-        "method": "getCompartmentId",
-        "name": "Compartment",
-    }, {
-        "columnName": "charge",
-        "method": "getCharge",
-        "name": "Charge",
-    }, {
-        "columnName": "symbol",
-        "method": "getSymbol",
-        "name": "Symbol",
-    }, {
-        "columnName": "fullName",
-        "method": "getFullName",
-        "name": "Full name",
-    }, {
-        "columnName": "abbreviation",
-        "method": "getAbbreviation",
-        "name": "Abbreviation",
-    }, {
-        "columnName": "formula",
-        "method": "getFormula",
-        "name": "Formula",
-    }, {
-        "columnName": "synonyms",
-        "method": "getSynonyms",
-        "name": "Synonyms",
-    }, {
-        "columnName": "formerSymbols",
-        "method": "getFormerSymbols",
-        "name": "Former symbols",
-    }, {
-        "columnName": "references",
-        "method": "getReferences",
-        "name": "References",
-        "formatFunction": function (references) {
-            var stringBuilder = [];
-            for (var i = 0; i < references.length; i++) {
-                var reference = references[i];
-                stringBuilder.push(reference.getType() + ":" + reference.getResource());
-            }
-            return stringBuilder.join(",");
-        },
-    }, {
-        "columnName": "linkedSubmodelId",
-        "method": "getLinkedSubmodelId",
-        "name": "Linked submodel",
-    }, {
-        "columnName": "elementId",
-        "method": "getElementId",
-        "name": "Element external id",
-    },];
+  return [{
+    "columnName": "id",
+    "method": "getId",
+    "name": "Id",
+  }, {
+    "columnName": "name",
+    "method": "getName",
+    "name": "Name",
+  }, {
+    "columnName": "description",
+    "method": "getDescription",
+    "name": "Description",
+  }, {
+    "columnName": "modelId",
+    "method": "getModelId",
+    "name": "Model",
+  }, {
+    "columnName": "type",
+    "method": "getType",
+    "name": "Type",
+  }, {
+    "columnName": "complexId",
+    "method": "getComplexId",
+    "name": "Complex",
+  }, {
+    "columnName": "compartmentId",
+    "method": "getCompartmentId",
+    "name": "Compartment",
+  }, {
+    "columnName": "charge",
+    "method": "getCharge",
+    "name": "Charge",
+  }, {
+    "columnName": "symbol",
+    "method": "getSymbol",
+    "name": "Symbol",
+  }, {
+    "columnName": "fullName",
+    "method": "getFullName",
+    "name": "Full name",
+  }, {
+    "columnName": "abbreviation",
+    "method": "getAbbreviation",
+    "name": "Abbreviation",
+  }, {
+    "columnName": "formula",
+    "method": "getFormula",
+    "name": "Formula",
+  }, {
+    "columnName": "synonyms",
+    "method": "getSynonyms",
+    "name": "Synonyms",
+  }, {
+    "columnName": "formerSymbols",
+    "method": "getFormerSymbols",
+    "name": "Former symbols",
+  }, {
+    "columnName": "references",
+    "method": "getReferences",
+    "name": "References",
+    "formatFunction": function (references) {
+      var stringBuilder = [];
+      for (var i = 0; i < references.length; i++) {
+        var reference = references[i];
+        stringBuilder.push(reference.getType() + ":" + reference.getResource());
+      }
+      return stringBuilder.join(",");
+    },
+  }, {
+    "columnName": "linkedSubmodelId",
+    "method": "getLinkedSubmodelId",
+    "name": "Linked submodel",
+  }, {
+    "columnName": "elementId",
+    "method": "getElementId",
+    "name": "Element external id",
+  },];
 };
 
 
diff --git a/frontend-js/src/main/js/gui/export/NetworkExportPanel.js b/frontend-js/src/main/js/gui/export/NetworkExportPanel.js
index d93fdebae2..8409f17553 100644
--- a/frontend-js/src/main/js/gui/export/NetworkExportPanel.js
+++ b/frontend-js/src/main/js/gui/export/NetworkExportPanel.js
@@ -17,43 +17,43 @@ function NetworkExportPanel(params) {
 NetworkExportPanel.prototype = Object.create(AbstractExportPanel.prototype);
 NetworkExportPanel.prototype.constructor = NetworkExportPanel;
 
-NetworkExportPanel.prototype.init = function() {
+NetworkExportPanel.prototype.init = function () {
 
   var self = this;
   var element = self.getElement();
   var configuration;
-  return ServerConnector.getConfiguration().then(function(result) {
+  return ServerConnector.getConfiguration().then(function (result) {
     configuration = result;
     var typeDiv = self._createSelectTypeDiv(configuration.getElementTypes());
     element.appendChild(typeDiv);
     element.appendChild(self._createSelectColumnDiv(self.getAllColumns()));
     return ServerConnector.getProjectStatistics(self.getProject().getProjectId());
-  }).then(function(statistics) {
+  }).then(function (statistics) {
     return self._createMiriamTypeDiv(statistics.getReactionAnnotations());
-  }).then(function(div) {
+  }).then(function (div) {
     element.appendChild(div);
     return self._createSelectIncludedCompartmentDiv();
-  }).then(function(div) {
+  }).then(function (div) {
     element.appendChild(div);
     return self._createSelectExcludedCompartmentDiv();
-  }).then(function(div) {
+  }).then(function (div) {
     element.appendChild(div);
     element.appendChild(self._createDownloadButton());
-  }).then(function() {
+  }).then(function () {
     $(window).trigger('resize');
   });
 
 };
 
-NetworkExportPanel.prototype.getAllColumns = function() {
-  return [ {
-    "columnName" : "elements",
-    "method" : "getElements",
-    "name" : "Elements",
-    "formatFunction" : function(elements, reaction, elementIds) {
+NetworkExportPanel.prototype.getAllColumns = function () {
+  return [{
+    "columnName": "elements",
+    "method": "getElements",
+    "name": "Elements",
+    "formatFunction": function (elements, reaction, elementIds) {
       var stringBuilder = [];
       var type;
-      var elementFormat = function(element) {
+      var elementFormat = function (element) {
         if (elementIds[element.getId()]) {
           stringBuilder.push(type + ":" + element.getId());
         }
@@ -68,42 +68,42 @@ NetworkExportPanel.prototype.getAllColumns = function() {
       return stringBuilder.join(",");
     },
   }, {
-    "columnName" : "id",
-    "method" : "getId",
-    "name" : "Id",
+    "columnName": "id",
+    "method": "getId",
+    "name": "Id",
   }, {
-    "columnName" : "description",
-    "method" : "getDescription",
-    "name" : "Description",
+    "columnName": "description",
+    "method": "getDescription",
+    "name": "Description",
   }, {
-    "columnName" : "modelId",
-    "method" : "getModelId",
-    "name" : "Model",
+    "columnName": "modelId",
+    "method": "getModelId",
+    "name": "Model",
   }, {
-    "columnName" : "type",
-    "method" : "getType",
-    "name" : "Type",
+    "columnName": "type",
+    "method": "getType",
+    "name": "Type",
   }, {
-    "columnName" : "symbol",
-    "method" : "getSymbol",
-    "name" : "Symbol",
+    "columnName": "symbol",
+    "method": "getSymbol",
+    "name": "Symbol",
   }, {
-    "columnName" : "abbreviation",
-    "method" : "getAbbreviation",
-    "name" : "Abbreviation",
+    "columnName": "abbreviation",
+    "method": "getAbbreviation",
+    "name": "Abbreviation",
   }, {
-    "columnName" : "formula",
-    "method" : "getFormula",
-    "name" : "Formula",
+    "columnName": "formula",
+    "method": "getFormula",
+    "name": "Formula",
   }, {
-    "columnName" : "synonyms",
-    "method" : "getSynonyms",
-    "name" : "Synonyms",
+    "columnName": "synonyms",
+    "method": "getSynonyms",
+    "name": "Synonyms",
   }, {
-    "columnName" : "references",
-    "method" : "getReferences",
-    "name" : "References",
-    "formatFunction" : function(references) {
+    "columnName": "references",
+    "method": "getReferences",
+    "name": "References",
+    "formatFunction": function (references) {
       var stringBuilder = [];
       for (var i = 0; i < references.length; i++) {
         var reference = references[i];
@@ -112,35 +112,35 @@ NetworkExportPanel.prototype.getAllColumns = function() {
       return stringBuilder.join(",");
     },
   }, {
-    "columnName" : "reactionId",
-    "method" : "getReactionId",
-    "name" : "Element external id",
+    "columnName": "reactionId",
+    "method": "getReactionId",
+    "name": "Element external id",
   }, {
-    "columnName" : "mechanicalConfidenceScore",
-    "method" : "getMechanicalConfidenceScore",
-    "name" : "Mechanical Confidence Score",
+    "columnName": "mechanicalConfidenceScore",
+    "method": "getMechanicalConfidenceScore",
+    "name": "Mechanical Confidence Score",
   }, {
-    "columnName" : "lowerBound",
-    "method" : "getLowerBound",
-    "name" : "Lower Bound",
+    "columnName": "lowerBound",
+    "method": "getLowerBound",
+    "name": "Lower Bound",
   }, {
-    "columnName" : "upperBound",
-    "method" : "getUpperBound",
-    "name" : "Upper Bound",
+    "columnName": "upperBound",
+    "method": "getUpperBound",
+    "name": "Upper Bound",
   }, {
-    "columnName" : "geneProteinReaction",
-    "method" : "getGeneProteinReaction",
-    "name" : "Gene Protein Reaction",
+    "columnName": "geneProteinReaction",
+    "method": "getGeneProteinReaction",
+    "name": "Gene Protein Reaction",
   }, {
-    "columnName" : "subsystem",
-    "method" : "getSubsystem",
-    "name" : "Subsystem",
-  }, ];
+    "columnName": "subsystem",
+    "method": "getSubsystem",
+    "name": "Subsystem",
+  },];
 };
 
 function matchReaction(reaction, elementIds) {
   var count = 0;
-  reaction.getElements().forEach(function(element) {
+  reaction.getElements().forEach(function (element) {
     if (elementIds[element.getId()]) {
       count++;
     }
@@ -148,45 +148,42 @@ function matchReaction(reaction, elementIds) {
   return count > 1;
 }
 
-NetworkExportPanel.prototype.createResponseString = function() {
+NetworkExportPanel.prototype.createResponseString = function () {
   var self = this;
   var types, miriamTypes;
   var includedCompartmentIds = [];
   var excludedCompartmentIds = [];
-  var models = [ self.getProject().getModel() ];
-  for (var i = 0; i < self.getProject().getModel().getSubmodels().length; i++) {
-    models.push(self.getProject().getModel().getSubmodels()[i]);
-  }
+  var models = self.getProject().getModels();
 
   var elementIds = [];
   var reactions = [];
-  return self.getSelectedTypes().then(function(result) {
+  return self.getSelectedTypes().then(function (result) {
     if (result.length === 0) {
       return Promise.reject(new GuiMessageError("You must select at least one type"));
     }
     types = result;
     return self.getSelectedIncludedCompartments();
-  }).then(function(result) {
-    result.forEach(function(compartment) {
+  }).then(function (result) {
+    result.forEach(function (compartment) {
       includedCompartmentIds.push(compartment.getId());
     });
     return self.getSelectedExcludedCompartments();
-  }).then(function(result) {
-    result.forEach(function(compartment) {
+  }).then(function (result) {
+    result.forEach(function (compartment) {
       excludedCompartmentIds.push(compartment.getId());
     });
 
     var promises = [];
     for (var i = 0; i < models.length; i++) {
       promises.push(models[i].getAliases({
-        type : types,
-        complete : true,
-        includedCompartmentIds : includedCompartmentIds,
-        excludedCompartmentIds : excludedCompartmentIds,
+        type: types,
+        complete: true,
+        includedCompartmentIds: includedCompartmentIds,
+        excludedCompartmentIds: excludedCompartmentIds,
       }));
     }
     return Promise.all(promises);
-  }).then(function(aliasesByModel) {
+  }).then(function (aliasesByModel) {
     var promises = [];
     for (var i = 0; i < models.length; i++) {
       promises.push(models[i].getReactionsForElements(aliasesByModel[i], true));
@@ -195,7 +192,7 @@ NetworkExportPanel.prototype.createResponseString = function() {
       }
     }
     return Promise.all(promises);
-  }).then(function(reactionsByModel) {
+  }).then(function (reactionsByModel) {
     for (var i = 0; i < models.length; i++) {
       for (var j = 0; j < reactionsByModel[i].length; j++) {
         var reaction = reactionsByModel[i][j];
@@ -205,10 +202,10 @@ NetworkExportPanel.prototype.createResponseString = function() {
       }
     }
     return self.getSelectedMiriamTypes();
-  }).then(function(result) {
+  }).then(function (result) {
     miriamTypes = result;
     return self.getSelectedColumns();
-  }).then(function(selectedColumns) {
+  }).then(function (selectedColumns) {
     if (selectedColumns.length === 0) {
       return Promise.reject(new GuiMessageError("You must select at least one column"));
     }
@@ -222,7 +219,7 @@ NetworkExportPanel.prototype.createResponseString = function() {
   });
 };
 
-NetworkExportPanel.prototype.createResponseRow = function(reaction, columns, miriamTypes, elementIds) {
+NetworkExportPanel.prototype.createResponseRow = function (reaction, columns, miriamTypes, elementIds) {
   var stringBuilder = [];
   var i, value;
   for (i = 0; i < columns.length; i++) {
diff --git a/frontend-js/src/main/js/gui/leftPanel/SubmapPanel.js b/frontend-js/src/main/js/gui/leftPanel/SubmapPanel.js
index 66b39646be..fb3bcf711f 100644
--- a/frontend-js/src/main/js/gui/leftPanel/SubmapPanel.js
+++ b/frontend-js/src/main/js/gui/leftPanel/SubmapPanel.js
@@ -85,11 +85,11 @@ SubmapPanel.prototype.init = function () {
   return new Promise(function (resolve) {
     var div = self.getControlElement(PanelControlElementType.SUBMAP_DIV);
     div.innerHTML = "";
-    var models = self.getMap().getProject().getModel().getSubmodels();
+    var models = self.getMap().getProject().getModels();
     var modelsByType = [];
     var types = [];
     var i;
-    for (i = 0; i < models.length; i++) {
+    for (i = 1; i < models.length; i++) {
       var model = models[i];
       if (modelsByType[model.getSubmodelType()] === undefined) {
         modelsByType[model.getSubmodelType()] = [];
@@ -105,7 +105,7 @@ SubmapPanel.prototype.init = function () {
       }
       div.appendChild(self.createTable(modelsByType[type], tableName));
     }
-    if (models.length === 0) {
+    if (models.length <= 1) {
       self.getParent().hideTab(self);
     }
     return resolve();
diff --git a/frontend-js/src/main/js/map/AbstractCustomMap.js b/frontend-js/src/main/js/map/AbstractCustomMap.js
index 3af752ca1a..e906e76f6a 100644
--- a/frontend-js/src/main/js/map/AbstractCustomMap.js
+++ b/frontend-js/src/main/js/map/AbstractCustomMap.js
@@ -113,13 +113,14 @@ AbstractCustomMap.prototype.createMapOptions = function () {
   var self = this;
   var model = self.getModel();
 
-  var centerPoint = this.getModel().getCenterLatLng();
 
   var zoom = ServerConnector.getSessionData(self.getProject()).getZoomLevel(model);
   if (zoom === undefined) {
     zoom = this.getMinZoom();
   }
 
+  var centerPoint;
+
   // if we have coordinate data stored in session then restore it
   var point = ServerConnector.getSessionData(self.getProject()).getCenter(model);
   if (point !== undefined) {
@@ -134,6 +135,8 @@ AbstractCustomMap.prototype.createMapOptions = function () {
 
     centerPoint = self.fromPointToLatLng(new google.maps.Point(model.getDefaultCenterX(), model.getDefaultCenterY()));
     zoom = model.getDefaultZoomLevel();
+  } else {
+    centerPoint = self.fromPointToLatLng(new google.maps.Point(model.getWidth() / 2, model.getHeight() / 2));
   }
 
   return {
@@ -413,36 +416,36 @@ AbstractCustomMap.prototype.registerMapClickEvents = function () {
   });
 };
 
-function activateMolStarLink(coordinates, map){
+function activateMolStarLink(coordinates, map) {
 
   ServerConnector.getClosestElementsByCoordinates({
     modelId: map.getId(),
     coordinates: coordinates,
     count: 1
-  }).then(function(identifiedElements){
+  }).then(function (identifiedElements) {
     return map.getDistance({
       modelId: map.getId(),
       coordinates: coordinates,
       element: identifiedElements[0]
-    }).then(function(distance){
+    }).then(function (distance) {
       if (distance == 0) return identifiedElements;
       else return Promise.reject(new Error());
     })
 
-  }).then(function(identifiedElements) {
+  }).then(function (identifiedElements) {
     if (identifiedElements[0].type !== 'ALIAS') return Promise.reject(new Error());
     return map.getModel().getAliasById(identifiedElements[0].id, true)
-  }).then (function(element){
+  }).then(function (element) {
     var uniprotIds = [];
-    for (var i =0; i < element.references.length; i++) {
+    for (var i = 0; i < element.references.length; i++) {
       var ref = element.references[i];
       if (ref.constructor.name === 'Annotation' && ref.getType() === 'UNIPROT') {
-          uniprotIds.push(ref.getResource());
+        uniprotIds.push(ref.getResource());
       }
     }
     if (uniprotIds.length > 0) map.getContextMenu().getMolStar().activateInContextMenu(uniprotIds);
     else map.getContextMenu().getMolStar().deactivateInContextMenu();
-  }, function(){
+  }, function () {
     map.getContextMenu().getMolStar().deactivateInContextMenu();
   });
 }
@@ -1078,11 +1081,11 @@ AbstractCustomMap.prototype.isDebug = function () {
 };
 
 AbstractCustomMap.prototype.getTopLeftLatLng = function () {
-  return this.getModel().getTopLeftLatLng();
+  return this.fromPointToLatLng(new google.maps.Point(0, 0))
 };
 
 AbstractCustomMap.prototype.getBottomRightLatLng = function () {
-  return this.getModel().getBottomRightLatLng();
+  return this.fromPointToLatLng(new google.maps.Point(this.getModel().getWidth(), this.getModel().getHeight()));
 };
 
 AbstractCustomMap.prototype.getElement = function () {
diff --git a/frontend-js/src/main/js/map/CustomMap.js b/frontend-js/src/main/js/map/CustomMap.js
index 86759aabad..241812f49f 100644
--- a/frontend-js/src/main/js/map/CustomMap.js
+++ b/frontend-js/src/main/js/map/CustomMap.js
@@ -33,7 +33,7 @@ function CustomMap(options) {
   if (!(options instanceof CustomMapOptions)) {
     options = new CustomMapOptions(options);
   }
-  AbstractCustomMap.call(this, options.getProject().getModel(), options);
+  AbstractCustomMap.call(this, options.getProject().getModels()[0], options);
 
   this.registerListenerType("onBioEntityClick");
   this.registerListenerType("onShowOverlay");
@@ -113,8 +113,8 @@ CustomMap.prototype.init = function () {
  */
 CustomMap.prototype.createSubmaps = function () {
   this.submaps = [];
-  for (var i = 0; i < this.getModel().getSubmodels().length; i++) {
-    this.submaps.push(new Submap(this, this.getModel().getSubmodels()[i]));
+  for (var i = 1; i < this.getProject().getModels().length; i++) {
+    this.submaps.push(new Submap(this, this.getProject().getModels()[i]));
   }
 };
 
diff --git a/frontend-js/src/main/js/map/Submap.js b/frontend-js/src/main/js/map/Submap.js
index 859628cea3..9926d7ffb1 100644
--- a/frontend-js/src/main/js/map/Submap.js
+++ b/frontend-js/src/main/js/map/Submap.js
@@ -91,7 +91,7 @@ Submap.prototype.open = function (htmlTag) {
 
     self.registerMapClickEvents();
 
-    var centerPoint = self.getModel().getCenterLatLng();
+    var centerPoint = self.fromPointToLatLng(new google.maps.Point(self.getModel().getWidth() / 2, self.getModel().getHeight() / 2));
     self.getGoogleMap().setCenter(centerPoint);
     self.addCenterButton();
 
diff --git a/frontend-js/src/main/js/map/data/MapModel.js b/frontend-js/src/main/js/map/data/MapModel.js
index da98828014..63f81fcdc4 100644
--- a/frontend-js/src/main/js/map/data/MapModel.js
+++ b/frontend-js/src/main/js/map/data/MapModel.js
@@ -39,8 +39,6 @@ function MapModel(configuration) {
   // but it can be extended)
   this._pointsData = [];
 
-  this._submodels = [];
-
   this._sbmlFunctions = [];
   this._sbmlParameters = [];
 
@@ -54,10 +52,6 @@ function MapModel(configuration) {
       this.setHeight(configuration.getHeight());
       this.setMinZoom(configuration.getMinZoom());
       this.setMaxZoom(configuration.getMaxZoom());
-      this.addSubmodels(configuration.getSubmodels());
-      this.setCenterLatLng(configuration.getCenterLatLng());
-      this.setTopLeftLatLng(configuration.getTopLeftLatLng());
-      this.setBottomRightLatLng(configuration.getBottomRightLatLng());
       this.setSubmodelType(configuration.getSubmodelType());
       this.setDefaultCenterX(configuration.getDefaultCenterX());
       this.setDefaultCenterY(configuration.getDefaultCenterY());
@@ -70,10 +64,6 @@ function MapModel(configuration) {
       this.setHeight(configuration.height);
       this.setMinZoom(configuration.minZoom);
       this.setMaxZoom(configuration.maxZoom);
-      this.addSubmodels(configuration.submodels);
-      this.setCenterLatLng(configuration.centerLatLng);
-      this.setTopLeftLatLng(configuration.topLeftLatLng);
-      this.setBottomRightLatLng(configuration.bottomRightLatLng);
       this.setSubmodelType(configuration.submodelType);
       this.setDefaultCenterX(configuration.defaultCenterX);
       this.setDefaultCenterY(configuration.defaultCenterY);
@@ -485,45 +475,6 @@ function createLatLng(param) {
   }
 }
 
-MapModel.prototype.setCenterLatLng = function (centerLatLng) {
-  var newVal = createLatLng(centerLatLng);
-  if (newVal === null) {
-    logger.warn("centerLatLng is invalid");
-  } else {
-    this._centerLatLng = newVal;
-  }
-};
-
-MapModel.prototype.getCenterLatLng = function () {
-  return this._centerLatLng;
-};
-
-MapModel.prototype.setTopLeftLatLng = function (topLeftLatLng) {
-  var newVal = createLatLng(topLeftLatLng);
-  if (newVal === null) {
-    logger.warn("topLeftLatLng is invalid");
-  } else {
-    this._topLeftLatLng = newVal;
-  }
-};
-
-MapModel.prototype.getTopLeftLatLng = function () {
-  return this._topLeftLatLng;
-};
-
-MapModel.prototype.setBottomRightLatLng = function (bottomRightLatLng) {
-  var newVal = createLatLng(bottomRightLatLng);
-  if (newVal === null) {
-    logger.warn("bottomRightLatLng is invalid");
-  } else {
-    this._bottomRightLatLng = newVal;
-  }
-};
-
-MapModel.prototype.getBottomRightLatLng = function () {
-  return this._bottomRightLatLng;
-};
-
 MapModel.prototype.getMaxZoom = function () {
   return this._maxZoom;
 };
@@ -544,37 +495,6 @@ MapModel.prototype.setTileSize = function (tileSize) {
   this._tileSize = tileSize;
 };
 
-MapModel.prototype.addSubmodels = function (submodels) {
-  if (submodels !== undefined) {
-    for (var i = 0; i < submodels.length; i++) {
-      this.addSubmodel(submodels[i]);
-    }
-  }
-};
-
-MapModel.prototype.addSubmodel = function (submodel) {
-  if (!(submodel instanceof MapModel)) {
-    submodel = new MapModel(submodel);
-  }
-  this._submodels.push(submodel);
-};
-
-MapModel.prototype.getSubmodels = function () {
-  return this._submodels;
-};
-
-MapModel.prototype.getSubmodelById = function (id) {
-  if (this.getId() === id) {
-    return this;
-  }
-  for (var i = 0; i < this._submodels.length; i++) {
-    if (this._submodels[i].getId() === id) {
-      return this._submodels[i];
-    }
-  }
-  return null;
-};
-
 MapModel.prototype.getByIdentifiedElement = function (ie, complete) {
   var self = this;
   if (ie.getType() === "ALIAS") {
diff --git a/frontend-js/src/main/js/map/data/Project.js b/frontend-js/src/main/js/map/data/Project.js
index adda342238..47432a6b43 100644
--- a/frontend-js/src/main/js/map/data/Project.js
+++ b/frontend-js/src/main/js/map/data/Project.js
@@ -19,6 +19,7 @@ function Project(data) {
   this.registerListenerType("onreload");
 
   this._dataOverlays = [];
+  this._models = [];
   this._elementsPointingToSubmap = [];
 
   if (data !== undefined) {
@@ -77,8 +78,11 @@ Project.prototype.update = function (data) {
   self.setHasWarnings(data.hasWarnings());
   self.setHasErrors(data.hasErrors());
 
-  if (data.getModel() !== undefined) {
-    self.setModel(new Model(data.getModel()));
+  if (data.getModels() !== undefined) {
+    var models = data.getModels();
+    for (var i = 0; i < models.length; i++) {
+      self.addModel(new Model(models[i]));
+    }
   }
 
   self.callListeners("onreload");
@@ -138,11 +142,23 @@ Project.prototype.getName = function () {
 Project.prototype.setName = function (name) {
   this._name = name;
 };
-Project.prototype.getModel = function () {
-  return this._model;
+Project.prototype.getModels = function () {
+  return this._models;
+};
+Project.prototype.getModelById = function (modelId) {
+  for (var i = 0; i < this._models.length; i++) {
+    if (this._models[i].getId() === modelId) {
+      return this._models[i];
+    }
+  }
+  return null;
+};
+Project.prototype.setModels = function (models) {
+  this._models = models;
 };
-Project.prototype.setModel = function (model) {
-  this._model = model;
+
+Project.prototype.addModel = function (model) {
+  this._models.push(model);
 };
 
 Project.prototype.getOverviewImages = function () {
diff --git a/frontend-js/src/main/js/map/surface/AliasSurface.js b/frontend-js/src/main/js/map/surface/AliasSurface.js
index 2aba79b1b4..c38438102c 100644
--- a/frontend-js/src/main/js/map/surface/AliasSurface.js
+++ b/frontend-js/src/main/js/map/surface/AliasSurface.js
@@ -121,7 +121,7 @@ AliasSurface.create = function (params) {
 AliasSurface.createFromIdentifiedElement = function (params) {
   var element = params.element;
   var map = params.map;
-  var model = map.getModel().getSubmodelById(element.getModelId());
+  var model = map.getProject().getModelById(element.getModelId());
   var fillOpacity;
   return ServerConnector.getConfigurationParam(ConfigurationType.OVERLAY_OPACITY).then(function (result) {
     fillOpacity = result;
diff --git a/frontend-js/src/main/js/minerva.js b/frontend-js/src/main/js/minerva.js
index 7f0a8f6e64..0cffc5c390 100644
--- a/frontend-js/src/main/js/minerva.js
+++ b/frontend-js/src/main/js/minerva.js
@@ -35,12 +35,14 @@ function processUrlGetParams(params) {
   var project = params.getProject();
   var sessionData = ServerConnector.getSessionData(project);
 
-  var modelId = project.getModel().getId();
+  var modelId;
   if (GuiConnector.getParams["submap"] !== undefined) {
     modelId = parseInt(GuiConnector.getParams["submap"]);
+  } else {
+    modelId = project.getModels()[0].getId()
   }
 
-  var model = project.getModel().getSubmodelById(modelId);
+  var model = project.getModelById(modelId);
 
   if (GuiConnector.getParams["x"] !== undefined && GuiConnector.getParams["y"] !== undefined) {
     var point = new google.maps.Point(GuiConnector.getParams["x"], GuiConnector.getParams["y"]);
diff --git a/frontend-js/src/main/js/plugin/MinervaPluginProxy.js b/frontend-js/src/main/js/plugin/MinervaPluginProxy.js
index 18bb5a27a3..6cd40e9835 100644
--- a/frontend-js/src/main/js/plugin/MinervaPluginProxy.js
+++ b/frontend-js/src/main/js/plugin/MinervaPluginProxy.js
@@ -61,7 +61,7 @@ function getElements(elementIdentifiers, customMap) {
   var modelScopePromises = [];
   for (var key in elementsByModelId) {
     if (elementsByModelId.hasOwnProperty(key)) {
-      var model = customMap.getModel().getSubmodelById(parseInt(key));
+      var model = customMap.getProject().getModelById(parseInt(key));
       modelScopePromises.push(model.getByIdentifiedElements(elementsByModelId[key], true));
     }
   }
@@ -71,7 +71,7 @@ function getElements(elementIdentifiers, customMap) {
     var elementPromises = [];
     for (var i = 0; i < identifiedElements.length; i++) {
       var element = identifiedElements[i];
-      var model = customMap.getModel().getSubmodelById(element.getModelId());
+      var model = customMap.getProject().getModelById(element.getModelId());
       var promise = model.getByIdentifiedElement(element, true);
       elementPromises.push(promise);
     }
@@ -98,14 +98,10 @@ function createProjectData(options) {
       });
     },
     getAllBioEntities: function () {
-      var models = [map.getModel()];
+      var models = map.getProject().getModels();
       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++) {
+      for (var i = 0; i < models.length; i++) {
         promises.push(models[i].getAliases({
           type: map.getConfiguration().getSimpleElementTypeNames(),
           complete: true
@@ -187,7 +183,7 @@ function getReactionsForElements(elementIdentifiers, customMap) {
   var modelScopePromises = [];
   for (var key in elementsByModelId) {
     if (elementsByModelId.hasOwnProperty(key)) {
-      var model = customMap.getModel().getSubmodelById(parseInt(key));
+      var model = customMap.getProject().getModelById(parseInt(key));
       var promise = model.getReactionsForElements(elementsByModelId[key], true);
       modelScopePromises.push(promise);
     }
diff --git a/frontend-js/src/test/js/gui/MapContextMenu-test.js b/frontend-js/src/test/js/gui/MapContextMenu-test.js
index 42c576cd05..b80cb3e41e 100644
--- a/frontend-js/src/test/js/gui/MapContextMenu-test.js
+++ b/frontend-js/src/test/js/gui/MapContextMenu-test.js
@@ -41,7 +41,7 @@ describe('MapContextMenu', function () {
         element: testDiv,
         customMap: map
       });
-      map.setActiveSubmapId(map.getProject().getModel().getId());
+      map.setActiveSubmapId(map.getProject().getModels()[0].getId());
       map.setActiveSubmapClickCoordinates(new google.maps.Point(2, 12));
 
       var handler = $($("a:contains('comment')", $(testDiv))[0]).data("handler");
@@ -60,7 +60,7 @@ describe('MapContextMenu', function () {
         element: testDiv,
         customMap: map
       });
-      map.setActiveSubmapId(map.getProject().getModel().getId());
+      map.setActiveSubmapId(map.getProject().getModels()[0].getId());
       map.setActiveSubmapClickCoordinates(new google.maps.Point(2, 12));
 
       assert.ok(!map.isDrawingOn());
diff --git a/frontend-js/src/test/js/gui/SelectionContextMenu-test.js b/frontend-js/src/test/js/gui/SelectionContextMenu-test.js
index 693b76345a..ed613d4947 100644
--- a/frontend-js/src/test/js/gui/SelectionContextMenu-test.js
+++ b/frontend-js/src/test/js/gui/SelectionContextMenu-test.js
@@ -33,7 +33,7 @@ describe('SelectionContextMenu', function () {
       });
       return contextMenu.init();
     }).then(function () {
-      map.setActiveSubmapId(map.getProject().getModel().getId());
+      map.setActiveSubmapId(map.getProject().getModels()[0].getId());
       map.setActiveSubmapClickCoordinates(new google.maps.Point(2, 12));
 
       var handler = $($("a:contains('PNG')", $(testDiv))[0]).data("handler");
@@ -54,7 +54,7 @@ describe('SelectionContextMenu', function () {
       });
       return contextMenu.init();
     }).then(function () {
-      map.setActiveSubmapId(map.getProject().getModel().getId());
+      map.setActiveSubmapId(map.getProject().getModels()[0].getId());
       map.setActiveSubmapClickCoordinates(new google.maps.Point(2, 12));
       var handler = $($("a:contains('CellDesigner')", $(testDiv))[0]).data("handler");
       return handler();
diff --git a/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js b/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js
index a646cce3f5..eaf001bb28 100644
--- a/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js
+++ b/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js
@@ -159,7 +159,7 @@ describe('OverlayPanel', function () {
       return panel.init().then(function () {
         return panel.openAddOverlayDialog();
       }).then(function () {
-        var overlay = helper.createOverlay(panel.getProject().getModel());
+        var overlay = helper.createOverlay(panel.getProject().getModels()[0]);
         return panel._addOverlayDialog.callListeners("onAddOverlay", overlay);
       }).then(function () {
         return panel.destroy();
diff --git a/frontend-js/src/test/js/helper.js b/frontend-js/src/test/js/helper.js
index a63b23d414..cbb33ed033 100644
--- a/frontend-js/src/test/js/helper.js
+++ b/frontend-js/src/test/js/helper.js
@@ -151,7 +151,7 @@ Helper.prototype.createProject = function () {
   var result = new Project();
   result.setProjectId("testId");
   result.setId(this.idCounter++);
-  result.setModel(this.createModel());
+  result.addModel(this.createModel());
   var overlay = this.createOverlay(result);
   result.addDataOverlay(overlay);
   return result;
@@ -309,19 +309,6 @@ Helper.prototype.createModel = function () {
   result.setHeight(800);
   result.setMaxZoom(8);
   result.setMinZoom(2);
-  result.setCenterLatLng({
-    lat: 10,
-    lng: 20
-  });
-  result.setTopLeftLatLng({
-    lat: 8,
-    lng: 8
-  });
-  result.setBottomRightLatLng({
-    lat: 30,
-    lng: 30
-  });
-
   return result;
 };
 
@@ -366,7 +353,7 @@ Helper.prototype.createCustomMapOptions = function (project) {
 
 Helper.prototype.createAbstractCustomMap = function () {
   var options = this.createCustomMapOptions();
-  return new AbstractCustomMap(options.getProject().getModel(), options);
+  return new AbstractCustomMap(options.getProject().getModels()[0], options);
 
 };
 
diff --git a/frontend-js/src/test/js/map/AbstractCustomMap-test.js b/frontend-js/src/test/js/map/AbstractCustomMap-test.js
index 011d3a7157..31aa1fc307 100644
--- a/frontend-js/src/test/js/map/AbstractCustomMap-test.js
+++ b/frontend-js/src/test/js/map/AbstractCustomMap-test.js
@@ -41,7 +41,7 @@ describe('AbstractCustomMap', function () {
     var layout = project.getDataOverlays()[0];
     var options = helper.createCustomMapOptions(project);
 
-    var mockObject = new AbstractCustomMap(project.getModel(), options);
+    var mockObject = new AbstractCustomMap(project.getModels()[0], options);
 
     var googleMap = helper.createGoogleMap();
 
@@ -76,7 +76,7 @@ describe('AbstractCustomMap', function () {
 
       var options = helper.createCustomMapOptions(project);
 
-      var mockObject = new AbstractCustomMap(project.getModel(), options);
+      var mockObject = new AbstractCustomMap(project.getModels()[0], options);
 
       var result = mockObject.createTypeOptions(layoutDataObj);
 
diff --git a/frontend-js/src/test/js/map/CustomMap-test.js b/frontend-js/src/test/js/map/CustomMap-test.js
index 1400b236af..b360261aba 100644
--- a/frontend-js/src/test/js/map/CustomMap-test.js
+++ b/frontend-js/src/test/js/map/CustomMap-test.js
@@ -34,7 +34,7 @@ describe('CustomMap', function () {
     it("with submaps", function () {
       var options = helper.createCustomMapOptions();
 
-      options.getProject().getModel().addSubmodel(helper.createModel());
+      options.getProject().addModel(helper.createModel());
 
       var map = new CustomMap(options);
       assert.ok(map);
@@ -805,7 +805,7 @@ describe('CustomMap', function () {
     var options = helper.createCustomMapOptions();
 
     var submodel = helper.createModel();
-    options.getProject().getModel().addSubmodel(submodel);
+    options.getProject().addModel(submodel);
 
     var map = new CustomMap(options);
 
@@ -827,7 +827,7 @@ describe('CustomMap', function () {
       var options = helper.createCustomMapOptions();
 
       var submodel = helper.createModel();
-      options.getProject().getModel().addSubmodel(submodel);
+      options.getProject().addModel(submodel);
 
       var map = new CustomMap(options);
       map.openSubmap(submodel.getId());
diff --git a/frontend-js/src/test/js/map/data/MapModel-test.js b/frontend-js/src/test/js/map/data/MapModel-test.js
index 5f0880a965..7006c3f0e5 100644
--- a/frontend-js/src/test/js/map/data/MapModel-test.js
+++ b/frontend-js/src/test/js/map/data/MapModel-test.js
@@ -133,7 +133,7 @@ describe('MapModel', function () {
     var model;
     return ServerConnector.getProject().then(function (project) {
 
-      model = project.getModel();
+      model = project.getModels()[0];
       var ie = new IdentifiedElement({
         modelId: 15781,
         type: "ALIAS",
diff --git a/frontend-js/src/test/js/map/overlay/SearchDbOverlay-test.js b/frontend-js/src/test/js/map/overlay/SearchDbOverlay-test.js
index cd228e1aa3..5e9a3e006b 100644
--- a/frontend-js/src/test/js/map/overlay/SearchDbOverlay-test.js
+++ b/frontend-js/src/test/js/map/overlay/SearchDbOverlay-test.js
@@ -197,7 +197,7 @@ describe('SearchDbOverlay', function () {
         var searchParams = new IdentifiedElement({
           type: "ALIAS",
           id: 329177,
-          modelId: project.getModel().getId()
+          modelId: project.getModels()[0].getId()
         });
         return searchDb.getDetailDataByIdentifiedElement(searchParams);
       }).then(function (result) {
@@ -213,7 +213,7 @@ describe('SearchDbOverlay', function () {
         var searchParams = new IdentifiedElement({
           type: "POINT",
           id: "2,3",
-          modelId: project.getModel().getId()
+          modelId: project.getModels()[0].getId()
         });
         return searchDb.getDetailDataByIdentifiedElement(searchParams);
       }).then(function (result) {
diff --git a/frontend-js/src/test/js/minerva-test.js b/frontend-js/src/test/js/minerva-test.js
index 1a149f451c..9e9e54d499 100644
--- a/frontend-js/src/test/js/minerva-test.js
+++ b/frontend-js/src/test/js/minerva-test.js
@@ -93,7 +93,7 @@ describe('minerva global', function () {
         return minerva.create(options);
       }).then(function (result) {
         var sessionData = ServerConnectorMock.getSessionData(options.getProject());
-        assert.equal(sessionData.getZoomLevel(options.getProject().getModel()), 5);
+        assert.equal(sessionData.getZoomLevel(options.getProject().getModels()[0]), 5);
         return result.destroy();
       });
     });
@@ -105,7 +105,7 @@ describe('minerva global', function () {
         options = helper.createCustomMapOptions(project);
         return minerva.create(options);
       }).then(function (result) {
-        var center = ServerConnectorMock.getSessionData(options.getProject()).getCenter(options.getProject().getModel());
+        var center = ServerConnectorMock.getSessionData(options.getProject()).getCenter(options.getProject().getModels()[0]);
         assert.ok(center instanceof google.maps.Point);
         assert.equal(center.x, 5);
         assert.equal(center.y, 6);
@@ -231,9 +231,6 @@ describe('minerva global', function () {
   it('create with show submodel GET param', function () {
     helper.setUrl("http://test/?submap=15781");
 
-    var project = helper.createProject();
-    project.getModel().setId(15781);
-
     return ServerConnectorMock.getProject().then(function (project) {
       var options = helper.createCustomMapOptions(project);
 
diff --git a/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js b/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js
index 10cf351524..b701ce3b01 100644
--- a/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js
+++ b/frontend-js/src/test/js/plugin/MinervaPluginProxy-test.js
@@ -70,7 +70,7 @@ describe('MinervaPluginProxy', function () {
       var params = {
         coordinates: new google.maps.Point(184.79, 365.76),
         zoom: 2,
-        modelId: map.getProject().getModel().getId()
+        modelId: map.getProject().getModels()[0].getId()
       };
       return map.getOverlayByName("search").searchByCoordinates(params);
     }).then(function () {
@@ -304,7 +304,7 @@ describe('MinervaPluginProxy', function () {
       });
     }).then(function () {
       var sessionData = ServerConnector.getSessionData(map.getProject());
-      var center = sessionData.getCenter(map.getProject().getModel());
+      var center = sessionData.getCenter(map.getProject().getModels()[0]);
       assert.ok(center instanceof google.maps.Point);
       assert.closeTo(parseFloat(center.x), 10, helper.EPSILON);
       assert.closeTo(parseFloat(center.y), 20, helper.EPSILON);
@@ -344,7 +344,7 @@ describe('MinervaPluginProxy', function () {
       });
     }).then(function () {
       var sessionData = ServerConnector.getSessionData(map.getProject());
-      var zoom = sessionData.getZoomLevel(map.getProject().getModel());
+      var zoom = sessionData.getZoomLevel(map.getProject().getModels()[0]);
       assert.equal(zoom, 10);
     }).then(function () {
       map.destroy();
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/model/Model.java b/model/src/main/java/lcsb/mapviewer/model/map/model/Model.java
index c489420b26..82bf729814 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/model/Model.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/model/Model.java
@@ -502,7 +502,7 @@ public interface Model {
    * 
    * @param identifier
    *          identifier of the model
-   * @return submodel identified by identifiere
+   * @return submodel identified by identifier
    */
   Model getSubmodelById(String identifier);
 
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelMetaData.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelMetaData.java
index c8f7f601e0..4fedb0ff45 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelMetaData.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelMetaData.java
@@ -1,18 +1,11 @@
 package lcsb.mapviewer.api.projects.models;
 
-import java.awt.geom.Point2D;
 import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.primefaces.model.map.LatLng;
 
 import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.model.ModelData;
-import lcsb.mapviewer.model.map.model.ModelSubmodelConnection;
 import lcsb.mapviewer.model.map.model.SubmodelType;
-import lcsb.mapviewer.services.utils.gmap.CoordinationConverter;
 
 public class ModelMetaData implements Serializable {
 
@@ -59,26 +52,6 @@ public class ModelMetaData implements Serializable {
    */
   private Integer maxZoom;
 
-  /**
-   * List of submodels in the model.
-   */
-  private List<ModelMetaData> submodels = new ArrayList<>();
-
-  /**
-   * Where is the center of the map in latitude, longitude format.
-   */
-  private LatLng centerLatLng;
-
-  /**
-   * Top-Left corner of the map (0,0) as a latLng coordinates.
-   */
-  private LatLng topLeftLatLng;
-
-  /**
-   * Bottom-Right corner of the map (width,height) as a latLng coordinates.
-   */
-  private LatLng bottomRightLatLng;
-
   /**
    * Type of the submodel.
    */
@@ -100,25 +73,10 @@ public class ModelMetaData implements Serializable {
     this.setTileSize(model.getTileSize());
     this.setWidth((int) (double) model.getWidth());
     this.setHeight((int) (double) model.getHeight());
-    int size = Math.max(width, height);
-    CoordinationConverter cConverter = new CoordinationConverter(model);
-    this.setCenterLatLng(cConverter.toLatLng(new Point2D.Double(size / 2, size / 2)));
-    this.setBottomRightLatLng(cConverter.toLatLng(new Point2D.Double(model.getWidth(), model.getHeight())));
-    this.setTopLeftLatLng(cConverter.toLatLng(new Point2D.Double(0, 0)));
     this.setDefaultCenterX(model.getDefaultCenterX());
     this.setDefaultCenterY(model.getDefaultCenterY());
     this.setDefaultZoomLevel(model.getDefaultZoomLevel());
 
-    List<ModelMetaData> submodels = new ArrayList<>();
-    List<ModelSubmodelConnection > submodelLinks = new ArrayList<>();
-    submodelLinks.addAll(model.getSubmodels());
-    submodelLinks.sort(ModelSubmodelConnection.ID_COMPARATOR);
-    for (ModelSubmodelConnection connection : submodelLinks) {
-      ModelMetaData submodelData = new ModelMetaData(connection.getSubmodel());
-      submodelData.setSubmodelType(connection.getType());
-      submodels.add(submodelData);
-    }
-    this.setSubmodels(submodels);
   }
 
   protected ModelMetaData() {
@@ -192,23 +150,6 @@ public class ModelMetaData implements Serializable {
     this.maxZoom = maxZoom;
   }
 
-  /**
-   * @return the centerLatLng
-   * @see #centerLatLng
-   */
-  public LatLng getCenterLatLng() {
-    return centerLatLng;
-  }
-
-  /**
-   * @param centerLatLng
-   *          the centerLatLng to set
-   * @see #centerLatLng
-   */
-  public void setCenterLatLng(LatLng centerLatLng) {
-    this.centerLatLng = centerLatLng;
-  }
-
   /**
    * @return the name
    * @see #name
@@ -226,40 +167,6 @@ public class ModelMetaData implements Serializable {
     this.name = name;
   }
 
-  /**
-   * @return the topLeftLatLng
-   * @see #topLeftLatLng
-   */
-  public LatLng getTopLeftLatLng() {
-    return topLeftLatLng;
-  }
-
-  /**
-   * @param topLeftLatLng
-   *          the topLeftLatLng to set
-   * @see #topLeftLatLng
-   */
-  public void setTopLeftLatLng(LatLng topLeftLatLng) {
-    this.topLeftLatLng = topLeftLatLng;
-  }
-
-  /**
-   * @return the bottomRightLatLng
-   * @see #bottomRightLatLng
-   */
-  public LatLng getBottomRightLatLng() {
-    return bottomRightLatLng;
-  }
-
-  /**
-   * @param bottomRightLatLng
-   *          the bottomRightLatLng to set
-   * @see #bottomRightLatLng
-   */
-  public void setBottomRightLatLng(LatLng bottomRightLatLng) {
-    this.bottomRightLatLng = bottomRightLatLng;
-  }
-
   /**
    * @return the width
    * @see #width
@@ -294,23 +201,6 @@ public class ModelMetaData implements Serializable {
     this.height = height;
   }
 
-  /**
-   * @return the submodels
-   * @see #submodels
-   */
-  public List<ModelMetaData> getSubmodels() {
-    return submodels;
-  }
-
-  /**
-   * @param submodels
-   *          the submodels to set
-   * @see #submodels
-   */
-  public void setSubmodels(List<ModelMetaData> submodels) {
-    this.submodels = submodels;
-  }
-
   /**
    * @return the idObject
    * @see #idObject
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java
index b59b1e7903..238d0a36a9 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java
@@ -43,12 +43,7 @@ public class ModelRestImpl extends BaseRestImpl {
     if (submodel == null) {
       return null;
     } else {
-      ModelMetaData result = new ModelMetaData(submodel);
-
-      List<ModelMetaData> metaDataToProcess = new ArrayList<>();
-      metaDataToProcess.add(result);
-      metaDataToProcess.addAll(result.getSubmodels());
-      return result;
+      return new ModelMetaData(submodel);
     }
   }
 
-- 
GitLab