From 5213ebf1c1c77168081a1b3f98d3663be5c69afd Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Fri, 29 Sep 2017 15:44:36 +0200
Subject: [PATCH] frontend for add zip projects

---
 .idea/modules.xml                             |  21 +
 .../mapviewer/converter/OverviewParser.java   |  15 +-
 .../mapviewer/converter/ProjectFactory.java   |   2 +-
 .../converter/zip/ImageZipEntryFile.java      |  91 +---
 .../converter/zip/LayoutZipEntryFile.java     | 114 +++--
 .../converter/zip/ZipEntryFileFactory.java    |   2 +-
 .../converter/OverviewParserTest.java         | 456 +++++++++--------
 converter/src/test/resources/log4j.properties |   2 +-
 converter/testFiles/invalid_overview_1.zip    | Bin 0 -> 6384 bytes
 .../testFiles/invalid_overview_1/coords.txt   |   4 -
 .../testFiles/invalid_overview_1/test.png     | Bin 10796 -> 0 bytes
 converter/testFiles/invalid_overview_2.zip    | Bin 0 -> 6384 bytes
 .../testFiles/invalid_overview_2/coords.txt   |   4 -
 .../testFiles/invalid_overview_2/test.png     | Bin 10796 -> 0 bytes
 converter/testFiles/invalid_overview_3.zip    | Bin 0 -> 6377 bytes
 .../testFiles/invalid_overview_3/coords.txt   |   4 -
 .../testFiles/invalid_overview_3/test.png     | Bin 10796 -> 0 bytes
 converter/testFiles/valid_overview.zip        | Bin 0 -> 6351 bytes
 converter/testFiles/valid_overview/coords.txt |   4 -
 converter/testFiles/valid_overview/test.png   | Bin 10796 -> 0 bytes
 frontend-js/.idea/frontend-js.iml             |   5 +-
 frontend-js/package.json                      |   1 +
 frontend-js/src/main/js/Configuration.js      |  14 +-
 .../src/main/js/gui/AddOverlayDialog.js       | 119 ++---
 .../src/main/js/gui/admin/AddProjectDialog.js | 365 ++++++++++++-
 frontend-js/src/main/js/gui/admin/ZipEntry.js |  37 ++
 frontend-js/src/main/js/map/OverlayParser.js  |  37 ++
 .../src/main/js/map/data/LayoutData.js        |  77 +--
 .../src/test/js/gui/AddOverlayDialog-test.js  |  35 --
 .../js/gui/admin/AddProjectDialog-test.js     |  41 +-
 .../src/test/js/map/OverlayParser-test.js     |  33 ++
 .../configuration/token=MOCK_TOKEN_ID&        |   2 +-
 .../map/complex_model_with_overlays.zip       | Bin 0 -> 2216 bytes
 .../map/complex_model_with_submaps.zip        | Bin 0 -> 8240 bytes
 .../ConfigurationController.java              | 115 +++--
 .../configuration/ConfigurationRestImpl.java  | 436 ++++++++--------
 .../api/projects/ProjectController.java       | 283 ++++++-----
 .../api/projects/ProjectRestImpl.java         |  68 ++-
 .../api/projects/ProjectRestImplTest.java     | 480 ++++++++++--------
 39 files changed, 1720 insertions(+), 1147 deletions(-)
 create mode 100644 converter/testFiles/invalid_overview_1.zip
 delete mode 100644 converter/testFiles/invalid_overview_1/coords.txt
 delete mode 100644 converter/testFiles/invalid_overview_1/test.png
 create mode 100644 converter/testFiles/invalid_overview_2.zip
 delete mode 100644 converter/testFiles/invalid_overview_2/coords.txt
 delete mode 100644 converter/testFiles/invalid_overview_2/test.png
 create mode 100644 converter/testFiles/invalid_overview_3.zip
 delete mode 100644 converter/testFiles/invalid_overview_3/coords.txt
 delete mode 100644 converter/testFiles/invalid_overview_3/test.png
 create mode 100644 converter/testFiles/valid_overview.zip
 delete mode 100644 converter/testFiles/valid_overview/coords.txt
 delete mode 100644 converter/testFiles/valid_overview/test.png
 create mode 100644 frontend-js/src/main/js/gui/admin/ZipEntry.js
 create mode 100644 frontend-js/src/main/js/map/OverlayParser.js
 create mode 100644 frontend-js/src/test/js/map/OverlayParser-test.js
 create mode 100644 frontend-js/testFiles/map/complex_model_with_overlays.zip
 create mode 100644 frontend-js/testFiles/map/complex_model_with_submaps.zip

diff --git a/.idea/modules.xml b/.idea/modules.xml
index 6e6dd9acbd..ae3706f249 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,7 +2,28 @@
 <project version="4">
   <component name="ProjectModuleManager">
     <modules>
+      <module fileurl="file://$PROJECT_DIR$/CellDesigner-plugin/CellDesigner-plugin.iml" filepath="$PROJECT_DIR$/CellDesigner-plugin/CellDesigner-plugin.iml" />
+      <module fileurl="file://$PROJECT_DIR$/annotation/annotation.iml" filepath="$PROJECT_DIR$/annotation/annotation.iml" />
+      <module fileurl="file://$PROJECT_DIR$/commons/commons.iml" filepath="$PROJECT_DIR$/commons/commons.iml" />
+      <module fileurl="file://$PROJECT_DIR$/comparison/comparison.iml" filepath="$PROJECT_DIR$/comparison/comparison.iml" />
+      <module fileurl="file://$PROJECT_DIR$/console/console.iml" filepath="$PROJECT_DIR$/console/console.iml" />
+      <module fileurl="file://$PROJECT_DIR$/converter/converter.iml" filepath="$PROJECT_DIR$/converter/converter.iml" />
+      <module fileurl="file://$PROJECT_DIR$/converter-CellDesigner/converter-CellDesigner.iml" filepath="$PROJECT_DIR$/converter-CellDesigner/converter-CellDesigner.iml" />
+      <module fileurl="file://$PROJECT_DIR$/converter-SBGNML/converter-SBGNML.iml" filepath="$PROJECT_DIR$/converter-SBGNML/converter-SBGNML.iml" />
+      <module fileurl="file://$PROJECT_DIR$/converter-graphics/converter-graphics.iml" filepath="$PROJECT_DIR$/converter-graphics/converter-graphics.iml" />
+      <module fileurl="file://$PROJECT_DIR$/editor/editor.iml" filepath="$PROJECT_DIR$/editor/editor.iml" />
+      <module fileurl="file://$PROJECT_DIR$/frontend-js/frontend-js.iml" filepath="$PROJECT_DIR$/frontend-js/frontend-js.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/minerva.iml" filepath="$PROJECT_DIR$/.idea/minerva.iml" />
+      <module fileurl="file://$PROJECT_DIR$/model/model.iml" filepath="$PROJECT_DIR$/model/model.iml" />
+      <module fileurl="file://$PROJECT_DIR$/model-command/model-command.iml" filepath="$PROJECT_DIR$/model-command/model-command.iml" />
+      <module fileurl="file://$PROJECT_DIR$/parent.iml" filepath="$PROJECT_DIR$/parent.iml" />
+      <module fileurl="file://$PROJECT_DIR$/pathvisio/pathvisio.iml" filepath="$PROJECT_DIR$/pathvisio/pathvisio.iml" />
+      <module fileurl="file://$PROJECT_DIR$/persist/persist.iml" filepath="$PROJECT_DIR$/persist/persist.iml" />
+      <module fileurl="file://$PROJECT_DIR$/quadTrees/quadTrees.iml" filepath="$PROJECT_DIR$/quadTrees/quadTrees.iml" />
+      <module fileurl="file://$PROJECT_DIR$/reactome/reactome.iml" filepath="$PROJECT_DIR$/reactome/reactome.iml" />
+      <module fileurl="file://$PROJECT_DIR$/rest-api/rest-api.iml" filepath="$PROJECT_DIR$/rest-api/rest-api.iml" />
+      <module fileurl="file://$PROJECT_DIR$/service/service.iml" filepath="$PROJECT_DIR$/service/service.iml" />
+      <module fileurl="file://$PROJECT_DIR$/web/web.iml" filepath="$PROJECT_DIR$/web/web.iml" />
     </modules>
   </component>
 </project>
\ No newline at end of file
diff --git a/converter/src/main/java/lcsb/mapviewer/converter/OverviewParser.java b/converter/src/main/java/lcsb/mapviewer/converter/OverviewParser.java
index 134f9ddb91..b04589b96d 100644
--- a/converter/src/main/java/lcsb/mapviewer/converter/OverviewParser.java
+++ b/converter/src/main/java/lcsb/mapviewer/converter/OverviewParser.java
@@ -13,6 +13,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.zip.ZipFile;
 
 import javax.imageio.ImageIO;
 
@@ -90,17 +91,17 @@ public class OverviewParser {
 	private static final Integer BUFFER_SIZE															 = 1024;
 
 	/**
-	 * String identifing {@link OverviewModelLink} connections.
+	 * String identifying {@link OverviewModelLink} connections.
 	 */
 	private static final String	 MODEL_LINK_TYPE													 = "MODEL";
 
 	/**
-	 * String identifing {@link OverviewImageLink} connections between images.
+	 * String identifying {@link OverviewImageLink} connections between images.
 	 */
 	private static final String	 IMAGE_LINK_TYPE													 = "IMAGE";
 
 	/**
-	 * String identifing {@link OverviewSearchLink} connections.
+	 * String identifying {@link OverviewSearchLink} connections.
 	 */
 	private static final String	 SEARCH_LINK_TYPE													 = "SEARCH";
 
@@ -125,7 +126,7 @@ public class OverviewParser {
 	 * @throws InvalidOverviewFile
 	 *           thrown when the zip file contains invalid data
 	 */
-	public List<OverviewImage> parseOverviewLinks(Set<Model> models, List<ImageZipEntryFile> files, String outputDirectory) throws InvalidOverviewFile {
+	public List<OverviewImage> parseOverviewLinks(Set<Model> models, List<ImageZipEntryFile> files, String outputDirectory, ZipFile zipFile) throws InvalidOverviewFile {
 		if (outputDirectory != null) {
 			File f = new File(outputDirectory);
 			if (!f.exists()) {
@@ -151,14 +152,14 @@ public class OverviewParser {
 					// copy file to file system
 					if (outputDirectory != null) {
 						imageFile = new File(outputDirectory + "/" + filename);
-					} else { // or temp file
+					} else { // or temporary file
 						imageFile = File.createTempFile("temp-file-name", ".png");
 						imageFile.deleteOnExit();
 					}
 					FileOutputStream fos = new FileOutputStream(imageFile);
 					byte[] bytes = new byte[BUFFER_SIZE];
 					int length;
-					InputStream is = entry.getInputStream();
+					InputStream is = zipFile.getInputStream(zipFile.getEntry(entry.getFilename()));
 					while ((length = is.read(bytes)) >= 0) {
 						fos.write(bytes, 0, length);
 					}
@@ -175,7 +176,7 @@ public class OverviewParser {
 					StringBuilder sb = new StringBuilder("");
 					byte[] buffer = new byte[BUFFER_SIZE];
 					int read = 0;
-					InputStream is = entry.getInputStream();
+                    InputStream is = zipFile.getInputStream(zipFile.getEntry(entry.getFilename()));
 					while ((read = is.read(buffer)) >= 0) {
 						sb.append(new String(buffer, 0, read));
 					}
diff --git a/converter/src/main/java/lcsb/mapviewer/converter/ProjectFactory.java b/converter/src/main/java/lcsb/mapviewer/converter/ProjectFactory.java
index 11c34bf4ef..357a3da361 100644
--- a/converter/src/main/java/lcsb/mapviewer/converter/ProjectFactory.java
+++ b/converter/src/main/java/lcsb/mapviewer/converter/ProjectFactory.java
@@ -58,7 +58,7 @@ public class ProjectFactory {
 
 		if (imageEntries.size() > 0) {
 			OverviewParser parser = new OverviewParser();
-			project.addOverviewImages(parser.parseOverviewLinks(models, imageEntries, params.getVisualizationDir()));
+			project.addOverviewImages(parser.parseOverviewLinks(models, imageEntries, params.getVisualizationDir(), zipFile));
 		}
 		return project;
 	}
diff --git a/converter/src/main/java/lcsb/mapviewer/converter/zip/ImageZipEntryFile.java b/converter/src/main/java/lcsb/mapviewer/converter/zip/ImageZipEntryFile.java
index 5b930d5dfb..cef2d1956b 100644
--- a/converter/src/main/java/lcsb/mapviewer/converter/zip/ImageZipEntryFile.java
+++ b/converter/src/main/java/lcsb/mapviewer/converter/zip/ImageZipEntryFile.java
@@ -1,9 +1,6 @@
 package lcsb.mapviewer.converter.zip;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.Serializable;
 
 /**
@@ -15,67 +12,31 @@ import java.io.Serializable;
  */
 public class ImageZipEntryFile extends ZipEntryFile implements Serializable {
 
-	/**
-	 * 
-	 */
-	private static final long	serialVersionUID	= 1L;
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default constructor.
+   */
+  public ImageZipEntryFile() {
+
+  }
+
+  /**
+   * Default constructor.
+   * 
+   * @param filename
+   *          {@link ZipEntryFile#filename}
+   * @param inputStream
+   *          input stream with the data for this entry.
+   * @see #baos
+   * @throws IOException
+   *           thrown when there is a problem with accessing input stream
+   */
+  public ImageZipEntryFile(String filename) {
+    super(filename);
+  }
 
-	/**
-	 * Size of the buffer used to copy input streams.
-	 */
-	private static final int	BUFFER_SIZE				= 1024;
-
-	/**
-	 * Copy of the {@link InputStream} of the file.
-	 */
-	private byte[]						bytes;
-
-	/**
-	 * Default constructor.
-	 */
-	public ImageZipEntryFile() {
-
-	}
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param filename
-	 *          {@link ZipEntryFile#filename}
-	 * @param inputStream
-	 *          input stream with the data for this entry.
-	 * @see #baos
-	 * @throws IOException
-	 *           thrown when there is a problem with accessing input stream
-	 */
-	public ImageZipEntryFile(String filename, InputStream inputStream) throws IOException {
-		super(filename);
-		setInputStream(inputStream);
-	}
-
-	/**
-	 * @return the inputStream
-	 * @see #inputStream
-	 */
-	public InputStream getInputStream() {
-		return new ByteArrayInputStream(bytes);
-	}
-
-	/**
-	 * @param inputStream
-	 *          the inputStream to set
-	 * @throws IOException
-	 *           thrown when there is aproblem with accessing inputStream
-	 * @see #inputStream
-	 */
-	public void setInputStream(InputStream inputStream) throws IOException {
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		byte[] buffer = new byte[BUFFER_SIZE];
-		int len;
-		while ((len = inputStream.read(buffer)) > -1) {
-			baos.write(buffer, 0, len);
-		}
-		baos.flush();
-		bytes = baos.toByteArray();
-	}
 }
diff --git a/converter/src/main/java/lcsb/mapviewer/converter/zip/LayoutZipEntryFile.java b/converter/src/main/java/lcsb/mapviewer/converter/zip/LayoutZipEntryFile.java
index 164b0aeba7..99b30c9a5e 100644
--- a/converter/src/main/java/lcsb/mapviewer/converter/zip/LayoutZipEntryFile.java
+++ b/converter/src/main/java/lcsb/mapviewer/converter/zip/LayoutZipEntryFile.java
@@ -11,70 +11,72 @@ import java.io.Serializable;
  */
 public class LayoutZipEntryFile extends ZipEntryFile implements Serializable {
 
-	/**
-	 * 
-	 */
-	private static final long serialVersionUID = 1L;
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
 
-	/**
-	 * Name of the layout.
-	 */
-	private String						name						 = "";
+  /**
+   * Name of the layout.
+   */
+  private String name = "";
 
-	/**
-	 * Description of the layout.
-	 */
-	private String						description			= "";
+  /**
+   * Description of the layout.
+   */
+  private String description = "";
 
-	/**
-	 * Default constructor.
-	 */
-	public LayoutZipEntryFile() {
+  /**
+   * Default constructor.
+   */
+  public LayoutZipEntryFile() {
 
-	}
+  }
 
-	/**
-	 * Default constructor.
-	 * 
-	 * @param filename
-	 *          {@link ZipEntryFile#filename}
-	 */
-	public LayoutZipEntryFile(String filename) {
-		super(filename);
-	}
+  /**
+   * Default constructor.
+   * 
+   * @param filename
+   *          {@link ZipEntryFile#filename}
+   */
+  public LayoutZipEntryFile(String filename, String name, String description) {
+    super(filename);
+    this.name = name;
+    this.description = description;
+  }
 
-	/**
-	 * @return the name
-	 * @see #name
-	 */
-	public String getName() {
-		return name;
-	}
+  /**
+   * @return the name
+   * @see #name
+   */
+  public String getName() {
+    return name;
+  }
 
-	/**
-	 * @param name
-	 *          the name to set
-	 * @see #name
-	 */
-	public void setName(String name) {
-		this.name = name;
-	}
+  /**
+   * @param name
+   *          the name to set
+   * @see #name
+   */
+  public void setName(String name) {
+    this.name = name;
+  }
 
-	/**
-	 * @return the description
-	 * @see #description
-	 */
-	public String getDescription() {
-		return description;
-	}
+  /**
+   * @return the description
+   * @see #description
+   */
+  public String getDescription() {
+    return description;
+  }
 
-	/**
-	 * @param description
-	 *          the description to set
-	 * @see #description
-	 */
-	public void setDescription(String description) {
-		this.description = description;
-	}
+  /**
+   * @param description
+   *          the description to set
+   * @see #description
+   */
+  public void setDescription(String description) {
+    this.description = description;
+  }
 
 }
diff --git a/converter/src/main/java/lcsb/mapviewer/converter/zip/ZipEntryFileFactory.java b/converter/src/main/java/lcsb/mapviewer/converter/zip/ZipEntryFileFactory.java
index 084e575cd0..1bcdc4b20e 100644
--- a/converter/src/main/java/lcsb/mapviewer/converter/zip/ZipEntryFileFactory.java
+++ b/converter/src/main/java/lcsb/mapviewer/converter/zip/ZipEntryFileFactory.java
@@ -165,7 +165,7 @@ public class ZipEntryFileFactory {
 				}
 				return zesf;
 			} else if (directory.equals(IMAGES_DIRECTORY)) {
-				ImageZipEntryFile result = new ImageZipEntryFile(entry.getName(), zipFile.getInputStream(entry));
+				ImageZipEntryFile result = new ImageZipEntryFile(entry.getName());
 				return result;
 			} else if (directory.equals(LAYOUT_DIRECTORY)) {
 				LayoutZipEntryFile result = createLayoutZipEntryFile(entry.getName(), zipFile.getInputStream(entry));
diff --git a/converter/src/test/java/lcsb/mapviewer/converter/OverviewParserTest.java b/converter/src/test/java/lcsb/mapviewer/converter/OverviewParserTest.java
index 50777ea476..feace015ae 100644
--- a/converter/src/test/java/lcsb/mapviewer/converter/OverviewParserTest.java
+++ b/converter/src/test/java/lcsb/mapviewer/converter/OverviewParserTest.java
@@ -10,9 +10,12 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.log4j.Logger;
@@ -28,226 +31,237 @@ import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.model.ModelFullIndexed;
 
 public class OverviewParserTest {
-	Logger				 logger	= Logger.getLogger(OverviewParserTest.class);
-	OverviewParser parser	= new OverviewParser();
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testParsingValidFile() throws Exception {
-		try {
-			Set<Model> models = createValidTestMapModel();
-			List<ImageZipEntryFile> imageEntries = createImageEntries("testFiles/valid_overview");
-			List<OverviewImage> result = parser.parseOverviewLinks(models, imageEntries, null);
-			assertNotNull(result);
-			assertEquals(1, result.size());
-
-			OverviewImage img = result.get(0);
-
-			assertEquals("test.png", img.getFilename());
-			assertEquals((Integer) 639, img.getHeight());
-			assertEquals((Integer) 963, img.getWidth());
-			assertEquals(2, img.getLinks().size());
-
-			OverviewLink link = img.getLinks().get(0);
-			List<Point2D> polygon = link.getPolygonCoordinates();
-			assertEquals(4, polygon.size());
-
-			assertTrue(link instanceof OverviewModelLink);
-
-			OverviewModelLink mLink = (OverviewModelLink) link;
-			Model mainModel = models.iterator().next();
-			assertEquals(mainModel.getModelData(), mLink.getLinkedModel());
-			assertEquals((Integer) 10, mLink.getxCoord());
-			assertEquals((Integer) 10, mLink.getyCoord());
-			assertEquals((Integer) 3, mLink.getZoomLevel());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	private List<ImageZipEntryFile> createImageEntries(String string) throws IOException {
-		List<ImageZipEntryFile> result = new ArrayList<ImageZipEntryFile>();
-		for (final File fileEntry : new File(string).listFiles()) {
-			if (!fileEntry.isDirectory()) {
-				result.add(new ImageZipEntryFile(fileEntry.getName(), new FileInputStream(fileEntry)));
-			}
-		}
-		return result;
-	}
-
-	@Test
-	public void testParsingValidFile2() throws Exception {
-		try {
-			Set<Model> models = createValidTestMapModel();
-
-			String tmpDir = "tmp";
-
-			new File(tmpDir).mkdirs();
-			List<ImageZipEntryFile> imageEntries = createImageEntries("testFiles/valid_overview");
-			List<OverviewImage> result = parser.parseOverviewLinks(models, imageEntries, tmpDir);
-
-			assertTrue(new File(tmpDir + "/test.png").exists());
-
-			assertNotNull(result);
-			assertEquals(1, result.size());
-			OverviewImage img = result.get(0);
-			assertEquals("test.png", img.getFilename());
-
-			new File(tmpDir).delete();
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParsingInvalidFile1() throws Exception {
-		try {
-			List<ImageZipEntryFile> imageEntries = createImageEntries("testFiles/invalid_overview_1");
-			Set<Model> models = createValidTestMapModel();
-
-			parser.parseOverviewLinks(models, imageEntries, null);
-			fail("Exception expected");
-		} catch (InvalidOverviewFile e) {
-			assertTrue(e.getMessage().contains("Unknown image filename"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParsingInvalidFile2() throws Exception {
-		try {
-			List<ImageZipEntryFile> imageEntries = createImageEntries("testFiles/invalid_overview_2");
-			Set<Model> models = createValidTestMapModel();
-
-			parser.parseOverviewLinks(models, imageEntries, null);
-			fail("Exception expected");
-		} catch (InvalidOverviewFile e) {
-			assertTrue(e.getMessage().contains("Unknown model"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParsingInvalidFile3() throws Exception {
-		try {
-			List<ImageZipEntryFile> imageEntries = createImageEntries("testFiles/invalid_overview_3");
-			Set<Model> models = createValidTestMapModel();
-
-			parser.parseOverviewLinks(models, imageEntries, null);
-			fail("Exception expected");
-		} catch (InvalidOverviewFile e) {
-			assertTrue(e.getMessage().contains("coordinates outside image"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	private Set<Model> createValidTestMapModel() {
-		Set<Model> result = new HashSet<>();
-		Model model = new ModelFullIndexed(null);
-		model.setName("main");
-		result.add(model);
-		return result;
-	}
-
-	/**
-	 * Test coordinates that overlap (exception is expected).
-	 * 
-	 * @throws Exception
-	 */
-	@Test
-	public void testParseInvalidCoordinates() throws Exception {
-		try {
-			String invalidCoordinates = "test.png	10,10 100,10 100,100 10,10	main.xml	10,10	3\n" + //
-					"test.png	10,10 10,400 400,400 400,10	main.xml	10,10	4";
-			Set<Model> models = createValidTestMapModel();
-
-			List<OverviewImage> images = new ArrayList<OverviewImage>();
-			OverviewImage oi = new OverviewImage();
-			oi.setFilename("test.png");
-			oi.setWidth(1000);
-			oi.setHeight(1000);
-			images.add(oi);
-
-			parser.processCoordinates(models, images, invalidCoordinates);
-
-			fail("Exception expected");
-		} catch (InvalidOverviewFile e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseValidCoordinates() throws Exception {
-		try {
-			String invalidCoordinates = "FILE	POLYGON	LINK_TARGET	MODEL_COORDINATES	MODEL_ZOOM_LEVEL	LINK_TYPE\n" + //
-					"test.png	10,10 100,10 100,100 10,10	main.xml	10,10	3	MODEL\n" + //
-					"test.png	200,200 200,400 400,400 400,200	main.xml	10,10	4	MODEL";
-			Set<Model> models = createValidTestMapModel();
-
-			List<OverviewImage> images = new ArrayList<OverviewImage>();
-			OverviewImage oi = new OverviewImage();
-			oi.setFilename("test.png");
-			oi.setWidth(1000);
-			oi.setHeight(1000);
-			images.add(oi);
-
-			parser.processCoordinates(models, images, invalidCoordinates);
-
-			assertEquals(2, oi.getLinks().size());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseValidComplexCoordinates() throws Exception {
-		try {
-			String invalidCoordinates = FileUtils.readFileToString(new File("testFiles/coordinates.txt"));
-			Set<Model> models = createValidTestMapModel();
-
-			List<OverviewImage> images = new ArrayList<>();
-			OverviewImage oi = new OverviewImage();
-			oi.setFilename("test.png");
-			oi.setWidth(1000);
-			oi.setHeight(1000);
-			images.add(oi);
-
-			OverviewImage oi2 = new OverviewImage();
-			oi2.setFilename("test2.png");
-			oi2.setWidth(1000);
-			oi2.setHeight(1000);
-			images.add(oi2);
-
-			parser.processCoordinates(models, images, invalidCoordinates);
-
-			assertEquals(2, oi.getLinks().size());
-			assertEquals(1, oi2.getLinks().size());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+  private static final String TEST_FILES_VALID_OVERVIEW_ZIP = "testFiles/valid_overview.zip";
+  Logger logger = Logger.getLogger(OverviewParserTest.class);
+  OverviewParser parser = new OverviewParser();
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testParsingValidFile() throws Exception {
+    try {
+      Set<Model> models = createValidTestMapModel();
+      List<ImageZipEntryFile> imageEntries = createImageEntries(TEST_FILES_VALID_OVERVIEW_ZIP);
+      List<OverviewImage> result = parser.parseOverviewLinks(models, imageEntries, null,
+          new ZipFile(TEST_FILES_VALID_OVERVIEW_ZIP));
+      assertNotNull(result);
+      assertEquals(1, result.size());
+
+      OverviewImage img = result.get(0);
+
+      assertEquals("test.png", img.getFilename());
+      assertEquals((Integer) 639, img.getHeight());
+      assertEquals((Integer) 963, img.getWidth());
+      assertEquals(2, img.getLinks().size());
+
+      OverviewLink link = img.getLinks().get(0);
+      List<Point2D> polygon = link.getPolygonCoordinates();
+      assertEquals(4, polygon.size());
+
+      assertTrue(link instanceof OverviewModelLink);
+
+      OverviewModelLink mLink = (OverviewModelLink) link;
+      Model mainModel = models.iterator().next();
+      assertEquals(mainModel.getModelData(), mLink.getLinkedModel());
+      assertEquals((Integer) 10, mLink.getxCoord());
+      assertEquals((Integer) 10, mLink.getyCoord());
+      assertEquals((Integer) 3, mLink.getZoomLevel());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private List<ImageZipEntryFile> createImageEntries(String string) throws IOException {
+    List<ImageZipEntryFile> result = new ArrayList<>();
+
+    ZipFile zipFile = new ZipFile(string);
+    try {
+      Enumeration<? extends ZipEntry> entries = zipFile.entries();
+      while (entries.hasMoreElements()) {
+        ZipEntry entry = entries.nextElement();
+        if (!entry.isDirectory()) {
+          result.add(new ImageZipEntryFile(entry.getName()));
+        }
+      }
+      return result;
+    } finally {
+      zipFile.close();
+    }
+  }
+
+  @Test
+  public void testParsingValidFile2() throws Exception {
+    try {
+      Set<Model> models = createValidTestMapModel();
+
+      String tmpDir = "tmp";
+
+      new File(tmpDir).mkdirs();
+      List<ImageZipEntryFile> imageEntries = createImageEntries(TEST_FILES_VALID_OVERVIEW_ZIP);
+      List<OverviewImage> result = parser.parseOverviewLinks(models, imageEntries, tmpDir,
+          new ZipFile(TEST_FILES_VALID_OVERVIEW_ZIP));
+
+      assertTrue(new File(tmpDir + "/test.png").exists());
+
+      assertNotNull(result);
+      assertEquals(1, result.size());
+      OverviewImage img = result.get(0);
+      assertEquals("test.png", img.getFilename());
+
+      new File(tmpDir).delete();
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParsingInvalidFile1() throws Exception {
+    try {
+      List<ImageZipEntryFile> imageEntries = createImageEntries("testFiles/invalid_overview_1.zip");
+      Set<Model> models = createValidTestMapModel();
+
+      parser.parseOverviewLinks(models, imageEntries, null, new ZipFile("testFiles/invalid_overview_1.zip"));
+      fail("Exception expected");
+    } catch (InvalidOverviewFile e) {
+      assertTrue(e.getMessage().contains("Unknown image filename"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParsingInvalidFile2() throws Exception {
+    try {
+      List<ImageZipEntryFile> imageEntries = createImageEntries("testFiles/invalid_overview_2.zip");
+      Set<Model> models = createValidTestMapModel();
+
+      parser.parseOverviewLinks(models, imageEntries, null, new ZipFile("testFiles/invalid_overview_2.zip"));
+      fail("Exception expected");
+    } catch (InvalidOverviewFile e) {
+      assertTrue(e.getMessage().contains("Unknown model"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParsingInvalidFile3() throws Exception {
+    try {
+      List<ImageZipEntryFile> imageEntries = createImageEntries("testFiles/invalid_overview_3.zip");
+      Set<Model> models = createValidTestMapModel();
+
+      parser.parseOverviewLinks(models, imageEntries, null, new ZipFile("testFiles/invalid_overview_3.zip"));
+      fail("Exception expected");
+    } catch (InvalidOverviewFile e) {
+      assertTrue(e.getMessage().contains("coordinates outside image"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private Set<Model> createValidTestMapModel() {
+    Set<Model> result = new HashSet<>();
+    Model model = new ModelFullIndexed(null);
+    model.setName("main");
+    result.add(model);
+    return result;
+  }
+
+  /**
+   * Test coordinates that overlap (exception is expected).
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testParseInvalidCoordinates() throws Exception {
+    try {
+      String invalidCoordinates = "test.png	10,10 100,10 100,100 10,10	main.xml	10,10	3\n" + //
+          "test.png	10,10 10,400 400,400 400,10	main.xml	10,10	4";
+      Set<Model> models = createValidTestMapModel();
+
+      List<OverviewImage> images = new ArrayList<OverviewImage>();
+      OverviewImage oi = new OverviewImage();
+      oi.setFilename("test.png");
+      oi.setWidth(1000);
+      oi.setHeight(1000);
+      images.add(oi);
+
+      parser.processCoordinates(models, images, invalidCoordinates);
+
+      fail("Exception expected");
+    } catch (InvalidOverviewFile e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseValidCoordinates() throws Exception {
+    try {
+      String invalidCoordinates = "FILE	POLYGON	LINK_TARGET	MODEL_COORDINATES	MODEL_ZOOM_LEVEL	LINK_TYPE\n" + //
+          "test.png	10,10 100,10 100,100 10,10	main.xml	10,10	3	MODEL\n" + //
+          "test.png	200,200 200,400 400,400 400,200	main.xml	10,10	4	MODEL";
+      Set<Model> models = createValidTestMapModel();
+
+      List<OverviewImage> images = new ArrayList<OverviewImage>();
+      OverviewImage oi = new OverviewImage();
+      oi.setFilename("test.png");
+      oi.setWidth(1000);
+      oi.setHeight(1000);
+      images.add(oi);
+
+      parser.processCoordinates(models, images, invalidCoordinates);
+
+      assertEquals(2, oi.getLinks().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseValidComplexCoordinates() throws Exception {
+    try {
+      String invalidCoordinates = FileUtils.readFileToString(new File("testFiles/coordinates.txt"));
+      Set<Model> models = createValidTestMapModel();
+
+      List<OverviewImage> images = new ArrayList<>();
+      OverviewImage oi = new OverviewImage();
+      oi.setFilename("test.png");
+      oi.setWidth(1000);
+      oi.setHeight(1000);
+      images.add(oi);
+
+      OverviewImage oi2 = new OverviewImage();
+      oi2.setFilename("test2.png");
+      oi2.setWidth(1000);
+      oi2.setHeight(1000);
+      images.add(oi2);
+
+      parser.processCoordinates(models, images, invalidCoordinates);
+
+      assertEquals(2, oi.getLinks().size());
+      assertEquals(1, oi2.getLinks().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
 }
diff --git a/converter/src/test/resources/log4j.properties b/converter/src/test/resources/log4j.properties
index ec610a35af..4d46bcbdbb 100644
--- a/converter/src/test/resources/log4j.properties
+++ b/converter/src/test/resources/log4j.properties
@@ -1,5 +1,5 @@
 #Set root logger 's level and its appender to an appender called CONSOLE which is defined below.
-log4j.rootLogger=info, CONSOLE, R
+log4j.rootLogger=info, CONSOLE
 
 #Set the behavior of the CONSOLE appender 
 log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
diff --git a/converter/testFiles/invalid_overview_1.zip b/converter/testFiles/invalid_overview_1.zip
new file mode 100644
index 0000000000000000000000000000000000000000..b3040204788c875114301808c2920fee4dda812b
GIT binary patch
literal 6384
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

literal 0
HcmV?d00001

diff --git a/converter/testFiles/invalid_overview_1/coords.txt b/converter/testFiles/invalid_overview_1/coords.txt
deleted file mode 100644
index 6b604ee16c..0000000000
--- a/converter/testFiles/invalid_overview_1/coords.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-FILE	POLYGON	LINK_TARGET	MODEL_COORDINATES	MODEL_ZOOM_LEVEL	LINK_TYPE
-unknowntest.png	10,10 100,10 100,100 100,10	main.xml	10,10	3	MODEL
-test.png	200,200 200,400 400,400 400,200	main.xml	1000,1000	4	MODEL
-
diff --git a/converter/testFiles/invalid_overview_1/test.png b/converter/testFiles/invalid_overview_1/test.png
deleted file mode 100644
index adbe702689a43364dc6f0a6cebedcc9277388a9c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 10796
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
T6ag1J;R!g}?zEw9^*{Mvpf}H#

diff --git a/converter/testFiles/invalid_overview_2.zip b/converter/testFiles/invalid_overview_2.zip
new file mode 100644
index 0000000000000000000000000000000000000000..c2d52c9ce246a4df4b3563863c1ca122927c7958
GIT binary patch
literal 6384
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

literal 0
HcmV?d00001

diff --git a/converter/testFiles/invalid_overview_2/coords.txt b/converter/testFiles/invalid_overview_2/coords.txt
deleted file mode 100644
index d25072502f..0000000000
--- a/converter/testFiles/invalid_overview_2/coords.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-FILE	POLYGON	LINK_TARGET	MODEL_COORDINATES	MODEL_ZOOM_LEVEL	LINK_TYPE
-test.png	10,10 100,10 100,100 100,10	unknown_main.xml	10,10	3	MODEL
-test.png	200,200 200,400 400,400 400,200	main.xml	1000,1000	4	MODEL
-
diff --git a/converter/testFiles/invalid_overview_2/test.png b/converter/testFiles/invalid_overview_2/test.png
deleted file mode 100644
index adbe702689a43364dc6f0a6cebedcc9277388a9c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 10796
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
T6ag1J;R!g}?zEw9^*{Mvpf}H#

diff --git a/converter/testFiles/invalid_overview_3.zip b/converter/testFiles/invalid_overview_3.zip
new file mode 100644
index 0000000000000000000000000000000000000000..9b995cf8be6b2a267e7f4f440bfce870ecbf761a
GIT binary patch
literal 6377
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
YyZ-MAprHOWHqxI(`3KQN`q%3}0Q&m~+yDRo

literal 0
HcmV?d00001

diff --git a/converter/testFiles/invalid_overview_3/coords.txt b/converter/testFiles/invalid_overview_3/coords.txt
deleted file mode 100644
index 63839f6e7d..0000000000
--- a/converter/testFiles/invalid_overview_3/coords.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-FILE	POLYGON	LINK_TARGET	MODEL_COORDINATES	MODEL_ZOOM_LEVEL	LINK_TYPE
-test.png	10,10 100,10 100,100 10000,10	main.xml	10,10	3	MODEL
-test.png	200,200 200,400 400,400 400,200	main.xml	1000,1000	4	MODEL
-
diff --git a/converter/testFiles/invalid_overview_3/test.png b/converter/testFiles/invalid_overview_3/test.png
deleted file mode 100644
index adbe702689a43364dc6f0a6cebedcc9277388a9c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 10796
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
T6ag1J;R!g}?zEw9^*{Mvpf}H#

diff --git a/converter/testFiles/valid_overview.zip b/converter/testFiles/valid_overview.zip
new file mode 100644
index 0000000000000000000000000000000000000000..edfff4deed85439da9ae079ad6a22be298f9a42a
GIT binary patch
literal 6351
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
Sf3J%2*CqO^y@KNJ>i+;wr}Urz

literal 0
HcmV?d00001

diff --git a/converter/testFiles/valid_overview/coords.txt b/converter/testFiles/valid_overview/coords.txt
deleted file mode 100644
index 6cc5a4478f..0000000000
--- a/converter/testFiles/valid_overview/coords.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-FILE	POLYGON	LINK_TARGET	MODEL_COORDINATES	MODEL_ZOOM_LEVEL	LINK_TYPE
-test.png	10,10 100,10 100,100 100,10	main.xml	10,10	3	MODEL
-test.png	200,200 200,400 400,400 400,200	main.xml	1000,1000	4	MODEL
-
diff --git a/converter/testFiles/valid_overview/test.png b/converter/testFiles/valid_overview/test.png
deleted file mode 100644
index adbe702689a43364dc6f0a6cebedcc9277388a9c..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 10796
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
T6ag1J;R!g}?zEw9^*{Mvpf}H#

diff --git a/frontend-js/.idea/frontend-js.iml b/frontend-js/.idea/frontend-js.iml
index 4feb4987b6..217608cacb 100644
--- a/frontend-js/.idea/frontend-js.iml
+++ b/frontend-js/.idea/frontend-js.iml
@@ -4,11 +4,12 @@
     <content url="file://$MODULE_DIR$">
       <sourceFolder url="file://$MODULE_DIR$/src/test" isTestSource="true" />
       <excludeFolder url="file://$MODULE_DIR$/.tmp" />
-      <excludeFolder url="file://$MODULE_DIR$/temp" />
       <excludeFolder url="file://$MODULE_DIR$/dist" />
+      <excludeFolder url="file://$MODULE_DIR$/temp" />
       <excludeFolder url="file://$MODULE_DIR$/tmp" />
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="chai-DefinitelyTyped" level="application" />
   </component>
-</module>
+</module>
\ No newline at end of file
diff --git a/frontend-js/package.json b/frontend-js/package.json
index dbf87572a8..6608366a59 100644
--- a/frontend-js/package.json
+++ b/frontend-js/package.json
@@ -43,6 +43,7 @@
     "http-status-codes": "^1.3.0",
     "js-cookie": "^2.1.3",
     "jstree": "^3.3.4",
+    "jszip": "^3.1.4",
     "log4js": "0.6.38",
     "pileup": "^0.6.8",
     "request": "^2.82.0"
diff --git a/frontend-js/src/main/js/Configuration.js b/frontend-js/src/main/js/Configuration.js
index f8bf26513b..5dc187dd7c 100644
--- a/frontend-js/src/main/js/Configuration.js
+++ b/frontend-js/src/main/js/Configuration.js
@@ -49,6 +49,7 @@ function Configuration(json) {
   self.setElementTypes(json.elementTypes);
   self.setReactionTypes(json.reactionTypes);
   self.setMiriamTypes(json.miriamTypes);
+  self.setMapTypes(json.mapTypes);
   self.setModificationStateTypes(json.modificationStateTypes);
   self.setPrivilegeTypes(json.privilegeTypes);
   self.setAnnotators(json.annotators);
@@ -98,12 +99,12 @@ Configuration.prototype.getElementTypeNames = function () {
 
 Configuration.prototype.getParentType = function (elementType) {
   var i;
-  for (var i = 0; i < this._elementTypes.length; i++) {
+  for (i = 0; i < this._elementTypes.length; i++) {
     if (this._elementTypes[i].className === elementType.parentClass) {
       return this._elementTypes[i];
     }
   }
-  for (var i = 0; i < this._reactionTypes.length; i++) {
+  for (i = 0; i < this._reactionTypes.length; i++) {
     if (this._reactionTypes[i].className === elementType.parentClass) {
       return this._reactionTypes[i];
     }
@@ -152,6 +153,13 @@ Configuration.prototype.setMiriamTypes = function (miriamTypes) {
   );
 };
 
+Configuration.prototype.setMapTypes = function (mapTypes) {
+  this._mapTypes = mapTypes;
+};
+Configuration.prototype.getMapTypes = function () {
+  return this._mapTypes;
+};
+
 Configuration.prototype.setPrivilegeTypes = function (privilegeTypes) {
   this._privilegeTypes = [];
   for (var key in privilegeTypes) {
@@ -206,7 +214,7 @@ Configuration.prototype.setAnnotators = function (annotators) {
   for (var key in annotators) {
     if (annotators.hasOwnProperty(key)) {
       var annotator = annotators[key];
-      this._annotators.push(new Annotator(annotators[key], this));
+      this._annotators.push(new Annotator(annotator, this));
     }
   }
 };
diff --git a/frontend-js/src/main/js/gui/AddOverlayDialog.js b/frontend-js/src/main/js/gui/AddOverlayDialog.js
index b78dc728ab..857b2930e5 100644
--- a/frontend-js/src/main/js/gui/AddOverlayDialog.js
+++ b/frontend-js/src/main/js/gui/AddOverlayDialog.js
@@ -8,6 +8,8 @@ var GuiUtils = require('./leftPanel/GuiUtils');
 var LayoutData = require('../map/data/LayoutData');
 var NetworkError = require('../NetworkError');
 
+var OverlayParser = require('../map/OverlayParser');
+
 var Functions = require('../Functions');
 var logger = require('../logger');
 var HttpStatus = require('http-status-codes');
@@ -24,7 +26,7 @@ function AddOverlayDialog(params) {
 AddOverlayDialog.prototype = Object.create(AbstractGuiElement.prototype);
 AddOverlayDialog.prototype.constructor = AddOverlayDialog;
 
-AddOverlayDialog.prototype.createGui = function() {
+AddOverlayDialog.prototype.createGui = function () {
   var self = this;
   var guiUtils = new GuiUtils();
   var content = document.createElement("div");
@@ -32,9 +34,9 @@ AddOverlayDialog.prototype.createGui = function() {
   content.style.height = "100%";
   content.appendChild(guiUtils.createLabel("Name: "));
   var nameInput = Functions.createElement({
-    type : "input",
-    inputType : "text",
-    name : "overlay-name",
+    type: "input",
+    inputType: "text",
+    name: "overlay-name",
   });
   content.appendChild(nameInput);
   content.appendChild(guiUtils.createNewLine());
@@ -42,19 +44,19 @@ AddOverlayDialog.prototype.createGui = function() {
   content.appendChild(guiUtils.createLabel("Description: "));
   content.appendChild(guiUtils.createNewLine());
   var descriptionInput = Functions.createElement({
-    type : "textarea",
-    name : "overlay-description",
+    type: "textarea",
+    name: "overlay-description",
   });
   content.appendChild(descriptionInput);
   content.appendChild(guiUtils.createNewLine());
 
   content.appendChild(guiUtils.createLabel("Upload file: "));
   var fileInput = Functions.createElement({
-    type : "input",
-    inputType : "file",
-    name : "overlay-file",
+    type: "input",
+    inputType: "file",
+    name: "overlay-file",
   });
-  fileInput.addEventListener("change", function() {
+  fileInput.addEventListener("change", function () {
     return self.processFile(fileInput.files[0]);
   }, false);
   content.appendChild(fileInput);
@@ -63,8 +65,8 @@ AddOverlayDialog.prototype.createGui = function() {
   content.appendChild(guiUtils.createLabel("Or provide list of elements here (one per line): "));
   content.appendChild(guiUtils.createNewLine());
   var contentInput = Functions.createElement({
-    type : "textarea",
-    name : "overlay-content",
+    type: "textarea",
+    name: "overlay-content",
   });
   content.appendChild(contentInput);
   content.appendChild(guiUtils.createNewLine());
@@ -72,21 +74,22 @@ AddOverlayDialog.prototype.createGui = function() {
   self.getElement().appendChild(content);
 };
 
-AddOverlayDialog.prototype.processFile = function(file) {
+AddOverlayDialog.prototype.processFile = function (file) {
   var self = this;
   self.setFileContent(null);
   if (file) {
-    return new Promise(function(resolve, reject) {
+    return new Promise(function (resolve, reject) {
       var reader = new FileReader();
       reader.readAsText(file, "UTF-8");
-      reader.onload = function(evt) {
+      reader.onload = function (evt) {
         try {
+          var overlayParser = new OverlayParser();
           self.setFileContent(evt.target.result);
-          var data = self.parseFile(evt.target.result);
+          var overlay = overlayParser.parse(evt.target.result);
           var nameInput = $("[name='overlay-name']", self.getElement())[0];
           var descriptionInput = $("[name='overlay-description']", self.getElement())[0];
-          if (data.name !== undefined) {
-            nameInput.value = data.name;
+          if (overlay.getName() !== undefined) {
+            nameInput.value = overlay.getName();
           } else {
             var filename = $("[name='overlay-file']", self.getElement())[0].value;
             if (filename.indexOf(".") > 0) {
@@ -97,15 +100,15 @@ AddOverlayDialog.prototype.processFile = function(file) {
             }
             nameInput.value = filename;
           }
-          if (data.description !== undefined) {
-            descriptionInput.value = data.description;
+          if (overlay.getDescription() !== undefined) {
+            descriptionInput.value = overlay.getDescription();
           }
           resolve(self.getFileContent());
         } catch (error) {
           reject(error);
         }
       };
-      reader.onerror = function() {
+      reader.onerror = function () {
         reject(new Error("Problem reading file"));
       };
     });
@@ -114,11 +117,11 @@ AddOverlayDialog.prototype.processFile = function(file) {
   }
 };
 
-AddOverlayDialog.prototype.setFileContent = function(fileContent) {
+AddOverlayDialog.prototype.setFileContent = function (fileContent) {
   this._fileContent = fileContent;
 };
 
-AddOverlayDialog.prototype.getFileContent = function() {
+AddOverlayDialog.prototype.getFileContent = function () {
   var self = this;
   var contentInput = $("[name='overlay-content']", self.getElement())[0];
 
@@ -135,43 +138,43 @@ AddOverlayDialog.prototype.getFileContent = function() {
   }
 };
 
-AddOverlayDialog.prototype.init = function() {
+AddOverlayDialog.prototype.init = function () {
   return Promise.resolve();
 };
 
-AddOverlayDialog.prototype.addOverlay = function() {
+AddOverlayDialog.prototype.addOverlay = function () {
   var self = this;
   var nameInput = $("[name='overlay-name']", self.getElement())[0];
   var descriptionInput = $("[name='overlay-description']", self.getElement())[0];
   var filename = $("[name='overlay-file']", self.getElement())[0].value;
   var overlay = new LayoutData({
-    name : nameInput.value,
-    description : descriptionInput.value,
-    content : self.getFileContent(),
-    filename : filename,
+    name: nameInput.value,
+    description: descriptionInput.value,
+    content: self.getFileContent(),
+    filename: filename,
   });
   GuiConnector.showProcessing();
   return ServerConnector.addOverlay({
-    overlay : overlay,
-    projectId : self.getProject().getProjectId(),
-  }).then(function(result) {
+    overlay: overlay,
+    projectId: self.getProject().getProjectId(),
+  }).then(function (result) {
     overlay = result;
     GuiConnector.hideProcessing();
     return self.callListeners("onAddOverlay", overlay);
   });
 };
 
-AddOverlayDialog.prototype.destroy = function() {
+AddOverlayDialog.prototype.destroy = function () {
   $(this.getElement()).dialog("destroy");
 };
 
-AddOverlayDialog.prototype.open = function() {
+AddOverlayDialog.prototype.open = function () {
   var self = this;
   var div = self.getElement();
   if (!$(div).hasClass("ui-dialog-content")) {
-    var buttons = [ {
-      text : "UPLOAD",
-      click : function() {
+    var buttons = [{
+      text: "UPLOAD",
+      click: function () {
         var dialog = this;
         var fileContent = self.getFileContent();
         if (fileContent === null) {
@@ -179,10 +182,10 @@ AddOverlayDialog.prototype.open = function() {
         } else if (fileContent.length > 1024 * 256) {
           GuiConnector.alert("File to big.<br>Please reduce file size or contact administrators.");
         } else {
-          return self.addOverlay().then(function(result) {
+          return self.addOverlay().then(function (result) {
             $(dialog).dialog("close");
             return result;
-          }, function(error) {
+          }, function (error) {
             GuiConnector.hideProcessing();
             if (error instanceof NetworkError && error.statusCode === HttpStatus.BAD_REQUEST) {
               var errorMessage = JSON.parse(error.content);
@@ -194,46 +197,20 @@ AddOverlayDialog.prototype.open = function() {
         }
       }
     }, {
-      text : "CANCEL",
-      click : function() {
+      text: "CANCEL",
+      click: function () {
         $(this).dialog("close");
       }
-    } ];
+    }];
 
     $(div).dialog({
-      title : "Add overlay",
-      buttons : buttons,
-      modal : true,
+      title: "Add overlay",
+      buttons: buttons,
+      modal: true,
     });
   }
 
   $(div).dialog("open");
 };
 
-AddOverlayDialog.prototype.parseFile = function(fileContent) {
-  var result = {};
-  var lines = fileContent.split("\n");
-  for (var i = 0; i < lines.length; i++) {
-    var line = lines[i];
-    if (line.startsWith("#")) {
-      if (line.indexOf("=") > 0) {
-        var name = line.substring(1, line.indexOf("=")).trim();
-        var value = line.substring(line.indexOf("=") + 1).trim();
-        if (name === "NAME") {
-          result.name = value;
-        } else if (name === "DESCRIPTION") {
-          result.description = value;
-        } else if (name === "TYPE") {
-          result.type = value;
-        }
-      } else {
-        logger.warn("Invalid overlay header line: " + line);
-      }
-    } else {
-      break;
-    }
-  }
-  return result;
-};
-
 module.exports = AddOverlayDialog;
diff --git a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
index 26dea5dfd6..966d914461 100644
--- a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
+++ b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
@@ -2,12 +2,14 @@
 
 /* exported logger */
 var Promise = require("bluebird");
+var JSZip = require("jszip");
 
 var AbstractGuiElement = require('../AbstractGuiElement');
 var ChooseAnnotatorsDialog = require('./ChooseAnnotatorsDialog');
 var ChooseValidatorsDialog = require('./ChooseValidatorsDialog');
 var GuiConnector = require('../../GuiConnector');
-var UserPreferences = require("../../map/data/UserPreferences");
+var OverlayParser = require('../../map/OverlayParser');
+var ZipEntry = require('./ZipEntry');
 
 var Functions = require('../../Functions');
 var logger = require('../../logger');
@@ -21,7 +23,10 @@ function AddProjectDialog(params) {
   AbstractGuiElement.call(this, params);
   var self = this;
   self.registerListenerType("onFileUpload");
+  self.registerListenerType("onZipFileUpload");
+  self.setZipEntries([]);
   $(self.getElement()).addClass("minerva-edit-project-dialog");
+  $(self.getElement()).css({overflow: "hidden"});
 
   self.createGui();
 }
@@ -36,7 +41,8 @@ AddProjectDialog.prototype.createGui = function () {
   var tabDiv = Functions.createElement({
     type: "div",
     name: "tabView",
-    className: "tabbable boxed parentTabs"
+    className: "tabbable boxed parentTabs",
+    style: "position:absolute;top:40px;bottom:10px;left:10px;right:10px"
   });
   element.appendChild(tabDiv);
 
@@ -48,7 +54,8 @@ AddProjectDialog.prototype.createGui = function () {
 
   var tabContentDiv = Functions.createElement({
     type: "div",
-    className: "tab-content"
+    className: "tab-content",
+    style: "height:100%"
   });
   tabDiv.appendChild(tabContentDiv);
 
@@ -83,6 +90,7 @@ AddProjectDialog.prototype.addTab = function (params) {
     navigationObject: navLi,
     navigationBar: params.tabMenuDiv
   });
+  contentDiv.style.overflow = "auto";
 
   if (params.content !== undefined) {
     contentDiv.appendChild(params.content);
@@ -148,6 +156,10 @@ AddProjectDialog.prototype.createGeneralTabContent = function () {
     var file = e.arg;
     return self.processFile(file);
   });
+  self.addListener("onFileUpload", function (e) {
+    var file = e.arg;
+    return self.setZipFileContent(file);
+  });
   self.addListener("onFileUpload", function (e) {
     var file = e.arg;
     if (file.name.lastIndexOf('.') > 0) {
@@ -308,11 +320,59 @@ AddProjectDialog.prototype.createOverlaysTabContent = function () {
 };
 
 AddProjectDialog.prototype._createOverlayTable = function () {
+  var self = this;
   var result = Functions.createElement({
     type: "div",
     style: "margin-top:10px;"
   });
 
+  var overlaysTable = Functions.createElement({
+    type: "table",
+    name: "overlaysTable",
+    className: "display",
+    style: "width:100%"
+  });
+  result.appendChild(overlaysTable);
+
+  $(overlaysTable).DataTable({
+    columns: [{
+      title: 'File name'
+    }, {
+      title: 'Name'
+    }, {
+      title: 'Description'
+    }]
+  });
+
+  $(overlaysTable).on("input", "[name='overlayName']", function () {
+    var input = this;
+    var filename = $(input).attr("data");
+    self.getEntryByFilename(filename).getData().name = $(input).val();
+  });
+
+  $(overlaysTable).on("input", "[name='overlayDescription']", function () {
+    var input = this;
+    var filename = $(input).attr("data");
+    self.getEntryByFilename(filename).getData().description = $(input).val();
+  });
+
+  self.addListener("onZipFileUpload", function () {
+    var entries = self.getZipEntries();
+    var dataTable = $($("[name='overlaysTable']", self.getElement())[0]).DataTable();
+    var data = [];
+    for (var i = 0; i < entries.length; i++) {
+      var entry = entries[i];
+      if (entry.getType() === "OVERLAY") {
+        var row = [];
+        row[0] = entry.getFilename();
+        row[1] = "<input data='" + entry.getFilename() + "' name='overlayName' value='" + entry.getData().name + "'/>";
+        row[2] = "<input data='" + entry.getFilename() + "' name='overlayDescription' value='" + entry.getData().description + "'/>";
+        data.push(row);
+      }
+    }
+    dataTable.clear().rows.add(data).draw();
+  });
+
   return result;
 };
 
@@ -321,17 +381,142 @@ AddProjectDialog.prototype.createSubmapsTab = function (tabMenuDiv, tabContentDi
   self.addTab({
     tabMenuDiv: tabMenuDiv,
     tabContentDiv: tabContentDiv,
-    name: "USERS",
+    name: "SUBMAPS",
     id: "project_submaps_tab",
     content: self.createSubmapsTabContent()
   });
 };
 
 AddProjectDialog.prototype.createSubmapsTabContent = function () {
+  var self = this;
   var result = Functions.createElement({
     type: "div",
     style: "margin-top:10px;"
   });
+  var submapsTable = Functions.createElement({
+    type: "table",
+    name: "submapsTable",
+    className: "display",
+    style: "width:100%"
+  });
+  result.appendChild(submapsTable);
+
+  $(submapsTable).DataTable({
+    columns: [{
+      title: 'File name'
+    }, {
+      title: 'Name'
+    }, {
+      title: 'Root map'
+    }, {
+      title: 'Mapping file'
+    }, {
+      title: 'Map type'
+    }]
+  });
+
+  $(submapsTable).on("input", "[name='submapName']", function () {
+    var input = this;
+    var filename = $(input).attr("data");
+    self.getEntryByFilename(filename).getData().name = $(input).val();
+  });
+
+  $(submapsTable).on("change", "[name='submapRoot']", function () {
+    var input = this;
+    if (!$(input).is(":checked")) {
+      this.checked = true;
+      GuiConnector.info("One model must be marked as a root");
+      return false;
+    }
+
+    var filename = $(input).attr("data");
+    var checkboxes = $("[name='submapRoot']", submapsTable);
+    for (var i = 0; i < checkboxes.length; i++) {
+      var checkbox = checkboxes[i];
+      if ($(checkbox).attr("data") !== filename) {
+        $(checkbox).attr('checked', false);
+        self.getEntryByFilename($(checkbox).attr("data")).getData().root = false;
+      }
+    }
+    self.getEntryByFilename(filename).getData().root = $(input).is(":checked");
+  });
+
+  $(submapsTable).on("change", "[name='submapMapping']", function () {
+    var input = this;
+    var filename = $(input).attr("data");
+    var checkboxes = $("[name='submapMapping']", submapsTable);
+    for (var i = 0; i < checkboxes.length; i++) {
+      var checkbox = checkboxes[i];
+      if ($(checkbox).attr("data") !== filename) {
+        $(checkbox).attr('checked', false);
+        self.getEntryByFilename($(checkbox).attr("data")).getData().mapping = false;
+      }
+    }
+    self.getEntryByFilename(filename).getData().mapping = $(input).is(":checked");
+  });
+
+  $(submapsTable).on("change", "[name='submapType']", function () {
+    var input = this;
+    var filename = $(input).attr("data");
+    return ServerConnector.getConfiguration().then(function (configuration) {
+      var mapTypes = configuration.getMapTypes();
+      for (var j = 0; j < mapTypes.length; j++) {
+        var mapType = mapTypes[j];
+        if (mapType.id === $(input).val()) {
+          self.getEntryByFilename(filename).getData().type = mapType;
+        }
+      }
+    });
+  });
+
+  self.addListener("onZipFileUpload", function () {
+    return ServerConnector.getConfiguration().then(function (configuration) {
+
+      var entries = self.getZipEntries();
+      var dataTable = $($("[name='submapsTable']", self.getElement())[0]).DataTable();
+      var data = [];
+      for (var i = 0; i < entries.length; i++) {
+        var entry = entries[i];
+        if (entry.getType() === "MAP") {
+          var row = [];
+          var rootCheckbox;
+          if (entry.getData().root) {
+            rootCheckbox = "<input name='submapRoot' type='checkbox' data='" + entry.getFilename() + "' checked='checked'/>";
+          } else {
+            rootCheckbox = "<input name='submapRoot' type='checkbox' data='" + entry.getFilename() + "'/>";
+          }
+          var mappingCheckbox;
+          if (entry.getData().mapping) {
+            mappingCheckbox = "<input name='submapMapping' type='checkbox' data='" + entry.getFilename() + "' checked='checked'/>";
+          } else {
+            mappingCheckbox = "<input name='submapMapping' type='checkbox' data='" + entry.getFilename() + "'/>";
+          }
+
+          var typeSelect = "<select data='" + entry.getFilename() + "' name='submapType'>";
+
+          typeSelect += "<option value='" + entry.getData().type.id + "' selected>" + entry.getData().type.name + "</option>";
+          var mapTypes = configuration.getMapTypes();
+          for (var j = 0; j < mapTypes.length; j++) {
+            var mapType = mapTypes[j];
+            if (mapType !== entry.getData().type) {
+              typeSelect += "<option value='" + mapType.id + "' >" + mapType.name + "</option>";
+            }
+          }
+          typeSelect += "</select>";
+
+
+          row[0] = entry.getFilename();
+          row[1] = "<input data='" + entry.getFilename() + "' name='submapName' value='" + entry.getData().name + "'/>";
+          row[2] = rootCheckbox;
+          row[3] = mappingCheckbox;
+          row[4] = typeSelect;
+          data.push(row);
+        }
+      }
+      dataTable.clear().rows.add(data).draw();
+    });
+  });
+
   return result;
 };
 
@@ -340,17 +525,48 @@ AddProjectDialog.prototype.createOverviewImagesTab = function (tabMenuDiv, tabCo
   self.addTab({
     tabMenuDiv: tabMenuDiv,
     tabContentDiv: tabContentDiv,
-    name: "USERS",
+    name: "IMAGES",
     id: "project_overview_images_tab",
     content: self.createOverviewImagesTabContent()
   });
 };
 
 AddProjectDialog.prototype.createOverviewImagesTabContent = function () {
+  var self = this;
   var result = Functions.createElement({
     type: "div",
     style: "margin-top:10px;"
   });
+
+  var imagesTable = Functions.createElement({
+    type: "table",
+    name: "imagesTable",
+    className: "display",
+    style: "width:100%"
+  });
+  result.appendChild(imagesTable);
+
+  $(imagesTable).DataTable({
+    columns: [{
+      title: 'File name'
+    }]
+  });
+
+  self.addListener("onZipFileUpload", function () {
+    var entries = self.getZipEntries();
+    var dataTable = $($("[name='imagesTable']", self.getElement())[0]).DataTable();
+    var data = [];
+    for (var i = 0; i < entries.length; i++) {
+      var entry = entries[i];
+      if (entry.getType() === "IMAGE") {
+        var row = [];
+        row[0] = entry.getFilename();
+        data.push(row);
+      }
+    }
+    dataTable.clear().rows.add(data).draw();
+  });
+
   return result;
 };
 
@@ -412,6 +628,20 @@ AddProjectDialog.prototype.destroy = function () {
   if (self._validatorsDialog !== undefined) {
     self._validatorsDialog.destroy();
   }
+  var overlaysTable = $("[name=overlaysTable]", self.getElement())[0];
+  if ($.fn.DataTable.isDataTable(overlaysTable)) {
+    $(overlaysTable).DataTable().destroy();
+  }
+  var submapsTable = $("[name=submapsTable]", self.getElement())[0];
+  if ($.fn.DataTable.isDataTable(submapsTable)) {
+    $(submapsTable).DataTable().destroy();
+  }
+
+  var imagesTable = $("[name=imagesTable]", self.getElement())[0];
+  if ($.fn.DataTable.isDataTable(imagesTable)) {
+    $(imagesTable).DataTable().destroy();
+  }
+
 };
 
 AddProjectDialog.prototype.open = function () {
@@ -445,7 +675,7 @@ AddProjectDialog.prototype.processFile = function (file) {
   if (file) {
     return new Promise(function (resolve, reject) {
       var reader = new FileReader();
-      reader.readAsText(file, "UTF-8");
+      reader.readAsText(file);
       reader.onload = function (evt) {
         try {
           self.setFileContent(evt.target.result);
@@ -464,6 +694,7 @@ AddProjectDialog.prototype.processFile = function (file) {
 };
 
 AddProjectDialog.prototype.setFileContent = function (fileContent) {
+  logger.debug(fileContent);
   this._fileContent = fileContent;
 };
 AddProjectDialog.prototype.getFileContent = function () {
@@ -593,7 +824,7 @@ AddProjectDialog.prototype.onSaveClicked = function () {
       "semantic-zoom": self.isSemanticZooming(),
       "annotate": self.isAnnotateAutomatically(),
       "verify-annotations": self.isVerifyAnnotations(),
-
+      "zip-entries": self.getZipEntries()
     };
     return ServerConnector.addProject(options);
   });
@@ -627,4 +858,124 @@ AddProjectDialog.prototype.checkValidity = function () {
   });
 };
 
+AddProjectDialog.prototype.setZipFileContent = function (file) {
+  var self = this;
+  if (file.name.toLowerCase().endsWith("zip")) {
+    var jsZip = new JSZip();
+    return jsZip.loadAsync(file).then(function (zip) {
+      var files = zip.files;
+      var promises = [];
+      var entries = [];
+      for (var key in files) {
+        if (files.hasOwnProperty(key)) {
+          promises.push(self.createZipEntry(files[key], zip));
+        }
+      }
+      return Promise.all(promises).then(function (result) {
+        for (var i = 0; i < result.length; i++) {
+          if (result[i] !== null) {
+            entries.push(result[i]);
+          }
+        }
+        return self.setZipEntries(entries);
+      });
+    });
+  } else {
+    return self.setZipEntries([]);
+  }
+};
+
+AddProjectDialog.prototype.createZipEntry = function (jsZipEntry, zipObject) {
+  if (jsZipEntry.dir) {
+    return null;
+  }
+  var filename = jsZipEntry.name.toLowerCase();
+  var type = null;
+  var data = {};
+  var processingPromise = Promise.resolve();
+  if (filename.startsWith("submaps")) {
+    type = "MAP";
+    if (filename.endsWith("mapping.xml")) {
+      data.mapping = true;
+    }
+  } else if (filename.startsWith("images")) {
+    type = "IMAGE";
+  } else if (filename.startsWith("layouts") || filename.startsWith("overlays")) {
+    type = "OVERLAY";
+    processingPromise = zipObject.file(jsZipEntry.name).async("string").then(function (content) {
+      var overlayParser = new OverlayParser();
+      var overlay = overlayParser.parse(content);
+      if (overlay.getName()) {
+        data.name = overlay.getName();
+      } else {
+        data.name = "";
+      }
+      if (overlay.getDescription()) {
+        data.description = overlay.getDescription();
+      } else {
+        data.description = "";
+      }
+    });
+  } else if (filename.indexOf("\\") === -1 && filename.indexOf("/") === -1) {
+    type = "MAP";
+    data.root = true;
+  } else {
+    throw new Error("Unrecognized file: " + filename);
+  }
+  if (type === "MAP") {
+    var name = jsZipEntry.name.toLowerCase();
+    this.setFileParserForFilename(name);
+    if (name.indexOf(".") > 0) {
+      name = name.substr(0, name.indexOf("."));
+    }
+    if (name.lastIndexOf("\\") >= 0) {
+      name = name.substr(name.lastIndexOf("\\") + 1);
+    }
+    if (name.lastIndexOf("/") >= 0) {
+      name = name.substr(name.lastIndexOf("/") + 1);
+    }
+    data.name = name;
+
+    processingPromise = processingPromise.then(function () {
+      return ServerConnector.getConfiguration().then(function (configuration) {
+        var mapTypes = configuration.getMapTypes();
+        for (var i = 0; i < mapTypes.length; i++) {
+          if (mapTypes[i].id === "UNKNOWN") {
+            data.type = mapTypes[i];
+          }
+        }
+        if (data.type === undefined) {
+          data.type = mapTypes[0];
+        }
+      });
+    });
+  }
+
+  return processingPromise.then(function () {
+    return new ZipEntry({filename: filename, type: type, data: data});
+  });
+};
+
+AddProjectDialog.prototype.getZipEntries = function () {
+  return this._zipEntries;
+};
+AddProjectDialog.prototype.setZipEntries = function (entries) {
+  var self = this;
+  self._zipEntries = entries;
+  return self.callListeners("onZipFileUpload", entries);
+
+};
+
+AddProjectDialog.prototype.getEntryByFilename = function (filename) {
+  var self = this;
+  var entries = self.getZipEntries();
+  for (var i = 0; i < entries.length; i++) {
+    var entry = entries[i];
+    if (entry.getFilename() === filename) {
+      return entry;
+    }
+  }
+  return null;
+};
+
 module.exports = AddProjectDialog;
diff --git a/frontend-js/src/main/js/gui/admin/ZipEntry.js b/frontend-js/src/main/js/gui/admin/ZipEntry.js
new file mode 100644
index 0000000000..c3891a3a01
--- /dev/null
+++ b/frontend-js/src/main/js/gui/admin/ZipEntry.js
@@ -0,0 +1,37 @@
+"use strict";
+
+var types = ["IMAGE", "OVERLAY", "MAP"];
+
+function ZipEntry(params) {
+  var self = this;
+  self.setType(params.type);
+  self.setFilename(params.filename);
+  self.setData(params.data);
+}
+
+ZipEntry.prototype.setType = function (type) {
+  if (types.indexOf(type) === -1) {
+    throw new Error("Unknown ZipEntryType: " + type + ".")
+  }
+  this._type = type;
+};
+ZipEntry.prototype.getType = function () {
+  return this._type;
+};
+
+ZipEntry.prototype.setFilename = function (filename) {
+  this._filename = filename;
+};
+
+ZipEntry.prototype.getFilename = function () {
+  return this._filename;
+};
+
+ZipEntry.prototype.setData = function (data) {
+  this._data = data;
+};
+ZipEntry.prototype.getData = function () {
+  return this._data;
+};
+
+module.exports = ZipEntry;
diff --git a/frontend-js/src/main/js/map/OverlayParser.js b/frontend-js/src/main/js/map/OverlayParser.js
new file mode 100644
index 0000000000..31fc9bc086
--- /dev/null
+++ b/frontend-js/src/main/js/map/OverlayParser.js
@@ -0,0 +1,37 @@
+"use strict";
+
+var logger = require('./../logger');
+var LayoutData = require('./data/LayoutData');
+
+function OverlayParser() {
+}
+
+OverlayParser.prototype.parse = function (content) {
+  var data = {content: content};
+  var lines = content.split("\n");
+  for (var i = 0; i < lines.length; i++) {
+    var line = lines[i];
+    if (line.startsWith("#")) {
+      if (line.indexOf("=") > 0) {
+        var name = line.substring(1, line.indexOf("=")).trim();
+        var value = line.substring(line.indexOf("=") + 1).trim();
+        if (name === "NAME") {
+          data.name = value;
+        } else if (name === "DESCRIPTION") {
+          data.description = value;
+        } else if (name === "TYPE") {
+          data.type = value;
+        }
+      } else {
+        logger.warn("Invalid overlay header line: " + line);
+      }
+    } else {
+      break;
+    }
+  }
+
+  return new LayoutData(data);
+};
+
+
+module.exports = OverlayParser;
diff --git a/frontend-js/src/main/js/map/data/LayoutData.js b/frontend-js/src/main/js/map/data/LayoutData.js
index 8d8c29ba94..2e2fa6d043 100644
--- a/frontend-js/src/main/js/map/data/LayoutData.js
+++ b/frontend-js/src/main/js/map/data/LayoutData.js
@@ -27,6 +27,7 @@ function LayoutData(layoutId, name) {
     this.setFilename(object.filename);
     this.setPublicOverlay(object.publicOverlay);
     this.setInputDataAvailable(object.inputDataAvailable);
+    this.setType(object.type);
     if (!this.getInputDataAvailable()) {
       this.setInitialized(true);
     }
@@ -42,54 +43,54 @@ function LayoutData(layoutId, name) {
 
 /**
  * Adds alias to the {@link LayoutData}
- * 
+ *
  * @param layoutAlias
  *          information about alias in a layout
  */
-LayoutData.prototype.addAlias = function(layoutAlias) {
+LayoutData.prototype.addAlias = function (layoutAlias) {
   this.aliases.push(layoutAlias);
   this.aliasById[layoutAlias.getId()] = layoutAlias;
 };
 
 /**
  * Adds reaction to the {@link LayoutData}
- * 
+ *
  * @param layoutReaction
  *          information about reaction in a layout
  */
-LayoutData.prototype.addReaction = function(layoutReaction) {
+LayoutData.prototype.addReaction = function (layoutReaction) {
   this.reactions.push(layoutReaction);
 };
 
-LayoutData.prototype.getId = function() {
+LayoutData.prototype.getId = function () {
   return this.id;
 };
 
-LayoutData.prototype.setId = function(id) {
+LayoutData.prototype.setId = function (id) {
   this.id = parseInt(id);
 };
 
-LayoutData.prototype.getDescription = function() {
+LayoutData.prototype.getDescription = function () {
   return this._description;
 };
 
-LayoutData.prototype.setDescription = function(description) {
+LayoutData.prototype.setDescription = function (description) {
   this._description = description;
 };
 
-LayoutData.prototype.getCreator = function() {
+LayoutData.prototype.getCreator = function () {
   return this._creator;
 };
 
-LayoutData.prototype.setCreator = function(creator) {
+LayoutData.prototype.setCreator = function (creator) {
   this._creator = creator;
 };
 
-LayoutData.prototype.getInputDataAvailable = function() {
+LayoutData.prototype.getInputDataAvailable = function () {
   return this._inputDataAvailable;
 };
 
-LayoutData.prototype.setInputDataAvailable = function(inputDataAvailable) {
+LayoutData.prototype.setInputDataAvailable = function (inputDataAvailable) {
   var value = inputDataAvailable;
   if (inputDataAvailable === undefined) {
     value = false;
@@ -104,23 +105,23 @@ LayoutData.prototype.setInputDataAvailable = function(inputDataAvailable) {
   this._inputDataAvailable = value;
 };
 
-LayoutData.prototype.getName = function() {
+LayoutData.prototype.getName = function () {
   return this.name;
 };
 
-LayoutData.prototype.setName = function(name) {
+LayoutData.prototype.setName = function (name) {
   this.name = name;
 };
 
-LayoutData.prototype.getDirectory = function() {
+LayoutData.prototype.getDirectory = function () {
   return this._directory;
 };
 
-LayoutData.prototype.setDirectory = function(directory) {
+LayoutData.prototype.setDirectory = function (directory) {
   this._directory = directory;
 };
 
-LayoutData.prototype.updateAlias = function(layoutAlias) {
+LayoutData.prototype.updateAlias = function (layoutAlias) {
   if (this.aliasById[layoutAlias.getId()] === undefined) {
     logger.warn("Cannot update alias, it doesn't exist. Alias: ", layoutAlias.getId());
   } else {
@@ -129,19 +130,19 @@ LayoutData.prototype.updateAlias = function(layoutAlias) {
 
 };
 
-LayoutData.prototype.getAliasById = function(id) {
+LayoutData.prototype.getAliasById = function (id) {
   return this.aliasById[id];
 };
 
-LayoutData.prototype.getFullAliasById = function(id) {
+LayoutData.prototype.getFullAliasById = function (id) {
   var self = this;
   var alias = self.getAliasById(id);
   if (alias !== undefined) {
     if (alias.getType() === LayoutAlias.LIGTH) {
       return ServerConnector.getFullOverlayElement({
-        element : new IdentifiedElement(alias),
-        overlay : self,
-      }).then(function(data) {
+        element: new IdentifiedElement(alias),
+        overlay: self,
+      }).then(function (data) {
         self.updateAlias(data);
         return alias;
       });
@@ -150,28 +151,28 @@ LayoutData.prototype.getFullAliasById = function(id) {
   return Promise.resolve(alias);
 };
 
-LayoutData.prototype.setInitialized = function(value) {
+LayoutData.prototype.setInitialized = function (value) {
   this._initialized = value;
 };
 
-LayoutData.prototype.isInitialized = function() {
+LayoutData.prototype.isInitialized = function () {
   return this._initialized;
 };
 
-LayoutData.prototype.getAliases = function() {
+LayoutData.prototype.getAliases = function () {
   return this.aliases;
 };
 
-LayoutData.prototype.getReactions = function() {
+LayoutData.prototype.getReactions = function () {
   return this.reactions;
 };
 
-LayoutData.prototype.init = function() {
+LayoutData.prototype.init = function () {
   var self = this;
   if (this.isInitialized()) {
     return Promise.resolve();
   }
-  return ServerConnector.getOverlayElements(self.getId()).then(function(data) {
+  return ServerConnector.getOverlayElements(self.getId()).then(function (data) {
     for (var i = 0; i < data.length; i++) {
       if (data[i] instanceof LayoutAlias) {
         self.addAlias(data[i]);
@@ -187,28 +188,36 @@ LayoutData.prototype.init = function() {
 
 };
 
-LayoutData.prototype.getPublicOverlay = function() {
+LayoutData.prototype.getPublicOverlay = function () {
   return this._publicOverlay;
 };
 
-LayoutData.prototype.setPublicOverlay = function(publicOverlay) {
+LayoutData.prototype.setPublicOverlay = function (publicOverlay) {
   this._publicOverlay = publicOverlay;
 };
 
-LayoutData.prototype.getContent = function() {
+LayoutData.prototype.getContent = function () {
   return this._content;
 };
 
-LayoutData.prototype.setContent = function(content) {
+LayoutData.prototype.setContent = function (content) {
   this._content = content;
 };
 
-LayoutData.prototype.getFilename = function() {
+LayoutData.prototype.getFilename = function () {
   return this._filename;
 };
 
-LayoutData.prototype.setFilename= function(filename) {
+LayoutData.prototype.setFilename = function (filename) {
   this._filename = filename;
 };
 
+LayoutData.prototype.getType = function () {
+  return this._type;
+};
+
+LayoutData.prototype.setType = function (type) {
+  this._type = type;
+};
+
 module.exports = LayoutData;
diff --git a/frontend-js/src/test/js/gui/AddOverlayDialog-test.js b/frontend-js/src/test/js/gui/AddOverlayDialog-test.js
index b9700d844d..26b190671f 100644
--- a/frontend-js/src/test/js/gui/AddOverlayDialog-test.js
+++ b/frontend-js/src/test/js/gui/AddOverlayDialog-test.js
@@ -12,23 +12,6 @@ var logger = require('../logger');
 
 describe('AddOverlayDialog', function() {
 
-  describe('processFile', function() {
-    it('default', function() {
-      return ServerConnector.getProject().then(function(project) {
-        var dialog = new AddOverlayDialog({
-          element : testDiv,
-          project : project,
-          customMap : null
-        });
-
-        var file = new Blob([ "#DESCRIPTION=xxx\nname\tvalue\ns1\t1" ]);
-        return dialog.processFile(file).then(function(content) {
-          assert.ok(content !== null);
-        });
-      });
-    });
-  });
-
   it('addOverlay', function() {
     var dialog;
     return ServerConnector.getProject().then(function(project) {
@@ -43,22 +26,4 @@ describe('AddOverlayDialog', function() {
     });
   });
 
-  
-  it('parse overlay file', function() {
-    return ServerConnector.getProject().then(function(project) {
-      var dialog = new AddOverlayDialog({
-        element : testDiv,
-        project : project,
-        customMap : null
-      });
-
-      return ServerConnector.sendGetRequest("testFiles/overlay/good.txt").then(function(fileContent) {
-        var obj = dialog.parseFile(fileContent);
-        assert.equal(obj.name, "example name");
-        assert.equal(obj.description, "layout description");
-        assert.equal(obj.type, "GENERIC");
-      });
-    });
-  });
-
 });
diff --git a/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js b/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js
index 50d5368971..219804ccf8 100644
--- a/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js
+++ b/frontend-js/src/test/js/gui/admin/AddProjectDialog-test.js
@@ -7,6 +7,7 @@ require("../../mocha-config");
 var AddProjectDialog = require('../../../../main/js/gui/admin/AddProjectDialog');
 var logger = require('../../logger');
 
+var fs = require("fs");
 var chai = require('chai');
 var assert = chai.assert;
 
@@ -20,6 +21,7 @@ describe('AddProjectDialog', function () {
       return dialog.init();
     }).then(function () {
       assert.ok(dialog.getNotifyEmail() !== "");
+      return dialog.destroy();
     });
   });
 
@@ -35,6 +37,7 @@ describe('AddProjectDialog', function () {
       assert.notOk(dialog.isCache());
       dialog.setCache(true);
       assert.ok(dialog.isCache());
+      return dialog.destroy();
     });
   });
 
@@ -55,6 +58,41 @@ describe('AddProjectDialog', function () {
         return dialog.getConverter();
       }).then(function (converter) {
         assert.equal("xml", converter.extension);
+        return dialog.destroy();
+      });
+    });
+  });
+
+  describe('setZipFileContent', function () {
+    it('submaps', function () {
+      var dialog = new AddProjectDialog({
+        element: testDiv,
+        customMap: null
+      });
+      var buf = fs.readFileSync("testFiles/map/complex_model_with_submaps.zip");
+      buf.name = "complex_model_with_submaps.zip";
+      return dialog.init().then(function () {
+        return dialog.setZipFileContent(buf);
+      }).then(function () {
+        assert.equal(5, dialog.getZipEntries().length);
+        return dialog.destroy();
+      });
+    });
+    it('overlays', function () {
+      var dialog = new AddProjectDialog({
+        element: testDiv,
+        customMap: null
+      });
+      var buf = fs.readFileSync("testFiles/map/complex_model_with_overlays.zip");
+      buf.name = "complex_model_with_overlays.zip";
+      return dialog.init().then(function () {
+        var dataTable = $($("[name='overlaysTable']", testDiv)[0]).DataTable();
+        assert.equal(0, dataTable.data().count());
+        return dialog.setZipFileContent(buf);
+      }).then(function () {
+        var dataTable = $($("[name='overlaysTable']", testDiv)[0]).DataTable();
+        assert.ok(dataTable.data().count() > 0);
+        return dialog.destroy();
       });
     });
   });
@@ -67,7 +105,7 @@ describe('AddProjectDialog', function () {
       });
 
       return dialog.showAnnotatorsDialog().then(function () {
-        dialog.destroy();
+        return dialog.destroy();
       });
     });
   });
@@ -110,6 +148,7 @@ describe('AddProjectDialog', function () {
         assert.ok(options["organism"] !== undefined);
         assert.ok(options["sbgn"] !== undefined);
         assert.ok(options["semantic-zoom"] !== undefined);
+        return dialog.destroy();
       });
     });
   });
diff --git a/frontend-js/src/test/js/map/OverlayParser-test.js b/frontend-js/src/test/js/map/OverlayParser-test.js
new file mode 100644
index 0000000000..b3a0f0ae08
--- /dev/null
+++ b/frontend-js/src/test/js/map/OverlayParser-test.js
@@ -0,0 +1,33 @@
+"use strict";
+
+require("../mocha-config.js");
+
+var OverlayParser = require('../../../main/js/map/OverlayParser');
+var chai = require('chai');
+var assert = chai.assert;
+
+describe('OverlayParser', function () {
+  describe('parse', function () {
+    it('simple', function () {
+      var parser = new OverlayParser();
+      var fileContent = "#NAME=some Name\n#DESCRIPTION=xxx\nname\tvalue\ns1\t1";
+
+      var overlay = parser.parse(fileContent);
+      assert.ok(overlay);
+      assert.equal(overlay.getDescription(), "xxx");
+      assert.equal(overlay.getName(), "some Name");
+      assert.ok(overlay.getContent());
+    });
+    it('with type', function () {
+
+      return ServerConnector.sendGetRequest("testFiles/overlay/good.txt").then(function (fileContent) {
+        var parser = new OverlayParser();
+        var overlay = parser.parse(fileContent);
+        assert.equal(overlay.getName(), "example name");
+        assert.equal(overlay.getDescription(), "layout description");
+        assert.equal(overlay.getType(), "GENERIC");
+      });
+    });
+  });
+
+});
diff --git a/frontend-js/testFiles/apiCalls/configuration/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/configuration/token=MOCK_TOKEN_ID&
index 87bada811f..38618b8344 100644
--- a/frontend-js/testFiles/apiCalls/configuration/token=MOCK_TOKEN_ID&
+++ b/frontend-js/testFiles/apiCalls/configuration/token=MOCK_TOKEN_ID&
@@ -1 +1 @@
-{"modelFormats":[{"handler":"lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser","extension":"xml","name":"CellDesigner SBML"},{"handler":"lcsb.mapviewer.converter.model.sbgnml.SbgnmlXmlConverter","extension":"sbgn","name":"SBGN-ML"}],"elementTypes":[{"name":"Degraded","className":"lcsb.mapviewer.model.map.species.Degraded","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.LeftSquareCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Protein","className":"lcsb.mapviewer.model.map.species.IonChannelProtein","parentClass":"lcsb.mapviewer.model.map.species.Protein"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.TopSquareCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Ion","className":"lcsb.mapviewer.model.map.species.Ion","parentClass":"lcsb.mapviewer.model.map.species.Chemical"},{"name":"Species","className":"lcsb.mapviewer.model.map.species.Species","parentClass":"lcsb.mapviewer.model.map.species.Element"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.RightSquareCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Drug","className":"lcsb.mapviewer.model.map.species.Drug","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Protein","className":"lcsb.mapviewer.model.map.species.Protein","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Protein","className":"lcsb.mapviewer.model.map.species.TruncatedProtein","parentClass":"lcsb.mapviewer.model.map.species.Protein"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.PathwayCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.BottomSquareCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"RNA","className":"lcsb.mapviewer.model.map.species.Rna","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Chemical","className":"lcsb.mapviewer.model.map.species.Chemical","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.Compartment","parentClass":"lcsb.mapviewer.model.map.species.Element"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.OvalCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.SquareCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Unknown","className":"lcsb.mapviewer.model.map.species.Unknown","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Element","className":"lcsb.mapviewer.model.map.species.Element","parentClass":"lcsb.mapviewer.model.map.BioEntity"},{"name":"Phenotype","className":"lcsb.mapviewer.model.map.species.Phenotype","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Complex","className":"lcsb.mapviewer.model.map.species.Complex","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Antisense RNA","className":"lcsb.mapviewer.model.map.species.AntisenseRna","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Protein","className":"lcsb.mapviewer.model.map.species.ReceptorProtein","parentClass":"lcsb.mapviewer.model.map.species.Protein"},{"name":"Simple molecule","className":"lcsb.mapviewer.model.map.species.SimpleMolecule","parentClass":"lcsb.mapviewer.model.map.species.Chemical"},{"name":"Protein","className":"lcsb.mapviewer.model.map.species.GenericProtein","parentClass":"lcsb.mapviewer.model.map.species.Protein"},{"name":"Gene","className":"lcsb.mapviewer.model.map.species.Gene","parentClass":"lcsb.mapviewer.model.map.species.Species"}],"modificationStateTypes":{"PHOSPHORYLATED":{"commonName":"phosphorylated","abbreviation":"P"},"METHYLATED":{"commonName":"methylated","abbreviation":"Me"},"PALMYTOYLATED":{"commonName":"palmytoylated","abbreviation":"Pa"},"ACETYLATED":{"commonName":"acetylated","abbreviation":"Ac"},"SULFATED":{"commonName":"sulfated","abbreviation":"S"},"GLYCOSYLATED":{"commonName":"glycosylated","abbreviation":"G"},"PRENYLATED":{"commonName":"prenylated","abbreviation":"Pr"},"UBIQUITINATED":{"commonName":"ubiquitinated","abbreviation":"Ub"},"PROTONATED":{"commonName":"protonated","abbreviation":"H"},"HYDROXYLATED":{"commonName":"hydroxylated","abbreviation":"OH"},"MYRISTOYLATED":{"commonName":"myristoylated","abbreviation":"My"},"UNKNOWN":{"commonName":"unknown","abbreviation":"?"},"EMPTY":{"commonName":"empty","abbreviation":""},"DONT_CARE":{"commonName":"don't care","abbreviation":"*"}},"miriamTypes":{"CHEMBL_TARGET":{"commonName":"ChEMBL target","uris":["urn:miriam:chembl.target"],"homepage":"https://www.ebi.ac.uk/chembldb/","registryIdentifier":"MIR:00000085"},"UNIPROT":{"commonName":"Uniprot","uris":["urn:miriam:uniprot"],"homepage":"http://www.uniprot.org/","registryIdentifier":"MIR:00000005"},"MI_R_BASE_MATURE_SEQUENCE":{"commonName":"miRBase Mature Sequence Database","uris":["urn:miriam:mirbase.mature"],"homepage":"http://www.mirbase.org/","registryIdentifier":"MIR:00000235"},"PFAM":{"commonName":"Protein Family Database","uris":["urn:miriam:pfam"],"homepage":"http://pfam.xfam.org//","registryIdentifier":"MIR:00000028"},"ENSEMBL_PLANTS":{"commonName":"Ensembl Plants","uris":["urn:miriam:ensembl.plant"],"homepage":"http://plants.ensembl.org/","registryIdentifier":"MIR:00000205"},"WIKIPEDIA":{"commonName":"Wikipedia (English)","uris":["urn:miriam:wikipedia.en"],"homepage":"http://en.wikipedia.org/wiki/Main_Page","registryIdentifier":"MIR:00000384"},"CHEBI":{"commonName":"Chebi","uris":["urn:miriam:obo.chebi","urn:miriam:chebi"],"homepage":"http://www.ebi.ac.uk/chebi/","registryIdentifier":"MIR:00000002"},"WIKIDATA":{"commonName":"Wikidata","uris":["urn:miriam:wikidata"],"homepage":"https://www.wikidata.org/","registryIdentifier":"MIR:00000549"},"REACTOME":{"commonName":"Reactome","uris":["urn:miriam:reactome"],"homepage":"http://www.reactome.org/","registryIdentifier":"MIR:00000018"},"EC":{"commonName":"Enzyme Nomenclature","uris":["urn:miriam:ec-code"],"homepage":"http://www.enzyme-database.org/","registryIdentifier":"MIR:00000004"},"UNIPROT_ISOFORM":{"commonName":"UniProt Isoform","uris":["urn:miriam:uniprot.isoform"],"homepage":"http://www.uniprot.org/","registryIdentifier":"MIR:00000388"},"OMIM":{"commonName":"Online Mendelian Inheritance in Man","uris":["urn:miriam:omim"],"homepage":"http://omim.org/","registryIdentifier":"MIR:00000016"},"DRUGBANK_TARGET_V4":{"commonName":"DrugBank Target v4","uris":["urn:miriam:drugbankv4.target"],"homepage":"http://www.drugbank.ca/targets","registryIdentifier":"MIR:00000528"},"MIR_TAR_BASE_MATURE_SEQUENCE":{"commonName":"miRTarBase Mature Sequence Database","uris":["urn:miriam:mirtarbase"],"homepage":"http://mirtarbase.mbc.nctu.edu.tw/","registryIdentifier":"MIR:00100739"},"CHEMBL_COMPOUND":{"commonName":"ChEMBL","uris":["urn:miriam:chembl.compound"],"homepage":"https://www.ebi.ac.uk/chembldb/","registryIdentifier":"MIR:00000084"},"KEGG_PATHWAY":{"commonName":"Kegg Pathway","uris":["urn:miriam:kegg.pathway"],"homepage":"http://www.genome.jp/kegg/pathway.html","registryIdentifier":"MIR:00000012"},"CAS":{"commonName":"Chemical Abstracts Service","uris":["urn:miriam:cas"],"homepage":"http://commonchemistry.org","registryIdentifier":"MIR:00000237"},"REFSEQ":{"commonName":"RefSeq","uris":["urn:miriam:refseq"],"homepage":"http://www.ncbi.nlm.nih.gov/projects/RefSeq/","registryIdentifier":"MIR:00000039"},"WORM_BASE":{"commonName":"WormBase","uris":["urn:miriam:wormbase"],"homepage":"http://wormbase.bio2rdf.org/fct","registryIdentifier":"MIR:00000027"},"MI_R_BASE_SEQUENCE":{"commonName":"miRBase Sequence Database","uris":["urn:miriam:mirbase"],"homepage":"http://www.mirbase.org/","registryIdentifier":"MIR:00000078"},"TAIR_LOCUS":{"commonName":"TAIR Locus","uris":["urn:miriam:tair.locus"],"homepage":"http://arabidopsis.org/index.jsp","registryIdentifier":"MIR:00000050"},"PHARM":{"commonName":"PharmGKB Pathways","uris":["urn:miriam:pharmgkb.pathways"],"homepage":"http://www.pharmgkb.org/","registryIdentifier":"MIR:00000089"},"PANTHER":{"commonName":"PANTHER Family","uris":["urn:miriam:panther.family","urn:miriam:panther"],"homepage":"http://www.pantherdb.org/","registryIdentifier":"MIR:00000060"},"TAXONOMY":{"commonName":"Taxonomy","uris":["urn:miriam:taxonomy"],"homepage":"http://www.ncbi.nlm.nih.gov/taxonomy/","registryIdentifier":"MIR:00000006"},"UNIGENE":{"commonName":"UniGene","uris":["urn:miriam:unigene"],"homepage":"http://www.ncbi.nlm.nih.gov/unigene","registryIdentifier":"MIR:00000346"},"HGNC":{"commonName":"HGNC","uris":["urn:miriam:hgnc"],"homepage":"http://www.genenames.org","registryIdentifier":"MIR:00000080"},"HGNC_SYMBOL":{"commonName":"HGNC Symbol","uris":["urn:miriam:hgnc.symbol"],"homepage":"http://www.genenames.org","registryIdentifier":"MIR:00000362"},"COG":{"commonName":"Clusters of Orthologous Groups","uris":["urn:miriam:cogs"],"homepage":"https://www.ncbi.nlm.nih.gov/COG/","registryIdentifier":"MIR:00000296"},"WIKIPATHWAYS":{"commonName":"WikiPathways","uris":["urn:miriam:wikipathways"],"homepage":"http://www.wikipathways.org/","registryIdentifier":"MIR:00000076"},"HMDB":{"commonName":"HMDB","uris":["urn:miriam:hmdb"],"homepage":"http://www.hmdb.ca/","registryIdentifier":"MIR:00000051"},"CHEMSPIDER":{"commonName":"ChemSpider","uris":["urn:miriam:chemspider"],"homepage":"http://www.chemspider.com//","registryIdentifier":"MIR:00000138"},"ENSEMBL":{"commonName":"Ensembl","uris":["urn:miriam:ensembl"],"homepage":"www.ensembl.org","registryIdentifier":"MIR:00000003"},"GO":{"commonName":"Gene Ontology","uris":["urn:miriam:obo.go","urn:miriam:go"],"homepage":"http://amigo.geneontology.org/amigo","registryIdentifier":"MIR:00000022"},"KEGG_REACTION":{"commonName":"Kegg Reaction","uris":["urn:miriam:kegg.reaction"],"homepage":"http://www.genome.jp/kegg/reaction/","registryIdentifier":"MIR:00000014"},"KEGG_ORTHOLOGY":{"commonName":"KEGG Orthology","uris":["urn:miriam:kegg.orthology"],"homepage":"http://www.genome.jp/kegg/ko.html","registryIdentifier":"MIR:00000116"},"PUBCHEM":{"commonName":"PubChem-compound","uris":["urn:miriam:pubchem.compound"],"homepage":"http://pubchem.ncbi.nlm.nih.gov/","registryIdentifier":"MIR:00000034"},"MESH_2012":{"commonName":"MeSH 2012","uris":["urn:miriam:mesh.2012","urn:miriam:mesh"],"homepage":"http://www.nlm.nih.gov/mesh/","registryIdentifier":"MIR:00000270"},"MGD":{"commonName":"Mouse Genome Database","uris":["urn:miriam:mgd"],"homepage":"http://www.informatics.jax.org/","registryIdentifier":"MIR:00000037"},"ENTREZ":{"commonName":"Entrez Gene","uris":["urn:miriam:ncbigene","urn:miriam:entrez.gene"],"homepage":"http://www.ncbi.nlm.nih.gov/gene","registryIdentifier":"MIR:00000069"},"PUBCHEM_SUBSTANCE":{"commonName":"PubChem-substance","uris":["urn:miriam:pubchem.substance"],"homepage":"http://pubchem.ncbi.nlm.nih.gov/","registryIdentifier":"MIR:00000033"},"CCDS":{"commonName":"Consensus CDS","uris":["urn:miriam:ccds"],"homepage":"http://www.ncbi.nlm.nih.gov/CCDS/","registryIdentifier":"MIR:00000375"},"KEGG_GENES":{"commonName":"Kegg Genes","uris":["urn:miriam:kegg.genes","urn:miriam:kegg.genes:hsa"],"homepage":"http://www.genome.jp/kegg/genes.html","registryIdentifier":"MIR:00000070"},"TOXICOGENOMIC_CHEMICAL":{"commonName":"Toxicogenomic Chemical","uris":["urn:miriam:ctd.chemical"],"homepage":"http://ctdbase.org/","registryIdentifier":"MIR:00000098"},"SGD":{"commonName":"Saccharomyces Genome Database","uris":["urn:miriam:sgd"],"homepage":"http://www.yeastgenome.org/","registryIdentifier":"MIR:00000023"},"KEGG_COMPOUND":{"commonName":"Kegg Compound","uris":["urn:miriam:kegg.compound"],"homepage":"http://www.genome.jp/kegg/ligand.html","registryIdentifier":"MIR:00000013"},"INTERPRO":{"commonName":"InterPro","uris":["urn:miriam:interpro"],"homepage":"http://www.ebi.ac.uk/interpro/","registryIdentifier":"MIR:00000011"},"UNKNOWN":{"commonName":"Unknown","uris":[],"homepage":null,"registryIdentifier":null},"DRUGBANK":{"commonName":"DrugBank","uris":["urn:miriam:drugbank"],"homepage":"http://www.drugbank.ca/","registryIdentifier":"MIR:00000102"},"PUBMED":{"commonName":"PubMed","uris":["urn:miriam:pubmed"],"homepage":"http://www.ncbi.nlm.nih.gov/PubMed/","registryIdentifier":"MIR:00000015"}},"imageFormats":[{"handler":"lcsb.mapviewer.converter.graphics.PngImageGenerator","extension":"png","name":"PNG image"},{"handler":"lcsb.mapviewer.converter.graphics.PdfImageGenerator","extension":"pdf","name":"PDF"},{"handler":"lcsb.mapviewer.converter.graphics.SvgImageGenerator","extension":"svg","name":"SVG image"}],"annotators":[{"name":"Biocompendium","className":"lcsb.mapviewer.annotation.services.annotators.BiocompendiumAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Protein"],"url":"http://biocompendium.embl.de/"},{"name":"Chebi","className":"lcsb.mapviewer.annotation.services.annotators.ChebiAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Chemical"],"url":"http://www.ebi.ac.uk/chebi/"},{"name":"Uniprot","className":"lcsb.mapviewer.annotation.services.annotators.UniprotAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Gene","lcsb.mapviewer.model.map.species.Rna"],"url":"http://www.uniprot.org/"},{"name":"Gene Ontology","className":"lcsb.mapviewer.annotation.services.annotators.GoAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Phenotype","lcsb.mapviewer.model.map.compartment.Compartment","lcsb.mapviewer.model.map.species.Complex"],"url":"http://amigo.geneontology.org/amigo"},{"name":"HGNC","className":"lcsb.mapviewer.annotation.services.annotators.HgncAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Rna","lcsb.mapviewer.model.map.species.Gene"],"url":"http://www.genenames.org"},{"name":"Recon annotator","className":"lcsb.mapviewer.annotation.services.annotators.ReconAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Chemical","lcsb.mapviewer.model.map.reaction.Reaction"],"url":"http://humanmetabolism.org/"},{"name":"Entrez Gene","className":"lcsb.mapviewer.annotation.services.annotators.EntrezAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Rna","lcsb.mapviewer.model.map.species.Gene"],"url":"http://www.ncbi.nlm.nih.gov/gene"},{"name":"Ensembl","className":"lcsb.mapviewer.annotation.services.annotators.EnsemblAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Rna","lcsb.mapviewer.model.map.species.Gene"],"url":"www.ensembl.org"}],"options":[{"idObject":9,"type":"EMAIL_ADDRESS","value":"your.account@domain.com"},{"idObject":10,"type":"EMAIL_LOGIN","value":"your@login"},{"idObject":11,"type":"EMAIL_PASSWORD","value":"email.secret.password"},{"idObject":13,"type":"EMAIL_IMAP_SERVER","value":"your.imap.domain.com"},{"idObject":12,"type":"EMAIL_SMTP_SERVER","value":"your.smtp.domain.com"},{"idObject":14,"type":"EMAIL_SMTP_PORT","value":"25"},{"idObject":6,"type":"DEFAULT_MAP","value":"sample"},{"idObject":4,"type":"LOGO_IMG","value":"udl.png"},{"idObject":3,"type":"LOGO_LINK","value":"http://wwwen.uni.lu/"},{"idObject":7,"type":"SEARCH_DISTANCE","value":"10"},{"idObject":1,"type":"REQUEST_ACCOUNT_EMAIL","value":"your.email@domain.com"},{"idObject":8,"type":"SEARCH_RESULT_NUMBER","value":"100"},{"idObject":2,"type":"GOOGLE_ANALYTICS_IDENTIFIER","value":""},{"idObject":5,"type":"LOGO_TEXT","value":"University of Luxembourg"},{"idObject":56,"type":"X_FRAME_DOMAIN","value":"http://localhost:8080/"},{"idObject":131,"type":"BIG_FILE_STORAGE_DIR","value":"minerva-big/"},{"idObject":138,"type":"LEGEND_FILE_1","value":"resources/images/legend_a.png"},{"idObject":139,"type":"LEGEND_FILE_2","value":"resources/images/legend_b.png"},{"idObject":140,"type":"LEGEND_FILE_3","value":"resources/images/legend_c.png"},{"idObject":141,"type":"LEGEND_FILE_4","value":"resources/images/legend_d.png"},{"idObject":142,"type":"USER_MANUAL_FILE","value":"resources/other/user_guide.pdf"},{"idObject":205,"type":"MIN_COLOR_VAL","value":"FF0000"},{"idObject":206,"type":"MAX_COLOR_VAL","value":"fbff00"},{"idObject":218,"type":"SIMPLE_COLOR_VAL","value":"00FF00"}],"privilegeTypes":{"VIEW_PROJECT":{"commonName":"View project","valueType":"boolean","objectType":"Project"},"LAYOUT_MANAGEMENT":{"commonName":"Manage layouts","valueType":"boolean","objectType":"Project"},"PROJECT_MANAGEMENT":{"commonName":"Map management","valueType":"boolean","objectType":null},"CUSTOM_LAYOUTS":{"commonName":"Custom layouts","valueType":"int","objectType":null},"ADD_MAP":{"commonName":"Add project","valueType":"boolean","objectType":null},"LAYOUT_VIEW":{"commonName":"View layout","valueType":"boolean","objectType":"Layout"},"MANAGE_GENOMES":{"commonName":"Manage genomes","valueType":"boolean","objectType":null},"EDIT_COMMENTS_PROJECT":{"commonName":"Manage comments","valueType":"boolean","objectType":"Project"},"CONFIGURATION_MANAGE":{"commonName":"Manage configuration","valueType":"boolean","objectType":null},"USER_MANAGEMENT":{"commonName":"User management","valueType":"boolean","objectType":null}},"overlayTypes":[{"name":"GENERIC"},{"name":"GENETIC_VARIANT"}],"buildDate":"30/08/2017 16:58","reactionTypes":[{"name":"Unknown positive influence","className":"lcsb.mapviewer.model.map.reaction.type.UnknownPositiveInfluenceReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Generic Reaction","className":"lcsb.mapviewer.model.map.reaction.Reaction","parentClass":"lcsb.mapviewer.model.map.BioEntity"},{"name":"Reduced physical stimulation","className":"lcsb.mapviewer.model.map.reaction.type.ReducedPhysicalStimulationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Negative influence","className":"lcsb.mapviewer.model.map.reaction.type.NegativeInfluenceReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Known transition omitted","className":"lcsb.mapviewer.model.map.reaction.type.KnownTransitionOmittedReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Reduced modulation","className":"lcsb.mapviewer.model.map.reaction.type.ReducedModulationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Translation","className":"lcsb.mapviewer.model.map.reaction.type.TranslationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Heterodimer association","className":"lcsb.mapviewer.model.map.reaction.type.HeterodimerAssociationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Transcription","className":"lcsb.mapviewer.model.map.reaction.type.TranscriptionReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Unknown reduced trigger","className":"lcsb.mapviewer.model.map.reaction.type.UnknownReducedTriggerReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Unknown negative influence","className":"lcsb.mapviewer.model.map.reaction.type.UnknownNegativeInfluenceReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Truncation","className":"lcsb.mapviewer.model.map.reaction.type.TruncationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Transport","className":"lcsb.mapviewer.model.map.reaction.type.TransportReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Reduced trigger","className":"lcsb.mapviewer.model.map.reaction.type.ReducedTriggerReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"State transition","className":"lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Positive influence","className":"lcsb.mapviewer.model.map.reaction.type.PositiveInfluenceReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Unknown reduced physical stimulation","className":"lcsb.mapviewer.model.map.reaction.type.UnknownReducedPhysicalStimulationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Boolean logic gate","className":"lcsb.mapviewer.model.map.reaction.type.BooleanLogicGateReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Unknown reduced modulation","className":"lcsb.mapviewer.model.map.reaction.type.UnknownReducedModulationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Unknown transition","className":"lcsb.mapviewer.model.map.reaction.type.UnknownTransitionReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Dissociation","className":"lcsb.mapviewer.model.map.reaction.type.DissociationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"}],"version":"11.0.0"}
\ No newline at end of file
+{"modelFormats":[{"handler":"lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser","extension":"xml","name":"CellDesigner SBML"},{"handler":"lcsb.mapviewer.converter.model.sbgnml.SbgnmlXmlConverter","extension":"sbgn","name":"SBGN-ML"}],"elementTypes":[{"name":"Degraded","className":"lcsb.mapviewer.model.map.species.Degraded","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.LeftSquareCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Protein","className":"lcsb.mapviewer.model.map.species.IonChannelProtein","parentClass":"lcsb.mapviewer.model.map.species.Protein"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.TopSquareCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Ion","className":"lcsb.mapviewer.model.map.species.Ion","parentClass":"lcsb.mapviewer.model.map.species.Chemical"},{"name":"Species","className":"lcsb.mapviewer.model.map.species.Species","parentClass":"lcsb.mapviewer.model.map.species.Element"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.RightSquareCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Drug","className":"lcsb.mapviewer.model.map.species.Drug","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Protein","className":"lcsb.mapviewer.model.map.species.Protein","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Protein","className":"lcsb.mapviewer.model.map.species.TruncatedProtein","parentClass":"lcsb.mapviewer.model.map.species.Protein"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.PathwayCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.BottomSquareCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"RNA","className":"lcsb.mapviewer.model.map.species.Rna","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Chemical","className":"lcsb.mapviewer.model.map.species.Chemical","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.Compartment","parentClass":"lcsb.mapviewer.model.map.species.Element"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.OvalCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Compartment","className":"lcsb.mapviewer.model.map.compartment.SquareCompartment","parentClass":"lcsb.mapviewer.model.map.compartment.Compartment"},{"name":"Unknown","className":"lcsb.mapviewer.model.map.species.Unknown","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Element","className":"lcsb.mapviewer.model.map.species.Element","parentClass":"lcsb.mapviewer.model.map.BioEntity"},{"name":"Phenotype","className":"lcsb.mapviewer.model.map.species.Phenotype","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Complex","className":"lcsb.mapviewer.model.map.species.Complex","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Antisense RNA","className":"lcsb.mapviewer.model.map.species.AntisenseRna","parentClass":"lcsb.mapviewer.model.map.species.Species"},{"name":"Protein","className":"lcsb.mapviewer.model.map.species.ReceptorProtein","parentClass":"lcsb.mapviewer.model.map.species.Protein"},{"name":"Simple molecule","className":"lcsb.mapviewer.model.map.species.SimpleMolecule","parentClass":"lcsb.mapviewer.model.map.species.Chemical"},{"name":"Protein","className":"lcsb.mapviewer.model.map.species.GenericProtein","parentClass":"lcsb.mapviewer.model.map.species.Protein"},{"name":"Gene","className":"lcsb.mapviewer.model.map.species.Gene","parentClass":"lcsb.mapviewer.model.map.species.Species"}],"modificationStateTypes":{"PHOSPHORYLATED":{"commonName":"phosphorylated","abbreviation":"P"},"METHYLATED":{"commonName":"methylated","abbreviation":"Me"},"PALMYTOYLATED":{"commonName":"palmytoylated","abbreviation":"Pa"},"ACETYLATED":{"commonName":"acetylated","abbreviation":"Ac"},"SULFATED":{"commonName":"sulfated","abbreviation":"S"},"GLYCOSYLATED":{"commonName":"glycosylated","abbreviation":"G"},"PRENYLATED":{"commonName":"prenylated","abbreviation":"Pr"},"UBIQUITINATED":{"commonName":"ubiquitinated","abbreviation":"Ub"},"PROTONATED":{"commonName":"protonated","abbreviation":"H"},"HYDROXYLATED":{"commonName":"hydroxylated","abbreviation":"OH"},"MYRISTOYLATED":{"commonName":"myristoylated","abbreviation":"My"},"UNKNOWN":{"commonName":"unknown","abbreviation":"?"},"EMPTY":{"commonName":"empty","abbreviation":""},"DONT_CARE":{"commonName":"don't care","abbreviation":"*"}},"imageFormats":[{"handler":"lcsb.mapviewer.converter.graphics.PngImageGenerator","extension":"png","name":"PNG image"},{"handler":"lcsb.mapviewer.converter.graphics.PdfImageGenerator","extension":"pdf","name":"PDF"},{"handler":"lcsb.mapviewer.converter.graphics.SvgImageGenerator","extension":"svg","name":"SVG image"}],"annotators":[{"name":"Biocompendium","className":"lcsb.mapviewer.annotation.services.annotators.BiocompendiumAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Gene","lcsb.mapviewer.model.map.species.Rna"],"url":"http://biocompendium.embl.de/"},{"name":"Chebi","className":"lcsb.mapviewer.annotation.services.annotators.ChebiAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Chemical"],"url":"http://www.ebi.ac.uk/chebi/"},{"name":"Uniprot","className":"lcsb.mapviewer.annotation.services.annotators.UniprotAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Gene","lcsb.mapviewer.model.map.species.Rna"],"url":"http://www.uniprot.org/"},{"name":"Gene Ontology","className":"lcsb.mapviewer.annotation.services.annotators.GoAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Phenotype","lcsb.mapviewer.model.map.compartment.Compartment","lcsb.mapviewer.model.map.species.Complex"],"url":"http://amigo.geneontology.org/amigo"},{"name":"HGNC","className":"lcsb.mapviewer.annotation.services.annotators.HgncAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Rna","lcsb.mapviewer.model.map.species.Gene"],"url":"http://www.genenames.org"},{"name":"Recon annotator","className":"lcsb.mapviewer.annotation.services.annotators.ReconAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Chemical","lcsb.mapviewer.model.map.reaction.Reaction"],"url":"http://humanmetabolism.org/"},{"name":"Entrez Gene","className":"lcsb.mapviewer.annotation.services.annotators.EntrezAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Rna","lcsb.mapviewer.model.map.species.Gene"],"url":"http://www.ncbi.nlm.nih.gov/gene"},{"name":"Ensembl","className":"lcsb.mapviewer.annotation.services.annotators.EnsemblAnnotator","elementClassNames":["lcsb.mapviewer.model.map.species.Protein","lcsb.mapviewer.model.map.species.Rna","lcsb.mapviewer.model.map.species.Gene"],"url":"www.ensembl.org"}],"buildDate":"            28/09/2017 15:11","reactionTypes":[{"name":"Unknown positive influence","className":"lcsb.mapviewer.model.map.reaction.type.UnknownPositiveInfluenceReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Generic Reaction","className":"lcsb.mapviewer.model.map.reaction.Reaction","parentClass":"lcsb.mapviewer.model.map.BioEntity"},{"name":"Reduced physical stimulation","className":"lcsb.mapviewer.model.map.reaction.type.ReducedPhysicalStimulationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Negative influence","className":"lcsb.mapviewer.model.map.reaction.type.NegativeInfluenceReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Known transition omitted","className":"lcsb.mapviewer.model.map.reaction.type.KnownTransitionOmittedReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Reduced modulation","className":"lcsb.mapviewer.model.map.reaction.type.ReducedModulationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Translation","className":"lcsb.mapviewer.model.map.reaction.type.TranslationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Heterodimer association","className":"lcsb.mapviewer.model.map.reaction.type.HeterodimerAssociationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Transcription","className":"lcsb.mapviewer.model.map.reaction.type.TranscriptionReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Unknown reduced trigger","className":"lcsb.mapviewer.model.map.reaction.type.UnknownReducedTriggerReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Unknown negative influence","className":"lcsb.mapviewer.model.map.reaction.type.UnknownNegativeInfluenceReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Truncation","className":"lcsb.mapviewer.model.map.reaction.type.TruncationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Transport","className":"lcsb.mapviewer.model.map.reaction.type.TransportReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Reduced trigger","className":"lcsb.mapviewer.model.map.reaction.type.ReducedTriggerReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"State transition","className":"lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Positive influence","className":"lcsb.mapviewer.model.map.reaction.type.PositiveInfluenceReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Unknown reduced physical stimulation","className":"lcsb.mapviewer.model.map.reaction.type.UnknownReducedPhysicalStimulationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Boolean logic gate","className":"lcsb.mapviewer.model.map.reaction.type.BooleanLogicGateReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Unknown reduced modulation","className":"lcsb.mapviewer.model.map.reaction.type.UnknownReducedModulationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Unknown transition","className":"lcsb.mapviewer.model.map.reaction.type.UnknownTransitionReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"},{"name":"Dissociation","className":"lcsb.mapviewer.model.map.reaction.type.DissociationReaction","parentClass":"lcsb.mapviewer.model.map.reaction.Reaction"}],"version":"11.0.1","mapTypes":[{"name":"Downstream targets","id":"DOWNSTREAM_TARGETS"},{"name":"Pathway","id":"PATHWAY"},{"name":"Unknown","id":"UNKNOWN"}],"miriamTypes":{"CHEMBL_TARGET":{"commonName":"ChEMBL target","uris":["urn:miriam:chembl.target"],"homepage":"https://www.ebi.ac.uk/chembldb/","registryIdentifier":"MIR:00000085"},"UNIPROT":{"commonName":"Uniprot","uris":["urn:miriam:uniprot"],"homepage":"http://www.uniprot.org/","registryIdentifier":"MIR:00000005"},"MI_R_BASE_MATURE_SEQUENCE":{"commonName":"miRBase Mature Sequence Database","uris":["urn:miriam:mirbase.mature"],"homepage":"http://www.mirbase.org/","registryIdentifier":"MIR:00000235"},"PFAM":{"commonName":"Protein Family Database","uris":["urn:miriam:pfam"],"homepage":"http://pfam.xfam.org//","registryIdentifier":"MIR:00000028"},"ENSEMBL_PLANTS":{"commonName":"Ensembl Plants","uris":["urn:miriam:ensembl.plant"],"homepage":"http://plants.ensembl.org/","registryIdentifier":"MIR:00000205"},"WIKIPEDIA":{"commonName":"Wikipedia (English)","uris":["urn:miriam:wikipedia.en"],"homepage":"http://en.wikipedia.org/wiki/Main_Page","registryIdentifier":"MIR:00000384"},"CHEBI":{"commonName":"Chebi","uris":["urn:miriam:obo.chebi","urn:miriam:chebi"],"homepage":"http://www.ebi.ac.uk/chebi/","registryIdentifier":"MIR:00000002"},"WIKIDATA":{"commonName":"Wikidata","uris":["urn:miriam:wikidata"],"homepage":"https://www.wikidata.org/","registryIdentifier":"MIR:00000549"},"REACTOME":{"commonName":"Reactome","uris":["urn:miriam:reactome"],"homepage":"http://www.reactome.org/","registryIdentifier":"MIR:00000018"},"EC":{"commonName":"Enzyme Nomenclature","uris":["urn:miriam:ec-code"],"homepage":"http://www.enzyme-database.org/","registryIdentifier":"MIR:00000004"},"UNIPROT_ISOFORM":{"commonName":"UniProt Isoform","uris":["urn:miriam:uniprot.isoform"],"homepage":"http://www.uniprot.org/","registryIdentifier":"MIR:00000388"},"OMIM":{"commonName":"Online Mendelian Inheritance in Man","uris":["urn:miriam:omim"],"homepage":"http://omim.org/","registryIdentifier":"MIR:00000016"},"DRUGBANK_TARGET_V4":{"commonName":"DrugBank Target v4","uris":["urn:miriam:drugbankv4.target"],"homepage":"http://www.drugbank.ca/targets","registryIdentifier":"MIR:00000528"},"MIR_TAR_BASE_MATURE_SEQUENCE":{"commonName":"miRTarBase Mature Sequence Database","uris":["urn:miriam:mirtarbase"],"homepage":"http://mirtarbase.mbc.nctu.edu.tw/","registryIdentifier":"MIR:00100739"},"CHEMBL_COMPOUND":{"commonName":"ChEMBL","uris":["urn:miriam:chembl.compound"],"homepage":"https://www.ebi.ac.uk/chembldb/","registryIdentifier":"MIR:00000084"},"KEGG_PATHWAY":{"commonName":"Kegg Pathway","uris":["urn:miriam:kegg.pathway"],"homepage":"http://www.genome.jp/kegg/pathway.html","registryIdentifier":"MIR:00000012"},"CAS":{"commonName":"Chemical Abstracts Service","uris":["urn:miriam:cas"],"homepage":"http://commonchemistry.org","registryIdentifier":"MIR:00000237"},"REFSEQ":{"commonName":"RefSeq","uris":["urn:miriam:refseq"],"homepage":"http://www.ncbi.nlm.nih.gov/projects/RefSeq/","registryIdentifier":"MIR:00000039"},"WORM_BASE":{"commonName":"WormBase","uris":["urn:miriam:wormbase"],"homepage":"http://wormbase.bio2rdf.org/fct","registryIdentifier":"MIR:00000027"},"MI_R_BASE_SEQUENCE":{"commonName":"miRBase Sequence Database","uris":["urn:miriam:mirbase"],"homepage":"http://www.mirbase.org/","registryIdentifier":"MIR:00000078"},"TAIR_LOCUS":{"commonName":"TAIR Locus","uris":["urn:miriam:tair.locus"],"homepage":"http://arabidopsis.org/index.jsp","registryIdentifier":"MIR:00000050"},"PHARM":{"commonName":"PharmGKB Pathways","uris":["urn:miriam:pharmgkb.pathways"],"homepage":"http://www.pharmgkb.org/","registryIdentifier":"MIR:00000089"},"PANTHER":{"commonName":"PANTHER Family","uris":["urn:miriam:panther.family","urn:miriam:panther"],"homepage":"http://www.pantherdb.org/","registryIdentifier":"MIR:00000060"},"TAXONOMY":{"commonName":"Taxonomy","uris":["urn:miriam:taxonomy"],"homepage":"http://www.ncbi.nlm.nih.gov/taxonomy/","registryIdentifier":"MIR:00000006"},"UNIGENE":{"commonName":"UniGene","uris":["urn:miriam:unigene"],"homepage":"http://www.ncbi.nlm.nih.gov/unigene","registryIdentifier":"MIR:00000346"},"HGNC":{"commonName":"HGNC","uris":["urn:miriam:hgnc"],"homepage":"http://www.genenames.org","registryIdentifier":"MIR:00000080"},"HGNC_SYMBOL":{"commonName":"HGNC Symbol","uris":["urn:miriam:hgnc.symbol"],"homepage":"http://www.genenames.org","registryIdentifier":"MIR:00000362"},"COG":{"commonName":"Clusters of Orthologous Groups","uris":["urn:miriam:cogs"],"homepage":"https://www.ncbi.nlm.nih.gov/COG/","registryIdentifier":"MIR:00000296"},"WIKIPATHWAYS":{"commonName":"WikiPathways","uris":["urn:miriam:wikipathways"],"homepage":"http://www.wikipathways.org/","registryIdentifier":"MIR:00000076"},"HMDB":{"commonName":"HMDB","uris":["urn:miriam:hmdb"],"homepage":"http://www.hmdb.ca/","registryIdentifier":"MIR:00000051"},"CHEMSPIDER":{"commonName":"ChemSpider","uris":["urn:miriam:chemspider"],"homepage":"http://www.chemspider.com//","registryIdentifier":"MIR:00000138"},"ENSEMBL":{"commonName":"Ensembl","uris":["urn:miriam:ensembl"],"homepage":"www.ensembl.org","registryIdentifier":"MIR:00000003"},"GO":{"commonName":"Gene Ontology","uris":["urn:miriam:obo.go","urn:miriam:go"],"homepage":"http://amigo.geneontology.org/amigo","registryIdentifier":"MIR:00000022"},"KEGG_REACTION":{"commonName":"Kegg Reaction","uris":["urn:miriam:kegg.reaction"],"homepage":"http://www.genome.jp/kegg/reaction/","registryIdentifier":"MIR:00000014"},"KEGG_ORTHOLOGY":{"commonName":"KEGG Orthology","uris":["urn:miriam:kegg.orthology"],"homepage":"http://www.genome.jp/kegg/ko.html","registryIdentifier":"MIR:00000116"},"PUBCHEM":{"commonName":"PubChem-compound","uris":["urn:miriam:pubchem.compound"],"homepage":"http://pubchem.ncbi.nlm.nih.gov/","registryIdentifier":"MIR:00000034"},"MESH_2012":{"commonName":"MeSH 2012","uris":["urn:miriam:mesh.2012","urn:miriam:mesh"],"homepage":"http://www.nlm.nih.gov/mesh/","registryIdentifier":"MIR:00000270"},"MGD":{"commonName":"Mouse Genome Database","uris":["urn:miriam:mgd"],"homepage":"http://www.informatics.jax.org/","registryIdentifier":"MIR:00000037"},"ENTREZ":{"commonName":"Entrez Gene","uris":["urn:miriam:ncbigene","urn:miriam:entrez.gene"],"homepage":"http://www.ncbi.nlm.nih.gov/gene","registryIdentifier":"MIR:00000069"},"PUBCHEM_SUBSTANCE":{"commonName":"PubChem-substance","uris":["urn:miriam:pubchem.substance"],"homepage":"http://pubchem.ncbi.nlm.nih.gov/","registryIdentifier":"MIR:00000033"},"CCDS":{"commonName":"Consensus CDS","uris":["urn:miriam:ccds"],"homepage":"http://www.ncbi.nlm.nih.gov/CCDS/","registryIdentifier":"MIR:00000375"},"KEGG_GENES":{"commonName":"Kegg Genes","uris":["urn:miriam:kegg.genes","urn:miriam:kegg.genes:hsa"],"homepage":"http://www.genome.jp/kegg/genes.html","registryIdentifier":"MIR:00000070"},"TOXICOGENOMIC_CHEMICAL":{"commonName":"Toxicogenomic Chemical","uris":["urn:miriam:ctd.chemical"],"homepage":"http://ctdbase.org/","registryIdentifier":"MIR:00000098"},"SGD":{"commonName":"Saccharomyces Genome Database","uris":["urn:miriam:sgd"],"homepage":"http://www.yeastgenome.org/","registryIdentifier":"MIR:00000023"},"KEGG_COMPOUND":{"commonName":"Kegg Compound","uris":["urn:miriam:kegg.compound"],"homepage":"http://www.genome.jp/kegg/ligand.html","registryIdentifier":"MIR:00000013"},"INTERPRO":{"commonName":"InterPro","uris":["urn:miriam:interpro"],"homepage":"http://www.ebi.ac.uk/interpro/","registryIdentifier":"MIR:00000011"},"UNKNOWN":{"commonName":"Unknown","uris":[],"homepage":null,"registryIdentifier":null},"DRUGBANK":{"commonName":"DrugBank","uris":["urn:miriam:drugbank"],"homepage":"http://www.drugbank.ca/","registryIdentifier":"MIR:00000102"},"PUBMED":{"commonName":"PubMed","uris":["urn:miriam:pubmed"],"homepage":"http://www.ncbi.nlm.nih.gov/PubMed/","registryIdentifier":"MIR:00000015"}},"options":[{"idObject":9,"type":"EMAIL_ADDRESS","value":"your.account@domain.com"},{"idObject":10,"type":"EMAIL_LOGIN","value":"your@login"},{"idObject":11,"type":"EMAIL_PASSWORD","value":"email.secret.password"},{"idObject":13,"type":"EMAIL_IMAP_SERVER","value":"your.imap.domain.com"},{"idObject":12,"type":"EMAIL_SMTP_SERVER","value":"your.smtp.domain.com"},{"idObject":14,"type":"EMAIL_SMTP_PORT","value":"25"},{"idObject":6,"type":"DEFAULT_MAP","value":"sample"},{"idObject":4,"type":"LOGO_IMG","value":"udl.png"},{"idObject":3,"type":"LOGO_LINK","value":"http://wwwen.uni.lu/"},{"idObject":7,"type":"SEARCH_DISTANCE","value":"10"},{"idObject":1,"type":"REQUEST_ACCOUNT_EMAIL","value":"your.email@domain.com"},{"idObject":8,"type":"SEARCH_RESULT_NUMBER","value":"100"},{"idObject":2,"type":"GOOGLE_ANALYTICS_IDENTIFIER","value":""},{"idObject":5,"type":"LOGO_TEXT","value":"University of Luxembourg"},{"idObject":56,"type":"X_FRAME_DOMAIN","value":"http://localhost:8080/"},{"idObject":131,"type":"BIG_FILE_STORAGE_DIR","value":"minerva-big/"},{"idObject":138,"type":"LEGEND_FILE_1","value":"resources/images/legend_a.png"},{"idObject":139,"type":"LEGEND_FILE_2","value":"resources/images/legend_b.png"},{"idObject":140,"type":"LEGEND_FILE_3","value":"resources/images/legend_c.png"},{"idObject":141,"type":"LEGEND_FILE_4","value":"resources/images/legend_d.png"},{"idObject":142,"type":"USER_MANUAL_FILE","value":"resources/other/user_guide.pdf"},{"idObject":205,"type":"MIN_COLOR_VAL","value":"FF0000"},{"idObject":206,"type":"MAX_COLOR_VAL","value":"fbff00"},{"idObject":218,"type":"SIMPLE_COLOR_VAL","value":"00FF00"}],"privilegeTypes":{"VIEW_PROJECT":{"commonName":"View project","valueType":"boolean","objectType":"Project"},"LAYOUT_MANAGEMENT":{"commonName":"Manage layouts","valueType":"boolean","objectType":"Project"},"PROJECT_MANAGEMENT":{"commonName":"Map management","valueType":"boolean","objectType":null},"CUSTOM_LAYOUTS":{"commonName":"Custom layouts","valueType":"int","objectType":null},"ADD_MAP":{"commonName":"Add project","valueType":"boolean","objectType":null},"LAYOUT_VIEW":{"commonName":"View layout","valueType":"boolean","objectType":"Layout"},"MANAGE_GENOMES":{"commonName":"Manage genomes","valueType":"boolean","objectType":null},"EDIT_COMMENTS_PROJECT":{"commonName":"Manage comments","valueType":"boolean","objectType":"Project"},"CONFIGURATION_MANAGE":{"commonName":"Manage configuration","valueType":"boolean","objectType":null},"USER_MANAGEMENT":{"commonName":"User management","valueType":"boolean","objectType":null}},"overlayTypes":[{"name":"GENERIC"},{"name":"GENETIC_VARIANT"}]}
\ No newline at end of file
diff --git a/frontend-js/testFiles/map/complex_model_with_overlays.zip b/frontend-js/testFiles/map/complex_model_with_overlays.zip
new file mode 100644
index 0000000000000000000000000000000000000000..0aa92bc0ab6aa5a047d64677c3520d45de75e878
GIT binary patch
literal 2216
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
Ds8myh

literal 0
HcmV?d00001

diff --git a/frontend-js/testFiles/map/complex_model_with_submaps.zip b/frontend-js/testFiles/map/complex_model_with_submaps.zip
new file mode 100644
index 0000000000000000000000000000000000000000..5985c849bbeff096451d99b43a430ec6c266cf5b
GIT binary patch
literal 8240
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

literal 0
HcmV?d00001

diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationController.java b/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationController.java
index e1ca1c0399..52d86daa0f 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationController.java
@@ -19,68 +19,71 @@ import lcsb.mapviewer.services.interfaces.IConfigurationService;
 
 @RestController
 public class ConfigurationController extends BaseController {
-	@Autowired
-	private ConfigurationRestImpl	configurationController;
+  @Autowired
+  private ConfigurationRestImpl configurationController;
 
-	@Autowired
-	private IConfigurationService	configurationService;
+  @Autowired
+  private IConfigurationService configurationService;
 
-	/**
-	 * Context used to determine deployment path.
-	 */
-	@Autowired
-	private ServletContext				context;
+  /**
+   * Context used to determine deployment path.
+   */
+  @Autowired
+  private ServletContext context;
 
-	@RequestMapping(value = "/configuration/", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
-	public Map<String, Object> getOverlayTypes(@CookieValue(value = Configuration.AUTH_TOKEN) String token) throws SecurityException {
-		Map<String, Object> result = new HashMap<>();
-		result.put("options", configurationController.getAllValues(token));
-		result.put("imageFormats", configurationController.getImageFormats(token));
-		result.put("modelFormats", configurationController.getModelFormats(token));
-		result.put("overlayTypes", configurationController.getOverlayTypes(token));
-		result.put("elementTypes", configurationController.getElementTypes(token));
-		result.put("reactionTypes", configurationController.getReactionTypes(token));
-		result.put("miriamTypes", configurationController.getMiriamTypes(token));
-		result.put("modificationStateTypes", configurationController.getModificationStateTypes(token));
-		result.put("privilegeTypes", configurationController.getPrivilegeTypes(token));
-		result.put("version", configurationService.getSystemSvnVersion(context.getRealPath("/")));
-		result.put("buildDate", configurationService.getSystemBuild(context.getRealPath("/")));
-		result.put("annotators", configurationController.getAnnotators(token));
-		return result;
-	}
+  @RequestMapping(value = "/configuration/", method = { RequestMethod.GET }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object> getOverlayTypes(@CookieValue(value = Configuration.AUTH_TOKEN) String token)
+      throws SecurityException {
+    Map<String, Object> result = new HashMap<>();
+    result.put("options", configurationController.getAllValues(token));
+    result.put("imageFormats", configurationController.getImageFormats(token));
+    result.put("modelFormats", configurationController.getModelFormats(token));
+    result.put("overlayTypes", configurationController.getOverlayTypes(token));
+    result.put("elementTypes", configurationController.getElementTypes(token));
+    result.put("reactionTypes", configurationController.getReactionTypes(token));
+    result.put("miriamTypes", configurationController.getMiriamTypes(token));
+    result.put("mapTypes", configurationController.getMapTypes(token));
+    result.put("modificationStateTypes", configurationController.getModificationStateTypes(token));
+    result.put("privilegeTypes", configurationController.getPrivilegeTypes(token));
+    result.put("version", configurationService.getSystemSvnVersion(context.getRealPath("/")));
+    result.put("buildDate", configurationService.getSystemBuild(context.getRealPath("/")));
+    result.put("annotators", configurationController.getAnnotators(token));
+    return result;
+  }
 
-	/**
-	 * @return the configurationController
-	 * @see #configurationController
-	 */
-	public ConfigurationRestImpl getConfigurationController() {
-		return configurationController;
-	}
+  /**
+   * @return the configurationController
+   * @see #configurationController
+   */
+  public ConfigurationRestImpl getConfigurationController() {
+    return configurationController;
+  }
 
-	/**
-	 * @param configurationController
-	 *          the configurationController to set
-	 * @see #configurationController
-	 */
-	public void setConfigurationController(ConfigurationRestImpl configurationController) {
-		this.configurationController = configurationController;
-	}
+  /**
+   * @param configurationController
+   *          the configurationController to set
+   * @see #configurationController
+   */
+  public void setConfigurationController(ConfigurationRestImpl configurationController) {
+    this.configurationController = configurationController;
+  }
 
-	/**
-	 * @return the configurationService
-	 * @see #configurationService
-	 */
-	public IConfigurationService getConfigurationService() {
-		return configurationService;
-	}
+  /**
+   * @return the configurationService
+   * @see #configurationService
+   */
+  public IConfigurationService getConfigurationService() {
+    return configurationService;
+  }
 
-	/**
-	 * @param configurationService
-	 *          the configurationService to set
-	 * @see #configurationService
-	 */
-	public void setConfigurationService(IConfigurationService configurationService) {
-		this.configurationService = configurationService;
-	}
+  /**
+   * @param configurationService
+   *          the configurationService to set
+   * @see #configurationService
+   */
+  public void setConfigurationService(IConfigurationService configurationService) {
+    this.configurationService = configurationService;
+  }
 
 }
\ No newline at end of file
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationRestImpl.java
index 6eb4066d9b..effd2cb87d 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationRestImpl.java
@@ -25,6 +25,8 @@ import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
 import lcsb.mapviewer.converter.model.sbgnml.SbgnmlXmlConverter;
 import lcsb.mapviewer.model.map.BioEntity;
 import lcsb.mapviewer.model.map.MiriamType;
+import lcsb.mapviewer.model.map.model.ModelSubmodelConnection;
+import lcsb.mapviewer.model.map.model.SubmodelType;
 import lcsb.mapviewer.model.map.reaction.Reaction;
 import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.model.map.species.field.ModificationState;
@@ -39,216 +41,228 @@ import lcsb.mapviewer.services.view.ConfigurationView;
 
 @Transactional(value = "txManager")
 public class ConfigurationRestImpl {
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private Logger								logger = Logger.getLogger(ConfigurationRestImpl.class);
-
-	@Autowired
-	private IUserService					userService;
-
-	@Autowired
-	private IConfigurationService	configurationService;
-
-	@Autowired
-	private ModelAnnotator				modelAnnotator;
-
-	public List<ConfigurationView> getAllValues(String token) throws SecurityException {
-		userService.getToken(token);
-		return configurationService.getAllValues();
-	}
-
-	/**
-	 * @return the userService
-	 * @see #userService
-	 */
-	public IUserService getUserService() {
-		return userService;
-	}
-
-	/**
-	 * @param userService
-	 *          the userService to set
-	 * @see #userService
-	 */
-	public void setUserService(IUserService userService) {
-		this.userService = userService;
-	}
-
-	/**
-	 * @return the configurationService
-	 * @see #configurationService
-	 */
-	public IConfigurationService getConfigurationService() {
-		return configurationService;
-	}
-
-	/**
-	 * @param configurationService
-	 *          the configurationService to set
-	 * @see #configurationService
-	 */
-	public void setConfigurationService(IConfigurationService configurationService) {
-		this.configurationService = configurationService;
-	}
-
-	public List<Map<String, Object>> getImageFormats(String token) throws SecurityException {
-		userService.getToken(token);
-
-		List<Map<String, Object>> result = new ArrayList<>();
-		ImageGenerators imageGenerators = new ImageGenerators();
-		List<Pair<String, Class<? extends AbstractImageGenerator>>> imageGeneratorList = imageGenerators.getAvailableImageGenerators();
-
-		for (Pair<String, Class<? extends AbstractImageGenerator>> element : imageGeneratorList) {
-			Map<String, Object> row = new HashMap<>();
-			row.put("name", element.getLeft());
-			row.put("handler", element.getRight().getCanonicalName());
-			row.put("extension", imageGenerators.getExtension(element.getRight()));
-			result.add(row);
-		}
-		return result;
-	}
-
-	public List<Map<String, Object>> getModelFormats(String token) throws SecurityException {
-		userService.getToken(token);
-		List<IConverter> converters = new ArrayList<>();
-		converters.add(new CellDesignerXmlParser());
-		converters.add(new SbgnmlXmlConverter());
-
-		List<Map<String, Object>> result = new ArrayList<>();
-
-		for (IConverter converter : converters) {
-			Map<String, Object> row = new HashMap<>();
-			row.put("name", converter.getCommonName());
-			row.put("handler", converter.getClass().getCanonicalName());
-			row.put("extension", converter.getFileExtension());
-			result.add(row);
-		}
-		return result;
-	}
-
-	public List<Map<String, Object>> getOverlayTypes(String token) throws SecurityException {
-		userService.getToken(token);
-		List<Map<String, Object>> result = new ArrayList<>();
-		for (ColorSchemaType type : ColorSchemaType.values()) {
-			Map<String, Object> map = new HashMap<>();
-			map.put("name", type.name());
-			result.add(map);
-		}
-		return result;
-	}
-
-	public Set<Map<String, String>> getElementTypes(String token) throws SecurityException {
-		userService.getToken(token);
-
-		return getClassStringTypesList(Element.class);
-	}
-
-	private Set<Map<String, String>> getClassStringTypesList(Class<?> elementClass) {
-		Set<Map<String, String>> result = new HashSet<>();
-		ElementUtils elementUtils = new ElementUtils();
-		ClassTreeNode top = elementUtils.getAnnotatedElementClassTree();
-		Queue<ClassTreeNode> queue = new LinkedList<>();
-		queue.add(top);
-		while (!queue.isEmpty()) {
-			ClassTreeNode clazz = queue.poll();
-			for (ClassTreeNode child : clazz.getChildren()) {
-				queue.add(child);
-			}
-			if (elementClass.isAssignableFrom(clazz.getClazz())) {
-				Map<String, String> row = new HashMap<>();
-				row.put("className", clazz.getClazz().getName());
-				row.put("name", clazz.getCommonName());
-				if (clazz.getParent() == null) {
-					row.put("parentClass", null);
-				} else {
-					row.put("parentClass", clazz.getParent().getClazz().getName());
-				}
-				result.add(row);
-			}
-		}
-		return result;
-	}
-
-	public Set<Map<String, String>> getReactionTypes(String token) throws SecurityException {
-		userService.getToken(token);
-
-		return getClassStringTypesList(Reaction.class);
-	}
-
-	public Map<String, Object> getMiriamTypes(String id) {
-		Map<String, Object> result = new HashMap<>();
-		for (MiriamType type : MiriamType.values()) {
-			result.put(type.name(), createMiriamTypeResponse(type));
-		}
-		return result;
-	}
-
-	private Map<String, Object> createMiriamTypeResponse(MiriamType type) {
-		Map<String, Object> result = new HashMap<>();
-		result.put("commonName", type.getCommonName());
-		result.put("homepage", type.getDbHomepage());
-		result.put("registryIdentifier", type.getRegistryIdentifier());
-		result.put("uris", type.getUris());
-
-		return result;
-	}
-
-	public Object getModificationStateTypes(String token) {
-		Map<String, Object> result = new HashMap<>();
-		for (ModificationState type : ModificationState.values()) {
-			result.put(type.name(), createModificationStateResponse(type));
-		}
-		return result;
-	}
-
-	private Map<String, Object> createModificationStateResponse(ModificationState type) {
-		Map<String, Object> result = new HashMap<>();
-		result.put("commonName", type.getFullName());
-		result.put("abbreviation", type.getAbbreviation());
-		return result;
-	}
-
-	public Map<String, Object> getPrivilegeTypes(String id) {
-		Map<String, Object> result = new HashMap<>();
-		for (PrivilegeType type : PrivilegeType.values()) {
-			result.put(type.name(), createPrivilegeTypeResponse(type));
-		}
-		return result;
-	}
-
-	private Map<String, Object> createPrivilegeTypeResponse(PrivilegeType type) {
-		Map<String, Object> result = new HashMap<>();
-		result.put("commonName", type.getCommonName());
-		if (type.getPrivilegeObjectType() != null) {
-			result.put("objectType", type.getPrivilegeObjectType().getSimpleName());
-		} else {
-			result.put("objectType", null);
-		}
-		if (type.isNumeric()) {
-			result.put("valueType", "int");
-		} else {
-			result.put("valueType", "boolean");
-		}
-		return result;
-	}
-
-	public List<Map<String, Object>> getAnnotators(String token) {
-		List<Map<String, Object>> result = new ArrayList<>();
-		for (ElementAnnotator annotator : modelAnnotator.getAvailableAnnotators()) {
-			result.add(prepareAnnotator(annotator));
-		}
-		return result;
-	}
-
-	private Map<String, Object> prepareAnnotator(ElementAnnotator annotator) {
-		Map<String, Object> result = new HashMap<>();
-		result.put("className", annotator.getClass().getName());
-		result.put("name", annotator.getCommonName());
-		result.put("url", annotator.getUrl());
-		result.put("elementClassNames", annotator.getValidClasses());
-		return result;
-	}
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private Logger logger = Logger.getLogger(ConfigurationRestImpl.class);
+
+  @Autowired
+  private IUserService userService;
+
+  @Autowired
+  private IConfigurationService configurationService;
+
+  @Autowired
+  private ModelAnnotator modelAnnotator;
+
+  public List<ConfigurationView> getAllValues(String token) throws SecurityException {
+    userService.getToken(token);
+    return configurationService.getAllValues();
+  }
+
+  /**
+   * @return the userService
+   * @see #userService
+   */
+  public IUserService getUserService() {
+    return userService;
+  }
+
+  /**
+   * @param userService
+   *          the userService to set
+   * @see #userService
+   */
+  public void setUserService(IUserService userService) {
+    this.userService = userService;
+  }
+
+  /**
+   * @return the configurationService
+   * @see #configurationService
+   */
+  public IConfigurationService getConfigurationService() {
+    return configurationService;
+  }
+
+  /**
+   * @param configurationService
+   *          the configurationService to set
+   * @see #configurationService
+   */
+  public void setConfigurationService(IConfigurationService configurationService) {
+    this.configurationService = configurationService;
+  }
+
+  public List<Map<String, Object>> getImageFormats(String token) throws SecurityException {
+    userService.getToken(token);
+
+    List<Map<String, Object>> result = new ArrayList<>();
+    ImageGenerators imageGenerators = new ImageGenerators();
+    List<Pair<String, Class<? extends AbstractImageGenerator>>> imageGeneratorList = imageGenerators
+        .getAvailableImageGenerators();
+
+    for (Pair<String, Class<? extends AbstractImageGenerator>> element : imageGeneratorList) {
+      Map<String, Object> row = new HashMap<>();
+      row.put("name", element.getLeft());
+      row.put("handler", element.getRight().getCanonicalName());
+      row.put("extension", imageGenerators.getExtension(element.getRight()));
+      result.add(row);
+    }
+    return result;
+  }
+
+  public List<Map<String, Object>> getModelFormats(String token) throws SecurityException {
+    userService.getToken(token);
+    List<IConverter> converters = new ArrayList<>();
+    converters.add(new CellDesignerXmlParser());
+    converters.add(new SbgnmlXmlConverter());
+
+    List<Map<String, Object>> result = new ArrayList<>();
+
+    for (IConverter converter : converters) {
+      Map<String, Object> row = new HashMap<>();
+      row.put("name", converter.getCommonName());
+      row.put("handler", converter.getClass().getCanonicalName());
+      row.put("extension", converter.getFileExtension());
+      result.add(row);
+    }
+    return result;
+  }
+
+  public List<Map<String, Object>> getOverlayTypes(String token) throws SecurityException {
+    userService.getToken(token);
+    List<Map<String, Object>> result = new ArrayList<>();
+    for (ColorSchemaType type : ColorSchemaType.values()) {
+      Map<String, Object> map = new HashMap<>();
+      map.put("name", type.name());
+      result.add(map);
+    }
+    return result;
+  }
+
+  public Set<Map<String, String>> getElementTypes(String token) throws SecurityException {
+    userService.getToken(token);
+
+    return getClassStringTypesList(Element.class);
+  }
+
+  private Set<Map<String, String>> getClassStringTypesList(Class<?> elementClass) {
+    Set<Map<String, String>> result = new HashSet<>();
+    ElementUtils elementUtils = new ElementUtils();
+    ClassTreeNode top = elementUtils.getAnnotatedElementClassTree();
+    Queue<ClassTreeNode> queue = new LinkedList<>();
+    queue.add(top);
+    while (!queue.isEmpty()) {
+      ClassTreeNode clazz = queue.poll();
+      for (ClassTreeNode child : clazz.getChildren()) {
+        queue.add(child);
+      }
+      if (elementClass.isAssignableFrom(clazz.getClazz())) {
+        Map<String, String> row = new HashMap<>();
+        row.put("className", clazz.getClazz().getName());
+        row.put("name", clazz.getCommonName());
+        if (clazz.getParent() == null) {
+          row.put("parentClass", null);
+        } else {
+          row.put("parentClass", clazz.getParent().getClazz().getName());
+        }
+        result.add(row);
+      }
+    }
+    return result;
+  }
+
+  public Set<Map<String, String>> getReactionTypes(String token) throws SecurityException {
+    userService.getToken(token);
+
+    return getClassStringTypesList(Reaction.class);
+  }
+
+  public Map<String, Object> getMiriamTypes(String id) {
+    Map<String, Object> result = new HashMap<>();
+    for (MiriamType type : MiriamType.values()) {
+      result.put(type.name(), createMiriamTypeResponse(type));
+    }
+    return result;
+  }
+
+  private Map<String, Object> createMiriamTypeResponse(MiriamType type) {
+    Map<String, Object> result = new HashMap<>();
+    result.put("commonName", type.getCommonName());
+    result.put("homepage", type.getDbHomepage());
+    result.put("registryIdentifier", type.getRegistryIdentifier());
+    result.put("uris", type.getUris());
+
+    return result;
+  }
+
+  public Object getModificationStateTypes(String token) {
+    Map<String, Object> result = new HashMap<>();
+    for (ModificationState type : ModificationState.values()) {
+      result.put(type.name(), createModificationStateResponse(type));
+    }
+    return result;
+  }
+
+  private Map<String, Object> createModificationStateResponse(ModificationState type) {
+    Map<String, Object> result = new HashMap<>();
+    result.put("commonName", type.getFullName());
+    result.put("abbreviation", type.getAbbreviation());
+    return result;
+  }
+
+  public Map<String, Object> getPrivilegeTypes(String id) {
+    Map<String, Object> result = new HashMap<>();
+    for (PrivilegeType type : PrivilegeType.values()) {
+      result.put(type.name(), createPrivilegeTypeResponse(type));
+    }
+    return result;
+  }
+
+  private Map<String, Object> createPrivilegeTypeResponse(PrivilegeType type) {
+    Map<String, Object> result = new HashMap<>();
+    result.put("commonName", type.getCommonName());
+    if (type.getPrivilegeObjectType() != null) {
+      result.put("objectType", type.getPrivilegeObjectType().getSimpleName());
+    } else {
+      result.put("objectType", null);
+    }
+    if (type.isNumeric()) {
+      result.put("valueType", "int");
+    } else {
+      result.put("valueType", "boolean");
+    }
+    return result;
+  }
+
+  public List<Map<String, Object>> getAnnotators(String token) {
+    List<Map<String, Object>> result = new ArrayList<>();
+    for (ElementAnnotator annotator : modelAnnotator.getAvailableAnnotators()) {
+      result.add(prepareAnnotator(annotator));
+    }
+    return result;
+  }
+
+  private Map<String, Object> prepareAnnotator(ElementAnnotator annotator) {
+    Map<String, Object> result = new HashMap<>();
+    result.put("className", annotator.getClass().getName());
+    result.put("name", annotator.getCommonName());
+    result.put("url", annotator.getUrl());
+    result.put("elementClassNames", annotator.getValidClasses());
+    return result;
+  }
+
+  public List<Map<String, Object>> getMapTypes(String token) {
+    List<Map<String, Object>> result = new ArrayList<>();
+    for (SubmodelType type : SubmodelType.values()) {
+      Map<String, Object> row = new HashMap<>();
+      row.put("id", type.name());
+      row.put("name", type.getCommonName());
+      result.add(row);
+    }
+    return result;
+  }
 
 }
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java
index 793084e98a..3c2db6e9d4 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectController.java
@@ -33,141 +33,152 @@ import lcsb.mapviewer.services.SecurityException;
 
 @RestController
 public class ProjectController extends BaseController {
-	private Logger					logger = Logger.getLogger(ProjectController.class);
-
-	@Autowired
-	private ServletContext	context;
-
-	@Autowired
-	private ProjectRestImpl	projectController;
-
-	@RequestMapping(value = "/projects/{projectId:.+}", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
-	public ProjectMetaData getProject(//
-			@PathVariable(value = "projectId") String projectId, //
-			@CookieValue(value = Configuration.AUTH_TOKEN) String token //
-	) throws SecurityException, ObjectNotFoundException {
-		return projectController.getProject(projectId, token);
-	}
-
-	@RequestMapping(value = "/projects/{projectId:.+}", method = { RequestMethod.PATCH }, produces = { MediaType.APPLICATION_JSON_VALUE })
-	public ProjectMetaData updateProject(//
-			@RequestBody String body, //
-			@PathVariable(value = "projectId") String projectId, //
-			@CookieValue(value = Configuration.AUTH_TOKEN) String token //
-	) throws SecurityException, IOException, QueryException {
-		Map<String, Object> node = parseBody(body);
-		Map<String, Object> data = getData(node, "project");
-		return projectController.updateProject(token, projectId, data);
-
-	}
-
-	@RequestMapping(value = "/projects/{projectId:.+}", method = { RequestMethod.POST }, produces = { MediaType.APPLICATION_JSON_VALUE })
-	public ProjectMetaData addProject(//
-			@RequestBody MultiValueMap<String,String> formData, //
-			@PathVariable(value = "projectId") String projectId, //
-			@CookieValue(value = Configuration.AUTH_TOKEN) String token //
-	) throws SecurityException, IOException, QueryException {
-		return projectController.addProject(token, projectId, formData, context.getRealPath("/"));
-
-	}
-
-	@RequestMapping(value = "/projects/{projectId:.+}", method = { RequestMethod.DELETE }, produces = { MediaType.APPLICATION_JSON_VALUE })
-	public ProjectMetaData removeProject(//
-			@PathVariable(value = "projectId") String projectId, //
-			@CookieValue(value = Configuration.AUTH_TOKEN) String token //
-	) throws SecurityException, IOException, QueryException {
-		return projectController.removeProject(token, projectId, context.getRealPath("/"));
-
-	}
-
-	@RequestMapping(value = "/projects/", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
-	public List<ProjectMetaData> getProjects(//
-			@CookieValue(value = Configuration.AUTH_TOKEN) String token //
-	) throws SecurityException, ObjectNotFoundException {
-		return projectController.getProjects(token);
-	}
-
-	@RequestMapping(value = "/projects/{projectId}/statistics", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
-	public Object getStatistics(//
-			@PathVariable(value = "projectId") String projectId, //
-			@CookieValue(value = Configuration.AUTH_TOKEN) String token //
-	) throws SecurityException, ObjectNotFoundException {
-		return projectController.getStatistics(projectId, token);
-	}
-
-	@RequestMapping(value = "/projects/{projectId}:downloadSource", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
-	public ResponseEntity<byte[]> getProjectSource(//
-			@CookieValue(value = Configuration.AUTH_TOKEN) String token, //
-			@PathVariable(value = "projectId") String projectId //
-	) throws SecurityException, QueryException {
-
-		FileEntry file = projectController.getSource(token, projectId);
-		MediaType type = MediaType.TEXT_PLAIN;
-		if (file.getOriginalFileName().endsWith("xml")) {
-			type = MediaType.APPLICATION_XML;
-		} else if (file.getOriginalFileName().endsWith("zip")) {
-			type = MediaType.APPLICATION_OCTET_STREAM;
-		}
-		return ResponseEntity
-				.ok().contentLength(file.getFileContent().length).contentType(type).header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName())
-				.body(file.getFileContent());
-	}
-
-	@RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadImage", method = { RequestMethod.GET },
-			produces = { MediaType.APPLICATION_JSON_VALUE })
-	public ResponseEntity<byte[]> getModelAsImage(//
-			@CookieValue(value = Configuration.AUTH_TOKEN) String token, //
-			@PathVariable(value = "projectId") String projectId, //
-			@PathVariable(value = "modelId") String modelId, //
-			@RequestParam(value = "handlerClass") String handlerClass, //
-			@RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, //
-			@RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, //
-			@RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, //
-			@RequestParam(value = "polygonString", defaultValue = "") String polygonString//
-	) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, DrawingException {
-
-		FileEntry file = projectController.getModelAsImage(token, projectId, modelId, handlerClass, backgroundOverlayId, overlayIds, zoomLevel, polygonString);
-		MediaType type = MediaType.APPLICATION_OCTET_STREAM;
-		return ResponseEntity
-				.ok().contentLength(file.getFileContent().length).contentType(type).header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName())
-				.body(file.getFileContent());
-	}
-
-	@RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadModel", method = { RequestMethod.GET },
-			produces = { MediaType.APPLICATION_JSON_VALUE })
-	public ResponseEntity<byte[]> getModelAsModelFile(//
-			@CookieValue(value = Configuration.AUTH_TOKEN) String token, //
-			@PathVariable(value = "projectId") String projectId, //
-			@PathVariable(value = "modelId") String modelId, //
-			@RequestParam(value = "handlerClass") String handlerClass, //
-			@RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, //
-			@RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, //
-			@RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, //
-			@RequestParam(value = "polygonString", defaultValue = "") String polygonString//
-	) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException, ConverterException,
-			InconsistentModelException {
-
-		FileEntry file = projectController.getModelAsModelFile(token, projectId, modelId, handlerClass, backgroundOverlayId, overlayIds, zoomLevel, polygonString);
-		MediaType type = MediaType.APPLICATION_OCTET_STREAM;
-		return ResponseEntity
-				.ok().contentLength(file.getFileContent().length).contentType(type).header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName())
-				.body(file.getFileContent());
-	}
-
-	/**
-	 * @return the context
-	 * @see #context
-	 */
-	public ServletContext getContext() {
-		return context;
-	}
-
-	/**
-	 * @param context the context to set
-	 * @see #context
-	 */
-	public void setContext(ServletContext context) {
-		this.context = context;
-	}
+  @SuppressWarnings("unused")
+  private Logger logger = Logger.getLogger(ProjectController.class);
+
+  @Autowired
+  private ServletContext context;
+
+  @Autowired
+  private ProjectRestImpl projectController;
+
+  @RequestMapping(value = "/projects/{projectId:.+}", method = { RequestMethod.GET }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public ProjectMetaData getProject(//
+      @PathVariable(value = "projectId") String projectId, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, ObjectNotFoundException {
+    return projectController.getProject(projectId, token);
+  }
+
+  @RequestMapping(value = "/projects/{projectId:.+}", method = { RequestMethod.PATCH }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public ProjectMetaData updateProject(//
+      @RequestBody String body, //
+      @PathVariable(value = "projectId") String projectId, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, IOException, QueryException {
+    Map<String, Object> node = parseBody(body);
+    Map<String, Object> data = getData(node, "project");
+    return projectController.updateProject(token, projectId, data);
+
+  }
+
+  @RequestMapping(value = "/projects/{projectId:.+}", method = { RequestMethod.POST }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public ProjectMetaData addProject(//
+      @RequestBody MultiValueMap<String, Object> formData, //
+      @PathVariable(value = "projectId") String projectId, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, IOException, QueryException {
+    return projectController.addProject(token, projectId, formData, context.getRealPath("/"));
+
+  }
+
+  @RequestMapping(value = "/projects/{projectId:.+}", method = { RequestMethod.DELETE }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public ProjectMetaData removeProject(//
+      @PathVariable(value = "projectId") String projectId, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, IOException, QueryException {
+    return projectController.removeProject(token, projectId, context.getRealPath("/"));
+
+  }
+
+  @RequestMapping(value = "/projects/", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public List<ProjectMetaData> getProjects(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, ObjectNotFoundException {
+    return projectController.getProjects(token);
+  }
+
+  @RequestMapping(value = "/projects/{projectId}/statistics", method = { RequestMethod.GET }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public Object getStatistics(//
+      @PathVariable(value = "projectId") String projectId, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, ObjectNotFoundException {
+    return projectController.getStatistics(projectId, token);
+  }
+
+  @RequestMapping(value = "/projects/{projectId}:downloadSource", method = { RequestMethod.GET }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public ResponseEntity<byte[]> getProjectSource(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "projectId") String projectId //
+  ) throws SecurityException, QueryException {
+
+    FileEntry file = projectController.getSource(token, projectId);
+    MediaType type = MediaType.TEXT_PLAIN;
+    if (file.getOriginalFileName().endsWith("xml")) {
+      type = MediaType.APPLICATION_XML;
+    } else if (file.getOriginalFileName().endsWith("zip")) {
+      type = MediaType.APPLICATION_OCTET_STREAM;
+    }
+    return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type)
+        .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName())
+        .body(file.getFileContent());
+  }
+
+  @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadImage", method = {
+      RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public ResponseEntity<byte[]> getModelAsImage(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "projectId") String projectId, //
+      @PathVariable(value = "modelId") String modelId, //
+      @RequestParam(value = "handlerClass") String handlerClass, //
+      @RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, //
+      @RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, //
+      @RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, //
+      @RequestParam(value = "polygonString", defaultValue = "") String polygonString//
+  ) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException,
+      DrawingException {
+
+    FileEntry file = projectController.getModelAsImage(token, projectId, modelId, handlerClass, backgroundOverlayId,
+        overlayIds, zoomLevel, polygonString);
+    MediaType type = MediaType.APPLICATION_OCTET_STREAM;
+    return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type)
+        .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName())
+        .body(file.getFileContent());
+  }
+
+  @RequestMapping(value = "/projects/{projectId}/models/{modelId}:downloadModel", method = {
+      RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public ResponseEntity<byte[]> getModelAsModelFile(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "projectId") String projectId, //
+      @PathVariable(value = "modelId") String modelId, //
+      @RequestParam(value = "handlerClass") String handlerClass, //
+      @RequestParam(value = "backgroundOverlayId", defaultValue = "") String backgroundOverlayId, //
+      @RequestParam(value = "overlayIds", defaultValue = "") String overlayIds, //
+      @RequestParam(value = "zoomLevel", defaultValue = "") String zoomLevel, //
+      @RequestParam(value = "polygonString", defaultValue = "") String polygonString//
+  ) throws SecurityException, QueryException, IOException, InvalidColorSchemaException, CommandExecutionException,
+      ConverterException, InconsistentModelException {
+
+    FileEntry file = projectController.getModelAsModelFile(token, projectId, modelId, handlerClass, backgroundOverlayId,
+        overlayIds, zoomLevel, polygonString);
+    MediaType type = MediaType.APPLICATION_OCTET_STREAM;
+    return ResponseEntity.ok().contentLength(file.getFileContent().length).contentType(type)
+        .header("Content-Disposition", "attachment; filename=" + file.getOriginalFileName())
+        .body(file.getFileContent());
+  }
+
+  /**
+   * @return the context
+   * @see #context
+   */
+  public ServletContext getContext() {
+    return context;
+  }
+
+  /**
+   * @param context
+   *          the context to set
+   * @see #context
+   */
+  public void setContext(ServletContext context) {
+    this.context = context;
+  }
 
 }
\ No newline at end of file
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
index b788a8feb8..6a50de4c1f 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/ProjectRestImpl.java
@@ -38,9 +38,14 @@ import lcsb.mapviewer.commands.SetFixedHierarchyLevelCommand;
 import lcsb.mapviewer.commands.SubModelCommand;
 import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.common.exception.NotImplementedException;
 import lcsb.mapviewer.converter.ConverterException;
 import lcsb.mapviewer.converter.IConverter;
 import lcsb.mapviewer.converter.graphics.AbstractImageGenerator.Params;
+import lcsb.mapviewer.converter.zip.ImageZipEntryFile;
+import lcsb.mapviewer.converter.zip.LayoutZipEntryFile;
+import lcsb.mapviewer.converter.zip.ModelZipEntryFile;
+import lcsb.mapviewer.converter.zip.ZipEntryFile;
 import lcsb.mapviewer.converter.graphics.DrawingException;
 import lcsb.mapviewer.converter.graphics.ImageGenerators;
 import lcsb.mapviewer.model.Project;
@@ -56,6 +61,7 @@ import lcsb.mapviewer.model.map.layout.ColorSchema;
 import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
 import lcsb.mapviewer.model.map.layout.Layout;
 import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.SubmodelType;
 import lcsb.mapviewer.model.map.reaction.Reaction;
 import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.model.user.PrivilegeType;
@@ -75,7 +81,7 @@ public class ProjectRestImpl extends BaseRestImpl {
 
   /**
    * Constant defining size of the array returned by
-   * {@link PathIterator#currentSegment(double[])} method. More nformation can be
+   * {@link PathIterator#currentSegment(double[])} method. More information can be
    * found <a href=
    * "http://docs.oracle.com/javase/7/docs/api/java/awt/geom/PathIterator.html#currentSegment(double[])"
    * >here</a>
@@ -473,8 +479,9 @@ public class ProjectRestImpl extends BaseRestImpl {
     }
   }
 
-  public ProjectMetaData addProject(String token, String projectId, MultiValueMap<String, String> data, String path)
+  public ProjectMetaData addProject(String token, String projectId, MultiValueMap<String, Object> data, String path)
       throws SecurityException, QueryException, IOException {
+    logger.info(data);
     AuthenticationToken authenticationToken = getUserService().getToken(token);
     User user = getUserService().getUserByToken(authenticationToken);
     Project project = getProjectService().getProjectByProjectId(projectId, authenticationToken);
@@ -493,6 +500,12 @@ public class ProjectRestImpl extends BaseRestImpl {
     }
     IConverter parser = getModelParser(parserClass);
 
+    List<ZipEntryFile> zipEntries = extractZipEntries(data);
+    params.complex(zipEntries.size() > 0);
+    for (ZipEntryFile entry : zipEntries) {
+      params.addZipEntry(entry);
+    }
+
     params.addUser(user.getLogin(), null);
     params.async(true);
     params.parser(parser);
@@ -504,7 +517,7 @@ public class ProjectRestImpl extends BaseRestImpl {
     params.notifyEmail(getFirstValue(data.get("notify-email")));
     params.projectDir(directory);
     params.projectDisease(getFirstValue(data.get("disease")));
-    params.projectFile(new ByteArrayInputStream(fileContent.getBytes(StandardCharsets.UTF_8)));
+    params.projectFile(new ByteArrayInputStream(fileContent.getBytes()));
     params.projectId(projectId);
     params.projectName(getFirstValue(data.get("name")));
     params.projectOrganism(getFirstValue(data.get("organism")));
@@ -525,12 +538,57 @@ public class ProjectRestImpl extends BaseRestImpl {
     return getProject(projectId, token);
   }
 
-  private String getFirstValue(List<String> list) {
+  protected List<ZipEntryFile> extractZipEntries(MultiValueMap<String, Object> data) {
+    int fileIndex = 0;
+    List<ZipEntryFile> result = new ArrayList<>();
+    while (data.get("zip-entries[" + fileIndex + "][_filename]") != null) {
+      ZipEntryFile entry = null;
+      String entryType = (String) data.get("zip-entries[" + fileIndex + "][_type]").get(0);
+      String filename = (String) data.get("zip-entries[" + fileIndex + "][_filename]").get(0);
+      if ("MAP".equalsIgnoreCase(entryType)) {
+        String submodelTypeKey = "zip-entries[" + fileIndex + "][_data][type][id]";
+        String rootKey = "zip-entries[" + fileIndex + "][_data][root]";
+        String mappingKey = "zip-entries[" + fileIndex + "][_data][mapping]";
+        SubmodelType mapType = SubmodelType.valueOf((String) data.get(submodelTypeKey).get(0));
+        String name = (String) data.get("zip-entries[" + fileIndex + "][_data][name]").get(0);
+        Boolean root = getBoolValue(data.get(rootKey), false);
+        Boolean mapping = getBoolValue(data.get(mappingKey), false);
+
+        entry = new ModelZipEntryFile(filename, name, root, mapping, mapType);
+      } else if ("OVERLAY".equalsIgnoreCase(entryType)) {
+        String name = (String) data.get("zip-entries[" + fileIndex + "][_data][name]").get(0);
+        String description = (String) data.get("zip-entries[" + fileIndex + "][_data][description]").get(0);
+        entry = new LayoutZipEntryFile(filename, name, description);
+      } else if ("IMAGE".equalsIgnoreCase(entryType)) {
+        entry = new ImageZipEntryFile(filename);
+      } else {
+        throw new Error("Unknown entry type: " + entryType);
+      }
+      fileIndex++;
+      result.add(entry);
+
+    }
+    return result;
+  }
+
+  private Boolean getBoolValue(List<Object> list, boolean defaultValue) {
+    if (list == null) {
+      return defaultValue;
+    }
+    Object obj = list.get(0);
+    if (obj instanceof Boolean) {
+      return (Boolean) list.get(0);
+    } else {
+      return "true".equalsIgnoreCase((String) obj);
+    }
+  }
+
+  private String getFirstValue(List<Object> list) {
     if (list == null) {
       return null;
     }
     if (list.size() > 0) {
-      return list.get(0);
+      return (String) list.get(0);
     }
     return null;
   }
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java
index 97482c2216..f7bfb87b87 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/projects/ProjectRestImplTest.java
@@ -2,6 +2,7 @@ package lcsb.mapviewer.api.projects;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
@@ -9,6 +10,7 @@ import static org.mockito.Mockito.times;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -19,6 +21,8 @@ import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
 
 import com.google.gson.Gson;
 
@@ -28,6 +32,10 @@ import lcsb.mapviewer.api.RestTestFunctions;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.converter.graphics.PdfImageGenerator;
 import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
+import lcsb.mapviewer.converter.zip.ImageZipEntryFile;
+import lcsb.mapviewer.converter.zip.LayoutZipEntryFile;
+import lcsb.mapviewer.converter.zip.ModelZipEntryFile;
+import lcsb.mapviewer.converter.zip.ZipEntryFile;
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.cache.FileEntry;
 import lcsb.mapviewer.model.map.MiriamType;
@@ -36,222 +44,260 @@ import lcsb.mapviewer.services.interfaces.IModelService;
 import lcsb.mapviewer.services.interfaces.IProjectService;
 
 public class ProjectRestImplTest extends RestTestFunctions {
-	Logger					logger = Logger.getLogger(ProjectRestImplTest.class);
-
-	@Autowired
-	ProjectRestImpl	_projectRestImpl;
-
-	@Autowired
-	IModelService		modelService;
-
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testGetModelAsImageForInvalidConverter() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			projectRest.getModelAsImage(token.getId(), "sample", "0", "", "", "", "", "");
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetModelAsImage() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			FileEntry result = projectRest.getModelAsImage(token.getId(), "sample", "0", PdfImageGenerator.class.getCanonicalName(), "", "", "", "");
-			assertNotNull(result);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetModelDataDependencies() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			ProjectMetaData result = projectRest.getProject("sample", token.getId());
-			Gson gson = new Gson();
-			assertNotNull(gson.toJson(result));
-			Mockito.verify(projectRest.getModelService(), times(0)).getLastModelByProjectId(anyString(), any());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test(expected = ObjectNotFoundException.class)
-	public void testGetInvalidMetaData() throws Exception {
-		ProjectRestImpl projectRest = createMockProjectRest(null);
-		projectRest.getProject("unknown_model_id", token.getId());
-	}
-
-	@Test
-	public void testGetModelAsImage2() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			projectRest.getModelAsImage(token.getId(), "sample", "0", PdfImageGenerator.class.getCanonicalName(), "", "", "", "");
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetModelAsFileModel() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			projectRest.getModelAsModelFile(token.getId(), "sample", "0", "", "", "", "", "");
-			fail("Exception expected");
-		} catch (QueryException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetModelAsFileModel2() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			projectRest.getModelAsModelFile(token.getId(), "sample", "0", CellDesignerXmlParser.class.getCanonicalName(), "", "", "", "0,0;90,0;90,90;90,0");
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetModelAsFileModel3() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			projectRest.getModelAsModelFile(token.getId(), "sample", "0", "", "", "", "", "0,0;90,0;90,90;90,0");
-			fail("Exception expected");
-		} catch (QueryException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetProject() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			ProjectMetaData result = projectRest.getProject("sample", token.getId());
-			Gson gson = new Gson();
-			assertNotNull(gson.toJson(result));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdateProject() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			Map<String,String> disease = new HashMap<>();
-			disease.put("type",MiriamType.MESH_2012.name());
-			disease.put("resource", "D010300");
-			Map<String, Object> data = new HashMap<>();
-			data.put("version", "1");
-			data.put("name", "test");
-			data.put("organism", null);
-			data.put("disease", disease);
-			data.put("projectId", "sample");
-			data.put("id", "0");
-			projectRest.updateProject(adminToken.getId(), "sample", data);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetProjects() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			List<ProjectMetaData> result = projectRest.getProjects(token.getId());
-			Gson gson = new Gson();
-			assertNotNull(gson.toJson(result));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetStatistics() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
-			Map<String, Object> result = projectRest.getStatistics("sample", token.getId());
-			Gson gson = new Gson();
-			assertNotNull(gson.toJson(result));
-
-			Map<?, ?> elementAnnotations = (Map<?, ?>) result.get("elementAnnotations");
-			assertEquals(elementAnnotations.get(MiriamType.CAS), 0);
-			assertEquals(elementAnnotations.get(MiriamType.ENTREZ), 1);
-
-			Map<?, ?> reactionAnnotations = (Map<?, ?>) result.get("reactionAnnotations");
-			assertEquals(reactionAnnotations.get(MiriamType.ENTREZ), 0);
-			assertEquals(reactionAnnotations.get(MiriamType.PUBMED), 1);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetMetaDataForComplexWithImages() throws Exception {
-		try {
-			ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/complex_model_with_submaps.zip");
-			ProjectMetaData result = projectRest.getProject("sample", token.getId());
-			Gson gson = new Gson();
-			assertNotNull(gson.toJson(result));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	private ProjectRestImpl createMockProjectRest(String string) throws Exception {
-		Model model = null;
-		Project project = null;
-		if (string != null) {
-			project = new Project();
-			model = super.getModelForFile(string, true);
-			project.addModel(model);
-			project.setProjectId(model.getName());
-		}
-		IModelService mockModelService = Mockito.mock(IModelService.class);
-		Mockito.when(mockModelService.getLastModelByProjectId(anyString(), any())).thenReturn(model);
-		_projectRestImpl.setModelService(mockModelService);
-
-		IProjectService projectServiceMock = Mockito.mock(IProjectService.class);
-		Mockito.when(projectServiceMock.getProjectByProjectId(anyString(), any())).thenReturn(project);
-		List<Project> projects = new ArrayList<>();
-		projects.add(project);
-		Mockito.when(projectServiceMock.getAllProjects(any())).thenReturn(projects);
-		_projectRestImpl.setProjectService(projectServiceMock);
-
-		return _projectRestImpl;
-	}
+  Logger logger = Logger.getLogger(ProjectRestImplTest.class);
+
+  @Autowired
+  ProjectRestImpl _projectRestImpl;
+
+  @Autowired
+  IModelService modelService;
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+  }
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testGetModelAsImageForInvalidConverter() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      projectRest.getModelAsImage(token.getId(), "sample", "0", "", "", "", "", "");
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetModelAsImage() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      FileEntry result = projectRest.getModelAsImage(token.getId(), "sample", "0",
+          PdfImageGenerator.class.getCanonicalName(), "", "", "", "");
+      assertNotNull(result);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetModelDataDependencies() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      ProjectMetaData result = projectRest.getProject("sample", token.getId());
+      Gson gson = new Gson();
+      assertNotNull(gson.toJson(result));
+      Mockito.verify(projectRest.getModelService(), times(0)).getLastModelByProjectId(anyString(), any());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test(expected = ObjectNotFoundException.class)
+  public void testGetInvalidMetaData() throws Exception {
+    ProjectRestImpl projectRest = createMockProjectRest(null);
+    projectRest.getProject("unknown_model_id", token.getId());
+  }
+
+  @Test
+  public void testGetModelAsImage2() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      projectRest.getModelAsImage(token.getId(), "sample", "0", PdfImageGenerator.class.getCanonicalName(), "", "", "",
+          "");
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetModelAsFileModel() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      projectRest.getModelAsModelFile(token.getId(), "sample", "0", "", "", "", "", "");
+      fail("Exception expected");
+    } catch (QueryException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetModelAsFileModel2() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      projectRest.getModelAsModelFile(token.getId(), "sample", "0", CellDesignerXmlParser.class.getCanonicalName(), "",
+          "", "", "0,0;90,0;90,90;90,0");
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetModelAsFileModel3() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      projectRest.getModelAsModelFile(token.getId(), "sample", "0", "", "", "", "", "0,0;90,0;90,90;90,0");
+      fail("Exception expected");
+    } catch (QueryException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetProject() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      ProjectMetaData result = projectRest.getProject("sample", token.getId());
+      Gson gson = new Gson();
+      assertNotNull(gson.toJson(result));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testUpdateProject() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      Map<String, String> disease = new HashMap<>();
+      disease.put("type", MiriamType.MESH_2012.name());
+      disease.put("resource", "D010300");
+      Map<String, Object> data = new HashMap<>();
+      data.put("version", "1");
+      data.put("name", "test");
+      data.put("organism", null);
+      data.put("disease", disease);
+      data.put("projectId", "sample");
+      data.put("id", "0");
+      projectRest.updateProject(adminToken.getId(), "sample", data);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetProjects() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      List<ProjectMetaData> result = projectRest.getProjects(token.getId());
+      Gson gson = new Gson();
+      assertNotNull(gson.toJson(result));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetStatistics() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/sample.xml");
+      Map<String, Object> result = projectRest.getStatistics("sample", token.getId());
+      Gson gson = new Gson();
+      assertNotNull(gson.toJson(result));
+
+      Map<?, ?> elementAnnotations = (Map<?, ?>) result.get("elementAnnotations");
+      assertEquals(elementAnnotations.get(MiriamType.CAS), 0);
+      assertEquals(elementAnnotations.get(MiriamType.ENTREZ), 1);
+
+      Map<?, ?> reactionAnnotations = (Map<?, ?>) result.get("reactionAnnotations");
+      assertEquals(reactionAnnotations.get(MiriamType.ENTREZ), 0);
+      assertEquals(reactionAnnotations.get(MiriamType.PUBMED), 1);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetMetaDataForComplexWithImages() throws Exception {
+    try {
+      ProjectRestImpl projectRest = createMockProjectRest("testFiles/model/complex_model_with_submaps.zip");
+      ProjectMetaData result = projectRest.getProject("sample", token.getId());
+      Gson gson = new Gson();
+      assertNotNull(gson.toJson(result));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testExtractZipEntries() throws Exception {
+    try {
+      MultiValueMap<String, Object> data = new LinkedMultiValueMap<>();
+      data.put("zip-entries[0][_type]",createLinkedList("MAP")); 
+      data.put("zip-entries[0][_filename]",createLinkedList("main.xml")); 
+      data.put("zip-entries[0][_data][root]",createLinkedList("true")); 
+      data.put("zip-entries[0][_data][name]",createLinkedList("main")); 
+      data.put("zip-entries[0][_data][type][id]",createLinkedList("UNKNOWN")); 
+      data.put("zip-entries[0][_data][type][name]",createLinkedList("Unknown")); 
+      data.put("zip-entries[1][_type]",createLinkedList("OVERLAY")); 
+      data.put("zip-entries[1][_filename]",createLinkedList("layouts/goodschema.txt")); 
+      data.put("zip-entries[1][_data][name]",createLinkedList("example name")); 
+      data.put("zip-entries[1][_data][description]",createLinkedList("layout description")); 
+      data.put("zip-entries[2][_type]",createLinkedList("IMAGE")); 
+      data.put("zip-entries[2][_filename]",createLinkedList("images/test.png")); 
+      List<ZipEntryFile> result = _projectRestImpl.extractZipEntries(data);
+      assertNotNull(result);
+      assertEquals(3, result.size());
+      assertTrue(result.get(0) instanceof ModelZipEntryFile);
+      assertTrue(result.get(1) instanceof LayoutZipEntryFile);
+      assertTrue(result.get(2) instanceof ImageZipEntryFile);
+      
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private LinkedList<Object> createLinkedList(Object string) {
+    LinkedList<Object> result = new LinkedList<>();
+    result.add(string);
+    return result;
+  }
+
+  private ProjectRestImpl createMockProjectRest(String string) throws Exception {
+    Model model = null;
+    Project project = null;
+    if (string != null) {
+      project = new Project();
+      model = super.getModelForFile(string, true);
+      project.addModel(model);
+      project.setProjectId(model.getName());
+    }
+    IModelService mockModelService = Mockito.mock(IModelService.class);
+    Mockito.when(mockModelService.getLastModelByProjectId(anyString(), any())).thenReturn(model);
+    _projectRestImpl.setModelService(mockModelService);
+
+    IProjectService projectServiceMock = Mockito.mock(IProjectService.class);
+    Mockito.when(projectServiceMock.getProjectByProjectId(anyString(), any())).thenReturn(project);
+    List<Project> projects = new ArrayList<>();
+    projects.add(project);
+    Mockito.when(projectServiceMock.getAllProjects(any())).thenReturn(projects);
+    _projectRestImpl.setProjectService(projectServiceMock);
+
+    return _projectRestImpl;
+  }
 
 }
-- 
GitLab