diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/ChemicalParser.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/ChemicalParser.java
index 4172c33e14352d92fffbcd540394c76e396246d5..ad9344e672f706de5d43a3b456c92b32d007ed60 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/ChemicalParser.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/ChemicalParser.java
@@ -401,7 +401,11 @@ public class ChemicalParser extends CachableInterface implements IExternalServic
       }
       if (result != null) {
         MeSH mesh = meshParser.getMeSH(result.getChemicalId());
+        if (mesh!=null) {
         result.addSynonyms(mesh.getSynonyms());
+        } else {
+          logger.warn("Problematic mesh id: "+result.getChemicalId());
+        }
       }
 
     } catch (IOException e) {
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/HgncAnnotator.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/HgncAnnotator.java
index a8b5d0184f95f048d3079058c796845288a244bc..18f3df2848899d4b6d2701a3c1157f7c0ecd3544 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/HgncAnnotator.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/annotators/HgncAnnotator.java
@@ -237,17 +237,17 @@ public class HgncAnnotator extends ElementAnnotator implements IExternalService
                   }
                 }
 
-							}
-						}
-					}
-				}
-            } catch (WrongResponseCodeIOException e) {
-              logger.warn(prefix + "Cannot find information for element.");
-			} catch (Exception e) {
-				throw new AnnotatorException(e);
-			}
-		}
-	}
+              }
+            }
+          }
+        }
+      } catch (WrongResponseCodeIOException e) {
+        logger.warn(prefix + "Cannot find information for element.");
+      } catch (Exception e) {
+        throw new AnnotatorException(e);
+      }
+    }
+  }
 
   /**
    * Creates query url for given {@link MiriamType#HGNC} identifier.
@@ -265,10 +265,12 @@ public class HgncAnnotator extends ElementAnnotator implements IExternalService
    *
    * @param name
    *          {@link MiriamType#HGNC_SYMBOL}
-   * @return url to restful api webpage for given hgnc symbol
+   * @return url to restful API web page for given HGNC symbol
    */
   private String getHgncNameUrl(String name) {
-    return REST_API_URL + "symbol/" + name;
+    String hgncSymbol = "" + name;
+    hgncSymbol = hgncSymbol.split("\\s+")[0];
+    return REST_API_URL + "symbol/" + hgncSymbol;
   }
 
   /**
@@ -304,34 +306,34 @@ public class HgncAnnotator extends ElementAnnotator implements IExternalService
       } else {
         Node entry = getNode("doc", resultNode.getChildNodes());
 
-				NodeList list = entry.getChildNodes();
-				for (int i = 0; i < list.getLength(); i++) {
-					Node node = list.item(i);
-					if (node.getNodeType() == Node.ELEMENT_NODE) {
-						if (node.getNodeName().equals("arr")) {
-							String type = getNodeAttr("name", node);
-							if (type.equals("uniprot_ids")) {
-								NodeList uniprotList = node.getChildNodes();
-								for (int j = 0; j < uniprotList.getLength(); j++) {
-									Node uniprotNode = uniprotList.item(j);
-									if (uniprotNode.getNodeType() == Node.ELEMENT_NODE) {
-										if (uniprotNode.getNodeName().equals("str")) {
-											result.add(createMiriamData(MiriamType.UNIPROT, uniprotNode.getTextContent()));
-										}
-									}
-								}
-							}
-						}
-					}
-				}
-			}
-			return result;
-        } catch (WrongResponseCodeIOException e) {
-          logger.warn("No HGNC data found for id: "+miriamData);
-          return new ArrayList<>();
-        } catch (Exception e) {
-			throw new AnnotatorException(e);
-		}
+        NodeList list = entry.getChildNodes();
+        for (int i = 0; i < list.getLength(); i++) {
+          Node node = list.item(i);
+          if (node.getNodeType() == Node.ELEMENT_NODE) {
+            if (node.getNodeName().equals("arr")) {
+              String type = getNodeAttr("name", node);
+              if (type.equals("uniprot_ids")) {
+                NodeList uniprotList = node.getChildNodes();
+                for (int j = 0; j < uniprotList.getLength(); j++) {
+                  Node uniprotNode = uniprotList.item(j);
+                  if (uniprotNode.getNodeType() == Node.ELEMENT_NODE) {
+                    if (uniprotNode.getNodeName().equals("str")) {
+                      result.add(createMiriamData(MiriamType.UNIPROT, uniprotNode.getTextContent()));
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      return result;
+    } catch (WrongResponseCodeIOException e) {
+      logger.warn("No HGNC data found for id: " + miriamData);
+      return new ArrayList<>();
+    } catch (Exception e) {
+      throw new AnnotatorException(e);
+    }
   }
 
   /**
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/ReferenceGenomeConnector.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/ReferenceGenomeConnector.java
index fbfb32622f483212e0043813cfd430b83fe40fa5..33d279d3158acc2d6eee1494ef039f7c8cee3e90 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/ReferenceGenomeConnector.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/ReferenceGenomeConnector.java
@@ -127,7 +127,7 @@ public interface ReferenceGenomeConnector {
 	 * @param version
 	 *          version of the reference genome
 	 * @throws IOException
-	 *           thrown when there is a problem with removeing file
+	 *           thrown when there is a problem with removing file
 	 */
 	void removeGenomeVersion(MiriamData organism, String version) throws IOException;
 
@@ -135,7 +135,7 @@ public interface ReferenceGenomeConnector {
 	 * Returns url to the file that describes reference genome.
 	 * 
 	 * @param organism
-	 *          organism of redference genome
+	 *          organism of reference genome
 	 * @param version
 	 *          version of the reference genome
 	 * @return url to the file that describes reference genome
diff --git a/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnector.java b/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnector.java
index d32370f0633f02eccd0bdb9b5a5d3920cb363318..d95d98b5c9dfe2889bb81014c9b241807a5e65d6 100644
--- a/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnector.java
+++ b/annotation/src/main/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnector.java
@@ -42,429 +42,433 @@ import lcsb.mapviewer.model.map.layout.ReferenceGenomeType;
  */
 public class UcscReferenceGenomeConnector extends AbstractReferenceGenomeConnector implements ReferenceGenomeConnector {
 
-	/**
-	 * Server domain name.
-	 */
-	private static final String	SERVER															= "hgdownload.cse.ucsc.edu";
-
-	/**
-	 * Prefix string used for marking queries in cache database that identifies
-	 * list of reference genome versions by organism id.
-	 */
-	static final String					FILENAME_BY_ORGANISM_VERSION_PREFIX	= "ORGANISM_VERSION_FILE:";
-
-	/**
-	 * Default class logger.
-	 */
-	private Logger							logger															= Logger.getLogger(UcscReferenceGenomeConnector.class);
-
-	/**
-	 * Regex pattern that helps to find out organism names in source file.
-	 */
-	private Pattern							organismNamePattern									= Pattern.compile("<!--([A-Za-z\\-\\.\\ ]+)Downloads [=]+ -->");
-
-	/**
-	 * Regex pattern that helps to find out reference genome versions.
-	 */
-	private Pattern							organismDataUrlPattern							= Pattern.compile("\\/goldenPath\\/([A-Za-z0-9\\-\\.]+)\\/bigZips\\/");
-
-	/**
-	 * Access point to taxonomy information.
-	 */
-	@Autowired
-	private TaxonomyBackend			taxonomyBackend;
-
-	/**
-	 * Default constructor.
-	 */
-	public UcscReferenceGenomeConnector() {
-		super(UcscReferenceGenomeConnector.class);
-	}
-
-	@Override
-	public List<String> getDownloadedGenomeVersions(MiriamData organism) {
-		List<String> results = new ArrayList<>();
-
-		List<ReferenceGenome> genomes = getReferenceGenomeDao().getByType(ReferenceGenomeType.UCSC);
-		for (ReferenceGenome referenceGenome : genomes) {
-			if (referenceGenome.getOrganism().equals(organism)) {
-				results.add(referenceGenome.getVersion());
-			}
-		}
-		return results;
-	}
-
-	@Override
-	public List<String> getAvailableGenomeVersion(MiriamData organism) throws ReferenceGenomeConnectorException {
-		Set<String> ids = new HashSet<>();
-		try {
-			String content = getWebPageContent("http://hgdownload.cse.ucsc.edu/downloads.html");
-			Integer start = null;
-			Integer end = content.length();
-			Matcher matcher = organismNamePattern.matcher(content);
-			while (matcher.find()) {
-				String name = matcher.group(1).trim();
-				if (start != null) {
-					end = matcher.start();
-					break;
-				}
-
-				if (name.equalsIgnoreCase("Shared Data")) {
-					continue;
-				}
-				if (name.equalsIgnoreCase("liftOver File")) {
-					continue;
-				}
-				MiriamData taxonomy = taxonomyBackend.getByName(name);
-				if (organism.equals(taxonomy)) {
-					start = matcher.end();
-				}
-			}
-			// we haven't found a start point for our organism (organism couldn't be
-			// found in the list of available organisms)
-			if (start != null) {
-				String organismContent = content.substring(start, end);
-
-				matcher = organismDataUrlPattern.matcher(organismContent);
-				while (matcher.find()) {
-					String name = matcher.group(1).trim();
-					ids.add(name);
-				}
-			}
-
-		} catch (IOException | TaxonomySearchException e) {
-			throw new ReferenceGenomeConnectorException("Problem with accessing UCSC database", e);
-		}
-		List<String> result = new ArrayList<>();
-		result.addAll(ids);
-		Collections.sort(result, new Comparator<String>() {
-			public int compare(String o1, String o2) {
-				return extractInt(o2) - extractInt(o1);
-			}
-
-		});
-		return result;
-	}
-
-	@Override
-	public List<MiriamData> getAvailableOrganisms() throws ReferenceGenomeConnectorException {
-		try {
-			List<MiriamData> result = new ArrayList<>();
-			String content = getWebPageContent("http://hgdownload.cse.ucsc.edu/downloads.html");
-
-			Matcher matcher = organismNamePattern.matcher(content);
-			while (matcher.find()) {
-				String name = matcher.group(1).trim();
-				if (name.equalsIgnoreCase("Shared Data")) {
-					continue;
-				}
-				if (name.equalsIgnoreCase("liftOver File")) {
-					continue;
-				}
-				MiriamData taxonomy = taxonomyBackend.getByName(name);
-				if (taxonomy != null) {
-					result.add(taxonomy);
-				}
-			}
-
-			return result;
-		} catch (IOException | TaxonomySearchException e) {
-			throw new ReferenceGenomeConnectorException("Problem with accessing UCSC database", e);
-		}
-	}
-
-	@Override
-	public void downloadGenomeVersion(MiriamData organism, String version, IProgressUpdater updater, boolean async)
-			throws FileNotAvailableException, IOException, ReferenceGenomeConnectorException {
-		try {
-			downloadGenomeVersion(organism, version, updater, async, getGenomeVersionFile(organism, version));
-		} catch (URISyntaxException e) {
-			throw new InvalidStateException(e);
-		}
-	}
-
-	@Override
-	public Object refreshCacheQuery(Object query) throws SourceNotAvailable {
-		String result = null;
-		try {
-			if (query instanceof String) {
-				String name = (String) query;
-				if (name.startsWith("http")) {
-					result = getWebPageContent(name);
-				} else if (name.startsWith(FILENAME_BY_ORGANISM_VERSION_PREFIX)) {
-					String[] tmp = name.substring(FILENAME_BY_ORGANISM_VERSION_PREFIX.length()).split("\n");
-					result = getGenomeVersionFile(new MiriamData(MiriamType.TAXONOMY, tmp[0]), tmp[1]);
-				} else {
-					throw new InvalidArgumentException("Don't know what to do with string \"" + query + "\"");
-				}
-			} else {
-				throw new InvalidArgumentException("Don't know what to do with class: " + query.getClass());
-			}
-		} catch (FileNotAvailableException e) {
-			throw new SourceNotAvailable("Cannot find file for the query: " + query, e);
-		} catch (IOException e) {
-			throw new SourceNotAvailable(e);
-		}
-		return result;
-	}
-
-	@Override
-	public void removeGenomeVersion(MiriamData organism, String version) throws IOException {
-		List<ReferenceGenome> genomes = getReferenceGenomeDao().getByType(ReferenceGenomeType.UCSC);
-		for (ReferenceGenome referenceGenome : genomes) {
-			if (referenceGenome.getOrganism().equals(organism) && referenceGenome.getVersion().equals(version)) {
-				// removing file from big file cache might not be the best idea here
-				if (getBigFileCache().isCached(referenceGenome.getSourceUrl())) {
-					getBigFileCache().removeFile(referenceGenome.getSourceUrl());
-				}
-				for (ReferenceGenomeGeneMapping mapping : referenceGenome.getGeneMapping()) {
-					if (getBigFileCache().isCached(mapping.getSourceUrl())) {
-						getBigFileCache().removeFile(mapping.getSourceUrl());
-					}
-				}
-				getReferenceGenomeDao().delete(referenceGenome);
-			}
-		}
-	}
-
-	/**
-	 * @return the taxonomyBackend
-	 * @see #taxonomyBackend
-	 */
-	public TaxonomyBackend getTaxonomyBackend() {
-		return taxonomyBackend;
-	}
-
-	/**
-	 * @param taxonomyBackend
-	 *          the taxonomyBackend to set
-	 * @see #taxonomyBackend
-	 */
-	public void setTaxonomyBackend(TaxonomyBackend taxonomyBackend) {
-		this.taxonomyBackend = taxonomyBackend;
-	}
-
-	/**
-	 * Task that will be able to fetch genome file from ftp server.
-	 * 
-	 * @author Piotr Gawron
-	 *
-	 */
-	private final class DownloadGenomeVersionTask implements Callable<Void> {
-
-		/**
-		 * Url to the file that we want to download.
-		 * 
-		 */
-		private String					 url;
-
-		/**
-		 * Callback listener that will receive information about upload progress.
-		 * 
-		 */
-		private IProgressUpdater updater;
-
-		/**
-		 * Organism for which we want to fetch genome.
-		 */
-		private MiriamData			 organism;
-
-		/**
-		 * Version of the genome.
-		 */
-		private String					 version;
-
-		/**
-		 * Default constructor.
-		 * 
-		 * @param url
-		 *          {@link #url}
-		 * @param updater
-		 *          {@link #updater}
-		 * @param organism
-		 *          {@link #organism}
-		 * @param version
-		 *          {@link #version}
-		 */
-		private DownloadGenomeVersionTask(MiriamData organism, String version, String url, IProgressUpdater updater) {
-			this.url = url;
-			this.organism = organism;
-			this.version = version;
-			if (updater != null) {
-				this.updater = updater;
-			} else {
-				this.updater = new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-					}
-				};
-			}
-		}
-
-		@Override
-		public Void call() throws Exception {
-			getDbUtils().createSessionForCurrentThread();
-			try {
-				ReferenceGenome referenceGenome = new ReferenceGenome();
-				referenceGenome.setOrganism(organism);
-				referenceGenome.setType(ReferenceGenomeType.UCSC);
-				referenceGenome.setVersion(version);
-				referenceGenome.setSourceUrl(url);
-				getReferenceGenomeDao().add(referenceGenome);
-				getReferenceGenomeDao().flush();
-				getReferenceGenomeDao().commit();
-				getDbUtils().closeSessionForCurrentThread();
-
-				getBigFileCache().downloadFile(url, false, new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-						if (updater != null) {
-							updater.setProgress(progress);
-						}
-						// we have to get the object because it's in separate thred
-						ReferenceGenome temp = getReferenceGenomeDao().getById(referenceGenome.getId());
-						temp.setDownloadProgress(progress);
-						getReferenceGenomeDao().update(temp);
-						getReferenceGenomeDao().commit();
-					}
-				});
-				return null;
-			} finally {
-				getDbUtils().closeSessionForCurrentThread();
-			}
-		}
-
-	}
-
-	@Override
-	public void downloadGenomeVersion(MiriamData organism, String version, IProgressUpdater updater, boolean async, String customUrl)
-			throws IOException, URISyntaxException, ReferenceGenomeConnectorException {
-		Callable<Void> computations = new DownloadGenomeVersionTask(organism, version, customUrl, updater);
-		if (async) {
-			getAsyncExecutorService().submit(computations);
-		} else {
-			Future<Void> task = getSyncExecutorService().submit(computations);
-			executeTask(task);
-		}
-	}
-
-	/**
-	 * Returns local path on ftp server to folder with data about given organism
-	 * and version.
-	 * 
-	 * @param organism
-	 *          organism of reference genome
-	 * @param version
-	 *          of reference genome
-	 * @return local path on ftp server to folder with data about reference genome
-	 */
-	private String getGenomePath(MiriamData organism, String version) {
-		return "/goldenPath/" + version + "/bigZips/";
-	}
-
-	@Override
-	public String getGenomeVersionFile(MiriamData organism, String version) throws FileNotAvailableException {
-		String filename = super.getCacheValue(FILENAME_BY_ORGANISM_VERSION_PREFIX + organism.getResource() + "\n" + version);
-		if (filename != null) {
-			return filename;
-		}
-		FTPClient ftp = createFtpClient();
-		try {
-			ftp.connect(SERVER);
-			// After connection attempt, you should check the reply code to verify
-			// success.
-			int reply = ftp.getReplyCode();
-
-			if (!FTPReply.isPositiveCompletion(reply)) {
-				throw new FileNotAvailableException("Cannot find file with genome for: " + organism + "; " + version + ". FTP server refused connection.");
-			} else {
-				ftp.enterLocalPassiveMode();
-				ftp.login("anonymous", "");
-				ftp.setFileType(FTP.BINARY_FILE_TYPE);
-
-				String remotePath = getGenomePath(organism, version);
-				FTPFile[] files = ftp.listFiles(remotePath);
-				for (FTPFile ftpFile : files) {
-					if (ftpFile.getName().endsWith(".2bit")) {
-						if (filename != null) {
-							logger.warn("More than one 2bit file found in a folder: " + remotePath + ". Using first: " + filename);
-						} else {
-							filename = ftpFile.getName();
-						}
-					}
-				}
-				ftp.logout();
-			}
-		} catch (IOException e) {
-			throw new FileNotAvailableException(e);
-		} finally {
-			if (ftp.isConnected()) {
-				try {
-					ftp.disconnect();
-				} catch (IOException ioe) {
-					throw new FileNotAvailableException("Cannot find file with genome for: " + organism + "; " + version + ". Problem with ftp connection.", ioe);
-				}
-			}
-		}
-		if (filename == null) {
-			throw new FileNotAvailableException("Cannot find file with genome for: " + organism + "; " + version);
-		}
-		String result = "ftp://" + SERVER + getGenomePath(organism, version) + filename;
-		super.setCacheValue(FILENAME_BY_ORGANISM_VERSION_PREFIX + organism.getResource() + "\n" + version, result);
-		return result;
-	}
-
-	/**
-	 * Creates new instance of {@link FTPClient}.
-	 * 
-	 * @return new instance of {@link FTPClient}
-	 */
-	FTPClient createFtpClient() {
-		FTPClient ftp = new FTPClient();
-		return ftp;
-	}
-
-	/**
-	 * Extracts int from the version of the genome. The genome version look like
-	 * follow: xxxx011.
-	 * 
-	 * @param s
-	 *          genome version where suffix part is integer number that informs
-	 *          about version
-	 * @return {@link Integer} representing version of the genome from string that
-	 *         describes genome version (it contains also some letters characters}
-	 */
-	int extractInt(String s) {
-		int startIndex = 0;
-		int endIndex = s.length() - 2;
-		for (int i = 0; i < s.length(); i++) {
-			startIndex = i;
-			if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
-				break;
-			}
-		}
-		for (int i = startIndex; i < s.length(); i++) {
-			if (s.charAt(i) < '0' || s.charAt(i) > '9') {
-				break;
-			}
-			endIndex = i;
-		}
-		endIndex++;
-		if (startIndex >= endIndex) {
-			return 0;
-		} else {
-			return Integer.parseInt(s.substring(startIndex, endIndex));
-		}
-	}
-
-	@Override
-	protected WebPageDownloader getWebPageDownloader() {
-		return super.getWebPageDownloader();
-	}
-
-	@Override
-	protected void setWebPageDownloader(WebPageDownloader webPageDownloader) {
-		super.setWebPageDownloader(webPageDownloader);
-	}
+  /**
+   * Server domain name.
+   */
+  private static final String SERVER = "hgdownload.cse.ucsc.edu";
+
+  /**
+   * Prefix string used for marking queries in cache database that identifies list
+   * of reference genome versions by organism id.
+   */
+  static final String FILENAME_BY_ORGANISM_VERSION_PREFIX = "ORGANISM_VERSION_FILE:";
+
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(UcscReferenceGenomeConnector.class);
+
+  /**
+   * Regex pattern that helps to find out organism names in source file.
+   */
+  private Pattern organismNamePattern = Pattern.compile("<!--([A-Za-z\\-\\.\\ ]+)Downloads [=]*[\\ ]*-->");
+
+  /**
+   * Regex pattern that helps to find out reference genome versions.
+   */
+  private Pattern organismDataUrlPattern = Pattern.compile("\\/goldenPath\\/([A-Za-z0-9\\-\\.]+)\\/bigZips\\/");
+
+  /**
+   * Access point to taxonomy information.
+   */
+  @Autowired
+  private TaxonomyBackend taxonomyBackend;
+
+  /**
+   * Default constructor.
+   */
+  public UcscReferenceGenomeConnector() {
+    super(UcscReferenceGenomeConnector.class);
+  }
+
+  @Override
+  public List<String> getDownloadedGenomeVersions(MiriamData organism) {
+    List<String> results = new ArrayList<>();
+
+    List<ReferenceGenome> genomes = getReferenceGenomeDao().getByType(ReferenceGenomeType.UCSC);
+    for (ReferenceGenome referenceGenome : genomes) {
+      if (referenceGenome.getOrganism().equals(organism)) {
+        results.add(referenceGenome.getVersion());
+      }
+    }
+    return results;
+  }
+
+  @Override
+  public List<String> getAvailableGenomeVersion(MiriamData organism) throws ReferenceGenomeConnectorException {
+    Set<String> ids = new HashSet<>();
+    try {
+      String content = getWebPageContent("http://hgdownload.cse.ucsc.edu/downloads.html");
+      Integer start = null;
+      Integer end = content.length();
+      Matcher matcher = organismNamePattern.matcher(content);
+      while (matcher.find()) {
+        String name = matcher.group(1).trim();
+        if (start != null) {
+          end = matcher.start();
+          break;
+        }
+
+        if (name.equalsIgnoreCase("Shared Data")) {
+          continue;
+        }
+        if (name.equalsIgnoreCase("liftOver File")) {
+          continue;
+        }
+        MiriamData taxonomy = taxonomyBackend.getByName(name);
+        if (organism.equals(taxonomy)) {
+          start = matcher.end();
+        }
+      }
+      // we haven't found a start point for our organism (organism couldn't be
+      // found in the list of available organisms)
+      if (start != null) {
+        String organismContent = content.substring(start, end);
+
+        matcher = organismDataUrlPattern.matcher(organismContent);
+        while (matcher.find()) {
+          String name = matcher.group(1).trim();
+          ids.add(name);
+        }
+      }
+
+    } catch (IOException | TaxonomySearchException e) {
+      throw new ReferenceGenomeConnectorException("Problem with accessing UCSC database", e);
+    }
+    List<String> result = new ArrayList<>();
+    result.addAll(ids);
+    Collections.sort(result, new Comparator<String>() {
+      public int compare(String o1, String o2) {
+        return extractInt(o2) - extractInt(o1);
+      }
+
+    });
+    return result;
+  }
+
+  @Override
+  public List<MiriamData> getAvailableOrganisms() throws ReferenceGenomeConnectorException {
+    try {
+      List<MiriamData> result = new ArrayList<>();
+      String content = getWebPageContent("http://hgdownload.cse.ucsc.edu/downloads.html");
+
+      Matcher matcher = organismNamePattern.matcher(content);
+      while (matcher.find()) {
+        String name = matcher.group(1).trim();
+        if (name.equalsIgnoreCase("Shared Data")) {
+          continue;
+        }
+        if (name.equalsIgnoreCase("liftOver File")) {
+          continue;
+        }
+        MiriamData taxonomy = taxonomyBackend.getByName(name);
+        if (taxonomy != null) {
+          result.add(taxonomy);
+        }
+      }
+
+      return result;
+    } catch (IOException | TaxonomySearchException e) {
+      throw new ReferenceGenomeConnectorException("Problem with accessing UCSC database", e);
+    }
+  }
+
+  @Override
+  public void downloadGenomeVersion(MiriamData organism, String version, IProgressUpdater updater, boolean async)
+      throws FileNotAvailableException, IOException, ReferenceGenomeConnectorException {
+    try {
+      downloadGenomeVersion(organism, version, updater, async, getGenomeVersionFile(organism, version));
+    } catch (URISyntaxException e) {
+      throw new InvalidStateException(e);
+    }
+  }
+
+  @Override
+  public Object refreshCacheQuery(Object query) throws SourceNotAvailable {
+    String result = null;
+    try {
+      if (query instanceof String) {
+        String name = (String) query;
+        if (name.startsWith("http")) {
+          result = getWebPageContent(name);
+        } else if (name.startsWith(FILENAME_BY_ORGANISM_VERSION_PREFIX)) {
+          String[] tmp = name.substring(FILENAME_BY_ORGANISM_VERSION_PREFIX.length()).split("\n");
+          result = getGenomeVersionFile(new MiriamData(MiriamType.TAXONOMY, tmp[0]), tmp[1]);
+        } else {
+          throw new InvalidArgumentException("Don't know what to do with string \"" + query + "\"");
+        }
+      } else {
+        throw new InvalidArgumentException("Don't know what to do with class: " + query.getClass());
+      }
+    } catch (FileNotAvailableException e) {
+      throw new SourceNotAvailable("Cannot find file for the query: " + query, e);
+    } catch (IOException e) {
+      throw new SourceNotAvailable(e);
+    }
+    return result;
+  }
+
+  @Override
+  public void removeGenomeVersion(MiriamData organism, String version) throws IOException {
+    List<ReferenceGenome> genomes = getReferenceGenomeDao().getByType(ReferenceGenomeType.UCSC);
+    for (ReferenceGenome referenceGenome : genomes) {
+      if (referenceGenome.getOrganism().equals(organism) && referenceGenome.getVersion().equals(version)) {
+        // removing file from big file cache might not be the best idea here
+        if (getBigFileCache().isCached(referenceGenome.getSourceUrl())) {
+          getBigFileCache().removeFile(referenceGenome.getSourceUrl());
+        }
+        for (ReferenceGenomeGeneMapping mapping : referenceGenome.getGeneMapping()) {
+          if (getBigFileCache().isCached(mapping.getSourceUrl())) {
+            getBigFileCache().removeFile(mapping.getSourceUrl());
+          }
+        }
+        getReferenceGenomeDao().delete(referenceGenome);
+      }
+    }
+  }
+
+  /**
+   * @return the taxonomyBackend
+   * @see #taxonomyBackend
+   */
+  public TaxonomyBackend getTaxonomyBackend() {
+    return taxonomyBackend;
+  }
+
+  /**
+   * @param taxonomyBackend
+   *          the taxonomyBackend to set
+   * @see #taxonomyBackend
+   */
+  public void setTaxonomyBackend(TaxonomyBackend taxonomyBackend) {
+    this.taxonomyBackend = taxonomyBackend;
+  }
+
+  /**
+   * Task that will be able to fetch genome file from ftp server.
+   * 
+   * @author Piotr Gawron
+   *
+   */
+  private final class DownloadGenomeVersionTask implements Callable<Void> {
+
+    /**
+     * Url to the file that we want to download.
+     * 
+     */
+    private String url;
+
+    /**
+     * Callback listener that will receive information about upload progress.
+     * 
+     */
+    private IProgressUpdater updater;
+
+    /**
+     * Organism for which we want to fetch genome.
+     */
+    private MiriamData organism;
+
+    /**
+     * Version of the genome.
+     */
+    private String version;
+
+    /**
+     * Default constructor.
+     * 
+     * @param url
+     *          {@link #url}
+     * @param updater
+     *          {@link #updater}
+     * @param organism
+     *          {@link #organism}
+     * @param version
+     *          {@link #version}
+     */
+    private DownloadGenomeVersionTask(MiriamData organism, String version, String url, IProgressUpdater updater) {
+      this.url = url;
+      this.organism = organism;
+      this.version = version;
+      if (updater != null) {
+        this.updater = updater;
+      } else {
+        this.updater = new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+          }
+        };
+      }
+    }
+
+    @Override
+    public Void call() throws Exception {
+      getDbUtils().createSessionForCurrentThread();
+      try {
+        ReferenceGenome referenceGenome = new ReferenceGenome();
+        referenceGenome.setOrganism(organism);
+        referenceGenome.setType(ReferenceGenomeType.UCSC);
+        referenceGenome.setVersion(version);
+        referenceGenome.setSourceUrl(url);
+        getReferenceGenomeDao().add(referenceGenome);
+        getReferenceGenomeDao().flush();
+        getReferenceGenomeDao().commit();
+        getDbUtils().closeSessionForCurrentThread();
+
+        getBigFileCache().downloadFile(url, false, new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+            if (updater != null) {
+              updater.setProgress(progress);
+            }
+            // we have to get the object because it's in separate thred
+            ReferenceGenome temp = getReferenceGenomeDao().getById(referenceGenome.getId());
+            temp.setDownloadProgress(progress);
+            getReferenceGenomeDao().update(temp);
+            getReferenceGenomeDao().commit();
+          }
+        });
+        return null;
+      } finally {
+        getDbUtils().closeSessionForCurrentThread();
+      }
+    }
+
+  }
+
+  @Override
+  public void downloadGenomeVersion(MiriamData organism, String version, IProgressUpdater updater, boolean async,
+      String customUrl) throws IOException, URISyntaxException, ReferenceGenomeConnectorException {
+    Callable<Void> computations = new DownloadGenomeVersionTask(organism, version, customUrl, updater);
+    if (async) {
+      getAsyncExecutorService().submit(computations);
+    } else {
+      Future<Void> task = getSyncExecutorService().submit(computations);
+      executeTask(task);
+    }
+  }
+
+  /**
+   * Returns local path on ftp server to folder with data about given organism and
+   * version.
+   * 
+   * @param organism
+   *          organism of reference genome
+   * @param version
+   *          of reference genome
+   * @return local path on ftp server to folder with data about reference genome
+   */
+  private String getGenomePath(MiriamData organism, String version) {
+    return "/goldenPath/" + version + "/bigZips/";
+  }
+
+  @Override
+  public String getGenomeVersionFile(MiriamData organism, String version) throws FileNotAvailableException {
+    String filename = super.getCacheValue(
+        FILENAME_BY_ORGANISM_VERSION_PREFIX + organism.getResource() + "\n" + version);
+    if (filename != null) {
+      return filename;
+    }
+    FTPClient ftp = createFtpClient();
+    try {
+      ftp.connect(SERVER);
+      // After connection attempt, you should check the reply code to verify
+      // success.
+      int reply = ftp.getReplyCode();
+
+      if (!FTPReply.isPositiveCompletion(reply)) {
+        throw new FileNotAvailableException(
+            "Cannot find file with genome for: " + organism + "; " + version + ". FTP server refused connection.");
+      } else {
+        ftp.enterLocalPassiveMode();
+        ftp.login("anonymous", "");
+        ftp.setFileType(FTP.BINARY_FILE_TYPE);
+
+        String remotePath = getGenomePath(organism, version);
+        FTPFile[] files = ftp.listFiles(remotePath);
+        for (FTPFile ftpFile : files) {
+          logger.debug(ftpFile.getName());
+          if (ftpFile.getName().endsWith(".2bit")) {
+            if (filename != null) {
+              logger.warn("More than one 2bit file found in a folder: " + remotePath + ". Using first: " + filename);
+            } else {
+              filename = ftpFile.getName();
+            }
+          }
+        }
+        ftp.logout();
+      }
+    } catch (IOException e) {
+      throw new FileNotAvailableException(e);
+    } finally {
+      if (ftp.isConnected()) {
+        try {
+          ftp.disconnect();
+        } catch (IOException ioe) {
+          throw new FileNotAvailableException(
+              "Cannot find file with genome for: " + organism + "; " + version + ". Problem with ftp connection.", ioe);
+        }
+      }
+    }
+    if (filename == null) {
+      throw new FileNotAvailableException("Cannot find file with genome for: " + organism + "; " + version);
+    }
+    String result = "ftp://" + SERVER + getGenomePath(organism, version) + filename;
+    super.setCacheValue(FILENAME_BY_ORGANISM_VERSION_PREFIX + organism.getResource() + "\n" + version, result);
+    return result;
+  }
+
+  /**
+   * Creates new instance of {@link FTPClient}.
+   * 
+   * @return new instance of {@link FTPClient}
+   */
+  FTPClient createFtpClient() {
+    FTPClient ftp = new FTPClient();
+    return ftp;
+  }
+
+  /**
+   * Extracts int from the version of the genome. The genome version look like
+   * follow: xxxx011.
+   * 
+   * @param s
+   *          genome version where suffix part is integer number that informs
+   *          about version
+   * @return {@link Integer} representing version of the genome from string that
+   *         describes genome version (it contains also some letters characters}
+   */
+  int extractInt(String s) {
+    int startIndex = 0;
+    int endIndex = s.length() - 2;
+    for (int i = 0; i < s.length(); i++) {
+      startIndex = i;
+      if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
+        break;
+      }
+    }
+    for (int i = startIndex; i < s.length(); i++) {
+      if (s.charAt(i) < '0' || s.charAt(i) > '9') {
+        break;
+      }
+      endIndex = i;
+    }
+    endIndex++;
+    if (startIndex >= endIndex) {
+      return 0;
+    } else {
+      return Integer.parseInt(s.substring(startIndex, endIndex));
+    }
+  }
+
+  @Override
+  protected WebPageDownloader getWebPageDownloader() {
+    return super.getWebPageDownloader();
+  }
+
+  @Override
+  protected void setWebPageDownloader(WebPageDownloader webPageDownloader) {
+    super.setWebPageDownloader(webPageDownloader);
+  }
 
 }
diff --git a/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/HgncAnnotatorTest.java b/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/HgncAnnotatorTest.java
index 71347a9620d10f39b0269c9f292b835750eef416..5dc32a4bd5510019c15bb6e27a7a4e08b3b025aa 100644
--- a/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/HgncAnnotatorTest.java
+++ b/annotation/src/test/java/lcsb/mapviewer/annotation/services/annotators/HgncAnnotatorTest.java
@@ -32,514 +32,538 @@ import lcsb.mapviewer.model.map.species.Species;
 
 public class HgncAnnotatorTest extends AnnotationTestFunctions {
 
-	final Logger					logger = Logger.getLogger(HgncAnnotatorTest.class);
-
-	@Autowired
-	private HgncAnnotator	hgncAnnotator;
-
-	@Before
-	public void setUp() {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testGetAnnotationsForSNCA() throws Exception {
-		try {
-			MiriamData snca = new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA");
-			GenericProtein proteinAlias = new GenericProtein("id");
-			proteinAlias.addMiriamData(snca);
-			hgncAnnotator.annotateElement(proteinAlias);
-			assertNotNull(proteinAlias.getSymbol());
-			assertTrue(proteinAlias.getFormerSymbols().size() > 0);
-			assertNotNull(proteinAlias.getFullName());
-			assertTrue(proteinAlias.getMiriamData().size() > 1);
-			assertTrue(proteinAlias.getSynonyms().size() > 0);
-
-			boolean ensemble = false;
-			boolean hgncId = false;
-			boolean hgncSymbol = false;
-			boolean refseq = false;
-			boolean entrez = false;
-			boolean uniprot = false;
-			for (MiriamData md : proteinAlias.getMiriamData()) {
-				if (MiriamType.ENSEMBL.equals(md.getDataType())) {
-					ensemble = true;
-				} else if (MiriamType.HGNC.equals(md.getDataType())) {
-					assertEquals("Invalid HGNC id", "11138", md.getResource());
-					hgncId = true;
-				} else if (MiriamType.HGNC_SYMBOL.equals(md.getDataType())) {
-					hgncSymbol = true;
-				} else if (MiriamType.REFSEQ.equals(md.getDataType())) {
-					refseq = true;
-				} else if (MiriamType.ENTREZ.equals(md.getDataType())) {
-					entrez = true;
-				} else if (MiriamType.UNIPROT.equals(md.getDataType())) {
-					uniprot = true;
-				}
-			}
-
-			assertTrue("Ensemble symbol cannot be found", ensemble);
-			assertTrue("Hgnc id cannot be found", hgncId);
-			assertTrue("Hgnc symbol cannot be found", hgncSymbol);
-			assertTrue("RefSeq cannot be found", refseq);
-			assertTrue("Entrez cannot be found", entrez);
-			assertTrue("Uniprot cannot be found", uniprot);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetAnnotationsForElementWithMultiHGNC() throws Exception {
-		try {
-			MiriamData snca = new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA");
-			MiriamData park7 = new MiriamData(MiriamType.HGNC_SYMBOL, "PARK7");
-			GenericProtein proteinAlias = new GenericProtein("id");
-			proteinAlias.addMiriamData(snca);
-			proteinAlias.addMiriamData(park7);
-			hgncAnnotator.annotateElement(proteinAlias);
-			
-			assertEquals(1, getWarnings().size());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetAnnotationsForHGNC_ID() throws Exception {
-		try {
-			MiriamData nsmf = new MiriamData(MiriamType.HGNC, "11138");
-			GenericProtein proteinAlias = new GenericProtein("id");
-			proteinAlias.addMiriamData(nsmf);
-			hgncAnnotator.annotateElement(proteinAlias);
-			assertNotNull(proteinAlias.getSymbol());
-			assertTrue(proteinAlias.getFormerSymbols().size() > 0);
-			assertNotNull(proteinAlias.getFullName());
-			assertTrue(proteinAlias.getMiriamData().size() > 1);
-			assertTrue(proteinAlias.getSynonyms().size() > 0);
-
-			boolean ensemble = false;
-			boolean hgncId = false;
-			boolean hgncSymbol = false;
-			boolean refseq = false;
-			boolean entrez = false;
-			for (MiriamData md : proteinAlias.getMiriamData()) {
-				if (MiriamType.ENSEMBL.equals(md.getDataType())) {
-					ensemble = true;
-				} else if (MiriamType.HGNC.equals(md.getDataType())) {
-					hgncId = true;
-				} else if (MiriamType.HGNC_SYMBOL.equals(md.getDataType())) {
-					hgncSymbol = true;
-				} else if (MiriamType.REFSEQ.equals(md.getDataType())) {
-					refseq = true;
-				} else if (MiriamType.ENTREZ.equals(md.getDataType())) {
-					entrez = true;
-				}
-			}
-
-			assertTrue("Ensemble symbol cannot be found", ensemble);
-			assertTrue("Hgnc id cannot be found", hgncId);
-			assertTrue("Hgnc symbol cannot be found", hgncSymbol);
-			assertTrue("RefSeq cannot be found", refseq);
-			assertTrue("Entrez cannot be found", entrez);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetAnnotationsForSNCA2() throws Exception {
-		try {
-			GenericProtein proteinAlias = new GenericProtein("id");
-			proteinAlias.setName("SNCA");
-			hgncAnnotator.annotateElement(proteinAlias);
-			assertNotNull(proteinAlias.getSymbol());
-			assertNotNull(proteinAlias.getName());
-			assertTrue(proteinAlias.getFormerSymbols().size() > 0);
-			assertNotNull(proteinAlias.getFullName());
-			assertTrue(proteinAlias.getMiriamData().size() > 1);
-			assertTrue(proteinAlias.getSynonyms().size() > 0);
-
-			boolean ensemble = false;
-			boolean hgncId = false;
-			boolean hgncSymbol = false;
-			boolean refseq = false;
-			boolean entrez = false;
-			for (MiriamData md : proteinAlias.getMiriamData()) {
-				if (MiriamType.ENSEMBL.equals(md.getDataType())) {
-					ensemble = true;
-				} else if (MiriamType.HGNC.equals(md.getDataType())) {
-					hgncId = true;
-				} else if (MiriamType.HGNC_SYMBOL.equals(md.getDataType())) {
-					hgncSymbol = true;
-				} else if (MiriamType.REFSEQ.equals(md.getDataType())) {
-					refseq = true;
-				} else if (MiriamType.ENTREZ.equals(md.getDataType())) {
-					entrez = true;
-				}
-			}
-
-			assertTrue("Ensemble symbol cannot be found", ensemble);
-			assertTrue("Hgnc id cannot be found", hgncId);
-			assertTrue("Hgnc symbol cannot be found", hgncSymbol);
-			assertTrue("RefSeq cannot be found", refseq);
-			assertTrue("Entrez cannot be found", entrez);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetAnnotationsForInvalid() throws Exception {
-		try {
-			Species proteinAlias = new GenericProtein("id");
-			proteinAlias.setName("UNKNNOWNASD asd");
-			hgncAnnotator.annotateElement(proteinAlias);
-
-			assertEquals(1, getWarnings().size());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetAnnotationsForInvalid2() throws Exception {
-		try {
-			Species proteinAlias = new GenericProtein("id");
-			proteinAlias.setName("cAMP/cGMP-dependent protein kinase");
-			hgncAnnotator.annotateElement(proteinAlias);
-
-			assertEquals(1, getWarnings().size());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test(timeout = 15000)
-	public void testCachableInterfaceInvalidate() throws Exception {
-		String query = "http://google.pl/";
-		try {
-			String newRes = "hello";
-
-			waitForRefreshCacheQueueToEmpty();
-
-			cache.setCachedQuery(query, hgncAnnotator.getCacheType(), newRes);
-			String res = cache.getStringByQuery(query, hgncAnnotator.getCacheType());
-			assertEquals(newRes, res);
-			cache.invalidateByQuery(query, hgncAnnotator.getCacheType());
-
-			waitForRefreshCacheQueueToEmpty();
-
-			res = cache.getStringByQuery(query, hgncAnnotator.getCacheType());
-
-			assertNotNull(res);
-
-			assertFalse("Value wasn't refreshed from db", newRes.equals(res));
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testStatus() throws Exception {
-		try {
-			assertEquals(ExternalServiceStatusType.OK, hgncAnnotator.getServiceStatus().getStatus());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetAnnotationsForInvalidMiriamSet() throws Exception {
-		try {
-			MiriamData md1 = new MiriamData(MiriamType.HGNC, "11138");
-			MiriamData md2 = new MiriamData(MiriamType.HGNC, "111382");
-			Species proteinAlias = new GenericProtein("");
-			proteinAlias.addMiriamData(md1);
-			proteinAlias.addMiriamData(md2);
-			hgncAnnotator.annotateElement(proteinAlias);
-			assertEquals(1, getWarnings().size());
-			assertEquals("SNCA", proteinAlias.getName());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testHgncIdToUniprot() throws Exception {
-		try {
-			List<MiriamData> result = hgncAnnotator.hgncToUniprot(new MiriamData(MiriamType.HGNC, "11138"));
-			assertEquals(1, result.size());
-			assertEquals(new MiriamData(MiriamType.UNIPROT, "P37840", HgncAnnotator.class), result.get(0));
-			assertEquals(0, hgncAnnotator.hgncToUniprot(new MiriamData(MiriamType.HGNC, "1", HgncAnnotator.class)).size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testHgncIdToName() throws Exception {
-		try {
-			assertEquals(new MiriamData(MiriamType.HGNC_SYMBOL, "FSD2", HgncAnnotator.class), hgncAnnotator.hgncIdToHgncName(new MiriamData(MiriamType.HGNC, "18024")));
-			assertEquals(new MiriamData(MiriamType.HGNC_SYMBOL, "LMOD1", HgncAnnotator.class), hgncAnnotator.hgncIdToHgncName(new MiriamData(MiriamType.HGNC, "6647")));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUnknownHgncIdToName() throws Exception {
-		try {
-			assertNull(hgncAnnotator.hgncIdToHgncName(new MiriamData(MiriamType.HGNC, "asd")));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testHgncToUniProt1() throws Exception {
-		try {
-			List<MiriamData> list = hgncAnnotator.hgncToUniprot(new MiriamData(MiriamType.HGNC_SYMBOL, "CASP8"));
-			assertEquals(1, list.size());
-			assertEquals("Q14790", list.get(0).getResource());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testHgncToUniProtWithInvalidArg() throws Exception {
-		try {
-			hgncAnnotator.hgncToUniprot(new MiriamData(MiriamType.CAS, "CASP8"));
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-
-	@Test
-	public void testHgncToEntrezWithInvalidArg() throws Exception {
-		try {
-			hgncAnnotator.hgncToEntrez(new MiriamData(MiriamType.CAS, "CASP8"));
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testIsValidHgnc() throws Exception {
-		try {
-			assertFalse(hgncAnnotator.isValidHgncMiriam(new MiriamData(MiriamType.CAS, "CASP8")));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testIsValidHgnc2() throws Exception {
-		try {
-			assertTrue(hgncAnnotator.isValidHgncMiriam(new MiriamData(MiriamType.HGNC_SYMBOL, "CASP8")));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-
-	@Test
-	public void testHgncIdToNameWithInvalidArg() throws Exception {
-		try {
-			hgncAnnotator.hgncIdToHgncName(new MiriamData(MiriamType.CAS, "CASP8"));
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testHgncToUniProt2() throws Exception {
-		try {
-
-			MiriamData data1 = new MiriamData(MiriamType.HGNC_SYMBOL, "CASP8");
-			MiriamData data2 = new MiriamData(MiriamType.HGNC_SYMBOL, "CASP10");
-
-			List<MiriamData> list = hgncAnnotator.hgncToUniprot(data1);
-			assertEquals(1, list.size());
-			assertEquals("Q14790", list.get(0).getResource());
-
-			list = hgncAnnotator.hgncToUniprot(data2);
-			assertEquals(1, list.size());
-			assertEquals("Q92851", list.get(0).getResource());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testHgncToUniProt3() throws Exception {
-		try {
-			MiriamData data1 = new MiriamData(MiriamType.HGNC_SYMBOL, "blablabla invalid name");
-			List<MiriamData> list = hgncAnnotator.hgncToUniprot(data1);
-			assertNotNull(list);
-			assertEquals(0, list.size());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testHgncToEntrez() throws Exception {
-		try {
-			// check by symbol
-			MiriamData data1 = new MiriamData(MiriamType.HGNC_SYMBOL, "PTGS1");
-			MiriamData entrez = hgncAnnotator.hgncToEntrez(data1);
-			assertNotNull(entrez);
-			assertTrue(new MiriamData(MiriamType.ENTREZ, "5742", HgncAnnotator.class).equals(entrez));
-
-			// check by id
-			data1 = new MiriamData(MiriamType.HGNC, "11138");
-			entrez = hgncAnnotator.hgncToEntrez(data1);
-			assertNotNull(entrez);
-			assertTrue(new MiriamData(MiriamType.ENTREZ, "6622", HgncAnnotator.class).equals(entrez));
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidHgncToEntrez() throws Exception {
-		try {
-			MiriamData data1 = new MiriamData(MiriamType.HGNC_SYMBOL, "xxxxxsd");
-			MiriamData entrez = hgncAnnotator.hgncToEntrez(data1);
-			assertNull(entrez);
-
-			data1 = new MiriamData(MiriamType.HGNC, "xxxxxsd");
-			entrez = hgncAnnotator.hgncToEntrez(data1);
-			assertNull(entrez);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRefreshInvalidCacheQuery() throws Exception {
-		try {
-			hgncAnnotator.refreshCacheQuery("invalid_query");
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-			assertTrue(e.getMessage().contains("Don't know what to do"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRefreshInvalidCacheQuery2() throws Exception {
-		try {
-			hgncAnnotator.refreshCacheQuery(new Object());
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-			assertTrue(e.getMessage().contains("Don't know what to do"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRefreshCacheQueryNotAvailable() throws Exception {
-		WebPageDownloader downloader = hgncAnnotator.getWebPageDownloader();
-		GeneralCacheInterface originalCache = hgncAnnotator.getCache();
-		try {
-			// exclude first cached value
-			hgncAnnotator.setCache(null);
-
-			WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
-			when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
-			hgncAnnotator.setWebPageDownloader(mockDownloader);
-			hgncAnnotator.refreshCacheQuery("http://google.pl/");
-			fail("Exception expected");
-		} catch (SourceNotAvailable e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			hgncAnnotator.setWebPageDownloader(downloader);
-			hgncAnnotator.setCache(originalCache);
-		}
-	}
-
-	@Test
-	public void testSimulateDownStatus() throws Exception {
-		WebPageDownloader downloader = hgncAnnotator.getWebPageDownloader();
-		try {
-			WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
-			when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
-			hgncAnnotator.setWebPageDownloader(mockDownloader);
-			assertEquals(ExternalServiceStatusType.DOWN, hgncAnnotator.getServiceStatus().getStatus());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			hgncAnnotator.setWebPageDownloader(downloader);
-		}
-	}
-
-	@Test
-	public void testSimulateChangedStatus() throws Exception {
-		WebPageDownloader downloader = hgncAnnotator.getWebPageDownloader();
-		try {
-			WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
-			when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenReturn("<response><result/></response>");
-			hgncAnnotator.setWebPageDownloader(mockDownloader);
-			assertEquals(ExternalServiceStatusType.CHANGED, hgncAnnotator.getServiceStatus().getStatus());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			hgncAnnotator.setWebPageDownloader(downloader);
-		}
-	}
+  final Logger logger = Logger.getLogger(HgncAnnotatorTest.class);
+
+  @Autowired
+  private HgncAnnotator hgncAnnotator;
+
+  @Before
+  public void setUp() {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testGetAnnotationsForSNCA() throws Exception {
+    try {
+      MiriamData snca = new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA");
+      GenericProtein proteinAlias = new GenericProtein("id");
+      proteinAlias.addMiriamData(snca);
+      hgncAnnotator.annotateElement(proteinAlias);
+      assertNotNull(proteinAlias.getSymbol());
+      assertTrue(proteinAlias.getFormerSymbols().size() > 0);
+      assertNotNull(proteinAlias.getFullName());
+      assertTrue(proteinAlias.getMiriamData().size() > 1);
+      assertTrue(proteinAlias.getSynonyms().size() > 0);
+
+      boolean ensemble = false;
+      boolean hgncId = false;
+      boolean hgncSymbol = false;
+      boolean refseq = false;
+      boolean entrez = false;
+      boolean uniprot = false;
+      for (MiriamData md : proteinAlias.getMiriamData()) {
+        if (MiriamType.ENSEMBL.equals(md.getDataType())) {
+          ensemble = true;
+        } else if (MiriamType.HGNC.equals(md.getDataType())) {
+          assertEquals("Invalid HGNC id", "11138", md.getResource());
+          hgncId = true;
+        } else if (MiriamType.HGNC_SYMBOL.equals(md.getDataType())) {
+          hgncSymbol = true;
+        } else if (MiriamType.REFSEQ.equals(md.getDataType())) {
+          refseq = true;
+        } else if (MiriamType.ENTREZ.equals(md.getDataType())) {
+          entrez = true;
+        } else if (MiriamType.UNIPROT.equals(md.getDataType())) {
+          uniprot = true;
+        }
+      }
+
+      assertTrue("Ensemble symbol cannot be found", ensemble);
+      assertTrue("Hgnc id cannot be found", hgncId);
+      assertTrue("Hgnc symbol cannot be found", hgncSymbol);
+      assertTrue("RefSeq cannot be found", refseq);
+      assertTrue("Entrez cannot be found", entrez);
+      assertTrue("Uniprot cannot be found", uniprot);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAnnotationsForElementWithMultiHGNC() throws Exception {
+    try {
+      MiriamData snca = new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA");
+      MiriamData park7 = new MiriamData(MiriamType.HGNC_SYMBOL, "PARK7");
+      GenericProtein proteinAlias = new GenericProtein("id");
+      proteinAlias.addMiriamData(snca);
+      proteinAlias.addMiriamData(park7);
+      hgncAnnotator.annotateElement(proteinAlias);
+
+      assertEquals(1, getWarnings().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAnnotationsForHGNC_ID() throws Exception {
+    try {
+      MiriamData nsmf = new MiriamData(MiriamType.HGNC, "11138");
+      GenericProtein proteinAlias = new GenericProtein("id");
+      proteinAlias.addMiriamData(nsmf);
+      hgncAnnotator.annotateElement(proteinAlias);
+      assertNotNull(proteinAlias.getSymbol());
+      assertTrue(proteinAlias.getFormerSymbols().size() > 0);
+      assertNotNull(proteinAlias.getFullName());
+      assertTrue(proteinAlias.getMiriamData().size() > 1);
+      assertTrue(proteinAlias.getSynonyms().size() > 0);
+
+      boolean ensemble = false;
+      boolean hgncId = false;
+      boolean hgncSymbol = false;
+      boolean refseq = false;
+      boolean entrez = false;
+      for (MiriamData md : proteinAlias.getMiriamData()) {
+        if (MiriamType.ENSEMBL.equals(md.getDataType())) {
+          ensemble = true;
+        } else if (MiriamType.HGNC.equals(md.getDataType())) {
+          hgncId = true;
+        } else if (MiriamType.HGNC_SYMBOL.equals(md.getDataType())) {
+          hgncSymbol = true;
+        } else if (MiriamType.REFSEQ.equals(md.getDataType())) {
+          refseq = true;
+        } else if (MiriamType.ENTREZ.equals(md.getDataType())) {
+          entrez = true;
+        }
+      }
+
+      assertTrue("Ensemble symbol cannot be found", ensemble);
+      assertTrue("Hgnc id cannot be found", hgncId);
+      assertTrue("Hgnc symbol cannot be found", hgncSymbol);
+      assertTrue("RefSeq cannot be found", refseq);
+      assertTrue("Entrez cannot be found", entrez);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAnnotationsForSNCA2() throws Exception {
+    try {
+      GenericProtein proteinAlias = new GenericProtein("id");
+      proteinAlias.setName("SNCA");
+      hgncAnnotator.annotateElement(proteinAlias);
+      assertNotNull(proteinAlias.getSymbol());
+      assertNotNull(proteinAlias.getName());
+      assertTrue(proteinAlias.getFormerSymbols().size() > 0);
+      assertNotNull(proteinAlias.getFullName());
+      assertTrue(proteinAlias.getMiriamData().size() > 1);
+      assertTrue(proteinAlias.getSynonyms().size() > 0);
+
+      boolean ensemble = false;
+      boolean hgncId = false;
+      boolean hgncSymbol = false;
+      boolean refseq = false;
+      boolean entrez = false;
+      for (MiriamData md : proteinAlias.getMiriamData()) {
+        if (MiriamType.ENSEMBL.equals(md.getDataType())) {
+          ensemble = true;
+        } else if (MiriamType.HGNC.equals(md.getDataType())) {
+          hgncId = true;
+        } else if (MiriamType.HGNC_SYMBOL.equals(md.getDataType())) {
+          hgncSymbol = true;
+        } else if (MiriamType.REFSEQ.equals(md.getDataType())) {
+          refseq = true;
+        } else if (MiriamType.ENTREZ.equals(md.getDataType())) {
+          entrez = true;
+        }
+      }
+
+      assertTrue("Ensemble symbol cannot be found", ensemble);
+      assertTrue("Hgnc id cannot be found", hgncId);
+      assertTrue("Hgnc symbol cannot be found", hgncSymbol);
+      assertTrue("RefSeq cannot be found", refseq);
+      assertTrue("Entrez cannot be found", entrez);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAnnotationsForBID() throws Exception {
+    try {
+      GenericProtein bidProtein = new GenericProtein("id");
+      bidProtein.setName("BID");
+      hgncAnnotator.annotateElement(bidProtein);
+      
+      GenericProtein bidMutationProtein = new GenericProtein("id2");
+      bidMutationProtein.setName("BID (p15)");
+      hgncAnnotator.annotateElement(bidMutationProtein);
+      
+      assertEquals(bidProtein.getSymbol(),bidMutationProtein.getSymbol());
+      assertEquals(bidProtein.getFormerSymbols(),bidMutationProtein.getFormerSymbols());
+      assertEquals(bidProtein.getFullName(),bidMutationProtein.getFullName());
+      assertEquals(bidProtein.getMiriamData(),bidMutationProtein.getMiriamData());
+      assertEquals(bidProtein.getSynonyms(),bidMutationProtein.getSynonyms());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAnnotationsForInvalid() throws Exception {
+    try {
+      Species proteinAlias = new GenericProtein("id");
+      proteinAlias.setName("UNKNNOWNASD asd");
+      hgncAnnotator.annotateElement(proteinAlias);
+
+      assertEquals(1, getWarnings().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAnnotationsForInvalid2() throws Exception {
+    try {
+      Species proteinAlias = new GenericProtein("id");
+      proteinAlias.setName("cAMP/cGMP-dependent protein kinase");
+      hgncAnnotator.annotateElement(proteinAlias);
+
+      assertEquals(1, getWarnings().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test(timeout = 15000)
+  public void testCachableInterfaceInvalidate() throws Exception {
+    String query = "http://google.pl/";
+    try {
+      String newRes = "hello";
+
+      waitForRefreshCacheQueueToEmpty();
+
+      cache.setCachedQuery(query, hgncAnnotator.getCacheType(), newRes);
+      String res = cache.getStringByQuery(query, hgncAnnotator.getCacheType());
+      assertEquals(newRes, res);
+      cache.invalidateByQuery(query, hgncAnnotator.getCacheType());
+
+      waitForRefreshCacheQueueToEmpty();
+
+      res = cache.getStringByQuery(query, hgncAnnotator.getCacheType());
+
+      assertNotNull(res);
+
+      assertFalse("Value wasn't refreshed from db", newRes.equals(res));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testStatus() throws Exception {
+    try {
+      assertEquals(ExternalServiceStatusType.OK, hgncAnnotator.getServiceStatus().getStatus());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAnnotationsForInvalidMiriamSet() throws Exception {
+    try {
+      MiriamData md1 = new MiriamData(MiriamType.HGNC, "11138");
+      MiriamData md2 = new MiriamData(MiriamType.HGNC, "111382");
+      Species proteinAlias = new GenericProtein("");
+      proteinAlias.addMiriamData(md1);
+      proteinAlias.addMiriamData(md2);
+      hgncAnnotator.annotateElement(proteinAlias);
+      assertEquals(1, getWarnings().size());
+      assertEquals("SNCA", proteinAlias.getName());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testHgncIdToUniprot() throws Exception {
+    try {
+      List<MiriamData> result = hgncAnnotator.hgncToUniprot(new MiriamData(MiriamType.HGNC, "11138"));
+      assertEquals(1, result.size());
+      assertEquals(new MiriamData(MiriamType.UNIPROT, "P37840", HgncAnnotator.class), result.get(0));
+      assertEquals(0, hgncAnnotator.hgncToUniprot(new MiriamData(MiriamType.HGNC, "1", HgncAnnotator.class)).size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testHgncIdToName() throws Exception {
+    try {
+      assertEquals(new MiriamData(MiriamType.HGNC_SYMBOL, "FSD2", HgncAnnotator.class),
+          hgncAnnotator.hgncIdToHgncName(new MiriamData(MiriamType.HGNC, "18024")));
+      assertEquals(new MiriamData(MiriamType.HGNC_SYMBOL, "LMOD1", HgncAnnotator.class),
+          hgncAnnotator.hgncIdToHgncName(new MiriamData(MiriamType.HGNC, "6647")));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testUnknownHgncIdToName() throws Exception {
+    try {
+      assertNull(hgncAnnotator.hgncIdToHgncName(new MiriamData(MiriamType.HGNC, "asd")));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testHgncToUniProt1() throws Exception {
+    try {
+      List<MiriamData> list = hgncAnnotator.hgncToUniprot(new MiriamData(MiriamType.HGNC_SYMBOL, "CASP8"));
+      assertEquals(1, list.size());
+      assertEquals("Q14790", list.get(0).getResource());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testHgncToUniProtWithInvalidArg() throws Exception {
+    try {
+      hgncAnnotator.hgncToUniprot(new MiriamData(MiriamType.CAS, "CASP8"));
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testHgncToEntrezWithInvalidArg() throws Exception {
+    try {
+      hgncAnnotator.hgncToEntrez(new MiriamData(MiriamType.CAS, "CASP8"));
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testIsValidHgnc() throws Exception {
+    try {
+      assertFalse(hgncAnnotator.isValidHgncMiriam(new MiriamData(MiriamType.CAS, "CASP8")));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testIsValidHgnc2() throws Exception {
+    try {
+      assertTrue(hgncAnnotator.isValidHgncMiriam(new MiriamData(MiriamType.HGNC_SYMBOL, "CASP8")));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testHgncIdToNameWithInvalidArg() throws Exception {
+    try {
+      hgncAnnotator.hgncIdToHgncName(new MiriamData(MiriamType.CAS, "CASP8"));
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testHgncToUniProt2() throws Exception {
+    try {
+
+      MiriamData data1 = new MiriamData(MiriamType.HGNC_SYMBOL, "CASP8");
+      MiriamData data2 = new MiriamData(MiriamType.HGNC_SYMBOL, "CASP10");
+
+      List<MiriamData> list = hgncAnnotator.hgncToUniprot(data1);
+      assertEquals(1, list.size());
+      assertEquals("Q14790", list.get(0).getResource());
+
+      list = hgncAnnotator.hgncToUniprot(data2);
+      assertEquals(1, list.size());
+      assertEquals("Q92851", list.get(0).getResource());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testHgncToUniProt3() throws Exception {
+    try {
+      MiriamData data1 = new MiriamData(MiriamType.HGNC_SYMBOL, "blablabla invalid name");
+      List<MiriamData> list = hgncAnnotator.hgncToUniprot(data1);
+      assertNotNull(list);
+      assertEquals(0, list.size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testHgncToEntrez() throws Exception {
+    try {
+      // check by symbol
+      MiriamData data1 = new MiriamData(MiriamType.HGNC_SYMBOL, "PTGS1");
+      MiriamData entrez = hgncAnnotator.hgncToEntrez(data1);
+      assertNotNull(entrez);
+      assertTrue(new MiriamData(MiriamType.ENTREZ, "5742", HgncAnnotator.class).equals(entrez));
+
+      // check by id
+      data1 = new MiriamData(MiriamType.HGNC, "11138");
+      entrez = hgncAnnotator.hgncToEntrez(data1);
+      assertNotNull(entrez);
+      assertTrue(new MiriamData(MiriamType.ENTREZ, "6622", HgncAnnotator.class).equals(entrez));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidHgncToEntrez() throws Exception {
+    try {
+      MiriamData data1 = new MiriamData(MiriamType.HGNC_SYMBOL, "xxxxxsd");
+      MiriamData entrez = hgncAnnotator.hgncToEntrez(data1);
+      assertNull(entrez);
+
+      data1 = new MiriamData(MiriamType.HGNC, "xxxxxsd");
+      entrez = hgncAnnotator.hgncToEntrez(data1);
+      assertNull(entrez);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRefreshInvalidCacheQuery() throws Exception {
+    try {
+      hgncAnnotator.refreshCacheQuery("invalid_query");
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+      assertTrue(e.getMessage().contains("Don't know what to do"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRefreshInvalidCacheQuery2() throws Exception {
+    try {
+      hgncAnnotator.refreshCacheQuery(new Object());
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+      assertTrue(e.getMessage().contains("Don't know what to do"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRefreshCacheQueryNotAvailable() throws Exception {
+    WebPageDownloader downloader = hgncAnnotator.getWebPageDownloader();
+    GeneralCacheInterface originalCache = hgncAnnotator.getCache();
+    try {
+      // exclude first cached value
+      hgncAnnotator.setCache(null);
+
+      WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
+      when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
+      hgncAnnotator.setWebPageDownloader(mockDownloader);
+      hgncAnnotator.refreshCacheQuery("http://google.pl/");
+      fail("Exception expected");
+    } catch (SourceNotAvailable e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      hgncAnnotator.setWebPageDownloader(downloader);
+      hgncAnnotator.setCache(originalCache);
+    }
+  }
+
+  @Test
+  public void testSimulateDownStatus() throws Exception {
+    WebPageDownloader downloader = hgncAnnotator.getWebPageDownloader();
+    try {
+      WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
+      when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
+      hgncAnnotator.setWebPageDownloader(mockDownloader);
+      assertEquals(ExternalServiceStatusType.DOWN, hgncAnnotator.getServiceStatus().getStatus());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      hgncAnnotator.setWebPageDownloader(downloader);
+    }
+  }
+
+  @Test
+  public void testSimulateChangedStatus() throws Exception {
+    WebPageDownloader downloader = hgncAnnotator.getWebPageDownloader();
+    try {
+      WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
+      when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString()))
+          .thenReturn("<response><result/></response>");
+      hgncAnnotator.setWebPageDownloader(mockDownloader);
+      assertEquals(ExternalServiceStatusType.CHANGED, hgncAnnotator.getServiceStatus().getStatus());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      hgncAnnotator.setWebPageDownloader(downloader);
+    }
+  }
 
 }
diff --git a/annotation/src/test/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnectorTest.java b/annotation/src/test/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnectorTest.java
index 5ff31b7460e125167a6e4df0574204fe723c3de1..0ae6336559f94305885ac9491bc3dbeda41e05a1 100644
--- a/annotation/src/test/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnectorTest.java
+++ b/annotation/src/test/java/lcsb/mapviewer/annotation/services/genome/UcscReferenceGenomeConnectorTest.java
@@ -49,921 +49,926 @@ import lcsb.mapviewer.persist.dao.map.layout.ReferenceGenomeDao;
 
 public class UcscReferenceGenomeConnectorTest extends AnnotationTestFunctions {
 
-	Logger											 logger	= Logger.getLogger(UcscReferenceGenomeConnectorTest.class);
-
-	@Autowired
-	UcscReferenceGenomeConnector connector;
-
-	@Autowired
-	ReferenceGenomeDao					 referenceGenomeDao;
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testRefreshCacheQuery() throws Exception {
-		try {
-			assertNotNull(connector.refreshCacheQuery("http://google.pl/"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetAvailableGenomeVersion() throws Exception {
-		MiriamData human = new MiriamData(MiriamType.TAXONOMY, "9606");
-		try {
-			List<String> list = connector.getAvailableGenomeVersion(human);
-			assertTrue(list.size() >= 17);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetAvailableGenomeVersionWhenProblemWithTaxonomyServer() throws Exception {
-		MiriamData human = new MiriamData(MiriamType.TAXONOMY, "9606");
-		TaxonomyBackend taxonomyBackend = connector.getTaxonomyBackend();
-		try {
-			// simulate problems with taxonomy server
-			TaxonomyBackend taxonomyMock = Mockito.mock(TaxonomyBackend.class);
-			when(taxonomyMock.getByName(anyString())).thenThrow(new TaxonomySearchException(null, null));
-			connector.setTaxonomyBackend(taxonomyMock);
-
-			connector.getAvailableGenomeVersion(human);
-			fail("Exception expected");
-		} catch (ReferenceGenomeConnectorException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			connector.setTaxonomyBackend(taxonomyBackend);
-		}
-	}
-
-	@Test
-	public void testGetAvailableGenomeVersionForInvalidTaxonomy() throws Exception {
-		MiriamData unknown = new MiriamData(MiriamType.TAXONOMY, "10101010101");
-		try {
-			List<String> list = connector.getAvailableGenomeVersion(unknown);
-			assertEquals(0, list.size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetAvailableOrganisms() throws Exception {
-		try {
-			MiriamData human = new MiriamData(MiriamType.TAXONOMY, "9606");
-			MiriamData chicken = new MiriamData(MiriamType.TAXONOMY, "9031");
-			List<MiriamData> list = connector.getAvailableOrganisms();
-			assertTrue(list.size() > 40);
-
-			assertTrue(list.contains(human));
-			assertTrue(list.contains(chicken));
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetAvailableOrganismsWhenUcscWebpageDown() throws Exception {
-		WebPageDownloader downloader = connector.getWebPageDownloader();
-		GeneralCacheInterface originalCache = connector.getCache();
-		try {
-			// exclude first cached value
-			connector.setCache(null);
-
-			WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
-			when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
-			connector.setWebPageDownloader(mockDownloader);
-			connector.getAvailableOrganisms();
-			fail("Exception expected");
-		} catch (ReferenceGenomeConnectorException e) {
-			assertTrue(e.getMessage().contains("Problem with accessing UCSC database"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			connector.setWebPageDownloader(downloader);
-			connector.setCache(originalCache);
-		}
-	}
-
-	@Test
-	public void testDownloadGenomeVersion() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "1570291");
-		String version = "eboVir3";
-
-		try {
-			dbUtils.createSessionForCurrentThread();
-			List<String> list = connector.getDownloadedGenomeVersions(yeast);
-			if (list.contains(version)) {
-				connector.removeGenomeVersion(yeast, version);
-			}
-			dbUtils.closeSessionForCurrentThread();
-			list = connector.getDownloadedGenomeVersions(yeast);
-
-			assertFalse(list.contains(version));
-
-			connector.downloadGenomeVersion(yeast, version, new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			}, false);
-
-			list = connector.getDownloadedGenomeVersions(yeast);
-			assertTrue(list.contains(version));
-
-			List<ReferenceGenome> genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
-			ReferenceGenome genome = null;
-			for (ReferenceGenome referenceGenome : genomes) {
-				if (referenceGenome.getVersion().equals(version)) {
-					genome = referenceGenome;
-				}
-			}
-			assertNotNull(genome);
-			connector.downloadGeneMappingGenomeVersion(genome, "test", null, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
-
-			dbUtils.createSessionForCurrentThread();
-			genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
-			genome = null;
-			for (ReferenceGenome referenceGenome : genomes) {
-				if (referenceGenome.getVersion().equals(version)) {
-					genome = referenceGenome;
-				}
-			}
-			assertNotNull(genome);
-			assertEquals(1, genome.getGeneMapping().size());
-			dbUtils.closeSessionForCurrentThread();
-
-			try {
-				// try to download the same thing for the second time
-				connector.downloadGeneMappingGenomeVersion(genome, "test", new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-					}
-				}, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
-				fail("Exception expected");
-			} catch (ReferenceGenomeConnectorException e) {
-				assertTrue(e.getMessage().contains("already exists"));
-			}
-
-			try {
-				// try to download something that is not big bed
-				connector.downloadGeneMappingGenomeVersion(genome, "test2", new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-					}
-				}, false, "http://www.biodalliance.org/datasets/flyThickets.txt");
-				fail("Exception expected");
-			} catch (ReferenceGenomeConnectorException e) {
-				assertTrue(e.getMessage().contains("Only big bed format files are supported"));
-			}
-
-//			connector.removeGeneMapping(genome.getGeneMapping().get(0));
-
-			int warningCount = getWarnings().size();
-
-			// try to remove invalid mapping
-			connector.removeGeneMapping(new ReferenceGenomeGeneMapping());
-
-			assertEquals(warningCount + 1, getWarnings().size());
-
-			dbUtils.createSessionForCurrentThread();
-			connector.removeGenomeVersion(yeast, version);
-			dbUtils.closeSessionForCurrentThread();
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@SuppressWarnings("unchecked")
-	@Test
-	public void testDownloadGenomeVersionWhenInternalUrlIsInvalid() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "1570291");
-		String version = "eboVir3";
-
-		ExecutorService originalExecutorService = connector.getSyncExecutorService();
-		try {
-			ExecutorService executorService = Mockito.mock(ExecutorService.class);
-			connector.setSyncExecutorService(executorService);
-			Future<?>  task = Mockito.mock(Future.class);
-			when(task.get()).thenThrow(new ExecutionException(new URISyntaxException("", "")));
-			when(executorService.submit(any(Callable.class))).thenReturn(task);
-
-			connector.downloadGenomeVersion(yeast, version, new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			}, false);
-			fail("Exception expected");
-
-		} catch (InvalidStateException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			connector.setSyncExecutorService(originalExecutorService);
-		}
-	}
-
-	@Test
-	public void testDownloadGenomeVersionAsync() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "1570291");
-		String version = "eboVir3";
-
-		BigFileCache bigFileCache = connector.getBigFileCache();
-		try {
-			dbUtils.createSessionForCurrentThread();
-			List<String> list = connector.getDownloadedGenomeVersions(yeast);
-			if (list.contains(version)) {
-				connector.removeGenomeVersion(yeast, version);
-			}
-			list = connector.getDownloadedGenomeVersions(yeast);
-
-			dbUtils.closeSessionForCurrentThread();
-
-			// create a mock for ftp connections (so we speed up tests), the real
-			// connection is tested elsewhere
-			BigFileCache mockCache = Mockito.mock(BigFileCache.class);
-			Mockito.doAnswer(new Answer<Void>() {
-
-				@Override
-				public Void answer(InvocationOnMock invocation) throws Throwable {
-					IProgressUpdater updater = (IProgressUpdater) invocation.getArguments()[2];
-					updater.setProgress(100);
-					return null;
-				}
-			}).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
-
-			connector.setBigFileCache(mockCache);
-
-			assertFalse(list.contains(version));
-
-			connector.downloadGenomeVersion(yeast, version, null, true);
-
-			waitForDownload();
-
-			dbUtils.createSessionForCurrentThread();
-			list = connector.getDownloadedGenomeVersions(yeast);
-			assertTrue(list.contains(version));
-
-			List<ReferenceGenome> genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
-			ReferenceGenome genome = null;
-			for (ReferenceGenome referenceGenome : genomes) {
-				if (referenceGenome.getVersion().equals(version)) {
-					genome = referenceGenome;
-				}
-			}
-			dbUtils.closeSessionForCurrentThread();
-			assertNotNull(genome);
-			connector.downloadGeneMappingGenomeVersion(genome, "test", new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			}, true, "http://www.biodalliance.org/datasets/flyThickets.bb");
-
-			waitForDownload();
-
-			genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
-			genome = null;
-			for (ReferenceGenome referenceGenome : genomes) {
-				if (referenceGenome.getVersion().equals(version)) {
-					genome = referenceGenome;
-				}
-			}
-			assertNotNull(genome);
-			referenceGenomeDao.refresh(genome);
-			assertEquals(1, genome.getGeneMapping().size());
-
-			try {
-				// try to download the same thing for the second time
-				connector.downloadGeneMappingGenomeVersion(genome, "test", new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-					}
-				}, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
-				fail("Exception expected");
-			} catch (ReferenceGenomeConnectorException e) {
-				assertTrue(e.getMessage().contains("already exists"));
-			}
-
-			try {
-				// try to download something that is not big bed
-				connector.downloadGeneMappingGenomeVersion(genome, "test2", new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-					}
-				}, false, "http://www.biodalliance.org/datasets/flyThickets.txt");
-				fail("Exception expected");
-			} catch (ReferenceGenomeConnectorException e) {
-				assertTrue(e.getMessage().contains("Only big bed format files are supported"));
-			}
-
-			connector.removeGeneMapping(genome.getGeneMapping().get(0));
-
-			int warningCount = getWarnings().size();
-
-			// try to remove invalid mapping
-			connector.removeGeneMapping(new ReferenceGenomeGeneMapping());
-
-			assertEquals(warningCount + 1, getWarnings().size());
-
-			connector.removeGenomeVersion(yeast, version);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			connector.setBigFileCache(bigFileCache);
-		}
-	}
-
-	@Test
-	public void testDownloadGenomeVersionAsyncWithException() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "1570291");
-		String version = "eboVir3";
-
-		BigFileCache bigFileCache = connector.getBigFileCache();
-		try {
-			dbUtils.createSessionForCurrentThread();
-			List<String> list = connector.getDownloadedGenomeVersions(yeast);
-			if (list.contains(version)) {
-				connector.removeGenomeVersion(yeast, version);
-			}
-			list = connector.getDownloadedGenomeVersions(yeast);
-
-			dbUtils.closeSessionForCurrentThread();
-
-			// create a mock for ftp connections (so we speed up tests), the real
-			// connection is tested elsewhere
-			BigFileCache mockCache = Mockito.mock(BigFileCache.class);
-
-			connector.setBigFileCache(mockCache);
-
-			assertFalse(list.contains(version));
-
-			connector.downloadGenomeVersion(yeast, version, new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			}, true);
-
-			waitForDownload();
-
-			dbUtils.createSessionForCurrentThread();
-			list = connector.getDownloadedGenomeVersions(yeast);
-			assertTrue(list.contains(version));
-
-			List<ReferenceGenome> genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
-			ReferenceGenome genome = null;
-			for (ReferenceGenome referenceGenome : genomes) {
-				if (referenceGenome.getVersion().equals(version)) {
-					genome = referenceGenome;
-				}
-			}
-			dbUtils.closeSessionForCurrentThread();
-			assertNotNull(genome);
-
-			Mockito.doThrow(new IOException()).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
-			assertEquals(0, getErrors().size());
-			connector.downloadGeneMappingGenomeVersion(genome, "test", new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			}, true, "http://www.biodalliance.org/datasets/flyThickets.bb");
-
-			waitForDownload();
-
-			logger.debug(getErrors());
-			// during this downlad we expect exception thrown by downloader
-			assertEquals(1, getErrors().size());
-
-			Mockito.doThrow(new OutOfMemoryError()).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
-			connector.downloadGeneMappingGenomeVersion(genome, "test2", new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			}, true, "http://www.biodalliance.org/datasets/flyThickets.bb");
-
-			waitForDownload();
-			// during this downlad we expect error, this shouldn't change list of
-			// errors
-			assertEquals(1, getErrors().size());
-
-			Mockito.doThrow(new URISyntaxException("", "")).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
-			connector.downloadGeneMappingGenomeVersion(genome, "test3", new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			}, true, "http://www.biodalliance.org/datasets/flyThickets.bb");
-
-			waitForDownload();
-
-			// during this downlad we expect error (exception thrown by downloader)
-			assertEquals(2, getErrors().size());
-
-			genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
-			genome = null;
-			for (ReferenceGenome referenceGenome : genomes) {
-				if (referenceGenome.getVersion().equals(version)) {
-					genome = referenceGenome;
-				}
-			}
-			assertNotNull(genome);
-			referenceGenomeDao.refresh(genome);
-			assertEquals(3, genome.getGeneMapping().size());
-
-			connector.removeGeneMapping(genome.getGeneMapping().get(2));
-			connector.removeGeneMapping(genome.getGeneMapping().get(1));
-			connector.removeGeneMapping(genome.getGeneMapping().get(0));
-			connector.removeGenomeVersion(yeast, version);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			connector.setBigFileCache(bigFileCache);
-		}
-	}
-
-	@Test
-	public void testDownloadGenomeVersionWithException() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "1570291");
-		String version = "eboVir3";
-
-		BigFileCache bigFileCache = connector.getBigFileCache();
-		try {
-			List<String> list = connector.getDownloadedGenomeVersions(yeast);
-			if (list.contains(version)) {
-				connector.removeGenomeVersion(yeast, version);
-			}
-			list = connector.getDownloadedGenomeVersions(yeast);
-
-			// create a mock for ftp connections (so we speed up tests), the real
-			// connection is tested elsewhere
-			BigFileCache mockCache = Mockito.mock(BigFileCache.class);
-
-			connector.setBigFileCache(mockCache);
-
-			assertFalse(list.contains(version));
-
-			connector.downloadGenomeVersion(yeast, version, new IProgressUpdater() {
-				@Override
-				public void setProgress(double progress) {
-				}
-			}, false);
-
-			list = connector.getDownloadedGenomeVersions(yeast);
-			assertTrue(list.contains(version));
-
-			List<ReferenceGenome> genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
-			ReferenceGenome genome = null;
-			for (ReferenceGenome referenceGenome : genomes) {
-				if (referenceGenome.getVersion().equals(version)) {
-					genome = referenceGenome;
-				}
-			}
-			assertNotNull(genome);
-
-			Mockito.doThrow(new IOException()).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
-			assertEquals(0, getErrors().size());
-			try {
-				connector.downloadGeneMappingGenomeVersion(genome, "test", new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-					}
-				}, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
-				fail("Exception expected");
-			} catch (IOException e) {
-
-			}
-
-			Mockito.doThrow(new RuntimeException()).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
-			try {
-				connector.downloadGeneMappingGenomeVersion(genome, "test2", new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-					}
-				}, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
-
-				fail("Exception expected");
-			} catch (InvalidStateException e) {
-
-			}
-
-			Mockito.doThrow(new URISyntaxException("", "")).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
-
-			try {
-				connector.downloadGeneMappingGenomeVersion(genome, "test3", new IProgressUpdater() {
-					@Override
-					public void setProgress(double progress) {
-					}
-				}, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
-				fail("Exception expected");
-			} catch (URISyntaxException e) {
-
-			}
-
-			genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
-			genome = null;
-			for (ReferenceGenome referenceGenome : genomes) {
-				if (referenceGenome.getVersion().equals(version)) {
-					genome = referenceGenome;
-				}
-			}
-			assertNotNull(genome);
-			referenceGenomeDao.refresh(genome);
-			assertEquals(3, genome.getGeneMapping().size());
-
-			connector.removeGeneMapping(genome.getGeneMapping().get(2));
-			connector.removeGeneMapping(genome.getGeneMapping().get(1));
-			connector.removeGeneMapping(genome.getGeneMapping().get(0));
-			connector.removeGenomeVersion(yeast, version);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			connector.setBigFileCache(bigFileCache);
-		}
-	}
-
-	@Test
-	public void testGetGenomeVersionFile() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
-		String version = "sacCer3";
-		try {
-			String url = connector.getGenomeVersionFile(yeast, version);
-			assertNotNull(url);
-			url.contains("sacCer3.2bit");
-			url.contains("ftp");
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetUnknownGenomeVersionFile() {
-		MiriamData human = new MiriamData(MiriamType.TAXONOMY, "9606");
-		String version = "hg8";
-		try {
-			connector.getGenomeVersionFile(human, version);
-			fail("Exception expected");
-		} catch (FileNotAvailableException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRefreshInvalid() throws Exception {
-		try {
-			connector.refreshCacheQuery("invalid query");
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-			assertTrue(e.getMessage().contains("Don't know what to do"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRefreshInvalid2() throws Exception {
-		try {
-			connector.refreshCacheQuery(new Object());
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-			assertTrue(e.getMessage().contains("Don't know what to do"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRefresh() throws Exception {
-		try {
-			MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
-			String version = "sacCer3";
-
-			String query = UcscReferenceGenomeConnector.FILENAME_BY_ORGANISM_VERSION_PREFIX + yeast.getResource() + "\n" + version;
-			Object res = connector.refreshCacheQuery(query);
-			assertNotNull(res);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRefreshUnknownFile() throws Exception {
-		try {
-			MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
-			String version = "unkVer";
-
-			String query = UcscReferenceGenomeConnector.FILENAME_BY_ORGANISM_VERSION_PREFIX + yeast.getResource() + "\n" + version;
-			connector.refreshCacheQuery(query);
-		} catch (SourceNotAvailable e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() throws Exception {
-		try {
-			UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector();
-			connectorUnderTest.setBigFileCache(connector.getBigFileCache());
-			connectorUnderTest.setDbUtils(connector.getDbUtils());
-			connectorUnderTest.setReferenceGenomeDao(connector.getReferenceGenomeDao());
-			connectorUnderTest.setReferenceGenomeGeneMappingDao(connector.getReferenceGenomeGeneMappingDao());
-
-			assertEquals(connector.getBigFileCache(), connectorUnderTest.getBigFileCache());
-			assertEquals(connector.getDbUtils(), connectorUnderTest.getDbUtils());
-			assertEquals(connector.getReferenceGenomeDao(), connectorUnderTest.getReferenceGenomeDao());
-			assertEquals(connector.getReferenceGenomeGeneMappingDao(), connectorUnderTest.getReferenceGenomeGeneMappingDao());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGenomeVersionExtractorForInvalidGenome() throws Exception {
-		try {
-			int version = connector.extractInt("");
-			assertEquals(0, version);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGenomeVersionExtractorForInvalidGenome2() throws Exception {
-		try {
-			int version = connector.extractInt("x");
-			assertEquals(0, version);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGenomeVersionExtractorForValid() throws Exception {
-		try {
-			int version = connector.extractInt("x1");
-			assertEquals(1, version);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGenomeVersionExtractorForValid2() throws Exception {
-		try {
-			int version = connector.extractInt("xy12z");
-			assertEquals(12, version);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRefreshCacheQueryNotAvailable() throws Exception {
-		WebPageDownloader downloader = connector.getWebPageDownloader();
-		GeneralCacheInterface originalCache = connector.getCache();
-		try {
-			// exclude first cached value
-			connector.setCache(null);
-			WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
-			when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
-			connector.setWebPageDownloader(mockDownloader);
-			connector.refreshCacheQuery("http://google.pl/");
-			fail("Exception expected");
-		} catch (SourceNotAvailable e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		} finally {
-			connector.setWebPageDownloader(downloader);
-			connector.setCache(originalCache);
-		}
-	}
-
-	@Test
-	public void testRefreshCacheQueryWhenFtpConnectionFails() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
-		String version = "sacCer3";
-
-		UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
-			@Override
-			FTPClient createFtpClient() {
-				FTPClient mockClient = Mockito.mock(FTPClient.class);
-				Mockito.doReturn(FTPReply.REQUEST_DENIED).when(mockClient).getReplyCode();
-				return mockClient;
-			}
-		};
-
-		try {
-			// exclude first cached value
-			connectorUnderTest.getGenomeVersionFile(yeast, version);
-			fail("Exception expected");
-		} catch (FileNotAvailableException e) {
-			assertTrue(e.getMessage().contains("FTP server refused connection"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetGenomeVersionFileWhenFtpConnectionFails2() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
-		String version = "sacCer3";
-
-		UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
-			@Override
-			FTPClient createFtpClient() {
-				FTPClient mockClient = Mockito.mock(FTPClient.class);
-				try {
-					Mockito.doThrow(new IOException()).when(mockClient).connect(anyString());
-					Mockito.doReturn(false).when(mockClient).isConnected();
-				} catch (Exception e) {
-					fail();
-				}
-				return mockClient;
-			}
-		};
-
-		try {
-			// exclude first cached value
-			connectorUnderTest.getGenomeVersionFile(yeast, version);
-			fail("Exception expected");
-		} catch (FileNotAvailableException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetGenomeVersionFileWhenFtpConnectionFails() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
-		String version = "sacCer3";
-
-		UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
-			@Override
-			FTPClient createFtpClient() {
-				FTPClient mockClient = Mockito.mock(FTPClient.class);
-				try {
-					Mockito.doThrow(new IOException()).when(mockClient).connect(anyString());
-					Mockito.doReturn(true).when(mockClient).isConnected();
-				} catch (Exception e) {
-					fail();
-				}
-				return mockClient;
-			}
-		};
-
-		try {
-			// exclude first cached value
-			connectorUnderTest.getGenomeVersionFile(yeast, version);
-			fail("Exception expected");
-		} catch (FileNotAvailableException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetGenomeVersionFileWhenFtpConnectionFails3() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
-		String version = "sacCer3";
-
-		UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
-			@Override
-			FTPClient createFtpClient() {
-				FTPClient mockClient = Mockito.mock(FTPClient.class);
-				try {
-					Mockito.doThrow(new IOException()).when(mockClient).connect(anyString());
-					Mockito.doReturn(true).when(mockClient).isConnected();
-					Mockito.doThrow(new IOException()).when(mockClient).disconnect();
-				} catch (Exception e) {
-					fail();
-				}
-				return mockClient;
-			}
-		};
-
-		try {
-			// exclude first cached value
-			connectorUnderTest.getGenomeVersionFile(yeast, version);
-			fail("Exception expected");
-		} catch (FileNotAvailableException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetGenomeVersionFileWhenFtpDisconnectConnectionFails() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
-		String version = "sacCer3";
-
-		UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
-			@Override
-			FTPClient createFtpClient() {
-				FTPClient mockClient = Mockito.mock(FTPClient.class);
-				try {
-					Mockito.doThrow(new IOException()).when(mockClient).disconnect();
-					Mockito.doReturn(new FTPFile[] {}).when(mockClient).listFiles(anyString());
-					Mockito.doReturn(FTPReply.COMMAND_OK).when(mockClient).getReplyCode();
-					Mockito.doReturn(true).when(mockClient).isConnected();
-				} catch (Exception e) {
-					fail();
-				}
-				return mockClient;
-			}
-		};
-
-		try {
-			// exclude first cached value
-			connectorUnderTest.getGenomeVersionFile(yeast, version);
-			fail("Exception expected");
-		} catch (FileNotAvailableException e) {
-			assertTrue(e.getMessage().contains("Problem with ftp connection"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetGenomeVersionFileWithMore2bitFiles() throws Exception {
-		MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
-		String version = "sacCer3";
-
-		UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
-			@Override
-			FTPClient createFtpClient() {
-				FTPClient mockClient = Mockito.mock(FTPClient.class);
-				try {
-					FTPFile file1 = new FTPFile();
-					file1.setName("1.2bit");
-					FTPFile file2 = new FTPFile();
-					file2.setName("2.2bit");
-					FTPFile[] files = new FTPFile[] { file1, file2 };
-
-					Mockito.doReturn(files).when(mockClient).listFiles(anyString());
-					Mockito.doReturn(FTPReply.COMMAND_OK).when(mockClient).getReplyCode();
-				} catch (Exception e) {
-					fail();
-				}
-				return mockClient;
-			}
-		};
-
-		try {
-			// exclude first cached value
-			String url = connectorUnderTest.getGenomeVersionFile(yeast, version);
-			assertEquals(1, getWarnings().size());
-			assertTrue(url.endsWith("1.2bit"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	private void waitForDownload() throws InterruptedException {
-		while (connector.getDownloadThreadCount() > 0) {
-			logger.debug("Waiting for download to finish");
-			Thread.sleep(100);
-		}
-	}
+  Logger logger = Logger.getLogger(UcscReferenceGenomeConnectorTest.class);
+
+  @Autowired
+  UcscReferenceGenomeConnector connector;
+
+  @Autowired
+  ReferenceGenomeDao referenceGenomeDao;
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testRefreshCacheQuery() throws Exception {
+    try {
+      assertNotNull(connector.refreshCacheQuery("http://google.pl/"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAvailableGenomeVersion() throws Exception {
+    MiriamData human = new MiriamData(MiriamType.TAXONOMY, "9606");
+    try {
+      List<String> list = connector.getAvailableGenomeVersion(human);
+      logger.debug(list);
+      assertTrue(list.size() >= 17);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAvailableGenomeVersionWhenProblemWithTaxonomyServer() throws Exception {
+    MiriamData human = new MiriamData(MiriamType.TAXONOMY, "9606");
+    TaxonomyBackend taxonomyBackend = connector.getTaxonomyBackend();
+    try {
+      // simulate problems with taxonomy server
+      TaxonomyBackend taxonomyMock = Mockito.mock(TaxonomyBackend.class);
+      when(taxonomyMock.getByName(anyString())).thenThrow(new TaxonomySearchException(null, null));
+      connector.setTaxonomyBackend(taxonomyMock);
+
+      connector.getAvailableGenomeVersion(human);
+      fail("Exception expected");
+    } catch (ReferenceGenomeConnectorException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      connector.setTaxonomyBackend(taxonomyBackend);
+    }
+  }
+
+  @Test
+  public void testGetAvailableGenomeVersionForInvalidTaxonomy() throws Exception {
+    MiriamData unknown = new MiriamData(MiriamType.TAXONOMY, "10101010101");
+    try {
+      List<String> list = connector.getAvailableGenomeVersion(unknown);
+      assertEquals(0, list.size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAvailableOrganisms() throws Exception {
+    try {
+      MiriamData human = new MiriamData(MiriamType.TAXONOMY, "9606");
+      MiriamData chicken = new MiriamData(MiriamType.TAXONOMY, "9031");
+      List<MiriamData> list = connector.getAvailableOrganisms();
+      logger.debug(list);
+      assertTrue(list.size() > 40);
+
+      assertTrue(list.contains(human));
+      assertTrue(list.contains(chicken));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAvailableOrganismsWhenUcscWebpageDown() throws Exception {
+    WebPageDownloader downloader = connector.getWebPageDownloader();
+    GeneralCacheInterface originalCache = connector.getCache();
+    try {
+      // exclude first cached value
+      connector.setCache(null);
+
+      WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
+      when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
+      connector.setWebPageDownloader(mockDownloader);
+      connector.getAvailableOrganisms();
+      fail("Exception expected");
+    } catch (ReferenceGenomeConnectorException e) {
+      assertTrue(e.getMessage().contains("Problem with accessing UCSC database"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      connector.setWebPageDownloader(downloader);
+      connector.setCache(originalCache);
+    }
+  }
+
+  @Test
+  public void testDownloadGenomeVersion() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "1570291");
+    String version = "eboVir3";
+
+    try {
+      dbUtils.createSessionForCurrentThread();
+      List<String> list = connector.getDownloadedGenomeVersions(yeast);
+      if (list.contains(version)) {
+        connector.removeGenomeVersion(yeast, version);
+      }
+      dbUtils.closeSessionForCurrentThread();
+      list = connector.getDownloadedGenomeVersions(yeast);
+
+      assertFalse(list.contains(version));
+
+      connector.downloadGenomeVersion(yeast, version, new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      }, false);
+
+      list = connector.getDownloadedGenomeVersions(yeast);
+      assertTrue(list.contains(version));
+
+      List<ReferenceGenome> genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
+      ReferenceGenome genome = null;
+      for (ReferenceGenome referenceGenome : genomes) {
+        if (referenceGenome.getVersion().equals(version)) {
+          genome = referenceGenome;
+        }
+      }
+      assertNotNull(genome);
+      connector.downloadGeneMappingGenomeVersion(genome, "test", null, false,
+          "http://www.biodalliance.org/datasets/flyThickets.bb");
+
+      dbUtils.createSessionForCurrentThread();
+      genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
+      genome = null;
+      for (ReferenceGenome referenceGenome : genomes) {
+        if (referenceGenome.getVersion().equals(version)) {
+          genome = referenceGenome;
+        }
+      }
+      assertNotNull(genome);
+      assertEquals(1, genome.getGeneMapping().size());
+      dbUtils.closeSessionForCurrentThread();
+
+      try {
+        // try to download the same thing for the second time
+        connector.downloadGeneMappingGenomeVersion(genome, "test", new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+          }
+        }, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
+        fail("Exception expected");
+      } catch (ReferenceGenomeConnectorException e) {
+        assertTrue(e.getMessage().contains("already exists"));
+      }
+
+      try {
+        // try to download something that is not big bed
+        connector.downloadGeneMappingGenomeVersion(genome, "test2", new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+          }
+        }, false, "http://www.biodalliance.org/datasets/flyThickets.txt");
+        fail("Exception expected");
+      } catch (ReferenceGenomeConnectorException e) {
+        assertTrue(e.getMessage().contains("Only big bed format files are supported"));
+      }
+
+      // connector.removeGeneMapping(genome.getGeneMapping().get(0));
+
+      int warningCount = getWarnings().size();
+
+      // try to remove invalid mapping
+      connector.removeGeneMapping(new ReferenceGenomeGeneMapping());
+
+      assertEquals(warningCount + 1, getWarnings().size());
+
+      dbUtils.createSessionForCurrentThread();
+      connector.removeGenomeVersion(yeast, version);
+      dbUtils.closeSessionForCurrentThread();
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  @Test
+  public void testDownloadGenomeVersionWhenInternalUrlIsInvalid() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "1570291");
+    String version = "eboVir3";
+
+    ExecutorService originalExecutorService = connector.getSyncExecutorService();
+    try {
+      ExecutorService executorService = Mockito.mock(ExecutorService.class);
+      connector.setSyncExecutorService(executorService);
+      Future<?> task = Mockito.mock(Future.class);
+      when(task.get()).thenThrow(new ExecutionException(new URISyntaxException("", "")));
+      when(executorService.submit(any(Callable.class))).thenReturn(task);
+
+      connector.downloadGenomeVersion(yeast, version, new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      }, false);
+      fail("Exception expected");
+
+    } catch (InvalidStateException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      connector.setSyncExecutorService(originalExecutorService);
+    }
+  }
+
+  @Test
+  public void testDownloadGenomeVersionAsync() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "1570291");
+    String version = "eboVir3";
+
+    BigFileCache bigFileCache = connector.getBigFileCache();
+    try {
+      dbUtils.createSessionForCurrentThread();
+      List<String> list = connector.getDownloadedGenomeVersions(yeast);
+      if (list.contains(version)) {
+        connector.removeGenomeVersion(yeast, version);
+      }
+      list = connector.getDownloadedGenomeVersions(yeast);
+
+      dbUtils.closeSessionForCurrentThread();
+
+      // create a mock for ftp connections (so we speed up tests), the real
+      // connection is tested elsewhere
+      BigFileCache mockCache = Mockito.mock(BigFileCache.class);
+      Mockito.doAnswer(new Answer<Void>() {
+
+        @Override
+        public Void answer(InvocationOnMock invocation) throws Throwable {
+          IProgressUpdater updater = (IProgressUpdater) invocation.getArguments()[2];
+          updater.setProgress(100);
+          return null;
+        }
+      }).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
+
+      connector.setBigFileCache(mockCache);
+
+      assertFalse(list.contains(version));
+
+      connector.downloadGenomeVersion(yeast, version, null, true);
+
+      waitForDownload();
+
+      dbUtils.createSessionForCurrentThread();
+      list = connector.getDownloadedGenomeVersions(yeast);
+      assertTrue(list.contains(version));
+
+      List<ReferenceGenome> genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
+      ReferenceGenome genome = null;
+      for (ReferenceGenome referenceGenome : genomes) {
+        if (referenceGenome.getVersion().equals(version)) {
+          genome = referenceGenome;
+        }
+      }
+      dbUtils.closeSessionForCurrentThread();
+      assertNotNull(genome);
+      connector.downloadGeneMappingGenomeVersion(genome, "test", new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      }, true, "http://www.biodalliance.org/datasets/flyThickets.bb");
+
+      waitForDownload();
+
+      genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
+      genome = null;
+      for (ReferenceGenome referenceGenome : genomes) {
+        if (referenceGenome.getVersion().equals(version)) {
+          genome = referenceGenome;
+        }
+      }
+      assertNotNull(genome);
+      referenceGenomeDao.refresh(genome);
+      assertEquals(1, genome.getGeneMapping().size());
+
+      try {
+        // try to download the same thing for the second time
+        connector.downloadGeneMappingGenomeVersion(genome, "test", new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+          }
+        }, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
+        fail("Exception expected");
+      } catch (ReferenceGenomeConnectorException e) {
+        assertTrue(e.getMessage().contains("already exists"));
+      }
+
+      try {
+        // try to download something that is not big bed
+        connector.downloadGeneMappingGenomeVersion(genome, "test2", new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+          }
+        }, false, "http://www.biodalliance.org/datasets/flyThickets.txt");
+        fail("Exception expected");
+      } catch (ReferenceGenomeConnectorException e) {
+        assertTrue(e.getMessage().contains("Only big bed format files are supported"));
+      }
+
+      connector.removeGeneMapping(genome.getGeneMapping().get(0));
+
+      int warningCount = getWarnings().size();
+
+      // try to remove invalid mapping
+      connector.removeGeneMapping(new ReferenceGenomeGeneMapping());
+
+      assertEquals(warningCount + 1, getWarnings().size());
+
+      connector.removeGenomeVersion(yeast, version);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      connector.setBigFileCache(bigFileCache);
+    }
+  }
+
+  @Test
+  public void testDownloadGenomeVersionAsyncWithException() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "1570291");
+    String version = "eboVir3";
+
+    BigFileCache bigFileCache = connector.getBigFileCache();
+    try {
+      dbUtils.createSessionForCurrentThread();
+      List<String> list = connector.getDownloadedGenomeVersions(yeast);
+      if (list.contains(version)) {
+        connector.removeGenomeVersion(yeast, version);
+      }
+      list = connector.getDownloadedGenomeVersions(yeast);
+
+      dbUtils.closeSessionForCurrentThread();
+
+      // create a mock for ftp connections (so we speed up tests), the real
+      // connection is tested elsewhere
+      BigFileCache mockCache = Mockito.mock(BigFileCache.class);
+
+      connector.setBigFileCache(mockCache);
+
+      assertFalse(list.contains(version));
+
+      connector.downloadGenomeVersion(yeast, version, new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      }, true);
+
+      waitForDownload();
+
+      dbUtils.createSessionForCurrentThread();
+      list = connector.getDownloadedGenomeVersions(yeast);
+      assertTrue(list.contains(version));
+
+      List<ReferenceGenome> genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
+      ReferenceGenome genome = null;
+      for (ReferenceGenome referenceGenome : genomes) {
+        if (referenceGenome.getVersion().equals(version)) {
+          genome = referenceGenome;
+        }
+      }
+      dbUtils.closeSessionForCurrentThread();
+      assertNotNull(genome);
+
+      Mockito.doThrow(new IOException()).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
+      assertEquals(0, getErrors().size());
+      connector.downloadGeneMappingGenomeVersion(genome, "test", new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      }, true, "http://www.biodalliance.org/datasets/flyThickets.bb");
+
+      waitForDownload();
+
+      logger.debug(getErrors());
+      // during this downlad we expect exception thrown by downloader
+      assertEquals(1, getErrors().size());
+
+      Mockito.doThrow(new OutOfMemoryError()).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
+      connector.downloadGeneMappingGenomeVersion(genome, "test2", new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      }, true, "http://www.biodalliance.org/datasets/flyThickets.bb");
+
+      waitForDownload();
+      // during this downlad we expect error, this shouldn't change list of
+      // errors
+      assertEquals(1, getErrors().size());
+
+      Mockito.doThrow(new URISyntaxException("", "")).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
+      connector.downloadGeneMappingGenomeVersion(genome, "test3", new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      }, true, "http://www.biodalliance.org/datasets/flyThickets.bb");
+
+      waitForDownload();
+
+      // during this downlad we expect error (exception thrown by downloader)
+      assertEquals(2, getErrors().size());
+
+      genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
+      genome = null;
+      for (ReferenceGenome referenceGenome : genomes) {
+        if (referenceGenome.getVersion().equals(version)) {
+          genome = referenceGenome;
+        }
+      }
+      assertNotNull(genome);
+      referenceGenomeDao.refresh(genome);
+      assertEquals(3, genome.getGeneMapping().size());
+
+      connector.removeGeneMapping(genome.getGeneMapping().get(2));
+      connector.removeGeneMapping(genome.getGeneMapping().get(1));
+      connector.removeGeneMapping(genome.getGeneMapping().get(0));
+      connector.removeGenomeVersion(yeast, version);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      connector.setBigFileCache(bigFileCache);
+    }
+  }
+
+  @Test
+  public void testDownloadGenomeVersionWithException() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "1570291");
+    String version = "eboVir3";
+
+    BigFileCache bigFileCache = connector.getBigFileCache();
+    try {
+      List<String> list = connector.getDownloadedGenomeVersions(yeast);
+      if (list.contains(version)) {
+        connector.removeGenomeVersion(yeast, version);
+      }
+      list = connector.getDownloadedGenomeVersions(yeast);
+
+      // create a mock for ftp connections (so we speed up tests), the real
+      // connection is tested elsewhere
+      BigFileCache mockCache = Mockito.mock(BigFileCache.class);
+
+      connector.setBigFileCache(mockCache);
+
+      assertFalse(list.contains(version));
+
+      connector.downloadGenomeVersion(yeast, version, new IProgressUpdater() {
+        @Override
+        public void setProgress(double progress) {
+        }
+      }, false);
+
+      list = connector.getDownloadedGenomeVersions(yeast);
+      assertTrue(list.contains(version));
+
+      List<ReferenceGenome> genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
+      ReferenceGenome genome = null;
+      for (ReferenceGenome referenceGenome : genomes) {
+        if (referenceGenome.getVersion().equals(version)) {
+          genome = referenceGenome;
+        }
+      }
+      assertNotNull(genome);
+
+      Mockito.doThrow(new IOException()).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
+      assertEquals(0, getErrors().size());
+      try {
+        connector.downloadGeneMappingGenomeVersion(genome, "test", new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+          }
+        }, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
+        fail("Exception expected");
+      } catch (IOException e) {
+
+      }
+
+      Mockito.doThrow(new RuntimeException()).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
+      try {
+        connector.downloadGeneMappingGenomeVersion(genome, "test2", new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+          }
+        }, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
+
+        fail("Exception expected");
+      } catch (InvalidStateException e) {
+
+      }
+
+      Mockito.doThrow(new URISyntaxException("", "")).when(mockCache).downloadFile(anyString(), anyBoolean(), any());
+
+      try {
+        connector.downloadGeneMappingGenomeVersion(genome, "test3", new IProgressUpdater() {
+          @Override
+          public void setProgress(double progress) {
+          }
+        }, false, "http://www.biodalliance.org/datasets/flyThickets.bb");
+        fail("Exception expected");
+      } catch (URISyntaxException e) {
+
+      }
+
+      genomes = referenceGenomeDao.getByType(ReferenceGenomeType.UCSC);
+      genome = null;
+      for (ReferenceGenome referenceGenome : genomes) {
+        if (referenceGenome.getVersion().equals(version)) {
+          genome = referenceGenome;
+        }
+      }
+      assertNotNull(genome);
+      referenceGenomeDao.refresh(genome);
+      assertEquals(3, genome.getGeneMapping().size());
+
+      connector.removeGeneMapping(genome.getGeneMapping().get(2));
+      connector.removeGeneMapping(genome.getGeneMapping().get(1));
+      connector.removeGeneMapping(genome.getGeneMapping().get(0));
+      connector.removeGenomeVersion(yeast, version);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      connector.setBigFileCache(bigFileCache);
+    }
+  }
+
+  @Test
+  public void testGetGenomeVersionFile() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
+    String version = "sacCer3";
+    try {
+      String url = connector.getGenomeVersionFile(yeast, version);
+      assertNotNull(url);
+      url.contains("sacCer3.2bit");
+      url.contains("ftp");
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetUnknownGenomeVersionFile() {
+    MiriamData human = new MiriamData(MiriamType.TAXONOMY, "9606");
+    String version = "hg8";
+    try {
+      connector.getGenomeVersionFile(human, version);
+      fail("Exception expected");
+    } catch (FileNotAvailableException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRefreshInvalid() throws Exception {
+    try {
+      connector.refreshCacheQuery("invalid query");
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+      assertTrue(e.getMessage().contains("Don't know what to do"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRefreshInvalid2() throws Exception {
+    try {
+      connector.refreshCacheQuery(new Object());
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+      assertTrue(e.getMessage().contains("Don't know what to do"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRefresh() throws Exception {
+    try {
+      MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
+      String version = "sacCer3";
+
+      String query = UcscReferenceGenomeConnector.FILENAME_BY_ORGANISM_VERSION_PREFIX + yeast.getResource() + "\n"
+          + version;
+      Object res = connector.refreshCacheQuery(query);
+      assertNotNull(res);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRefreshUnknownFile() throws Exception {
+    try {
+      MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
+      String version = "unkVer";
+
+      String query = UcscReferenceGenomeConnector.FILENAME_BY_ORGANISM_VERSION_PREFIX + yeast.getResource() + "\n"
+          + version;
+      connector.refreshCacheQuery(query);
+    } catch (SourceNotAvailable e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetters() throws Exception {
+    try {
+      UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector();
+      connectorUnderTest.setBigFileCache(connector.getBigFileCache());
+      connectorUnderTest.setDbUtils(connector.getDbUtils());
+      connectorUnderTest.setReferenceGenomeDao(connector.getReferenceGenomeDao());
+      connectorUnderTest.setReferenceGenomeGeneMappingDao(connector.getReferenceGenomeGeneMappingDao());
+
+      assertEquals(connector.getBigFileCache(), connectorUnderTest.getBigFileCache());
+      assertEquals(connector.getDbUtils(), connectorUnderTest.getDbUtils());
+      assertEquals(connector.getReferenceGenomeDao(), connectorUnderTest.getReferenceGenomeDao());
+      assertEquals(connector.getReferenceGenomeGeneMappingDao(), connectorUnderTest.getReferenceGenomeGeneMappingDao());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGenomeVersionExtractorForInvalidGenome() throws Exception {
+    try {
+      int version = connector.extractInt("");
+      assertEquals(0, version);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGenomeVersionExtractorForInvalidGenome2() throws Exception {
+    try {
+      int version = connector.extractInt("x");
+      assertEquals(0, version);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGenomeVersionExtractorForValid() throws Exception {
+    try {
+      int version = connector.extractInt("x1");
+      assertEquals(1, version);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGenomeVersionExtractorForValid2() throws Exception {
+    try {
+      int version = connector.extractInt("xy12z");
+      assertEquals(12, version);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRefreshCacheQueryNotAvailable() throws Exception {
+    WebPageDownloader downloader = connector.getWebPageDownloader();
+    GeneralCacheInterface originalCache = connector.getCache();
+    try {
+      // exclude first cached value
+      connector.setCache(null);
+      WebPageDownloader mockDownloader = Mockito.mock(WebPageDownloader.class);
+      when(mockDownloader.getFromNetwork(anyString(), anyString(), anyString())).thenThrow(new IOException());
+      connector.setWebPageDownloader(mockDownloader);
+      connector.refreshCacheQuery("http://google.pl/");
+      fail("Exception expected");
+    } catch (SourceNotAvailable e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      connector.setWebPageDownloader(downloader);
+      connector.setCache(originalCache);
+    }
+  }
+
+  @Test
+  public void testRefreshCacheQueryWhenFtpConnectionFails() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
+    String version = "sacCer3";
+
+    UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
+      @Override
+      FTPClient createFtpClient() {
+        FTPClient mockClient = Mockito.mock(FTPClient.class);
+        Mockito.doReturn(FTPReply.REQUEST_DENIED).when(mockClient).getReplyCode();
+        return mockClient;
+      }
+    };
+
+    try {
+      // exclude first cached value
+      connectorUnderTest.getGenomeVersionFile(yeast, version);
+      fail("Exception expected");
+    } catch (FileNotAvailableException e) {
+      assertTrue(e.getMessage().contains("FTP server refused connection"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetGenomeVersionFileWhenFtpConnectionFails2() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
+    String version = "sacCer3";
+
+    UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
+      @Override
+      FTPClient createFtpClient() {
+        FTPClient mockClient = Mockito.mock(FTPClient.class);
+        try {
+          Mockito.doThrow(new IOException()).when(mockClient).connect(anyString());
+          Mockito.doReturn(false).when(mockClient).isConnected();
+        } catch (Exception e) {
+          fail();
+        }
+        return mockClient;
+      }
+    };
+
+    try {
+      // exclude first cached value
+      connectorUnderTest.getGenomeVersionFile(yeast, version);
+      fail("Exception expected");
+    } catch (FileNotAvailableException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetGenomeVersionFileWhenFtpConnectionFails() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
+    String version = "sacCer3";
+
+    UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
+      @Override
+      FTPClient createFtpClient() {
+        FTPClient mockClient = Mockito.mock(FTPClient.class);
+        try {
+          Mockito.doThrow(new IOException()).when(mockClient).connect(anyString());
+          Mockito.doReturn(true).when(mockClient).isConnected();
+        } catch (Exception e) {
+          fail();
+        }
+        return mockClient;
+      }
+    };
+
+    try {
+      // exclude first cached value
+      connectorUnderTest.getGenomeVersionFile(yeast, version);
+      fail("Exception expected");
+    } catch (FileNotAvailableException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetGenomeVersionFileWhenFtpConnectionFails3() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
+    String version = "sacCer3";
+
+    UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
+      @Override
+      FTPClient createFtpClient() {
+        FTPClient mockClient = Mockito.mock(FTPClient.class);
+        try {
+          Mockito.doThrow(new IOException()).when(mockClient).connect(anyString());
+          Mockito.doReturn(true).when(mockClient).isConnected();
+          Mockito.doThrow(new IOException()).when(mockClient).disconnect();
+        } catch (Exception e) {
+          fail();
+        }
+        return mockClient;
+      }
+    };
+
+    try {
+      // exclude first cached value
+      connectorUnderTest.getGenomeVersionFile(yeast, version);
+      fail("Exception expected");
+    } catch (FileNotAvailableException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetGenomeVersionFileWhenFtpDisconnectConnectionFails() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
+    String version = "sacCer3";
+
+    UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
+      @Override
+      FTPClient createFtpClient() {
+        FTPClient mockClient = Mockito.mock(FTPClient.class);
+        try {
+          Mockito.doThrow(new IOException()).when(mockClient).disconnect();
+          Mockito.doReturn(new FTPFile[] {}).when(mockClient).listFiles(anyString());
+          Mockito.doReturn(FTPReply.COMMAND_OK).when(mockClient).getReplyCode();
+          Mockito.doReturn(true).when(mockClient).isConnected();
+        } catch (Exception e) {
+          fail();
+        }
+        return mockClient;
+      }
+    };
+
+    try {
+      // exclude first cached value
+      connectorUnderTest.getGenomeVersionFile(yeast, version);
+      fail("Exception expected");
+    } catch (FileNotAvailableException e) {
+      assertTrue(e.getMessage().contains("Problem with ftp connection"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetGenomeVersionFileWithMore2bitFiles() throws Exception {
+    MiriamData yeast = new MiriamData(MiriamType.TAXONOMY, "4932");
+    String version = "sacCer3";
+
+    UcscReferenceGenomeConnector connectorUnderTest = new UcscReferenceGenomeConnector() {
+      @Override
+      FTPClient createFtpClient() {
+        FTPClient mockClient = Mockito.mock(FTPClient.class);
+        try {
+          FTPFile file1 = new FTPFile();
+          file1.setName("1.2bit");
+          FTPFile file2 = new FTPFile();
+          file2.setName("2.2bit");
+          FTPFile[] files = new FTPFile[] { file1, file2 };
+
+          Mockito.doReturn(files).when(mockClient).listFiles(anyString());
+          Mockito.doReturn(FTPReply.COMMAND_OK).when(mockClient).getReplyCode();
+        } catch (Exception e) {
+          fail();
+        }
+        return mockClient;
+      }
+    };
+
+    try {
+      // exclude first cached value
+      String url = connectorUnderTest.getGenomeVersionFile(yeast, version);
+      assertEquals(1, getWarnings().size());
+      assertTrue(url.endsWith("1.2bit"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private void waitForDownload() throws InterruptedException {
+    while (connector.getDownloadThreadCount() > 0) {
+      logger.debug("Waiting for download to finish");
+      Thread.sleep(100);
+    }
+  }
 }
diff --git a/commons/src/main/java/lcsb/mapviewer/common/comparator/StringSetComparator.java b/commons/src/main/java/lcsb/mapviewer/common/comparator/StringSetComparator.java
index 201874c8bd606faaa39472d6bbbfc73f1bca8737..1e3c4759d40fdc9747cb2cd3a22a9d2f62b4c7df 100644
--- a/commons/src/main/java/lcsb/mapviewer/common/comparator/StringSetComparator.java
+++ b/commons/src/main/java/lcsb/mapviewer/common/comparator/StringSetComparator.java
@@ -1,48 +1,48 @@
-package lcsb.mapviewer.common.comparator;
-
-import java.util.Comparator;
-import java.util.Set;
-
-import org.apache.log4j.Logger;
-
-/**
- * Comparator used for comparing sets of strings.
- * 
- * @author Piotr Gawron
- * 
- */
-public class StringSetComparator implements Comparator<Set<String>> {
-	/**
-	 * Default class logger.
-	 */
-	private Logger	logger	= Logger.getLogger(StringSetComparator.class);
-
-	@Override
-	public int compare(Set<String> arg0, Set<String> arg1) {
-		if (arg0 == null) {
-			if (arg1 == null) {
-				return 0;
-			} else {
-				return 1;
-			}
-		} else if (arg1 == null) {
-			return -1;
-		}
-
-		for (String string : arg1) {
-			if (!arg0.contains(string)) {
-				logger.debug(string + " couldn't be found in " + arg0);
-				return 1;
-			}
-		}
-
-		for (String string : arg0) {
-			if (!arg1.contains(string)) {
-				logger.debug(string + " couldn't be found in " + arg1);
-				return -1;
-			}
-		}
-		return 0;
-	}
-
-}
+package lcsb.mapviewer.common.comparator;
+
+import java.util.Comparator;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Comparator used for comparing sets of strings.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class StringSetComparator implements Comparator<Set<String>> {
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(StringSetComparator.class);
+
+  @Override
+  public int compare(Set<String> arg0, Set<String> arg1) {
+    if (arg0 == null) {
+      if (arg1 == null) {
+        return 0;
+      } else {
+        return 1;
+      }
+    } else if (arg1 == null) {
+      return -1;
+    }
+
+    for (String string : arg1) {
+      if (!arg0.contains(string)) {
+        logger.debug(string + " couldn't be found in " + arg0);
+        return 1;
+      }
+    }
+
+    for (String string : arg0) {
+      if (!arg1.contains(string)) {
+        logger.debug(string + " couldn't be found in " + arg1);
+        return -1;
+      }
+    }
+    return 0;
+  }
+
+}
diff --git a/commons/src/main/java/lcsb/mapviewer/common/geometry/LineTransformation.java b/commons/src/main/java/lcsb/mapviewer/common/geometry/LineTransformation.java
index 89dc7109f73ea3e44caede6c204294c2d2c3a0de..85025057e118337ea06839372e38649379e3acb9 100644
--- a/commons/src/main/java/lcsb/mapviewer/common/geometry/LineTransformation.java
+++ b/commons/src/main/java/lcsb/mapviewer/common/geometry/LineTransformation.java
@@ -1,199 +1,199 @@
-package lcsb.mapviewer.common.geometry;
-
-import java.awt.geom.Line2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-
-import lcsb.mapviewer.common.Configuration;
-
-import org.apache.log4j.Logger;
-
-/**
- * Class with basic operators on lines.
- * 
- * @author Piotr Gawron
- * 
- */
-public class LineTransformation {
-
-	/**
-	 * Which value in the PathIterartor segment information array corrsepond to X
-	 * coordinate in the cubicTo type.
-	 */
-	private static final int	SEG_CUBICTO_END_Y_COORDINATE_INDEX		= 5;
-	/**
-	 * Which value in the PathIterartor segment information array corrsepond to Y
-	 * coordinate in the cubicTo type.
-	 */
-	private static final int	SEG_CUBICTO_END_X_COORDINATE_INDEX		= 4;
-	/**
-	 * Length of the PathIterartor segment information array.
-	 */
-	private static final int	PATH_ITERATOR_COORDINATES_STRUCT_SIZE	= 6;
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger			logger																= Logger.getLogger(LineTransformation.class.getName());
-
-	/**
-	 * Returns a cross point between path and a line.
-	 * 
-	 * @param line
-	 *          line for which we are looking for the intersection
-	 * @param pi
-	 *          PathIterator for which we are looking for the intersection
-	 * @return point of intersection beteewn path and line if the points doesn't
-	 *         exist then null is returned
-	 */
-	public Point2D getIntersectionWithPathIterator(final Line2D line, final PathIterator pi) {
-		if (pi == null) {
-			return null;
-		}
-		double[] coordinates = new double[PATH_ITERATOR_COORDINATES_STRUCT_SIZE];
-		Point2D first = null;
-		Point2D last = null;
-		Point2D actual = null;
-		while (!pi.isDone()) {
-			int type = pi.currentSegment(coordinates);
-			last = actual;
-			actual = new Point2D.Double(coordinates[0], coordinates[1]);
-			switch (type) {
-				case PathIterator.SEG_MOVETO:
-					break;
-				case PathIterator.SEG_LINETO:
-					break;
-				case PathIterator.SEG_QUADTO:
-					break;
-				case PathIterator.SEG_CUBICTO:
-
-					// in case when there is an arc we define only end points of the arc
-					// as a border
-					actual = new Point2D.Double(coordinates[SEG_CUBICTO_END_X_COORDINATE_INDEX], coordinates[SEG_CUBICTO_END_Y_COORDINATE_INDEX]);
-					break;
-				case PathIterator.SEG_CLOSE:
-					actual = first;
-					break;
-				default:
-					break;
-			}
-			if (first == null) {
-				first = actual;
-
-				// check if the two following points are not the same (this could cause
-				// NaN values)
-			} else if (last.distance(actual) > Configuration.EPSILON) {
-				double x1 = last.getX();
-				double y1 = last.getY();
-				double x2 = actual.getX();
-				double y2 = actual.getY();
-				double x3 = line.getX1();
-				double y3 = line.getY1();
-				double x4 = line.getX2();
-				double y4 = line.getY2();
-				if (Line2D.linesIntersect(x1, y1, x2, y2, x3, y3, x4, y4)) {
-					double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
-					double xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
-					double yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
-					return new Point2D.Double(xi, yi);
-				}
-			}
-
-			pi.next();
-		}
-		return null;
-	}
-
-	/**
-	 * Returns a distance between line segment and a point.
-	 * 
-	 * @param line
-	 *          line segment to which we are looking the shortest distance
-	 * @param point
-	 *          point from which are looking the shortest distance
-	 * @return distance between line and a point
-	 */
-	public double distBetweenPointAndLineSegment(final Line2D line, final Point2D point) {
-		return distBetweenPointAndLineSegment(line.getP1(), line.getP2(), point);
-	}
-
-	/**
-	 * Returns a distance between line segment (defined by v and w points) and a
-	 * point.
-	 * 
-	 * @param v
-	 *          start point of the line
-	 * @param w
-	 *          end point of the line
-	 * @param point
-	 *          point from which we want to find a distance
-	 * @return distance between point and line segment
-	 */
-	public double distBetweenPointAndLineSegment(final Point2D v, final Point2D w, final Point2D point) {
-		// Return minimum distance between line segment vw and point p
-		double l2 = v.distanceSq(w); // i.e. |w-v|^2 - avoid a sqrt
-		if (l2 == 0.0) {
-			return point.distance(v); // v == w case
-		}
-		// Consider the line extending the segment, parameterized as v + t (w - v).
-		// We find projection of point p onto the line.
-		// It falls where t = [(p-v) . (w-v)] / |w-v|^2
-		double t = ((point.getX() - v.getX()) * (w.getX() - v.getX()) + (point.getY() - v.getY()) * (w.getY() - v.getY())) / l2;
-		if (t < 0.0) {
-			return point.distance(v); // Beyond the 'v' end of the segment
-		} else if (t > 1.0) {
-			return point.distance(w); // Beyond the 'w' end of the segment
-		}
-		// Projection falls on the segment
-		return point.distance(v.getX() + t * (w.getX() - v.getX()), v.getY() + t * (w.getY() - v.getY()));
-	}
-
-	/**
-	 * Returns a point that is on the line and is as close as possible to the
-	 * point.
-	 * 
-	 * @param line
-	 *          line on which the point should be found
-	 * @param point
-	 *          point to which the result should be as close as possible
-	 * @return point on the line that is as close as possible to the parameter
-	 *         point
-	 */
-	public Point2D closestPointOnSegmentLineToPoint(final Line2D line, final Point2D point) {
-		Point2D result = closestPointOnSegmentLineToPoint(line.getP1(), line.getP2(), point);
-		return result;
-	}
-
-	/**
-	 * Returns a point that is on the line (v-w) and is as close as possible to
-	 * the point.
-	 * 
-	 * @param v
-	 *          start of the line segment
-	 * @param w
-	 *          end of the line segment
-	 * @param p
-	 *          point to which the result should be as close as possible
-	 * @return point on the line (v-w) that is as close as possible to the
-	 *         parameter point
-	 */
-	public Point2D closestPointOnSegmentLineToPoint(final Point2D v, final Point2D w, final Point2D p) {
-		// Return minimum distance between line segment vw and point p
-		double l2 = v.distanceSq(w); // i.e. |w-v|^2 - avoid a sqrt
-		if (l2 == 0.0) {
-			return v; // v == w case
-		}
-		// Consider the line extending the segment, parameterized as v + t (w - v).
-		// We find projection of point p onto the line.
-		// It falls where t = [(p-v) . (w-v)] / |w-v|^2
-		double t = ((p.getX() - v.getX()) * (w.getX() - v.getX()) + (p.getY() - v.getY()) * (w.getY() - v.getY())) / l2;
-		if (t < 0.0) {
-			return v; // Beyond the 'v' end of the segment
-		} else if (t > 1.0) {
-			return w; // Beyond the 'w' end of the segment
-		}
-		// Projection falls on the segment
-		return new Point2D.Double(v.getX() + t * (w.getX() - v.getX()), v.getY() + t * (w.getY() - v.getY()));
-	}
-
-}
+package lcsb.mapviewer.common.geometry;
+
+import java.awt.geom.Line2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.Configuration;
+
+/**
+ * Class with basic operators on lines.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class LineTransformation {
+
+  /**
+   * Which value in the PathIterartor segment information array corrsepond to X
+   * coordinate in the cubicTo type.
+   */
+  private static final int SEG_CUBICTO_END_Y_COORDINATE_INDEX = 5;
+  /**
+   * Which value in the PathIterartor segment information array corrsepond to Y
+   * coordinate in the cubicTo type.
+   */
+  private static final int SEG_CUBICTO_END_X_COORDINATE_INDEX = 4;
+  /**
+   * Length of the PathIterartor segment information array.
+   */
+  private static final int PATH_ITERATOR_COORDINATES_STRUCT_SIZE = 6;
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(LineTransformation.class.getName());
+
+  /**
+   * Returns a cross point between path and a line.
+   * 
+   * @param line
+   *          line for which we are looking for the intersection
+   * @param pi
+   *          PathIterator for which we are looking for the intersection
+   * @return point of intersection between path and line if the points doesn't
+   *         exist then null is returned
+   */
+  public Point2D getIntersectionWithPathIterator(final Line2D line, final PathIterator pi) {
+    if (pi == null) {
+      return null;
+    }
+    double[] coordinates = new double[PATH_ITERATOR_COORDINATES_STRUCT_SIZE];
+    Point2D first = null;
+    Point2D last = null;
+    Point2D actual = null;
+    while (!pi.isDone()) {
+      int type = pi.currentSegment(coordinates);
+      last = actual;
+      actual = new Point2D.Double(coordinates[0], coordinates[1]);
+      switch (type) {
+      case PathIterator.SEG_MOVETO:
+        break;
+      case PathIterator.SEG_LINETO:
+        break;
+      case PathIterator.SEG_QUADTO:
+        break;
+      case PathIterator.SEG_CUBICTO:
+
+        // in case when there is an arc we define only end points of the arc
+        // as a border
+        actual = new Point2D.Double(coordinates[SEG_CUBICTO_END_X_COORDINATE_INDEX],
+            coordinates[SEG_CUBICTO_END_Y_COORDINATE_INDEX]);
+        break;
+      case PathIterator.SEG_CLOSE:
+        actual = first;
+        break;
+      default:
+        break;
+      }
+      if (first == null) {
+        first = actual;
+
+        // check if the two following points are not the same (this could cause
+        // NaN values)
+      } else if (last.distance(actual) > Configuration.EPSILON) {
+        double x1 = last.getX();
+        double y1 = last.getY();
+        double x2 = actual.getX();
+        double y2 = actual.getY();
+        double x3 = line.getX1();
+        double y3 = line.getY1();
+        double x4 = line.getX2();
+        double y4 = line.getY2();
+        if (Line2D.linesIntersect(x1, y1, x2, y2, x3, y3, x4, y4)) {
+          double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
+          double xi = ((x3 - x4) * (x1 * y2 - y1 * x2) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
+          double yi = ((y3 - y4) * (x1 * y2 - y1 * x2) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
+          return new Point2D.Double(xi, yi);
+        }
+      }
+
+      pi.next();
+    }
+    return null;
+  }
+
+  /**
+   * Returns a distance between line segment and a point.
+   * 
+   * @param line
+   *          line segment to which we are looking the shortest distance
+   * @param point
+   *          point from which are looking the shortest distance
+   * @return distance between line and a point
+   */
+  public double distBetweenPointAndLineSegment(final Line2D line, final Point2D point) {
+    return distBetweenPointAndLineSegment(line.getP1(), line.getP2(), point);
+  }
+
+  /**
+   * Returns a distance between line segment (defined by v and w points) and a
+   * point.
+   * 
+   * @param v
+   *          start point of the line
+   * @param w
+   *          end point of the line
+   * @param point
+   *          point from which we want to find a distance
+   * @return distance between point and line segment
+   */
+  public double distBetweenPointAndLineSegment(final Point2D v, final Point2D w, final Point2D point) {
+    // Return minimum distance between line segment vw and point p
+    double l2 = v.distanceSq(w); // i.e. |w-v|^2 - avoid a sqrt
+    if (l2 == 0.0) {
+      return point.distance(v); // v == w case
+    }
+    // Consider the line extending the segment, parameterized as v + t (w - v).
+    // We find projection of point p onto the line.
+    // It falls where t = [(p-v) . (w-v)] / |w-v|^2
+    double t = ((point.getX() - v.getX()) * (w.getX() - v.getX()) + (point.getY() - v.getY()) * (w.getY() - v.getY()))
+        / l2;
+    if (t < 0.0) {
+      return point.distance(v); // Beyond the 'v' end of the segment
+    } else if (t > 1.0) {
+      return point.distance(w); // Beyond the 'w' end of the segment
+    }
+    // Projection falls on the segment
+    return point.distance(v.getX() + t * (w.getX() - v.getX()), v.getY() + t * (w.getY() - v.getY()));
+  }
+
+  /**
+   * Returns a point that is on the line and is as close as possible to the point.
+   * 
+   * @param line
+   *          line on which the point should be found
+   * @param point
+   *          point to which the result should be as close as possible
+   * @return point on the line that is as close as possible to the parameter point
+   */
+  public Point2D closestPointOnSegmentLineToPoint(final Line2D line, final Point2D point) {
+    Point2D result = closestPointOnSegmentLineToPoint(line.getP1(), line.getP2(), point);
+    return result;
+  }
+
+  /**
+   * Returns a point that is on the line (v-w) and is as close as possible to the
+   * point.
+   * 
+   * @param v
+   *          start of the line segment
+   * @param w
+   *          end of the line segment
+   * @param p
+   *          point to which the result should be as close as possible
+   * @return point on the line (v-w) that is as close as possible to the parameter
+   *         point
+   */
+  public Point2D closestPointOnSegmentLineToPoint(final Point2D v, final Point2D w, final Point2D p) {
+    // Return minimum distance between line segment vw and point p
+    double l2 = v.distanceSq(w); // i.e. |w-v|^2 - avoid a sqrt
+    if (l2 == 0.0) {
+      return v; // v == w case
+    }
+    // Consider the line extending the segment, parameterized as v + t (w - v).
+    // We find projection of point p onto the line.
+    // It falls where t = [(p-v) . (w-v)] / |w-v|^2
+    double t = ((p.getX() - v.getX()) * (w.getX() - v.getX()) + (p.getY() - v.getY()) * (w.getY() - v.getY())) / l2;
+    if (t < 0.0) {
+      return v; // Beyond the 'v' end of the segment
+    } else if (t > 1.0) {
+      return w; // Beyond the 'w' end of the segment
+    }
+    // Projection falls on the segment
+    return new Point2D.Double(v.getX() + t * (w.getX() - v.getX()), v.getY() + t * (w.getY() - v.getY()));
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerElementCollection.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerElementCollection.java
index 685768126502bce1aac27fae0f11a2adb1a8c303..477a446ee6c97c1994c57505e4f0eecc82caa0ac 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerElementCollection.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerElementCollection.java
@@ -17,9 +17,8 @@ import lcsb.mapviewer.model.map.species.Gene;
 import lcsb.mapviewer.model.map.species.Protein;
 import lcsb.mapviewer.model.map.species.Rna;
 import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
+import lcsb.mapviewer.model.map.species.field.AbstractSiteModification;
 import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
 
 /**
  * This structure contains information about {@link CellDesignerElement
@@ -28,216 +27,215 @@ import lcsb.mapviewer.model.map.species.field.RnaRegion;
  */
 public class CellDesignerElementCollection {
 
-	/**
-	 * Element by element identifier (it's CellDesigner identifier).
-	 */
-	private Map<String, CellDesignerElement<?>> elementById = new HashMap<>();
-
-	/**
-	 * Returns element by given identifier.
-	 * 
-	 * @param speciesId
-	 *          element identifier
-	 * @return element by given identifier
-	 * 
-	 * @param <T>
-	 *          type of returned object
-	 */
-	@SuppressWarnings("unchecked")
-	public <T extends CellDesignerElement<?>> T getElementByElementId(String speciesId) {
-		return (T) elementById.get(speciesId);
-	}
-
-	/**
-	 * 
-	 */
-	private Map<String, String> sbmlIdByElement = new HashMap<>();
-
-	/**
-	 * Returns element identifier that should be used for model element when
-	 * creating cell designer xml file.
-	 * 
-	 * @param modelElement
-	 *          model element for which we want to obtain identifier
-	 * @return identifier of cell designer element that will be exported
-	 */
-	public String getElementId(Element modelElement) {
-		if ("default".equals(modelElement.getElementId())) {
-			return modelElement.getElementId();
-		} else {
-			String sbmlId = getSbmlId(modelElement, true);
-			if (sbmlIdByElement.get(sbmlId) == null) {
-				String id = "s_id_" + modelElement.getElementId();
-				if (sbmlIdByElement.values().contains(id)) {
-					throw new InvalidArgumentException("id duplicates");
-				}
-				sbmlIdByElement.put(sbmlId, id);
-			}
-			return sbmlIdByElement.get(sbmlId);
-
-		}
-	}
-
-	/**
-	 * Creates a String that identifies element as distinct SBML entity.
-	 * 
-	 * @param modelElement
-	 *          element that we want to identify
-	 * @param useComplex
-	 *          should we use identifier of a complex. This should be used by
-	 *          default (because if the complex is different then element should
-	 *          have different identifier). However, when element asks complex for
-	 *          id, complex will try to resolve ids of children (because this is
-	 *          what defines complex identity), and in such situation it should
-	 *          disable resolving complex, because there will by infinity cyclic
-	 *          calls and stack overflow error will be thrown.
-	 * @return unique String for SBML entity
-	 */
-	private String getSbmlId(Element modelElement, boolean useComplex) {
-		String compartmenName = "default";
-		if (modelElement.getCompartment() != null) {
-			compartmenName = modelElement.getCompartment().getName();
-		}
-
-		String modifications = "";
-		if (modelElement instanceof AntisenseRna) {
-			AntisenseRna asAntisenseRna = ((AntisenseRna) modelElement);
-			for (AntisenseRnaRegion region : asAntisenseRna.getRegions()) {
-				modifications += region.getState();
-			}
-		} else if (modelElement instanceof Gene) {
-			Gene asGene = ((Gene) modelElement);
-			for (ModificationResidue region : asGene.getModificationResidues()) {
-				modifications += region.getState();
-			}
-		} else if (modelElement instanceof Protein) {
-			Protein asProtein = ((Protein) modelElement);
-			modifications = asProtein.getStructuralState();
-			for (ModificationResidue region : asProtein.getModificationResidues()) {
-				modifications += region.getState();
-			}
-		} else if (modelElement instanceof Rna) {
-			Rna asRna = ((Rna) modelElement);
-			for (RnaRegion region : asRna.getRegions()) {
-				modifications += region.getState();
-			}
-		} else if (modelElement instanceof Complex) {
-			Complex asComplex = ((Complex) modelElement);
-			modifications = asComplex.getStructuralState();
-		}
-
-		String complexId = "";
-		String homodimer = "";
-		if (modelElement instanceof Species) {
-			homodimer = ((Species) modelElement).getHomodimer() + "";
-			if (((Species) modelElement).getComplex() != null) {
-				if (useComplex) {
-					if (!isCyclicNesting(((Species) modelElement).getComplex())) {
-						complexId = getElementId(((Species) modelElement).getComplex());
-					} else {
-						throw new InvalidArgumentException("Cycling nested structure found in element: " + modelElement.getElementId());
-					}
-				} else {
-					complexId = ((Species) modelElement).getComplex().getName();
-				}
-			}
-		}
-		String childrenId = "";
-		if (modelElement instanceof Complex) {
-			Complex asComplex = (Complex) modelElement;
-			List<String> childIds = new ArrayList<>();
-			for (Species child : asComplex.getAllChildren()) {
-				childIds.add(getSbmlId(child, false));
-			}
-			Collections.sort(childIds);
-			for (String string : childIds) {
-				childrenId += string + "\n";
-			}
-		}
-
-		// identifier that distinguish elements in SBML depends only on type,
-		// name, compartment, modifications, homodimer, state, complex where it's
-		// located,
-		// children of the complex
-		String sbmlId = compartmenName + "\n" + modelElement.getName() + "\n" + modelElement.getStringType() + "\n" + modifications + "\n" + complexId + "\n"
-				+ homodimer + "\n" + childrenId;
-
-		return sbmlId;
-	}
-
-	/**
-	 * Checks if complex parenting is cyclic.
-	 * 
-	 * @param complex
-	 *          complex for which data is checked
-	 * @return true if parent of the complex is also a (grand)child of this
-	 *         complex, false otherwise
-	 */
-	private boolean isCyclicNesting(Complex complex) {
-		Set<Complex> foundComplexes = new HashSet<>();
-		while (complex != null) {
-			if (foundComplexes.contains(complex)) {
-				return true;
-			}
-			foundComplexes.add(complex);
-			complex = complex.getComplex();
-		}
-		return false;
-	}
-
-	/**
-	 * Adds cell designer structures.
-	 * 
-	 * @param elements
-	 *          list of objects to add
-	 */
-	public void addElements(List<? extends CellDesignerElement<?>> elements) {
-		for (CellDesignerElement<?> element : elements) {
-			addElement(element);
-		}
-	}
-
-	/**
-	 * Adds cell designer object.
-	 * 
-	 * @param element
-	 *          object to add
-	 */
-	public void addElement(CellDesignerElement<?> element) {
-		addElement(element, element.getElementId());
-	}
-
-	/**
-	 * Adds CellDesigner element with custom id (instead the one obtained from
-	 * CellDesigner structure).
-	 * 
-	 * @param element
-	 *          element to be add
-	 * @param id
-	 *          id that should be used for identifying element
-	 */
-	public void addElement(CellDesignerElement<?> element, String id) {
-		if (elementById.get(id) != null) {
-			throw new InvalidArgumentException(
-					"[" + element.getClass().getSimpleName() + " " + element.getElementId() + "]\t" + "Element with given id alread exists. ID: " + id);
-		}
-		elementById.put(id, element);
-	}
-
-	/**
-	 * Adds CellDesigner structure in a way that it would be accessed via
-	 * identifier for model structure. Method used only for unit test.
-	 * 
-	 * @param modelElement
-	 *          model element that will create identifier
-	 * @param element
-	 *          element to be added
-	 */
-	public void addModelElement(Element modelElement, CellDesignerElement<?> element) {
-		addElement(element, getElementId(modelElement));
-		if (getElementByElementId(element.getElementId()) == null) {
-			addElement(element);
-		}
-	}
+  /**
+   * Element by element identifier (it's CellDesigner identifier).
+   */
+  private Map<String, CellDesignerElement<?>> elementById = new HashMap<>();
+
+  /**
+   * Returns element by given identifier.
+   * 
+   * @param speciesId
+   *          element identifier
+   * @return element by given identifier
+   * 
+   * @param <T>
+   *          type of returned object
+   */
+  @SuppressWarnings("unchecked")
+  public <T extends CellDesignerElement<?>> T getElementByElementId(String speciesId) {
+    return (T) elementById.get(speciesId);
+  }
+
+  /**
+   * 
+   */
+  private Map<String, String> sbmlIdByElement = new HashMap<>();
+
+  /**
+   * Returns element identifier that should be used for model element when
+   * creating cell designer xml file.
+   * 
+   * @param modelElement
+   *          model element for which we want to obtain identifier
+   * @return identifier of cell designer element that will be exported
+   */
+  public String getElementId(Element modelElement) {
+    if ("default".equals(modelElement.getElementId())) {
+      return modelElement.getElementId();
+    } else {
+      String sbmlId = getSbmlId(modelElement, true);
+      if (sbmlIdByElement.get(sbmlId) == null) {
+        String id = "s_id_" + modelElement.getElementId();
+        if (sbmlIdByElement.values().contains(id)) {
+          throw new InvalidArgumentException("id duplicates");
+        }
+        sbmlIdByElement.put(sbmlId, id);
+      }
+      return sbmlIdByElement.get(sbmlId);
+
+    }
+  }
+
+  /**
+   * Creates a String that identifies element as distinct SBML entity.
+   * 
+   * @param modelElement
+   *          element that we want to identify
+   * @param useComplex
+   *          should we use identifier of a complex. This should be used by
+   *          default (because if the complex is different then element should
+   *          have different identifier). However, when element asks complex for
+   *          id, complex will try to resolve ids of children (because this is
+   *          what defines complex identity), and in such situation it should
+   *          disable resolving complex, because there will by infinity cyclic
+   *          calls and stack overflow error will be thrown.
+   * @return unique String for SBML entity
+   */
+  private String getSbmlId(Element modelElement, boolean useComplex) {
+    String compartmenName = "default";
+    if (modelElement.getCompartment() != null) {
+      compartmenName = modelElement.getCompartment().getName();
+    }
+
+    String modifications = "";
+    List<ModificationResidue> regions = new ArrayList<>();
+    if (modelElement instanceof AntisenseRna) {
+      AntisenseRna asAntisenseRna = ((AntisenseRna) modelElement);
+      regions.addAll(asAntisenseRna.getRegions());
+    } else if (modelElement instanceof Gene) {
+      Gene asGene = ((Gene) modelElement);
+      regions.addAll(asGene.getModificationResidues());
+    } else if (modelElement instanceof Protein) {
+      Protein asProtein = ((Protein) modelElement);
+      modifications = asProtein.getStructuralState();
+      regions.addAll(asProtein.getModificationResidues());
+    } else if (modelElement instanceof Rna) {
+      Rna asRna = ((Rna) modelElement);
+      regions.addAll(asRna.getRegions());
+    } else if (modelElement instanceof Complex) {
+      Complex asComplex = ((Complex) modelElement);
+      modifications = asComplex.getStructuralState();
+    }
+    for (ModificationResidue region : regions) {
+      if (region instanceof AbstractSiteModification) {
+        modifications += ((AbstractSiteModification) region).getState();
+      }
+    }
+
+    String complexId = "";
+    String homodimer = "";
+    if (modelElement instanceof Species) {
+      homodimer = ((Species) modelElement).getHomodimer() + "";
+      if (((Species) modelElement).getComplex() != null) {
+        if (useComplex) {
+          if (!isCyclicNesting(((Species) modelElement).getComplex())) {
+            complexId = getElementId(((Species) modelElement).getComplex());
+          } else {
+            throw new InvalidArgumentException(
+                "Cycling nested structure found in element: " + modelElement.getElementId());
+          }
+        } else {
+          complexId = ((Species) modelElement).getComplex().getName();
+        }
+      }
+    }
+    String childrenId = "";
+    if (modelElement instanceof Complex) {
+      Complex asComplex = (Complex) modelElement;
+      List<String> childIds = new ArrayList<>();
+      for (Species child : asComplex.getAllChildren()) {
+        childIds.add(getSbmlId(child, false));
+      }
+      Collections.sort(childIds);
+      for (String string : childIds) {
+        childrenId += string + "\n";
+      }
+    }
+
+    // identifier that distinguish elements in SBML depends only on type,
+    // name, compartment, modifications, homodimer, state, complex where it's
+    // located,
+    // children of the complex
+    String sbmlId = compartmenName + "\n" + modelElement.getName() + "\n" + modelElement.getStringType() + "\n"
+        + modifications + "\n" + complexId + "\n" + homodimer + "\n" + childrenId;
+
+    return sbmlId;
+  }
+
+  /**
+   * Checks if complex parenting is cyclic.
+   * 
+   * @param complex
+   *          complex for which data is checked
+   * @return true if parent of the complex is also a (grand)child of this complex,
+   *         false otherwise
+   */
+  private boolean isCyclicNesting(Complex complex) {
+    Set<Complex> foundComplexes = new HashSet<>();
+    while (complex != null) {
+      if (foundComplexes.contains(complex)) {
+        return true;
+      }
+      foundComplexes.add(complex);
+      complex = complex.getComplex();
+    }
+    return false;
+  }
+
+  /**
+   * Adds cell designer structures.
+   * 
+   * @param elements
+   *          list of objects to add
+   */
+  public void addElements(List<? extends CellDesignerElement<?>> elements) {
+    for (CellDesignerElement<?> element : elements) {
+      addElement(element);
+    }
+  }
+
+  /**
+   * Adds cell designer object.
+   * 
+   * @param element
+   *          object to add
+   */
+  public void addElement(CellDesignerElement<?> element) {
+    addElement(element, element.getElementId());
+  }
+
+  /**
+   * Adds CellDesigner element with custom id (instead the one obtained from
+   * CellDesigner structure).
+   * 
+   * @param element
+   *          element to be add
+   * @param id
+   *          id that should be used for identifying element
+   */
+  public void addElement(CellDesignerElement<?> element, String id) {
+    if (elementById.get(id) != null) {
+      throw new InvalidArgumentException("[" + element.getClass().getSimpleName() + " " + element.getElementId() + "]\t"
+          + "Element with given id alread exists. ID: " + id);
+    }
+    elementById.put(id, element);
+  }
+
+  /**
+   * Adds CellDesigner structure in a way that it would be accessed via identifier
+   * for model structure. Method used only for unit test.
+   * 
+   * @param modelElement
+   *          model element that will create identifier
+   * @param element
+   *          element to be added
+   */
+  public void addModelElement(Element modelElement, CellDesignerElement<?> element) {
+    addElement(element, getElementId(modelElement));
+    if (getElementByElementId(element.getElementId()) == null) {
+      addElement(element);
+    }
+  }
 
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/SpeciesAliasXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/SpeciesAliasXmlParser.java
index c92137511e64402519dcbd6714373403b9a57589..30ab81753601fb2038ed17e7c881db0dc4b95766 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/SpeciesAliasXmlParser.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/alias/SpeciesAliasXmlParser.java
@@ -1,252 +1,255 @@
-package lcsb.mapviewer.converter.model.celldesigner.alias;
-
-import org.apache.log4j.Logger;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
-import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerComplexSpecies;
-import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerElement;
-import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerSpecies;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.View;
-import lcsb.mapviewer.model.map.compartment.Compartment;
-import lcsb.mapviewer.model.map.compartment.PathwayCompartment;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelData;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.Species;
-
-/**
- * Parser of CellDesigner xml used for parsing SpeciesAlias.
- * 
- * @author Piotr Gawron
- * 
- * @see Complex
- */
-public class SpeciesAliasXmlParser extends AbstractAliasXmlParser<Species> {
-  /**
-   * Default class logger.
-   */
-  private Logger logger = Logger.getLogger(SpeciesAliasXmlParser.class.getName());
-
-  /**
-   * Collection of {@link CellDesignerElement cell designer elements} parsed from
-   * xml.
-   */
-  private CellDesignerElementCollection elements;
-
-  /**
-   * Model for which we parse elements.
-   */
-  private Model model;
-
-  /**
-   * Default constructor with model object for which we parse data.
-   * 
-   * @param model
-   *          model for which we parse elements
-   * @param elements
-   *          collection of {@link CellDesignerElement cell designer elements}
-   *          parsed from xml
-   */
-  public SpeciesAliasXmlParser(CellDesignerElementCollection elements, Model model) {
-    this.elements = elements;
-    this.model = model;
-  }
-
-  @Override
-  Species parseXmlAlias(Node aliasNode) throws InvalidXmlSchemaException {
-
-    String speciesId = getNodeAttr("species", aliasNode);
-    String aliasId = getNodeAttr("id", aliasNode);
-    CellDesignerSpecies<?> species = elements.getElementByElementId(speciesId);
-    if (species == null) {
-      throw new InvalidXmlSchemaException("Unknown species for alias (speciesId: " + speciesId + ")");
-    }
-    if (species instanceof CellDesignerComplexSpecies) {
-      logger.warn("[" + speciesId + "," + aliasId
-          + "]\tSpecies is defined as a complex, but alias is not a complex. Changing alias to complex.");
-    }
-
-    elements.addElement(species, aliasId);
-    Species result = species.createModelElement(aliasId);
-
-    String state = "usual";
-    NodeList nodes = aliasNode.getChildNodes();
-    View usualView = null;
-    View briefView = null;
-    for (int x = 0; x < nodes.getLength(); x++) {
-      Node node = nodes.item(x);
-      if (node.getNodeType() == Node.ELEMENT_NODE) {
-        if (node.getNodeName().equalsIgnoreCase("celldesigner:activity")) {
-          result.setActivity(getNodeValue(node).equalsIgnoreCase("active"));
-        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:bounds")) {
-          result.setX(getNodeAttr("X", node));
-          result.setY(getNodeAttr("Y", node));
-        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:font")) {
-          result.setFontSize(getNodeAttr("size", node));
-        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:view")) {
-          state = getNodeAttr("state", node);
-        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:usualView")) {
-          usualView = getCommonParser().getView(node);
-        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:briefView")) {
-          briefView = getCommonParser().getView(node);
-        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:info")) {
-          processAliasState(node, result);
-        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:structuralState")) {
-          // not handled
-          continue;
-        } else {
-          throw new InvalidXmlSchemaException("Unknown element of celldesigner:speciesAlias: " + node.getNodeName());
-        }
-      }
-    }
-
-    View view = null;
-    if (state.equalsIgnoreCase("usual")) {
-      view = usualView;
-    } else if (state.equalsIgnoreCase("brief")) {
-      view = briefView;
-    }
-
-    if (view != null) {
-      // inner position defines the position in compartment
-      // result.moveBy(view.innerPosition);
-      result.setWidth(view.getBoxSize().width);
-      result.setHeight(view.getBoxSize().height);
-      result.setLineWidth(view.getSingleLine().getWidth());
-      result.setColor(view.getColor());
-    } else {
-      throw new InvalidXmlSchemaException("No view in Alias");
-    }
-    result.setState(state);
-    String compartmentAliasId = getNodeAttr("compartmentAlias", aliasNode);
-    if (!compartmentAliasId.isEmpty()) {
-      Compartment compartment = model.getElementByElementId(compartmentAliasId);
-      if (compartment == null) {
-        throw new InvalidXmlSchemaException("CompartmentAlias does not exist: " + compartmentAliasId);
-      } else {
-        result.setCompartment(compartment);
-        compartment.addElement(result);
-      }
-    }
-    String complexAliasId = getNodeAttr("complexSpeciesAlias", aliasNode);
-    if (!complexAliasId.isEmpty()) {
-      Complex complex = model.getElementByElementId(complexAliasId);
-      if (complex == null) {
-        throw new InvalidXmlSchemaException(
-            "ComplexAlias does not exist: " + complexAliasId + ", current: " + result.getElementId());
-      } else {
-        result.setComplex(complex);
-        complex.addSpecies(result);
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Process node with information about alias state and puts data into alias.
-   * 
-   * @param node
-   *          node where information about alias state is stored
-   * @param alias
-   *          alias object to be modified if necessary
-   */
-  private void processAliasState(Node node, Species alias) {
-    String state = getNodeAttr("state", node);
-    if ("open".equalsIgnoreCase(state)) {
-      String prefix = getNodeAttr("prefix", node);
-      String label = getNodeAttr("label", node);
-      alias.setStatePrefix(prefix);
-      alias.setStateLabel(label);
-    } else if ("empty".equalsIgnoreCase(state)) {
-      return;
-    } else if (state == null || state.isEmpty()) {
-      return;
-    } else {
-      throw new NotImplementedException("[Alias: " + alias.getElementId() + "] Unkown alias state: " + state);
-    }
-
-  }
-
-  @Override
-  public String toXml(Species species) {
-    Compartment ca = null;
-    // artificial compartment aliases should be excluded
-    if (species.getCompartment() != null && !(species.getCompartment() instanceof PathwayCompartment)) {
-      ca = (Compartment) species.getCompartment();
-    } else if (species.getComplex() == null) {
-      ModelData model = species.getModelData();
-      if (model != null) {
-        for (Compartment cAlias : model.getModel().getCompartments()) {
-          if (!(cAlias instanceof PathwayCompartment) && cAlias.cross(species)) {
-            if (ca == null) {
-              ca = cAlias;
-            } else if (ca.getSize() > cAlias.getSize()) {
-              ca = cAlias;
-            }
-          }
-        }
-      }
-    }
-
-    Complex complex = species.getComplex();
-
-    String compartmentAliasId = null;
-    if (ca != null) {
-      compartmentAliasId = ca.getElementId();
-    }
-    StringBuilder sb = new StringBuilder("");
-    sb.append("<celldesigner:speciesAlias ");
-    sb.append("id=\"" + species.getElementId() + "\" ");
-    sb.append("species=\"" + elements.getElementId(species) + "\" ");
-    if (compartmentAliasId != null) {
-      sb.append("compartmentAlias=\"" + compartmentAliasId + "\" ");
-    }
-
-    if (complex != null) {
-      sb.append("complexSpeciesAlias=\"" + complex.getElementId() + "\" ");
-    }
-    sb.append(">\n");
-
-    if (species.getActivity() != null) {
-      if (species.getActivity()) {
-        sb.append("<celldesigner:activity>active</celldesigner:activity>\n");
-      } else {
-        sb.append("<celldesigner:activity>inactive</celldesigner:activity>\n");
-      }
-    }
-
-    sb.append("<celldesigner:bounds ");
-    sb.append("x=\"" + species.getX() + "\" ");
-    sb.append("y=\"" + species.getY() + "\" ");
-    sb.append("w=\"" + species.getWidth() + "\" ");
-    sb.append("h=\"" + species.getHeight() + "\" ");
-    sb.append("/>\n");
-
-    sb.append("<celldesigner:font size=\"" + species.getFontSize() + "\"/>\n");
-
-    // TODO to be improved
-    sb.append("<celldesigner:view state=\"usual\"/>\n");
-    sb.append("<celldesigner:usualView>");
-    sb.append("<celldesigner:innerPosition x=\"" + species.getX() + "\" y=\"" + species.getY() + "\"/>");
-    sb.append("<celldesigner:boxSize width=\"" + species.getWidth() + "\" height=\"" + species.getHeight() + "\"/>");
-    sb.append("<celldesigner:singleLine width=\"" + species.getLineWidth() + "\"/>");
-    sb.append("<celldesigner:paint color=\"" + colorToString(species.getColor()) + "\" scheme=\"Color\"/>");
-    sb.append("</celldesigner:usualView>\n");
-    sb.append("<celldesigner:briefView>");
-    sb.append("<celldesigner:innerPosition x=\"" + species.getX() + "\" y=\"" + species.getY() + "\"/>");
-    sb.append("<celldesigner:boxSize width=\"" + species.getWidth() + "\" height=\"" + species.getHeight() + "\"/>");
-    sb.append("<celldesigner:singleLine width=\"" + species.getLineWidth() + "\"/>");
-    sb.append("<celldesigner:paint color=\"" + colorToString(species.getColor()) + "\" scheme=\"Color\"/>");
-    sb.append("</celldesigner:briefView>\n");
-    if (species.getStateLabel() != null || species.getStatePrefix() != null) {
-      sb.append("<celldesigner:info state=\"open\" prefix=\"" + species.getStatePrefix() + "\" label=\""
-          + species.getStateLabel() + "\"/>\n");
-    }
-    sb.append("</celldesigner:speciesAlias>\n");
-    return sb.toString();
-  }
-}
+package lcsb.mapviewer.converter.model.celldesigner.alias;
+
+import org.apache.log4j.Logger;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
+import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerComplexSpecies;
+import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerElement;
+import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerSpecies;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.View;
+import lcsb.mapviewer.model.map.compartment.Compartment;
+import lcsb.mapviewer.model.map.compartment.PathwayCompartment;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelData;
+import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * Parser of CellDesigner xml used for parsing SpeciesAlias.
+ * 
+ * @author Piotr Gawron
+ * 
+ * @see Complex
+ */
+public class SpeciesAliasXmlParser extends AbstractAliasXmlParser<Species> {
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(SpeciesAliasXmlParser.class.getName());
+
+  /**
+   * Collection of {@link CellDesignerElement cell designer elements} parsed from
+   * xml.
+   */
+  private CellDesignerElementCollection elements;
+
+  /**
+   * Model for which we parse elements.
+   */
+  private Model model;
+
+  /**
+   * Default constructor with model object for which we parse data.
+   * 
+   * @param model
+   *          model for which we parse elements
+   * @param elements
+   *          collection of {@link CellDesignerElement cell designer elements}
+   *          parsed from xml
+   */
+  public SpeciesAliasXmlParser(CellDesignerElementCollection elements, Model model) {
+    this.elements = elements;
+    this.model = model;
+  }
+
+  @Override
+  Species parseXmlAlias(Node aliasNode) throws InvalidXmlSchemaException {
+
+    String speciesId = getNodeAttr("species", aliasNode);
+    String aliasId = getNodeAttr("id", aliasNode);
+    CellDesignerSpecies<?> species = elements.getElementByElementId(speciesId);
+    if (species == null) {
+      throw new InvalidXmlSchemaException("Unknown species for alias (speciesId: " + speciesId + ")");
+    }
+    if (species instanceof CellDesignerComplexSpecies) {
+      logger.warn("[" + speciesId + "," + aliasId
+          + "]\tSpecies is defined as a complex, but alias is not a complex. Changing alias to complex.");
+    }
+
+    elements.addElement(species, aliasId);
+    Species result = species.createModelElement(aliasId);
+
+    String state = "usual";
+    NodeList nodes = aliasNode.getChildNodes();
+    View usualView = null;
+    View briefView = null;
+    for (int x = 0; x < nodes.getLength(); x++) {
+      Node node = nodes.item(x);
+      if (node.getNodeType() == Node.ELEMENT_NODE) {
+        if (node.getNodeName().equalsIgnoreCase("celldesigner:activity")) {
+          result.setActivity(getNodeValue(node).equalsIgnoreCase("active"));
+        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:bounds")) {
+          result.setX(getNodeAttr("X", node));
+          result.setY(getNodeAttr("Y", node));
+        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:font")) {
+          result.setFontSize(getNodeAttr("size", node));
+        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:view")) {
+          state = getNodeAttr("state", node);
+        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:usualView")) {
+          usualView = getCommonParser().getView(node);
+        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:briefView")) {
+          briefView = getCommonParser().getView(node);
+        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:info")) {
+          processAliasState(node, result);
+        } else if (node.getNodeName().equalsIgnoreCase("celldesigner:structuralState")) {
+          // not handled
+          continue;
+        } else {
+          throw new InvalidXmlSchemaException("Unknown element of celldesigner:speciesAlias: " + node.getNodeName());
+        }
+      }
+    }
+
+    View view = null;
+    if (state.equalsIgnoreCase("usual")) {
+      view = usualView;
+    } else if (state.equalsIgnoreCase("brief")) {
+      view = briefView;
+    }
+
+    if (view != null) {
+      // inner position defines the position in compartment
+      // result.moveBy(view.innerPosition);
+      result.setWidth(view.getBoxSize().width);
+      result.setHeight(view.getBoxSize().height);
+      result.setLineWidth(view.getSingleLine().getWidth());
+      result.setColor(view.getColor());
+    } else {
+      throw new InvalidXmlSchemaException("No view in Alias");
+    }
+    result.setState(state);
+    String compartmentAliasId = getNodeAttr("compartmentAlias", aliasNode);
+    if (!compartmentAliasId.isEmpty()) {
+      Compartment compartment = model.getElementByElementId(compartmentAliasId);
+      if (compartment == null) {
+        throw new InvalidXmlSchemaException("CompartmentAlias does not exist: " + compartmentAliasId);
+      } else {
+        result.setCompartment(compartment);
+        compartment.addElement(result);
+      }
+    }
+    String complexAliasId = getNodeAttr("complexSpeciesAlias", aliasNode);
+    if (!complexAliasId.isEmpty()) {
+      Complex complex = model.getElementByElementId(complexAliasId);
+      if (complex == null) {
+        throw new InvalidXmlSchemaException(
+            "ComplexAlias does not exist: " + complexAliasId + ", current: " + result.getElementId());
+      } else {
+        result.setComplex(complex);
+        complex.addSpecies(result);
+      }
+    }
+    
+
+    species.updateModelElementAfterLayoutAdded(result);
+    return result;
+  }
+
+  /**
+   * Process node with information about alias state and puts data into alias.
+   * 
+   * @param node
+   *          node where information about alias state is stored
+   * @param alias
+   *          alias object to be modified if necessary
+   */
+  private void processAliasState(Node node, Species alias) {
+    String state = getNodeAttr("state", node);
+    if ("open".equalsIgnoreCase(state)) {
+      String prefix = getNodeAttr("prefix", node);
+      String label = getNodeAttr("label", node);
+      alias.setStatePrefix(prefix);
+      alias.setStateLabel(label);
+    } else if ("empty".equalsIgnoreCase(state)) {
+      return;
+    } else if (state == null || state.isEmpty()) {
+      return;
+    } else {
+      throw new NotImplementedException("[Alias: " + alias.getElementId() + "] Unkown alias state: " + state);
+    }
+
+  }
+
+  @Override
+  public String toXml(Species species) {
+    Compartment ca = null;
+    // artificial compartment aliases should be excluded
+    if (species.getCompartment() != null && !(species.getCompartment() instanceof PathwayCompartment)) {
+      ca = (Compartment) species.getCompartment();
+    } else if (species.getComplex() == null) {
+      ModelData model = species.getModelData();
+      if (model != null) {
+        for (Compartment cAlias : model.getModel().getCompartments()) {
+          if (!(cAlias instanceof PathwayCompartment) && cAlias.cross(species)) {
+            if (ca == null) {
+              ca = cAlias;
+            } else if (ca.getSize() > cAlias.getSize()) {
+              ca = cAlias;
+            }
+          }
+        }
+      }
+    }
+
+    Complex complex = species.getComplex();
+
+    String compartmentAliasId = null;
+    if (ca != null) {
+      compartmentAliasId = ca.getElementId();
+    }
+    StringBuilder sb = new StringBuilder("");
+    sb.append("<celldesigner:speciesAlias ");
+    sb.append("id=\"" + species.getElementId() + "\" ");
+    sb.append("species=\"" + elements.getElementId(species) + "\" ");
+    if (compartmentAliasId != null) {
+      sb.append("compartmentAlias=\"" + compartmentAliasId + "\" ");
+    }
+
+    if (complex != null) {
+      sb.append("complexSpeciesAlias=\"" + complex.getElementId() + "\" ");
+    }
+    sb.append(">\n");
+
+    if (species.getActivity() != null) {
+      if (species.getActivity()) {
+        sb.append("<celldesigner:activity>active</celldesigner:activity>\n");
+      } else {
+        sb.append("<celldesigner:activity>inactive</celldesigner:activity>\n");
+      }
+    }
+
+    sb.append("<celldesigner:bounds ");
+    sb.append("x=\"" + species.getX() + "\" ");
+    sb.append("y=\"" + species.getY() + "\" ");
+    sb.append("w=\"" + species.getWidth() + "\" ");
+    sb.append("h=\"" + species.getHeight() + "\" ");
+    sb.append("/>\n");
+
+    sb.append("<celldesigner:font size=\"" + species.getFontSize() + "\"/>\n");
+
+    // TODO to be improved
+    sb.append("<celldesigner:view state=\"usual\"/>\n");
+    sb.append("<celldesigner:usualView>");
+    sb.append("<celldesigner:innerPosition x=\"" + species.getX() + "\" y=\"" + species.getY() + "\"/>");
+    sb.append("<celldesigner:boxSize width=\"" + species.getWidth() + "\" height=\"" + species.getHeight() + "\"/>");
+    sb.append("<celldesigner:singleLine width=\"" + species.getLineWidth() + "\"/>");
+    sb.append("<celldesigner:paint color=\"" + colorToString(species.getColor()) + "\" scheme=\"Color\"/>");
+    sb.append("</celldesigner:usualView>\n");
+    sb.append("<celldesigner:briefView>");
+    sb.append("<celldesigner:innerPosition x=\"" + species.getX() + "\" y=\"" + species.getY() + "\"/>");
+    sb.append("<celldesigner:boxSize width=\"" + species.getWidth() + "\" height=\"" + species.getHeight() + "\"/>");
+    sb.append("<celldesigner:singleLine width=\"" + species.getLineWidth() + "\"/>");
+    sb.append("<celldesigner:paint color=\"" + colorToString(species.getColor()) + "\" scheme=\"Color\"/>");
+    sb.append("</celldesigner:briefView>\n");
+    if (species.getStateLabel() != null || species.getStatePrefix() != null) {
+      sb.append("<celldesigner:info state=\"open\" prefix=\"" + species.getStatePrefix() + "\" label=\""
+          + species.getStateLabel() + "\"/>\n");
+    }
+    sb.append("</celldesigner:speciesAlias>\n");
+    return sb.toString();
+  }
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AbstractCellDesignerAliasConverter.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AbstractCellDesignerAliasConverter.java
index 6742baaafabf2462881b1dac6dfca6943aa871c3..172182d4c2297b28e480a927a17c29b7526b71fe 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AbstractCellDesignerAliasConverter.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AbstractCellDesignerAliasConverter.java
@@ -1,235 +1,425 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import java.awt.geom.Line2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.geometry.LineTransformation;
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerEllipseTransformation;
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerPolygonTransformation;
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerRectangleTransformation;
-import lcsb.mapviewer.model.graphics.PolylineData;
-import lcsb.mapviewer.model.map.species.Element;
-
-/**
- * This abstract class is an interface for setting up graphical data for alias
- * from CellDesigner specific format into standard layout.
- * 
- * @author Piotr Gawron
- * 
- * @param <T>
- */
-public abstract class AbstractCellDesignerAliasConverter<T extends Element> implements ICellDesignerAliasConverter<T> {
-
-	/**
-	 * Default class logger.
-	 */
-	private static Logger												logger									= Logger.getLogger(AbstractCellDesignerAliasConverter.class);
-
-	/**
-	 * CellDesigner graphical helper with polygon transformation functions.
-	 */
-	private CellDesignerPolygonTransformation		polygonTransformation		= new CellDesignerPolygonTransformation();
-
-	/**
-	 * CellDesigner graphical helper with lin transformation functions.
-	 */
-	private LineTransformation									lineTransformation			= new LineTransformation();
-
-	/**
-	 * CellDesigner graphical helper with ellipse transformation functions.
-	 */
-	private CellDesignerEllipseTransformation		ellipseTransformation		= new CellDesignerEllipseTransformation();
-
-	/**
-	 * CellDesigner graphical helper with rectangle transformation functions.
-	 */
-	private CellDesignerRectangleTransformation	rectangleTransformation	= new CellDesignerRectangleTransformation();
-
-	/**
-	 * What is the distance between homodimer aliases when homodimer>1.
-	 */
-	public static final int											HOMODIMER_OFFSET				= 6;
-
-	/**
-	 * Should the converter use sbgn standard.
-	 */
-	private boolean															sbgn;
-
-	/**
-	 * Default constructor that prevents from instatiation of the class.
-	 * 
-	 * @param sbgn
-	 *          Should the converter use sbgn standard
-	 */
-	protected AbstractCellDesignerAliasConverter(boolean sbgn) {
-		this.sbgn = sbgn;
-	};
-
-	@Override
-	public CellDesignerAnchor getAnchorForCoordinates(T alias, Point2D point) {
-		double dist = Double.MAX_VALUE;
-		CellDesignerAnchor result = null;
-		for (CellDesignerAnchor anchor : CellDesignerAnchor.values()) {
-			double newDist = getPointCoordinates(alias, anchor).distance(point);
-			if (newDist < dist) {
-				dist = newDist;
-				result = anchor;
-			}
-		}
-		// if the distance to all known anchors is too big then assume center
-		if (dist > 1) {
-			return null;
-		}
-		return result;
-	}
-
-	@Override
-	public abstract Point2D getPointCoordinates(T alias, CellDesignerAnchor anchor);
-
-	@Override
-	public Point2D getAnchorPointCoordinates(T alias, CellDesignerAnchor anchor, PolylineData ld) {
-		if (anchor != null && anchor.getAngle() != null) {
-			return getPointCoordinates(alias, anchor);
-		} else {
-			Point2D p1 = ld.getPoints().get(1);
-			Point2D p2 = ld.getPoints().get(0);
-			double dx = p2.getX() - p1.getX();
-			double dy = p2.getY() - p1.getY();
-			double angle = Math.atan2(dy, dx);
-			return getAnchorPointCoordinates(alias, angle);
-		}
-	}
-
-	/**
-	 * This method computes coordinates that should be associated with the angle
-	 * on the border of the alias.
-	 * 
-	 * @param alias
-	 *          alias to be investigated
-	 * @param angle
-	 *          angle on the border of the alias
-	 * @return coordinates on the border of the alias described by the angle
-	 */
-	protected Point2D getAnchorPointCoordinates(T alias, double angle) {
-		Point2D result = null;
-		if (alias.getWidth() == 0 && alias.getHeight() == 0) {
-			result = alias.getCenter();
-		} else {
-			double dist = Math.max(alias.getWidth(), alias.getHeight()) * 2;
-			Point2D startPoint = alias.getCenter();
-			double x = startPoint.getX() - Math.cos(angle) * dist;
-			double y = startPoint.getY() - Math.sin(angle) * dist;
-			Point2D endPoint = new Point2D.Double(x, y);
-			Line2D line = new Line2D.Double(startPoint, endPoint);
-			result = lineTransformation.getIntersectionWithPathIterator(line, getBoundPathIterator(alias));
-			if (result == null) {
-				logger.warn("Unknown crossing point: " + line.getP1() + "; " + line.getP2());
-				result = alias.getCenter();
-			}
-		}
-		return result;
-	}
-
-	/**
-	 * This method returns border of the alias as a PathIterator.
-	 * 
-	 * @param alias
-	 *          object for which we want to find a border
-	 * @return border of the alias
-	 */
-	protected abstract PathIterator getBoundPathIterator(T alias);
-
-	/**
-	 * Checks if anchor is valid for the alias to find a point on the border.
-	 * 
-	 * @param alias
-	 *          object to be checked
-	 * @param anchor
-	 *          anchor point
-	 * @return true if the conditions are ok (alias size >0 and angle != null)
-	 */
-	protected boolean invalidAnchorPosition(T alias, CellDesignerAnchor anchor) {
-		if (anchor == null || anchor.getAngle() == null) {
-			return true;
-		}
-		if (alias.getWidth() == 0 && alias.getHeight() == 0) {
-			return true;
-		}
-		// TODO handle with one of params equal to 0
-
-		return false;
-	}
-
-	/**
-	 * @return the polygonTransformation
-	 */
-	protected CellDesignerPolygonTransformation getPolygonTransformation() {
-		return polygonTransformation;
-	}
-
-	/**
-	 * @param polygonTransformation
-	 *          the polygonTransformation to set
-	 */
-	protected void setPolygonTransformation(CellDesignerPolygonTransformation polygonTransformation) {
-		this.polygonTransformation = polygonTransformation;
-	}
-
-	/**
-	 * @return the lineTransformation
-	 */
-	protected LineTransformation getLineTransformation() {
-		return lineTransformation;
-	}
-
-	/**
-	 * @param lineTransformation
-	 *          the lineTransformation to set
-	 */
-	protected void setLineTransformation(LineTransformation lineTransformation) {
-		this.lineTransformation = lineTransformation;
-	}
-
-	/**
-	 * @return the ellipseTransformation
-	 */
-	protected CellDesignerEllipseTransformation getEllipseTransformation() {
-		return ellipseTransformation;
-	}
-
-	/**
-	 * @param ellipseTransformation
-	 *          the ellipseTransformation to set
-	 */
-	protected void setEllipseTransformation(CellDesignerEllipseTransformation ellipseTransformation) {
-		this.ellipseTransformation = ellipseTransformation;
-	}
-
-	/**
-	 * @return the rectangleTransformation
-	 */
-	protected CellDesignerRectangleTransformation getRectangleTransformation() {
-		return rectangleTransformation;
-	}
-
-	/**
-	 * @param rectangleTransformation
-	 *          the rectangleTransformation to set
-	 */
-	protected void setRectangleTransformation(CellDesignerRectangleTransformation rectangleTransformation) {
-		this.rectangleTransformation = rectangleTransformation;
-	}
-
-	/**
-	 * @return the sbgn
-	 * @see #sbgn
-	 */
-	protected boolean isSbgn() {
-		return sbgn;
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.common.exception.InvalidStateException;
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.common.geometry.LineTransformation;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerEllipseTransformation;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerPolygonTransformation;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerRectangleTransformation;
+import lcsb.mapviewer.model.graphics.PolylineData;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * This abstract class is an interface for setting up graphical data for alias
+ * from CellDesigner specific format into standard layout.
+ * 
+ * @author Piotr Gawron
+ * 
+ * @param <T>
+ */
+public abstract class AbstractCellDesignerAliasConverter<T extends Element> implements ICellDesignerAliasConverter<T> {
+
+  /**
+   * PI value.
+   */
+  private static final double PI = Math.PI;
+
+  /**
+   * Constant determining angle of the top right corner.
+   */
+  protected static final double RIGHT_TOP_RESIDUE_MAX_ANGLE = 0.25 * PI;
+
+  /**
+   * Constant determining angle of the top left corner.
+   */
+  protected static final double TOP_RESIDUE_MAX_ANGLE = 0.75 * PI;
+
+  /**
+   * Constant determining angle of the bottom left corner.
+   */
+  protected static final double LEFT_RESIDUE_MAX_ANGLE = 1.25 * PI;
+
+  /**
+   * Constant determining angle of the bottom right corner.
+   */
+  protected static final double BOTTOM_RESIDUE_MAX_ANGLE = 1.75 * PI;
+
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(AbstractCellDesignerAliasConverter.class);
+
+  /**
+   * CellDesigner graphical helper with polygon transformation functions.
+   */
+  private CellDesignerPolygonTransformation polygonTransformation = new CellDesignerPolygonTransformation();
+
+  /**
+   * CellDesigner graphical helper with line transformation functions.
+   */
+  private LineTransformation lineTransformation = new LineTransformation();
+
+  /**
+   * CellDesigner graphical helper with ellipse transformation functions.
+   */
+  private CellDesignerEllipseTransformation ellipseTransformation = new CellDesignerEllipseTransformation();
+
+  /**
+   * CellDesigner graphical helper with rectangle transformation functions.
+   */
+  private CellDesignerRectangleTransformation rectangleTransformation = new CellDesignerRectangleTransformation();
+
+  /**
+   * What is the distance between homodimer aliases when homodimer>1.
+   */
+  public static final int HOMODIMER_OFFSET = 6;
+
+  /**
+   * Should the converter use SBGN standard.
+   */
+  private boolean sbgn;
+
+  /**
+   * Default constructor that prevents from instantiation of the class.
+   * 
+   * @param sbgn
+   *          Should the converter use SBGN standard
+   */
+  protected AbstractCellDesignerAliasConverter(boolean sbgn) {
+    this.sbgn = sbgn;
+  };
+
+  @Override
+  public CellDesignerAnchor getAnchorForCoordinates(T alias, Point2D point) {
+    double dist = Double.MAX_VALUE;
+    CellDesignerAnchor result = null;
+    for (CellDesignerAnchor anchor : CellDesignerAnchor.values()) {
+      double newDist = getPointCoordinates(alias, anchor).distance(point);
+      if (newDist < dist) {
+        dist = newDist;
+        result = anchor;
+      }
+    }
+    // if the distance to all known anchors is too big then assume center
+    if (dist > 1) {
+      return null;
+    }
+    return result;
+  }
+
+  @Override
+  public abstract Point2D getPointCoordinates(T alias, CellDesignerAnchor anchor);
+
+  @Override
+  public Point2D getAnchorPointCoordinates(T alias, CellDesignerAnchor anchor, PolylineData ld) {
+    if (anchor != null && anchor.getAngle() != null) {
+      return getPointCoordinates(alias, anchor);
+    } else {
+      Point2D p1 = ld.getPoints().get(1);
+      Point2D p2 = ld.getPoints().get(0);
+      double dx = p2.getX() - p1.getX();
+      double dy = p2.getY() - p1.getY();
+      double angle = Math.atan2(dy, dx);
+      return getAnchorPointCoordinates(alias, angle);
+    }
+  }
+
+  /**
+   * This method computes coordinates that should be associated with the angle on
+   * the border of the alias.
+   * 
+   * @param alias
+   *          alias to be investigated
+   * @param angle
+   *          angle on the border of the alias
+   * @return coordinates on the border of the alias described by the angle
+   */
+  protected Point2D getAnchorPointCoordinates(T alias, double angle) {
+    Point2D result = null;
+    if (alias.getWidth() == 0 && alias.getHeight() == 0) {
+      result = alias.getCenter();
+    } else {
+      double dist = Math.max(alias.getWidth(), alias.getHeight()) * 2;
+      Point2D startPoint = alias.getCenter();
+      double x = startPoint.getX() - Math.cos(angle) * dist;
+      double y = startPoint.getY() - Math.sin(angle) * dist;
+      Point2D endPoint = new Point2D.Double(x, y);
+      Line2D line = new Line2D.Double(startPoint, endPoint);
+      result = lineTransformation.getIntersectionWithPathIterator(line, getBoundPathIterator(alias));
+      if (result == null) {
+        logger.warn("Unknown crossing point: " + line.getP1() + "; " + line.getP2());
+        result = alias.getCenter();
+      }
+    }
+    return result;
+  }
+
+  /**
+   * This method returns border of the alias as a PathIterator.
+   * 
+   * @param alias
+   *          object for which we want to find a border
+   * @return border of the alias
+   */
+  protected abstract PathIterator getBoundPathIterator(T alias);
+
+  /**
+   * Checks if anchor is valid for the alias to find a point on the border.
+   * 
+   * @param alias
+   *          object to be checked
+   * @param anchor
+   *          anchor point
+   * @return true if the conditions are ok (alias size >0 and angle != null)
+   */
+  protected boolean invalidAnchorPosition(T alias, CellDesignerAnchor anchor) {
+    if (anchor == null || anchor.getAngle() == null) {
+      return true;
+    }
+    if (alias.getWidth() == 0 && alias.getHeight() == 0) {
+      return true;
+    }
+    // TODO handle with one of params equal to 0
+
+    return false;
+  }
+
+  /**
+   * @return the polygonTransformation
+   */
+  protected CellDesignerPolygonTransformation getPolygonTransformation() {
+    return polygonTransformation;
+  }
+
+  /**
+   * @param polygonTransformation
+   *          the polygonTransformation to set
+   */
+  protected void setPolygonTransformation(CellDesignerPolygonTransformation polygonTransformation) {
+    this.polygonTransformation = polygonTransformation;
+  }
+
+  /**
+   * @return the lineTransformation
+   */
+  protected LineTransformation getLineTransformation() {
+    return lineTransformation;
+  }
+
+  /**
+   * @param lineTransformation
+   *          the lineTransformation to set
+   */
+  protected void setLineTransformation(LineTransformation lineTransformation) {
+    this.lineTransformation = lineTransformation;
+  }
+
+  /**
+   * @return the ellipseTransformation
+   */
+  protected CellDesignerEllipseTransformation getEllipseTransformation() {
+    return ellipseTransformation;
+  }
+
+  /**
+   * @param ellipseTransformation
+   *          the ellipseTransformation to set
+   */
+  protected void setEllipseTransformation(CellDesignerEllipseTransformation ellipseTransformation) {
+    this.ellipseTransformation = ellipseTransformation;
+  }
+
+  /**
+   * @return the rectangleTransformation
+   */
+  protected CellDesignerRectangleTransformation getRectangleTransformation() {
+    return rectangleTransformation;
+  }
+
+  /**
+   * @param rectangleTransformation
+   *          the rectangleTransformation to set
+   */
+  protected void setRectangleTransformation(CellDesignerRectangleTransformation rectangleTransformation) {
+    this.rectangleTransformation = rectangleTransformation;
+  }
+
+  /**
+   * @return the sbgn
+   * @see #sbgn
+   */
+  protected boolean isSbgn() {
+    return sbgn;
+  }
+
+  /**
+   * Returns coordinates on the {@link Species} border for given angle for
+   * residues.
+   * 
+   * @param species
+   *          object on border which the point is looked for
+   * @param angle
+   *          CellDEsigner specific angle defining coordinates (;/)
+   * @return coordinates on the alias border that correspond to the angle
+   */
+  @Override
+  public Point2D getResidueCoordinates(final T species, double angle) {
+    Point2D result = null;
+    if (species.getWidth() == 0 && species.getHeight() == 0) {
+      result = species.getCenter();
+    } else {
+      double x = 0;
+      double y = 0;
+      while (angle > 2 * PI) {
+        angle -= 2 * PI;
+      }
+      while (angle < 0) {
+        angle += 2 * PI;
+      }
+      if (angle < RIGHT_TOP_RESIDUE_MAX_ANGLE) {
+        // CHECKSTYLE:OFF 0.5 is much readable than any other suggestion
+        double ratio = 0.5 + angle / (PI / 2);
+        // CHECKSTYLE:ON
+        x = species.getX() + species.getWidth();
+        y = species.getY() + species.getHeight() * (1 - ratio);
+      } else if (angle < TOP_RESIDUE_MAX_ANGLE) {
+        double ratio = (angle - RIGHT_TOP_RESIDUE_MAX_ANGLE) / (PI / 2);
+        y = species.getY();
+        x = species.getX() + species.getWidth() * (1 - ratio);
+      } else if (angle < LEFT_RESIDUE_MAX_ANGLE) {
+        double ratio = (angle - TOP_RESIDUE_MAX_ANGLE) / (PI / 2);
+        y = species.getY() + species.getHeight() * (ratio);
+        x = species.getX();
+      } else if (angle < BOTTOM_RESIDUE_MAX_ANGLE) {
+        double ratio = (angle - LEFT_RESIDUE_MAX_ANGLE) / (PI / 2);
+        y = species.getY() + species.getHeight();
+        x = species.getX() + species.getWidth() * ratio;
+      } else if (angle <= 2 * PI + Configuration.EPSILON) {
+        double ratio = (angle - BOTTOM_RESIDUE_MAX_ANGLE) / (PI / 2);
+        y = species.getY() + species.getHeight() * (1 - ratio);
+        x = species.getX() + species.getWidth();
+      } else {
+        throw new InvalidStateException();
+      }
+      Point2D center = species.getCenter();
+      double correctedAngle = -Math.atan2((y - center.getY()), (x - center.getX()));
+      result = getPointCoordinatesOnBorder(species, correctedAngle);
+    }
+    return result;
+
+  }
+
+  /**
+   * Returns coordinates on the {@link Element} border for given angle.
+   * 
+   * @param elemnt
+   *          {@link Element} on border which the point is looked for
+   * @param angle
+   *          angle between X axis center point of {@link Species} and point that
+   *          we are looking for
+   * @return coordinates on the {@link Species} border that correspond to the
+   *         angle
+   */
+  protected Point2D getPointCoordinatesOnBorder(final T elemnt, final double angle) {
+    Point2D result = null;
+    if (elemnt.getWidth() == 0 && elemnt.getHeight() == 0) {
+      result = elemnt.getCenter();
+    } else {
+      double dist = Math.max(elemnt.getWidth(), elemnt.getHeight()) * 2;
+      Point2D startPoint = elemnt.getCenter();
+      double x = startPoint.getX() + Math.cos(angle) * dist;
+      double y = startPoint.getY() - Math.sin(angle) * dist;
+      Point2D endPoint = new Point2D.Double(x, y);
+      Line2D line = new Line2D.Double(startPoint, endPoint);
+      result = lineTransformation.getIntersectionWithPathIterator(line, getBoundPathIterator(elemnt));
+    }
+    return result;
+
+  }
+
+  @Override
+  public Double getAngleForPoint(T element, Point2D position) {
+    double result = -1;
+    double correctedAngle = -Math.atan2((position.getY() - element.getCenterY()),
+        (position.getX() - element.getCenterX()));
+
+    double dist = Math.max(element.getWidth(), element.getHeight()) * 2;
+    Point2D startPoint = element.getCenter();
+    double x = startPoint.getX() + Math.cos(correctedAngle) * dist;
+    double y = startPoint.getY() - Math.sin(correctedAngle) * dist;
+    Point2D endPoint = new Point2D.Double(x, y);
+    Line2D line = new Line2D.Double(startPoint, endPoint);
+
+    GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
+
+    path.moveTo(element.getX(), element.getY());
+    path.lineTo(element.getX(), element.getY() + element.getHeight());
+    path.lineTo(element.getX() + element.getWidth(), element.getY() + element.getHeight());
+    path.lineTo(element.getX() + element.getWidth(), element.getY());
+    path.closePath();
+
+    Point2D pointOnBorder = lineTransformation.getIntersectionWithPathIterator(line,
+        path.getPathIterator(new AffineTransform()));
+
+    if (Math.abs(pointOnBorder.getX() - element.getX() - element.getWidth()) < Configuration.EPSILON && //
+        pointOnBorder.getY() - element.getY() - element.getHeight() / 2 < Configuration.EPSILON) {
+      double ratio = 1 - (pointOnBorder.getY() - element.getY()) / element.getHeight();
+      result = (ratio - 0.5) * (PI / 2);
+    } else if (Math.abs(pointOnBorder.getY() - element.getY()) < Configuration.EPSILON) {
+      double ratio = 1 - (pointOnBorder.getX() - element.getX()) / element.getWidth();
+      result = ratio * (PI / 2) + RIGHT_TOP_RESIDUE_MAX_ANGLE;
+    } else if (Math.abs(pointOnBorder.getX() - element.getX()) < Configuration.EPSILON) {
+      double ratio = (pointOnBorder.getY() - element.getY()) / element.getHeight();
+      result = ratio * (PI / 2) + TOP_RESIDUE_MAX_ANGLE;
+    } else if (Math.abs(pointOnBorder.getY() - element.getY() - element.getHeight()) < Configuration.EPSILON) {
+      double ratio = (pointOnBorder.getX() - element.getX()) / element.getWidth();
+      result = ratio * (PI / 2) + LEFT_RESIDUE_MAX_ANGLE;
+    } else if (Math.abs(pointOnBorder.getX() - element.getX() - element.getWidth()) < Configuration.EPSILON && //
+        pointOnBorder.getY() - element.getY() - element.getHeight() < Configuration.EPSILON) {
+      double ratio = 1 - (pointOnBorder.getY() - element.getY()) / element.getHeight();
+      result = ratio * (PI / 2) + BOTTOM_RESIDUE_MAX_ANGLE;
+    } else {
+      logger.warn("Problem with finding angle. Using default 0");
+      result = 0;
+    }
+    return result;
+  }
+
+  @Override
+  public Double getCellDesignerPositionByCoordinates(ModificationResidue mr) {
+    return null;
+  }
+
+  @Override
+  public Point2D getCoordinatesByPosition(Element element, Double pos) {
+    return this.getCoordinatesByPosition(element, pos, 0.0);
+  }
+
+  @Override
+  public Point2D getCoordinatesByPosition(Element element, Double pos, Double width) {
+    throw new NotImplementedException("Not implemented for: " + this.getClass());
+  }
+
+  @Override
+  public Double getCellDesignerSize(ModificationResidue mr) {
+    throw new NotImplementedException("Not implemented for: " + this.getClass());
+  }
+
+  @Override
+  public Double getWidthBySize(Element element, Double size) {
+    throw new NotImplementedException("Not implemented for: " + this.getClass());
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AntisenseRnaCellDesignerAliasConverter.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AntisenseRnaCellDesignerAliasConverter.java
index f558c3d7f1ead56135c366f2a461978a2fa981ae..613c3b51b2199bb16f5d73f2872e593a6f65f5ba 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AntisenseRnaCellDesignerAliasConverter.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AntisenseRnaCellDesignerAliasConverter.java
@@ -1,115 +1,146 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import java.awt.geom.AffineTransform;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.util.ArrayList;
-
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.Species;
-
-/**
- * Class that provides CellDesigner specific graphical information for
- * AntisenseRna. It's used for conversion from xml to normal x,y coordinates.
- * 
- * @author Piotr Gawron
- * 
- */
-public class AntisenseRnaCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Species> {
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param sbgn
-	 *          Should the converter use sbgn standard
-	 */
-	protected AntisenseRnaCellDesignerAliasConverter(boolean sbgn) {
-		super(sbgn);
-	}
-
-	/**
-	 * How big should be the arc in rectangle for nucleic acid feature
-	 * representation.
-	 */
-	private static final int RECTANGLE_CORNER_ARC_SIZE = 5;
-
-	@Override
-	public Point2D getPointCoordinates(Species alias, CellDesignerAnchor anchor) {
-		if (invalidAnchorPosition(alias, anchor)) {
-			return alias.getCenter();
-		}
-		if (isSbgn()) {
-			return getRectangleTransformation().getPointOnRectangleByAnchor(alias.getX(), alias.getY(), alias.getWidth(), alias.getHeight(), anchor);
-		}
-		ArrayList<Point2D> points = getPoints(alias);
-		return getPolygonTransformation().getPointOnPolygonByAnchor(points, anchor);
-	}
-
-	@Override
-	protected PathIterator getBoundPathIterator(Species alias) {
-		return getAntisebseRnaPath(alias).getPathIterator(new AffineTransform());
-	}
-
-	/**
-	 * Returns shape of the AntisenseRna as a list of points.
-	 * 
-	 * @param alias
-	 *          alias for which we are looking for a border
-	 * @return list of points defining border of the given alias
-	 */
-	private ArrayList<Point2D> getPoints(Element alias) {
-		double x = alias.getX();
-		double y = alias.getY();
-		double width = alias.getWidth();
-		double height = alias.getHeight();
-		ArrayList<Point2D> points = new ArrayList<Point2D>();
-
-		// CHECKSTYLE:OFF
-		points.add(new Point2D.Double(x + width / 8, y + height / 2));
-		points.add(new Point2D.Double(x, y));
-		points.add(new Point2D.Double(x + width * 3 / 8, y));
-		points.add(new Point2D.Double(x + width * 3 / 4, y));
-		points.add(new Point2D.Double(x + width * 7 / 8, y + height / 2));
-		points.add(new Point2D.Double(x + width, y + height));
-		points.add(new Point2D.Double(x + width * 5 / 8, y + height));
-		points.add(new Point2D.Double(x + width / 4, y + height));
-		// CHECKSTYLE:ON
-		return points;
-	}
-
-	/**
-	 * Returns shape of the AntisenseRna as a GeneralPath object.
-	 * 
-	 * @param alias
-	 *          alias for which we are looking for a border
-	 * @return GeneralPath object defining border of the given alias
-	 */
-	private GeneralPath getAntisebseRnaPath(Element alias) {
-		// CHECKSTYLE:OFF
-		GeneralPath path;
-		if (!isSbgn()) {
-			path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 4);
-			path.moveTo(alias.getX(), alias.getY());
-			path.lineTo(alias.getX() + alias.getWidth() * 3 / 4, alias.getY());
-			path.lineTo(alias.getX() + alias.getWidth(), alias.getY() + alias.getHeight());
-			path.lineTo(alias.getX() + alias.getWidth() / 4, alias.getY() + alias.getHeight());
-			path.closePath();
-		} else {
-			path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 6);
-			double x = alias.getX(), y = alias.getY(), width = alias.getWidth(), height = alias.getHeight();
-
-			path.moveTo(x, y);
-			path.lineTo(x, y + height - RECTANGLE_CORNER_ARC_SIZE);
-			path.curveTo(x, y + height, x + RECTANGLE_CORNER_ARC_SIZE, y + height, x + RECTANGLE_CORNER_ARC_SIZE, y + height);
-			path.lineTo(x + width - RECTANGLE_CORNER_ARC_SIZE, y + height);
-			path.curveTo(x + width, y + height, x + width, y + height - RECTANGLE_CORNER_ARC_SIZE, x + width, y + height - RECTANGLE_CORNER_ARC_SIZE);
-			path.lineTo(x + width, y);
-			path.closePath();
-		}
-		// CHECKSTYLE:ON
-		return path;
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.AbstractRegionModification;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * Class that provides CellDesigner specific graphical information for
+ * AntisenseRna. It's used for conversion from xml to normal x,y coordinates.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class AntisenseRnaCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Species> {
+
+  /**
+   * Default constructor.
+   * 
+   * @param sbgn
+   *          Should the converter use sbgn standard
+   */
+  protected AntisenseRnaCellDesignerAliasConverter(boolean sbgn) {
+    super(sbgn);
+  }
+
+  /**
+   * How big should be the arc in rectangle for nucleic acid feature
+   * representation.
+   */
+  private static final int RECTANGLE_CORNER_ARC_SIZE = 5;
+
+  @Override
+  public Point2D getPointCoordinates(Species alias, CellDesignerAnchor anchor) {
+    if (invalidAnchorPosition(alias, anchor)) {
+      return alias.getCenter();
+    }
+    if (isSbgn()) {
+      return getRectangleTransformation().getPointOnRectangleByAnchor(alias.getX(), alias.getY(), alias.getWidth(),
+          alias.getHeight(), anchor);
+    }
+    ArrayList<Point2D> points = getPoints(alias);
+    return getPolygonTransformation().getPointOnPolygonByAnchor(points, anchor);
+  }
+
+  @Override
+  protected PathIterator getBoundPathIterator(Species alias) {
+    return getAntisebseRnaPath(alias).getPathIterator(new AffineTransform());
+  }
+
+  /**
+   * Returns shape of the AntisenseRna as a list of points.
+   * 
+   * @param alias
+   *          alias for which we are looking for a border
+   * @return list of points defining border of the given alias
+   */
+  private ArrayList<Point2D> getPoints(Element alias) {
+    double x = alias.getX();
+    double y = alias.getY();
+    double width = alias.getWidth();
+    double height = alias.getHeight();
+    ArrayList<Point2D> points = new ArrayList<Point2D>();
+
+    // CHECKSTYLE:OFF
+    points.add(new Point2D.Double(x + width / 8, y + height / 2));
+    points.add(new Point2D.Double(x, y));
+    points.add(new Point2D.Double(x + width * 3 / 8, y));
+    points.add(new Point2D.Double(x + width * 3 / 4, y));
+    points.add(new Point2D.Double(x + width * 7 / 8, y + height / 2));
+    points.add(new Point2D.Double(x + width, y + height));
+    points.add(new Point2D.Double(x + width * 5 / 8, y + height));
+    points.add(new Point2D.Double(x + width / 4, y + height));
+    // CHECKSTYLE:ON
+    return points;
+  }
+
+  /**
+   * Returns shape of the AntisenseRna as a GeneralPath object.
+   * 
+   * @param alias
+   *          alias for which we are looking for a border
+   * @return GeneralPath object defining border of the given alias
+   */
+  private GeneralPath getAntisebseRnaPath(Element alias) {
+    // CHECKSTYLE:OFF
+    GeneralPath path;
+    if (!isSbgn()) {
+      path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 4);
+      path.moveTo(alias.getX(), alias.getY());
+      path.lineTo(alias.getX() + alias.getWidth() * 3 / 4, alias.getY());
+      path.lineTo(alias.getX() + alias.getWidth(), alias.getY() + alias.getHeight());
+      path.lineTo(alias.getX() + alias.getWidth() / 4, alias.getY() + alias.getHeight());
+      path.closePath();
+    } else {
+      path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 6);
+      double x = alias.getX(), y = alias.getY(), width = alias.getWidth(), height = alias.getHeight();
+
+      path.moveTo(x, y);
+      path.lineTo(x, y + height - RECTANGLE_CORNER_ARC_SIZE);
+      path.curveTo(x, y + height, x + RECTANGLE_CORNER_ARC_SIZE, y + height, x + RECTANGLE_CORNER_ARC_SIZE, y + height);
+      path.lineTo(x + width - RECTANGLE_CORNER_ARC_SIZE, y + height);
+      path.curveTo(x + width, y + height, x + width, y + height - RECTANGLE_CORNER_ARC_SIZE, x + width,
+          y + height - RECTANGLE_CORNER_ARC_SIZE);
+      path.lineTo(x + width, y);
+      path.closePath();
+    }
+    // CHECKSTYLE:ON
+    return path;
+  }
+
+  @Override
+  public Double getCellDesignerPositionByCoordinates(ModificationResidue mr) {
+    return (mr.getPosition().getX() - mr.getSpecies().getX()) / (mr.getSpecies().getWidth() * 3.0 / 4.0);
+  }
+
+  @Override
+  public Point2D getCoordinatesByPosition(Element element, Double pos, Double width) {
+    double x = element.getX() + element.getWidth() * 3.0 / 4.0 * pos;
+    x = Math.max(element.getX() + width / 2, x);
+    x = Math.min(element.getX() + element.getWidth() * 3.0 / 4.0 - width / 2, x);
+    return new Point2D.Double(x, element.getY());
+  }
+
+  @Override
+  public Double getCellDesignerSize(ModificationResidue mr) {
+    if (mr instanceof AbstractRegionModification) {
+      return ((AbstractRegionModification) mr).getWidth() / (mr.getSpecies().getWidth() * 3.0 / 4.0);
+    }
+    throw new NotImplementedException("Not implemented for: " + this.getClass() + ", " + mr.getClass());
+  }
+
+  @Override
+  public Double getWidthBySize(Element element, Double size) {
+    return size * (element.getWidth() * 3.0 / 4.0);
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/CellDesignerAliasConverter.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/CellDesignerAliasConverter.java
index 5e0364e6f7e83784d7235803566b5782f5fd505e..272366e5235cbb35a1c659af5e50d575cbce2b02 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/CellDesignerAliasConverter.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/CellDesignerAliasConverter.java
@@ -1,114 +1,153 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import java.awt.geom.Point2D;
-
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
-import lcsb.mapviewer.model.graphics.PolylineData;
-import lcsb.mapviewer.model.map.species.AntisenseRna;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.Degraded;
-import lcsb.mapviewer.model.map.species.Drug;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.Gene;
-import lcsb.mapviewer.model.map.species.Ion;
-import lcsb.mapviewer.model.map.species.Phenotype;
-import lcsb.mapviewer.model.map.species.Protein;
-import lcsb.mapviewer.model.map.species.Rna;
-import lcsb.mapviewer.model.map.species.SimpleMolecule;
-import lcsb.mapviewer.model.map.species.Unknown;
-import lcsb.mapviewer.modelutils.map.ElementUtils;
-
-/**
- * This class is designed to obtain CellDesigner specific data from
- * {@link Element}.
- * 
- * @author Piotr Gawron
- * 
- */
-
-public class CellDesignerAliasConverter implements ICellDesignerAliasConverter<Element> {
-
-	/**
-	 * Class helping with transforming objectcs into meaningfull identifiers.
-	 */
-	private static ElementUtils eu = new ElementUtils();
-
-	/**
-	 * Returns a converter for given {@link Element}. If converter doesn't exist
-	 * exception is thrown.
-	 * 
-	 * @param element
-	 *          element for which we are loooking for a converter
-	 * @param sbgn
-	 *          Should the converter use sbgn standard
-	 * @return converter that can be applied for the given element
-	 */
-	private ICellDesignerAliasConverter<? extends Element> getConverterForAlias(Element element, boolean sbgn) {
-		if (element == null) {
-			throw new InvalidArgumentException("element cannot be null");
-		}
-		if (element instanceof Protein) {
-			return new ProteinCellDesignerAliasConverter(sbgn);
-		} else if (element instanceof Degraded) {
-			return new DegradedCellDesignerAliasConverter(sbgn);
-		} else if (element instanceof Complex) {
-			return new ComplexCellDesignerAliasConverter(sbgn);
-		} else if (element instanceof SimpleMolecule) {
-			return new SimpleMoleculeCellDesignerAliasConverter(sbgn);
-		} else if (element instanceof Drug) {
-			return new DrugCellDesignerAliasConverter(sbgn);
-		} else if (element instanceof Ion) {
-			return new IonCellDesignerAliasConverter(sbgn);
-		} else if (element instanceof Phenotype) {
-			return new PhenotypeCellDesignerAliasConverter(sbgn);
-		} else if (element instanceof Rna) {
-			return new RnaCellDesignerAliasConverter(sbgn);
-		} else if (element instanceof AntisenseRna) {
-			return new AntisenseRnaCellDesignerAliasConverter(sbgn);
-		} else if (element instanceof Gene) {
-			return new GeneCellDesignerAliasConverter(sbgn);
-		} else if (element instanceof Unknown) {
-			return new UnknownCellDesignerAliasConverter(sbgn);
-		} else {
-			throw new NotImplementedException(eu.getElementTag(element) + "Unknown converter for class");
-		}
-	}
-
-	/**
-	 * Converter used for operations on the {@link Element} given in constructor.
-	 */
-	@SuppressWarnings("rawtypes")
-	private ICellDesignerAliasConverter converter = null;
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param sbgn
-	 *          Should the converter use sbgn standard
-	 * @param element
-	 *          element for which this converter will be used
-	 */
-	public CellDesignerAliasConverter(Element element, boolean sbgn) {
-		converter = getConverterForAlias(element, sbgn);
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public CellDesignerAnchor getAnchorForCoordinates(Element element, Point2D point) {
-		return converter.getAnchorForCoordinates(element, point);
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public Point2D getPointCoordinates(Element element, CellDesignerAnchor anchor) {
-		return converter.getPointCoordinates(element, anchor);
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public Point2D getAnchorPointCoordinates(Element element, CellDesignerAnchor anchor, PolylineData line) {
-		return converter.getAnchorPointCoordinates(element, anchor, line);
-	}
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import java.awt.geom.Point2D;
+
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
+import lcsb.mapviewer.model.graphics.PolylineData;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.Degraded;
+import lcsb.mapviewer.model.map.species.Drug;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Ion;
+import lcsb.mapviewer.model.map.species.Phenotype;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.SimpleMolecule;
+import lcsb.mapviewer.model.map.species.Unknown;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.modelutils.map.ElementUtils;
+
+/**
+ * This class is designed to obtain CellDesigner specific data from
+ * {@link Element}.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+
+public class CellDesignerAliasConverter implements ICellDesignerAliasConverter<Element> {
+
+  /**
+   * Class helping with transforming objects into meaningful identifiers.
+   */
+  private static ElementUtils eu = new ElementUtils();
+
+  /**
+   * Returns a converter for given {@link Element}. If converter doesn't exist
+   * exception is thrown.
+   * 
+   * @param element
+   *          element for which we are looking for a converter
+   * @param sbgn
+   *          Should the converter use SBGN standard
+   * @return converter that can be applied for the given element
+   */
+  private ICellDesignerAliasConverter<? extends Element> getConverterForAlias(Element element, boolean sbgn) {
+    if (element == null) {
+      throw new InvalidArgumentException("element cannot be null");
+    }
+    if (element instanceof Protein) {
+      return new ProteinCellDesignerAliasConverter(sbgn);
+    } else if (element instanceof Degraded) {
+      return new DegradedCellDesignerAliasConverter(sbgn);
+    } else if (element instanceof Complex) {
+      return new ComplexCellDesignerAliasConverter(sbgn);
+    } else if (element instanceof SimpleMolecule) {
+      return new SimpleMoleculeCellDesignerAliasConverter(sbgn);
+    } else if (element instanceof Drug) {
+      return new DrugCellDesignerAliasConverter(sbgn);
+    } else if (element instanceof Ion) {
+      return new IonCellDesignerAliasConverter(sbgn);
+    } else if (element instanceof Phenotype) {
+      return new PhenotypeCellDesignerAliasConverter(sbgn);
+    } else if (element instanceof Rna) {
+      return new RnaCellDesignerAliasConverter(sbgn);
+    } else if (element instanceof AntisenseRna) {
+      return new AntisenseRnaCellDesignerAliasConverter(sbgn);
+    } else if (element instanceof Gene) {
+      return new GeneCellDesignerAliasConverter(sbgn);
+    } else if (element instanceof Unknown) {
+      return new UnknownCellDesignerAliasConverter(sbgn);
+    } else {
+      throw new NotImplementedException(eu.getElementTag(element) + "Unknown converter for class");
+    }
+  }
+
+  /**
+   * Converter used for operations on the {@link Element} given in constructor.
+   */
+  @SuppressWarnings("rawtypes")
+  private ICellDesignerAliasConverter converter = null;
+
+  /**
+   * Default constructor.
+   * 
+   * @param sbgn
+   *          Should the converter use SBGN standard
+   * @param element
+   *          element for which this converter will be used
+   */
+  public CellDesignerAliasConverter(Element element, boolean sbgn) {
+    converter = getConverterForAlias(element, sbgn);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public CellDesignerAnchor getAnchorForCoordinates(Element element, Point2D point) {
+    return converter.getAnchorForCoordinates(element, point);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public Point2D getPointCoordinates(Element element, CellDesignerAnchor anchor) {
+    return converter.getPointCoordinates(element, anchor);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public Point2D getAnchorPointCoordinates(Element element, CellDesignerAnchor anchor, PolylineData line) {
+    return converter.getAnchorPointCoordinates(element, anchor, line);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public Double getAngleForPoint(Element element, Point2D position) {
+    return converter.getAngleForPoint(element, position);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public Point2D getResidueCoordinates(Element species, double angle) {
+    return converter.getResidueCoordinates(species, angle);
+  }
+
+  @Override
+  public Double getCellDesignerPositionByCoordinates(ModificationResidue mr) {
+    return converter.getCellDesignerPositionByCoordinates(mr);
+  }
+
+  @Override
+  public Point2D getCoordinatesByPosition(Element element, Double pos) {
+    return converter.getCoordinatesByPosition(element, pos);
+  }
+
+  @Override
+  public Double getCellDesignerSize(ModificationResidue mr) {
+    return converter.getCellDesignerSize(mr);
+  }
+
+  @Override
+  public Double getWidthBySize(Element element, Double size) {
+    return converter.getWidthBySize(element, size);
+  }
+
+  @Override
+  public Point2D getCoordinatesByPosition(Element element, Double pos, Double width) {
+    return converter.getCoordinatesByPosition(element, pos, width);
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/GeneCellDesignerAliasConverter.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/GeneCellDesignerAliasConverter.java
index 5a26c2bc169c3060fa19aa41b66e3fe0240c293c..e09ff00182661df44f68ddf28c40d997e8534ae5 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/GeneCellDesignerAliasConverter.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/GeneCellDesignerAliasConverter.java
@@ -1,81 +1,120 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import java.awt.Rectangle;
-import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.Species;
-
-/**
- * Class that provides CellDesigner specific graphical information for Gene.
- * It's used for conversion from xml to normal x,y coordinates.
- * 
- * @author Piotr Gawron
- * 
- */
-public class GeneCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Species> {
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param sbgn
-	 *          Should the converter use sbgn standard
-	 */
-	protected GeneCellDesignerAliasConverter(boolean sbgn) {
-		super(sbgn);
-	}
-
-	/**
-	 * How big should be the arc in rectangle for nucleic acid feature representation.
-	 */
-	private static final int	RECTANGLE_CORNER_ARC_SIZE	= 5;
-
-	@Override
-	public Point2D getPointCoordinates(Species alias, CellDesignerAnchor anchor) {
-		if (invalidAnchorPosition(alias, anchor)) {
-			return alias.getCenter();
-		}
-		return getRectangleTransformation().getPointOnRectangleByAnchor(alias.getX(), alias.getY(), alias.getWidth(), alias.getHeight(), anchor);
-	}
-
-	/**
-	 * Shape representation of the gene alias.
-	 * 
-	 * @param alias
-	 *          alias for which we are looking for a Shape
-	 * @return Shape object that represents alias
-	 */
-	private Shape getGeneShape(Element alias) {
-		if (!isSbgn()) {
-			Shape shape;
-			shape = new Rectangle(alias.getX().intValue(), alias.getY().intValue(), alias.getWidth().intValue(), alias.getHeight().intValue());
-			return shape;
-		} else {
-			GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
-			double x = alias.getX(), y = alias.getY(), width = alias.getWidth(), height = alias.getHeight();
-			
-			path.moveTo(x, y);
-			path.lineTo(x, y + height - RECTANGLE_CORNER_ARC_SIZE);
-			path.curveTo(x, y + height,
-																			x + RECTANGLE_CORNER_ARC_SIZE, y + height,
-																			x + RECTANGLE_CORNER_ARC_SIZE, y + height);
-			path.lineTo(x + width - RECTANGLE_CORNER_ARC_SIZE, y + height);
-			path.curveTo(x + width, y + height,
-																			x + width, y + height - RECTANGLE_CORNER_ARC_SIZE,
-																			x + width, y + height - RECTANGLE_CORNER_ARC_SIZE);
-			path.lineTo(x + width, y);
-			path.closePath();
-			return path;
-		}
-	}
-
-	@Override
-	public PathIterator getBoundPathIterator(Species alias) {
-		return getGeneShape(alias).getPathIterator(new AffineTransform());
-	}
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.field.AbstractRegionModification;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * Class that provides CellDesigner specific graphical information for Gene.
+ * It's used for conversion from xml to normal x,y coordinates.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class GeneCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Gene> {
+
+  Logger logger = Logger.getLogger(GeneCellDesignerAliasConverter.class);
+
+  /**
+   * Default constructor.
+   * 
+   * @param sbgn
+   *          Should the converter use SBGN standard
+   */
+  protected GeneCellDesignerAliasConverter(boolean sbgn) {
+    super(sbgn);
+  }
+
+  /**
+   * How big should be the arc in rectangle for nucleic acid feature
+   * representation.
+   */
+  private static final int RECTANGLE_CORNER_ARC_SIZE = 5;
+
+  @Override
+  public Point2D getPointCoordinates(Gene alias, CellDesignerAnchor anchor) {
+    if (invalidAnchorPosition(alias, anchor)) {
+      return alias.getCenter();
+    }
+    return getRectangleTransformation().getPointOnRectangleByAnchor(alias.getX(), alias.getY(), alias.getWidth(),
+        alias.getHeight(), anchor);
+  }
+
+  /**
+   * Shape representation of the gene alias.
+   * 
+   * @param alias
+   *          alias for which we are looking for a Shape
+   * @return Shape object that represents alias
+   */
+  private Shape getGeneShape(Element alias) {
+    if (!isSbgn()) {
+      Shape shape;
+      shape = new Rectangle(alias.getX().intValue(), alias.getY().intValue(), alias.getWidth().intValue(),
+          alias.getHeight().intValue());
+      return shape;
+    } else {
+      GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
+      double x = alias.getX(), y = alias.getY(), width = alias.getWidth(), height = alias.getHeight();
+
+      path.moveTo(x, y);
+      path.lineTo(x, y + height - RECTANGLE_CORNER_ARC_SIZE);
+      path.curveTo(x, y + height, x + RECTANGLE_CORNER_ARC_SIZE, y + height, x + RECTANGLE_CORNER_ARC_SIZE, y + height);
+      path.lineTo(x + width - RECTANGLE_CORNER_ARC_SIZE, y + height);
+      path.curveTo(x + width, y + height, x + width, y + height - RECTANGLE_CORNER_ARC_SIZE, x + width,
+          y + height - RECTANGLE_CORNER_ARC_SIZE);
+      path.lineTo(x + width, y);
+      path.closePath();
+      return path;
+    }
+  }
+
+  @Override
+  public PathIterator getBoundPathIterator(Gene alias) {
+    return getGeneShape(alias).getPathIterator(new AffineTransform());
+  }
+
+  @Override
+  public Double getCellDesignerPositionByCoordinates(ModificationResidue mr) {
+    Double result = (mr.getPosition().getX() - mr.getSpecies().getX()) / mr.getSpecies().getWidth();
+    result = Math.min(result, 1.0);
+    result = Math.max(result, 0.0);
+    return result;
+  }
+
+  @Override
+  public Point2D getCoordinatesByPosition(Element element, Double pos, Double modificationWidth) {
+    double x = element.getX() + element.getWidth() * pos;
+    x = Math.max(element.getX() + modificationWidth/2, x);
+    x = Math.min(element.getX() + element.getWidth() - modificationWidth/2, x);
+
+    Point2D result = new Point2D.Double(x, element.getY());
+    return result;
+  }
+
+  @Override
+  public Double getCellDesignerSize(ModificationResidue mr) {
+    if (mr instanceof AbstractRegionModification) {
+      return ((AbstractRegionModification) mr).getWidth() / mr.getSpecies().getWidth();
+    }
+    throw new NotImplementedException("Not implemented for: " + this.getClass() + ", " + mr.getClass());
+  }
+
+  @Override
+  public Double getWidthBySize(Element element, Double size) {
+    return size * element.getWidth();
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ICellDesignerAliasConverter.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ICellDesignerAliasConverter.java
index a42fa6d4b6ff3245e52fb8e0189c30cc997c34c4..21de988f8c52418e8b59b56e71157538192e4b75 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ICellDesignerAliasConverter.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ICellDesignerAliasConverter.java
@@ -1,61 +1,96 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import java.awt.geom.Point2D;
-
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
-import lcsb.mapviewer.model.graphics.PolylineData;
-import lcsb.mapviewer.model.map.species.Element;
-
-/**
- * Interface that defines functions usefull in transforming graphical
- * information from objects retrieved from CellDesigner xml into abslote values.
- * 
- * @author Piotr Gawron
- * 
- * @param <T>
- */
-public interface ICellDesignerAliasConverter<T extends Element> {
-	/**
-	 * This method computes which anchor is the most probable for describing the
-	 * point on the border of alias. There are 16 possible anchors on the border
-	 * of every alias and one undefined point that will be used if no point can be
-	 * found (see {@link CellDesignerAnchor} to find information about anchors).
-	 * 
-	 * @param alias
-	 *          object for which we try to find anchor
-	 * @param point
-	 *          point on the border of alias for which we try to find anchor
-	 * @return CellDesigner anchor point that describe the best point on the
-	 *         border
-	 */
-	CellDesignerAnchor getAnchorForCoordinates(T alias, Point2D point);
-
-	/**
-	 * This method transform CellDesigner anchor point on the alias into x,y
-	 * coordinates.
-	 * 
-	 * @param alias
-	 *          we want to find coordinates on this alias border
-	 * @param anchor
-	 *          CelDesigner anchor that defines point on the border
-	 * @return point on the border that is defined by the anchor point
-	 */
-	Point2D getPointCoordinates(T alias, CellDesignerAnchor anchor);
-
-	/**
-	 * This method transform CellDesigner anchor point on the alias into x,y
-	 * coordinates. If the anchor point doesn't define point then the line
-	 * parameter is used to find the right angle on the alias border and point on
-	 * the border with this angle is used as a result.
-	 * 
-	 * @param alias
-	 *          we want to find coordinates on this alias border
-	 * @param anchor
-	 *          CelDesigner anchor that defines point on the border
-	 * @param line
-	 *          line that starts in the alias
-	 * @return point on the border that is defined by the anchor point
-	 */
-	Point2D getAnchorPointCoordinates(T alias, CellDesignerAnchor anchor, PolylineData line);
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import java.awt.geom.Point2D;
+
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
+import lcsb.mapviewer.model.graphics.PolylineData;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * Interface that defines functions useful in transforming graphical information
+ * from objects retrieved from CellDesigner xml into absolute values.
+ * 
+ * @author Piotr Gawron
+ * 
+ * @param <T>
+ */
+public interface ICellDesignerAliasConverter<T extends Element> {
+  /**
+   * This method computes which anchor is the most probable for describing the
+   * point on the border of alias. There are 16 possible anchors on the border of
+   * every alias and one undefined point that will be used if no point can be
+   * found (see {@link CellDesignerAnchor} to find information about anchors).
+   * 
+   * @param alias
+   *          object for which we try to find anchor
+   * @param point
+   *          point on the border of alias for which we try to find anchor
+   * @return CellDesigner anchor point that describe the best point on the border
+   */
+  CellDesignerAnchor getAnchorForCoordinates(T alias, Point2D point);
+
+  /**
+   * This method transform CellDesigner anchor point on the alias into x,y
+   * coordinates.
+   * 
+   * @param alias
+   *          we want to find coordinates on this alias border
+   * @param anchor
+   *          CelDesigner anchor that defines point on the border
+   * @return point on the border that is defined by the anchor point
+   */
+  Point2D getPointCoordinates(T alias, CellDesignerAnchor anchor);
+
+  /**
+   * This method transform CellDesigner anchor point on the alias into x,y
+   * coordinates. If the anchor point doesn't define point then the line parameter
+   * is used to find the right angle on the alias border and point on the border
+   * with this angle is used as a result.
+   * 
+   * @param alias
+   *          we want to find coordinates on this alias border
+   * @param anchor
+   *          CelDesigner anchor that defines point on the border
+   * @param line
+   *          line that starts in the alias
+   * @return point on the border that is defined by the anchor point
+   */
+  Point2D getAnchorPointCoordinates(T alias, CellDesignerAnchor anchor, PolylineData line);
+
+  Point2D getResidueCoordinates(final T species, double angle);
+
+  Double getAngleForPoint(T alias, Point2D position);
+
+  public Double getCellDesignerPositionByCoordinates(ModificationResidue mr);
+
+  /**
+   * Gets coordinates on element based on CellDesigner position
+   * 
+   * @param element
+   *          element on which we want to find coordinates
+   * @param pos
+   *          CellDesigner position (value between 0-1)
+   * @return coordinates on the element
+   */
+  public Point2D getCoordinatesByPosition(Element element, Double pos);
+
+  /**
+   * Gets coordinates on element based on CellDesigner position taking into
+   * account width of the {@link ModificationResidue} that we want to place.
+   * 
+   * @param element
+   *          element on which we want to find coordinates
+   * @param pos
+   *          CellDesigner position (value between 0-1)
+   * @param modificationWidth
+   *          width of the {@link ModificationResidue}
+   * @return coordinates on the element
+   */
+  public Point2D getCoordinatesByPosition(Element element, Double pos, Double modificationWidth);
+
+  public Double getCellDesignerSize(ModificationResidue mr);
+
+  public Double getWidthBySize(Element element, Double size);
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/IonCellDesignerAliasConverter.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/IonCellDesignerAliasConverter.java
index 1b1fbd6efe3e581f63203a1a1a131fbc9439afdd..5b8e000b5062070ba9f4db784de1e266afa7e821 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/IonCellDesignerAliasConverter.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/IonCellDesignerAliasConverter.java
@@ -3,9 +3,12 @@ package lcsb.mapviewer.converter.model.celldesigner.geometry;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 
+import org.apache.log4j.Logger;
+
 import lcsb.mapviewer.common.exception.NotImplementedException;
 import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
 import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Ion;
 import lcsb.mapviewer.model.map.species.Species;
 
 /**
@@ -15,86 +18,102 @@ import lcsb.mapviewer.model.map.species.Species;
  * @author Piotr Gawron
  * 
  */
-public class IonCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Species> {
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param sbgn
-	 *          Should the converter use sbgn standard
-	 */
-	protected IonCellDesignerAliasConverter(boolean sbgn) {
-		super(sbgn);
-	}
-
-	@Override
-	public Point2D getPointCoordinates(Species alias, CellDesignerAnchor anchor) {
-		double diameter = getDiameter(alias);
-		double x = getXCoord(alias, diameter);
-		double y = getYCoord(alias);
-		if (invalidAnchorPosition(alias, anchor)) {
-			return alias.getCenter();
-		}
-
-		return getEllipseTransformation().getPointOnEllipseByAnchor(x, y, diameter, diameter, anchor);
-	}
-
-	/**
-	 * Returns transformed y coordinate for the ion alias.
-	 * 
-	 * @param alias
-	 *          object alias to to which we are looking for y coordinate
-	 * @return y coordinate of the alias
-	 */
-	private double getYCoord(Element alias) {
-		double y = alias.getY();
-		return y;
-	}
-
-	/**
-	 * Returns transformed x coordinate for the ion alias.
-	 * 
-	 * @param alias
-	 *          object alias to to which we are looking for x coordinate
-	 * @param diameter
-	 *          diameter of the circle representing alias
-	 * @return x coordinate of the alias
-	 */
-	private double getXCoord(Element alias, double diameter) {
-		double x = alias.getX() + (alias.getWidth() - diameter) / 2;
-		return x;
-	}
-
-	/**
-	 * Returns diameter of the ion alias.
-	 * 
-	 * @param alias
-	 *          object alias to to which we are looking for diameter.
-	 * @return diameter of the alias
-	 */
-	private double getDiameter(Element alias) {
-		double diameter = Math.min(alias.getWidth(), alias.getHeight());
-		if (diameter < 0) {
-			diameter = 0;
-		}
-		return diameter;
-	}
-
-	@Override
-	public Point2D getAnchorPointCoordinates(Species alias, double angle) {
-		if (alias.getWidth() == 0 && alias.getHeight() == 0) {
-			return alias.getCenter();
-		}
-		double diameter = getDiameter(alias);
-		double x = getXCoord(alias, diameter);
-		double y = getYCoord(alias);
-		Point2D result = getEllipseTransformation().getPointOnEllipseByRadian(x, y, diameter, diameter, angle);
-		return result;
-
-	}
-
-	@Override
-	protected PathIterator getBoundPathIterator(Species alias) {
-		throw new NotImplementedException("This class doesn't have bound");
-	}
+public class IonCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Ion> {
+
+  Logger logger = Logger.getLogger(IonCellDesignerAliasConverter.class);
+
+  /**
+   * Default constructor.
+   * 
+   * @param sbgn
+   *          Should the converter use SBGN standard
+   */
+  protected IonCellDesignerAliasConverter(boolean sbgn) {
+    super(sbgn);
+  }
+
+  @Override
+  public Point2D getPointCoordinates(Ion alias, CellDesignerAnchor anchor) {
+    double diameter = getDiameter(alias);
+    double x = getXCoord(alias, diameter);
+    double y = getYCoord(alias);
+    if (invalidAnchorPosition(alias, anchor)) {
+      return alias.getCenter();
+    }
+
+    return getEllipseTransformation().getPointOnEllipseByAnchor(x, y, diameter, diameter, anchor);
+  }
+
+  /**
+   * Returns transformed y coordinate for the ion alias.
+   * 
+   * @param alias
+   *          object alias to to which we are looking for y coordinate
+   * @return y coordinate of the alias
+   */
+  private double getYCoord(Element alias) {
+    double y = alias.getY();
+    return y;
+  }
+
+  /**
+   * Returns transformed x coordinate for the ion alias.
+   * 
+   * @param alias
+   *          object alias to to which we are looking for x coordinate
+   * @param diameter
+   *          diameter of the circle representing alias
+   * @return x coordinate of the alias
+   */
+  private double getXCoord(Element alias, double diameter) {
+    double x = alias.getX() + (alias.getWidth() - diameter) / 2;
+    return x;
+  }
+
+  /**
+   * Returns diameter of the ion alias.
+   * 
+   * @param alias
+   *          object alias to to which we are looking for diameter.
+   * @return diameter of the alias
+   */
+  private double getDiameter(Element alias) {
+    double diameter = Math.min(alias.getWidth(), alias.getHeight());
+    if (diameter < 0) {
+      diameter = 0;
+    }
+    return diameter;
+  }
+
+  @Override
+  public Point2D getAnchorPointCoordinates(Ion alias, double angle) {
+    if (alias.getWidth() == 0 && alias.getHeight() == 0) {
+      return alias.getCenter();
+    }
+    double diameter = getDiameter(alias);
+    double x = getXCoord(alias, diameter);
+    double y = getYCoord(alias);
+    Point2D result = getEllipseTransformation().getPointOnEllipseByRadian(x, y, diameter, diameter, angle);
+    return result;
+
+  }
+
+  @Override
+  protected PathIterator getBoundPathIterator(Ion alias) {
+    throw new NotImplementedException("This class doesn't have bound");
+  }
+
+  @Override
+  public Point2D getPointCoordinatesOnBorder(Ion ion, final double angle) {
+    if (ion.getWidth() == 0 && ion.getHeight() == 0) {
+      logger.warn("Looking for coordinates for the alias with 0 size");
+      return ion.getCenter();
+    }
+    double diameter = getDiameter(ion);
+    double x = getXCoord(ion, diameter);
+    double y = getYCoord(ion);
+    Point2D result = getEllipseTransformation().getPointOnEllipseByRadian(x, y, diameter, diameter, angle);
+    return result;
+
+  }
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/RnaCellDesignerAliasConverter.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/RnaCellDesignerAliasConverter.java
index 0cee48a0e63f19509fc0dc46c7ea5b004cea319d..e48e6caea925d4f626e17389745624220d7250bf 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/RnaCellDesignerAliasConverter.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/RnaCellDesignerAliasConverter.java
@@ -1,118 +1,150 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import java.awt.geom.AffineTransform;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.util.ArrayList;
-
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.Species;
-
-/**
- * Class that provides CellDesigner specific graphical information for Rna.
- * It's used for conversion from xml to normal x,y coordinates.
- * 
- * @author Piotr Gawron
- * 
- */
-public class RnaCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Species> {
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param sbgn
-	 *          Should the converter use sbgn standard
-	 */
-	protected RnaCellDesignerAliasConverter(boolean sbgn) {
-		super(sbgn);
-	}
-
-	/**
-	 * How big should be the arc in rectangle for nucleic acid feature representation.
-	 */	
-	private static final int	RECTANGLE_CORNER_ARC_SIZE	= 5;
-	
-	@Override
-	public Point2D getPointCoordinates(Species alias, CellDesignerAnchor anchor) {
-		if (invalidAnchorPosition(alias, anchor)) {
-			return alias.getCenter();
-		}
-		if (isSbgn()) {
-			return getRectangleTransformation().getPointOnRectangleByAnchor(alias.getX(), alias.getY(),
-																																			alias.getWidth(), alias.getHeight(), anchor);
-		}
-		ArrayList<Point2D> points = getPoints(alias);
-		return getPolygonTransformation().getPointOnPolygonByAnchor(points, anchor);
-	}
-
-	@Override
-	public PathIterator getBoundPathIterator(Species alias) {
-		return getRnaPath(alias).getPathIterator(new AffineTransform());
-	}
-
-	/**
-	 * Returns shape of the Rna as a list of points.
-	 * 
-	 * @param alias
-	 *          alias for which we are looking for a border
-	 * @return list of points defining border of the given alias
-	 */
-	private ArrayList<Point2D> getPoints(Element alias) {
-		double x = alias.getX();
-		double y = alias.getY();
-		double width = alias.getWidth();
-		double height = alias.getHeight();
-		ArrayList<Point2D> points = new ArrayList<Point2D>();
-		// CHECKSTYLE:OFF
-		points.add(new Point2D.Double(x + width / 8, y + height / 2));
-		points.add(new Point2D.Double(x + width / 4, y));
-		points.add(new Point2D.Double(x + width * 5 / 8, y));
-		points.add(new Point2D.Double(x + width, y));
-		points.add(new Point2D.Double(x + width * 7 / 8, y + height / 2));
-		points.add(new Point2D.Double(x + width * 3 / 4, y + height));
-		points.add(new Point2D.Double(x + width * 3 / 8, y + height));
-		// CHECKSTYLE:ON
-		points.add(new Point2D.Double(x, y + height));
-		return points;
-	}
-
-	/**
-	 * Returns shape of the Rna as a GeneralPath object.
-	 * 
-	 * @param alias
-	 *          alias for which we are looking for a border
-	 * @return GeneralPath object defining border of the given alias
-	 */
-	private GeneralPath getRnaPath(Element alias) {
-		// CHECKSTYLE:OFF
-		GeneralPath path;
-		if (!isSbgn()) {
-			path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 4);
-			path.moveTo(alias.getX() + alias.getWidth() / 4, alias.getY());
-			path.lineTo(alias.getX() + alias.getWidth(), alias.getY());
-			path.lineTo(alias.getX() + alias.getWidth() * 3 / 4, alias.getY() + alias.getHeight());
-			path.lineTo(alias.getX(), alias.getY() + alias.getHeight());
-			path.closePath();
-		} else {
-			path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 6);
-			double x = alias.getX(), y = alias.getY(), width = alias.getWidth(), height = alias.getHeight();
-			
-			path.moveTo(x, y);
-			path.lineTo(x, y + height - RECTANGLE_CORNER_ARC_SIZE);
-			path.curveTo(x, y + height,
-																			x + RECTANGLE_CORNER_ARC_SIZE, y + height,
-																			x + RECTANGLE_CORNER_ARC_SIZE, y + height);
-			path.lineTo(x + width - RECTANGLE_CORNER_ARC_SIZE, y + height);
-			path.curveTo(x + width, y + height,
-																			x + width, y + height - RECTANGLE_CORNER_ARC_SIZE,
-																			x + width, y + height - RECTANGLE_CORNER_ARC_SIZE);
-			path.lineTo(x + width, y);
-			path.closePath();
-		}
-		// CHECKSTYLE:ON
-		return path;
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.AbstractRegionModification;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * Class that provides CellDesigner specific graphical information for Rna. It's
+ * used for conversion from xml to normal x,y coordinates.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class RnaCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Species> {
+  Logger logger = Logger.getLogger(RnaCellDesignerAliasConverter.class);
+
+  /**
+   * Default constructor.
+   * 
+   * @param sbgn
+   *          Should the converter use sbgn standard
+   */
+  protected RnaCellDesignerAliasConverter(boolean sbgn) {
+    super(sbgn);
+  }
+
+  /**
+   * How big should be the arc in rectangle for nucleic acid feature
+   * representation.
+   */
+  private static final int RECTANGLE_CORNER_ARC_SIZE = 5;
+
+  @Override
+  public Point2D getPointCoordinates(Species alias, CellDesignerAnchor anchor) {
+    if (invalidAnchorPosition(alias, anchor)) {
+      return alias.getCenter();
+    }
+    if (isSbgn()) {
+      return getRectangleTransformation().getPointOnRectangleByAnchor(alias.getX(), alias.getY(), alias.getWidth(),
+          alias.getHeight(), anchor);
+    }
+    ArrayList<Point2D> points = getPoints(alias);
+    return getPolygonTransformation().getPointOnPolygonByAnchor(points, anchor);
+  }
+
+  @Override
+  public PathIterator getBoundPathIterator(Species alias) {
+    return getRnaPath(alias).getPathIterator(new AffineTransform());
+  }
+
+  /**
+   * Returns shape of the Rna as a list of points.
+   * 
+   * @param alias
+   *          alias for which we are looking for a border
+   * @return list of points defining border of the given alias
+   */
+  private ArrayList<Point2D> getPoints(Element alias) {
+    double x = alias.getX();
+    double y = alias.getY();
+    double width = alias.getWidth();
+    double height = alias.getHeight();
+    ArrayList<Point2D> points = new ArrayList<Point2D>();
+    // CHECKSTYLE:OFF
+    points.add(new Point2D.Double(x + width / 8, y + height / 2));
+    points.add(new Point2D.Double(x + width / 4, y));
+    points.add(new Point2D.Double(x + width * 5 / 8, y));
+    points.add(new Point2D.Double(x + width, y));
+    points.add(new Point2D.Double(x + width * 7 / 8, y + height / 2));
+    points.add(new Point2D.Double(x + width * 3 / 4, y + height));
+    points.add(new Point2D.Double(x + width * 3 / 8, y + height));
+    // CHECKSTYLE:ON
+    points.add(new Point2D.Double(x, y + height));
+    return points;
+  }
+
+  /**
+   * Returns shape of the Rna as a GeneralPath object.
+   * 
+   * @param alias
+   *          alias for which we are looking for a border
+   * @return GeneralPath object defining border of the given alias
+   */
+  private GeneralPath getRnaPath(Element alias) {
+    // CHECKSTYLE:OFF
+    GeneralPath path;
+    if (!isSbgn()) {
+      path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 4);
+      path.moveTo(alias.getX() + alias.getWidth() / 4, alias.getY());
+      path.lineTo(alias.getX() + alias.getWidth(), alias.getY());
+      path.lineTo(alias.getX() + alias.getWidth() * 3 / 4, alias.getY() + alias.getHeight());
+      path.lineTo(alias.getX(), alias.getY() + alias.getHeight());
+      path.closePath();
+    } else {
+      path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 6);
+      double x = alias.getX(), y = alias.getY(), width = alias.getWidth(), height = alias.getHeight();
+
+      path.moveTo(x, y);
+      path.lineTo(x, y + height - RECTANGLE_CORNER_ARC_SIZE);
+      path.curveTo(x, y + height, x + RECTANGLE_CORNER_ARC_SIZE, y + height, x + RECTANGLE_CORNER_ARC_SIZE, y + height);
+      path.lineTo(x + width - RECTANGLE_CORNER_ARC_SIZE, y + height);
+      path.curveTo(x + width, y + height, x + width, y + height - RECTANGLE_CORNER_ARC_SIZE, x + width,
+          y + height - RECTANGLE_CORNER_ARC_SIZE);
+      path.lineTo(x + width, y);
+      path.closePath();
+    }
+    // CHECKSTYLE:ON
+    return path;
+  }
+
+  @Override
+  public Double getCellDesignerPositionByCoordinates(ModificationResidue mr) {
+    return (mr.getPosition().getX() - mr.getSpecies().getX() - mr.getSpecies().getWidth() / 4.0)
+        / (mr.getSpecies().getWidth() * 3.0 / 4.0);
+  }
+
+  @Override
+  public Point2D getCoordinatesByPosition(Element element, Double pos, Double modificationWidth) {
+    double x = element.getX() + element.getWidth() / 4.0 + element.getWidth() * 3.0 / 4.0 * pos;
+    x = Math.max(element.getX() + modificationWidth / 2, x);
+    x = Math.min(element.getX() + element.getWidth() - modificationWidth / 2, x);
+
+    return new Point2D.Double(x, element.getY());
+  }
+
+  @Override
+  public Double getCellDesignerSize(ModificationResidue mr) {
+    if (mr instanceof AbstractRegionModification) {
+      return ((AbstractRegionModification) mr).getWidth() / (mr.getSpecies().getWidth() * 3.0 / 4.0);
+    }
+    throw new NotImplementedException("Not implemented for: " + this.getClass() + ", " + mr.getClass());
+  }
+
+  @Override
+  public Double getWidthBySize(Element element, Double size) {
+    return size * (element.getWidth() * 3.0 / 4.0);
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/SimpleMoleculeCellDesignerAliasConverter.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/SimpleMoleculeCellDesignerAliasConverter.java
index 858fea5cdb7e39849900ca9d3e3fc7cd7e640405..20a2e974e2f43a7c7e2057016045fe912044bcf9 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/SimpleMoleculeCellDesignerAliasConverter.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/SimpleMoleculeCellDesignerAliasConverter.java
@@ -3,9 +3,11 @@ package lcsb.mapviewer.converter.model.celldesigner.geometry;
 import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 
+import org.apache.log4j.Logger;
+
 import lcsb.mapviewer.common.exception.NotImplementedException;
 import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
-import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.SimpleMolecule;
 
 /**
  * Class that provides CellDesigner specific graphical information for
@@ -14,52 +16,69 @@ import lcsb.mapviewer.model.map.species.Species;
  * @author Piotr Gawron
  * 
  */
-public class SimpleMoleculeCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Species> {
+public class SimpleMoleculeCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<SimpleMolecule> {
+
+  Logger logger = Logger.getLogger(SimpleMoleculeCellDesignerAliasConverter.class);
+
+  /**
+   * Default constructor.
+   * 
+   * @param sbgn
+   *          Should the converter use sbgn standard
+   */
+  protected SimpleMoleculeCellDesignerAliasConverter(boolean sbgn) {
+    super(sbgn);
+  }
+
+  @Override
+  public Point2D getPointCoordinates(SimpleMolecule alias, CellDesignerAnchor anchor) {
+    double x = alias.getX();
+    double y = alias.getY();
+    double width = Math.max(alias.getWidth(), 1);
+    double height = Math.max(alias.getHeight(), 1);
+    if (invalidAnchorPosition(alias, anchor)) {
+      return alias.getCenter();
+    }
+    if (isSbgn()) {
+      return getEllipseTransformation().getPointOnEllipseByAnchor(x + (width - height) / 2, y, height, height, anchor);
+    }
+    return getEllipseTransformation().getPointOnEllipseByAnchor(x, y, width, height, anchor);
+  }
 
-	/**
-	 * Default constructor.
-	 * 
-	 * @param sbgn
-	 *          Should the converter use sbgn standard
-	 */
-	protected SimpleMoleculeCellDesignerAliasConverter(boolean sbgn) {
-		super(sbgn);
-	}
+  @Override
+  public Point2D getAnchorPointCoordinates(SimpleMolecule alias, double angle) {
+    if (alias.getWidth().equals(0.0) && alias.getHeight().equals(0.0)) {
+      return alias.getCenter();
+    }
+    Point2D result;
+    if (!isSbgn()) {
+      result = getEllipseTransformation().getPointOnEllipseByRadian(alias.getX(), alias.getY(), alias.getWidth(),
+          alias.getHeight(), angle);
+    } else {
+      result = getEllipseTransformation().getPointOnEllipseByRadian(
+          alias.getX() + (alias.getWidth() - alias.getHeight()) / 2, alias.getY(), alias.getHeight(), alias.getHeight(),
+          angle);
+    }
+    return result;
 
-	@Override
-	public Point2D getPointCoordinates(Species alias, CellDesignerAnchor anchor) {
-		double x = alias.getX();
-		double y = alias.getY();
-		double width = Math.max(alias.getWidth(), 1);
-		double height = Math.max(alias.getHeight(), 1);
-		if (invalidAnchorPosition(alias, anchor)) {
-			return alias.getCenter();
-		}
-		if (isSbgn()) {
-			return getEllipseTransformation().getPointOnEllipseByAnchor(x + (width - height) / 2, y, height, height, anchor);
-		}
-		return getEllipseTransformation().getPointOnEllipseByAnchor(x, y, width, height, anchor);
-	}
+  }
 
-	@Override
-	public Point2D getAnchorPointCoordinates(Species alias, double angle) {
-		if (alias.getWidth().equals(0.0) && alias.getHeight().equals(0.0)) {
-			return alias.getCenter();
-		}
-		Point2D result;
-		if (!isSbgn()) {
-			result = getEllipseTransformation().getPointOnEllipseByRadian(alias.getX(), alias.getY(), alias.getWidth(), alias.getHeight(), angle);
-		} else {
-			result = getEllipseTransformation()
-					.getPointOnEllipseByRadian(alias.getX() + (alias.getWidth() - alias.getHeight()) / 2, alias.getY(), alias.getHeight(), alias.getHeight(), angle);
-		}
-		return result;
+  @Override
+  public PathIterator getBoundPathIterator(SimpleMolecule alias) {
+    throw new NotImplementedException("This class doesn't provide boundPath");
+  }
 
-	}
+  @Override
+  public Point2D getPointCoordinatesOnBorder(final SimpleMolecule simpleMolecule, final double angle) {
+    if (simpleMolecule.getWidth() == 0 && simpleMolecule.getHeight() == 0) {
+      logger.warn("Looking for coordinates on border of alias of size 0");
+      return simpleMolecule.getCenter();
+    }
+    Point2D result;
+    result = getEllipseTransformation().getPointOnEllipseByRadian(simpleMolecule.getX(), simpleMolecule.getY(),
+        simpleMolecule.getWidth(), simpleMolecule.getHeight(), angle);
+    return result;
 
-	@Override
-	public PathIterator getBoundPathIterator(Species alias) {
-		throw new NotImplementedException("This class doesn't provide boundPath");
-	}
+  }
 
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/UnknownCellDesignerAliasConverter.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/UnknownCellDesignerAliasConverter.java
index 0d54efec3d264b791b1955358f4fb0db027ebd76..70ac03254ba23e788bb2ea297636a495db6acc17 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/UnknownCellDesignerAliasConverter.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/geometry/UnknownCellDesignerAliasConverter.java
@@ -1,54 +1,73 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
-import lcsb.mapviewer.model.map.species.Species;
-
-/**
- * Class that provides CellDesigner specific graphical information for
- * {@link lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerUnknown.model.map.species.Unknown
- * Unknown}. It's used for conversion from xml to normal x,y coordinates.
- * 
- * @author Piotr Gawron
- * 
- */
-public class UnknownCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Species> {
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param sbgn
-	 *          Should the converter use sbgn standard
-	 */
-	protected UnknownCellDesignerAliasConverter(boolean sbgn) {
-		super(sbgn);
-	}
-
-	@Override
-	public Point2D getPointCoordinates(Species alias, CellDesignerAnchor anchor) {
-		if (invalidAnchorPosition(alias, anchor)) {
-			return alias.getCenter();
-		}
-		return getEllipseTransformation().getPointOnEllipseByAnchor(alias.getX(), alias.getY(), alias.getWidth(), alias.getHeight(), anchor);
-	}
-
-	@Override
-	public PathIterator getBoundPathIterator(Species alias) {
-		throw new NotImplementedException("This class doesn't provide boundPath");
-	}
-
-	@Override
-	public Point2D getAnchorPointCoordinates(Species alias, double angle) {
-		if (alias.getWidth() == 0 && alias.getHeight() == 0) {
-			return alias.getCenter();
-		}
-		Point2D result;
-		result = getEllipseTransformation().getPointOnEllipseByRadian(alias.getX(), alias.getY(), alias.getWidth(), alias.getHeight(), angle);
-		return result;
-
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.Unknown;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * Class that provides CellDesigner specific graphical information for
+ * {@link lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerUnknown.model.map.species.Unknown
+ * Unknown}. It's used for conversion from xml to normal x,y coordinates.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class UnknownCellDesignerAliasConverter extends AbstractCellDesignerAliasConverter<Unknown> {
+
+  Logger logger = Logger.getLogger(UnknownCellDesignerAliasConverter.class);
+
+  /**
+   * Default constructor.
+   * 
+   * @param sbgn
+   *          Should the converter use sbgn standard
+   */
+  protected UnknownCellDesignerAliasConverter(boolean sbgn) {
+    super(sbgn);
+  }
+
+  @Override
+  public Point2D getPointCoordinates(Unknown alias, CellDesignerAnchor anchor) {
+    if (invalidAnchorPosition(alias, anchor)) {
+      return alias.getCenter();
+    }
+    return getEllipseTransformation().getPointOnEllipseByAnchor(alias.getX(), alias.getY(), alias.getWidth(),
+        alias.getHeight(), anchor);
+  }
+
+  @Override
+  public PathIterator getBoundPathIterator(Unknown alias) {
+    throw new NotImplementedException("This class doesn't provide boundPath");
+  }
+
+  @Override
+  public Point2D getAnchorPointCoordinates(Unknown alias, double angle) {
+    if (alias.getWidth() == 0 && alias.getHeight() == 0) {
+      return alias.getCenter();
+    }
+    Point2D result;
+    result = getEllipseTransformation().getPointOnEllipseByRadian(alias.getX(), alias.getY(), alias.getWidth(),
+        alias.getHeight(), angle);
+    return result;
+
+  }
+
+  @Override
+  public Point2D getPointCoordinatesOnBorder(Unknown unknown, final double angle) {
+    if (unknown.getWidth() == 0 && unknown.getHeight() == 0) {
+      logger.warn("Looking for coordinates for unknown of 0 size");
+      return unknown.getCenter();
+    }
+    Point2D result;
+    result = getEllipseTransformation().getPointOnEllipseByRadian(unknown.getX(), unknown.getY(), unknown.getWidth(),
+        unknown.getHeight(), angle);
+    return result;
+  }
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/AntisenseRnaXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/AntisenseRnaXmlParser.java
index 1213df96ac1b3cb495499cfb166636eb1a3ee052..2db1d9e5e3ea02f845d68116bb05730abfcf0028 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/AntisenseRnaXmlParser.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/AntisenseRnaXmlParser.java
@@ -5,15 +5,19 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
 import lcsb.mapviewer.common.Pair;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
 import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
 import lcsb.mapviewer.converter.model.celldesigner.annotation.RestAnnotationParser;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerAntisenseRna;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerElement;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerAntisenseRnaRegion;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.ModificationType;
 import lcsb.mapviewer.model.map.species.AntisenseRna;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegionType;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.ProteinBindingDomain;
 
 /**
  * Class that performs parsing of the CellDesigner xml for AntisenseRna object.
@@ -23,151 +27,163 @@ import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegionType;
  */
 public class AntisenseRnaXmlParser extends AbstractElementXmlParser<CellDesignerAntisenseRna, AntisenseRna> {
 
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private Logger												logger = Logger.getLogger(AntisenseRnaXmlParser.class.getName());
-
-	/**
-	 * List of {@link CellDesignerElement celldesigner elements} obtained during
-	 * parsing process.
-	 */
-	private CellDesignerElementCollection	elements;
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param elements
-	 *          list of {@link CellDesignerElement celldesigner elements} obtained
-	 *          during parsing process
-	 */
-	public AntisenseRnaXmlParser(CellDesignerElementCollection elements) {
-		this.elements = elements;
-	}
-
-	@Override
-	public Pair<String, CellDesignerAntisenseRna> parseXmlElement(Node antisenseRnaNode) throws InvalidXmlSchemaException {
-		CellDesignerAntisenseRna antisenseRna = new CellDesignerAntisenseRna();
-		String identifier = getNodeAttr("id", antisenseRnaNode);
-		antisenseRna.setName(decodeName(getNodeAttr("name", antisenseRnaNode)));
-		NodeList list = antisenseRnaNode.getChildNodes();
-		for (int i = 0; i < list.getLength(); i++) {
-			Node node = list.item(i);
-			if (node.getNodeType() == Node.ELEMENT_NODE) {
-				if (node.getNodeName().equals("celldesigner:notes")) {
-					antisenseRna.setNotes(getRap().getNotes(node));
-				} else if (node.getNodeName().equals("celldesigner:listOfRegions")) {
-					NodeList residueList = node.getChildNodes();
-					for (int j = 0; j < residueList.getLength(); j++) {
-						Node residueNode = residueList.item(j);
-						if (residueNode.getNodeType() == Node.ELEMENT_NODE) {
-							if (residueNode.getNodeName().equalsIgnoreCase("celldesigner:region")) {
-								antisenseRna.addRegion(getAntisenseRnaRegion(residueNode));
-							} else {
-								throw new InvalidXmlSchemaException("Unknown element of celldesigner:listOfRegions " + residueNode.getNodeName());
-							}
-						}
-					}
-				} else {
-					throw new InvalidXmlSchemaException("Unknown element of celldesigner:antisenseRna " + node.getNodeName());
-				}
-			}
-		}
-		Pair<String, CellDesignerAntisenseRna> result = new Pair<String, CellDesignerAntisenseRna>(identifier, antisenseRna);
-		return result;
-	}
-
-	@Override
-	public String toXml(AntisenseRna antisenseRna) {
-		String attributes = "";
-		String result = "";
-		attributes += " id=\"ar_" + elements.getElementId(antisenseRna) + "\"";
-		if (!antisenseRna.getName().equals("")) {
-			attributes += " name=\"" + escapeXml(encodeName(antisenseRna.getName())) + "\"";
-		}
-		result += "<celldesigner:AntisenseRNA" + attributes + ">";
-		result += "<celldesigner:notes>";
-		result += "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title/></head><body>";
-
-		RestAnnotationParser rap = new RestAnnotationParser();
-		result += rap.createAnnotationString(antisenseRna);
-		result += antisenseRna.getNotes();
-		result += "</body></html>";
-		result += "</celldesigner:notes>";
-		if (antisenseRna.getRegions().size() > 0) {
-			result += "<celldesigner:listOfRegions>";
-			for (AntisenseRnaRegion region : antisenseRna.getRegions()) {
-				result += toXml(region);
-			}
-			result += "</celldesigner:listOfRegions>";
-		}
-		result += "</celldesigner:AntisenseRNA>";
-		return result;
-	}
-
-	/**
-	 * Transforms AntisenseRnaRegion into CellDEsigner xml representation.
-	 * 
-	 * @param region
-	 *          object to be transformed
-	 * @return xml representation of the given region
-	 */
-	private String toXml(AntisenseRnaRegion region) {
-		String result = "";
-		String attributes = "";
-		if (!region.getIdAntisenseRnaRegion().equals("")) {
-			attributes += " id=\"" + region.getIdAntisenseRnaRegion() + "\"";
-		}
-		if (!region.getName().equals("")) {
-			attributes += " name=\"" + escapeXml(region.getName()) + "\"";
-		}
-		if (region.getSize() != 0) {
-			attributes += " size=\"" + region.getSize() + "\"";
-		}
-		if (region.getPos() != 0) {
-			attributes += " pos=\"" + region.getPos() + "\"";
-		}
-		if (region.getType() != null) {
-			attributes += " type=\"" + region.getType().getName() + "\"";
-		}
-		result += "<celldesigner:region " + attributes + ">";
-		result += "</celldesigner:region>";
-
-		return result;
-	}
-
-	/**
-	 * Method that parse xml node into AntisenseRnaRegion element.
-	 * 
-	 * @param regionNode
-	 *          xml node to parse
-	 * @return AntisenseRnaRegion object from xml node
-	 * @throws InvalidXmlSchemaException
-	 *           thrown when input xml node doesn't follow defined schema
-	 */
-	private CellDesignerAntisenseRnaRegion getAntisenseRnaRegion(Node regionNode) throws InvalidXmlSchemaException {
-		CellDesignerAntisenseRnaRegion residue = new CellDesignerAntisenseRnaRegion();
-		residue.setIdAntisenseRnaRegion(getNodeAttr("id", regionNode));
-		residue.setName(getNodeAttr("name", regionNode));
-		residue.setSize(getNodeAttr("size", regionNode));
-		residue.setPos(getNodeAttr("pos", regionNode));
-		String typeString = getNodeAttr("type", regionNode);
-		if (typeString != null) {
-			AntisenseRnaRegionType type = AntisenseRnaRegionType.getTypeByString(typeString);
-			if (type == null) {
-				throw new InvalidXmlSchemaException("Unknown antisense rna region type: " + typeString);
-			}
-			residue.setType(type);
-		}
-		NodeList list = regionNode.getChildNodes();
-		for (int i = 0; i < list.getLength(); i++) {
-			Node node = list.item(i);
-			if (node.getNodeType() == Node.ELEMENT_NODE) {
-				throw new InvalidXmlSchemaException("Unknown element of celldesigner:region " + node.getNodeName());
-			}
-		}
-		return residue;
-	}
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private Logger logger = Logger.getLogger(AntisenseRnaXmlParser.class.getName());
+
+  /**
+   * List of {@link CellDesignerElement celldesigner elements} obtained during
+   * parsing process.
+   */
+  private CellDesignerElementCollection elements;
+
+  /**
+   * Default constructor.
+   * 
+   * @param elements
+   *          list of {@link CellDesignerElement celldesigner elements} obtained
+   *          during parsing process
+   */
+  public AntisenseRnaXmlParser(CellDesignerElementCollection elements) {
+    this.elements = elements;
+  }
+
+  @Override
+  public Pair<String, CellDesignerAntisenseRna> parseXmlElement(Node antisenseRnaNode)
+      throws InvalidXmlSchemaException {
+    CellDesignerAntisenseRna antisenseRna = new CellDesignerAntisenseRna();
+    String identifier = getNodeAttr("id", antisenseRnaNode);
+    antisenseRna.setName(decodeName(getNodeAttr("name", antisenseRnaNode)));
+    NodeList list = antisenseRnaNode.getChildNodes();
+    for (int i = 0; i < list.getLength(); i++) {
+      Node node = list.item(i);
+      if (node.getNodeType() == Node.ELEMENT_NODE) {
+        if (node.getNodeName().equals("celldesigner:notes")) {
+          antisenseRna.setNotes(getRap().getNotes(node));
+        } else if (node.getNodeName().equals("celldesigner:listOfRegions")) {
+          NodeList residueList = node.getChildNodes();
+          for (int j = 0; j < residueList.getLength(); j++) {
+            Node residueNode = residueList.item(j);
+            if (residueNode.getNodeType() == Node.ELEMENT_NODE) {
+              if (residueNode.getNodeName().equalsIgnoreCase("celldesigner:region")) {
+                antisenseRna.addRegion(getAntisenseRnaRegion(residueNode));
+              } else {
+                throw new InvalidXmlSchemaException(
+                    "Unknown element of celldesigner:listOfRegions " + residueNode.getNodeName());
+              }
+            }
+          }
+        } else {
+          throw new InvalidXmlSchemaException("Unknown element of celldesigner:antisenseRna " + node.getNodeName());
+        }
+      }
+    }
+    Pair<String, CellDesignerAntisenseRna> result = new Pair<String, CellDesignerAntisenseRna>(identifier,
+        antisenseRna);
+    return result;
+  }
+
+  @Override
+  public String toXml(AntisenseRna antisenseRna) {
+    String attributes = "";
+    String result = "";
+    attributes += " id=\"ar_" + elements.getElementId(antisenseRna) + "\"";
+    if (!antisenseRna.getName().equals("")) {
+      attributes += " name=\"" + escapeXml(encodeName(antisenseRna.getName())) + "\"";
+    }
+    result += "<celldesigner:AntisenseRNA" + attributes + ">";
+    result += "<celldesigner:notes>";
+    result += "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title/></head><body>";
+
+    RestAnnotationParser rap = new RestAnnotationParser();
+    result += rap.createAnnotationString(antisenseRna);
+    result += antisenseRna.getNotes();
+    result += "</body></html>";
+    result += "</celldesigner:notes>";
+    if (antisenseRna.getRegions().size() > 0) {
+      result += "<celldesigner:listOfRegions>";
+      for (ModificationResidue region : antisenseRna.getRegions()) {
+        result += toXml(region);
+      }
+      result += "</celldesigner:listOfRegions>";
+    }
+    result += "</celldesigner:AntisenseRNA>";
+    return result;
+  }
+
+  /**
+   * Transforms AntisenseRnaRegion into CellDEsigner xml representation.
+   * 
+   * @param region
+   *          object to be transformed
+   * @return xml representation of the given region
+   */
+  private String toXml(ModificationResidue region) {
+    CellDesignerModificationResidue cellDesignerModificationResidue = new CellDesignerModificationResidue(region);
+
+    String result = "";
+    String attributes = "";
+    if (!region.getIdModificationResidue().equals("")) {
+      attributes += " id=\"" + region.getIdModificationResidue() + "\"";
+    }
+    if (!region.getName().equals("")) {
+      attributes += " name=\"" + escapeXml(region.getName()) + "\"";
+    }
+    String type = null;
+    if (region instanceof CodingRegion) {
+      attributes += " size=\"" + cellDesignerModificationResidue.getSize() + "\"";
+      type = "CodingRegion";
+    } else if (region instanceof ModificationSite) {
+      type = "Modification Site";
+    } else if (region instanceof ProteinBindingDomain) {
+      attributes += " size=\"" + cellDesignerModificationResidue.getSize() + "\"";
+      type = "proteinBindingDomain";
+    } else {
+      throw new InvalidArgumentException("Unknown modificatin type: " + region.getClass());
+    }
+
+    attributes += " pos=\"" + cellDesignerModificationResidue.getPos() + "\"";
+    attributes += " type=\"" + type + "\"";
+    result += "<celldesigner:region " + attributes + ">";
+    result += "</celldesigner:region>";
+
+    return result;
+  }
+
+  /**
+   * Method that parse xml node into AntisenseRnaRegion element.
+   * 
+   * @param regionNode
+   *          xml node to parse
+   * @return AntisenseRnaRegion object from xml node
+   * @throws InvalidXmlSchemaException
+   *           thrown when input xml node doesn't follow defined schema
+   */
+  private CellDesignerModificationResidue getAntisenseRnaRegion(Node regionNode) throws InvalidXmlSchemaException {
+    CellDesignerModificationResidue residue = new CellDesignerModificationResidue();
+    residue.setIdModificationResidue(getNodeAttr("id", regionNode));
+    residue.setName(getNodeAttr("name", regionNode));
+    residue.setSize(getNodeAttr("size", regionNode));
+    residue.setPos(getNodeAttr("pos", regionNode));
+    String typeString = getNodeAttr("type", regionNode);
+    if (typeString != null) {
+      try {
+        residue.setModificationType(ModificationType.getByCellDesignerName(typeString));
+      } catch (InvalidArgumentException e) {
+        throw new InvalidXmlSchemaException(e);
+      }
+    }
+
+    NodeList list = regionNode.getChildNodes();
+    for (int i = 0; i < list.getLength(); i++) {
+      Node node = list.item(i);
+      if (node.getNodeType() == Node.ELEMENT_NODE) {
+        throw new InvalidXmlSchemaException("Unknown element of celldesigner:region " + node.getNodeName());
+      }
+    }
+    return residue;
+  }
 
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/GeneXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/GeneXmlParser.java
index 3813032e290fcb0a5a8632fe27ec6c362aba596e..7e041680e5843dd51d8387cdb9998218cb368ea9 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/GeneXmlParser.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/GeneXmlParser.java
@@ -5,158 +5,194 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
 import lcsb.mapviewer.common.Pair;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
 import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
 import lcsb.mapviewer.converter.model.celldesigner.annotation.RestAnnotationParser;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.CellDesignerAliasConverter;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerElement;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerGene;
 import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.ModificationType;
 import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
 import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.RegulatoryRegion;
+import lcsb.mapviewer.model.map.species.field.TranscriptionSite;
 
 /**
- * Class that performs parsing of the CellDesigner xml for {@link CellDesignerGene} object.
+ * Class that performs parsing of the CellDesigner xml for
+ * {@link CellDesignerGene} object.
  * 
  * @author Piotr Gawron
  * 
  */
 public class GeneXmlParser extends AbstractElementXmlParser<CellDesignerGene, Gene> {
 
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private Logger logger = Logger.getLogger(GeneXmlParser.class.getName());
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private Logger logger = Logger.getLogger(GeneXmlParser.class.getName());
 
-	/**
-	 * Collection of {@link CellDesignerElement cell designer elements} parsed
-	 * from xml.
-	 */
-	private CellDesignerElementCollection	elements;
+  /**
+   * Collection of {@link CellDesignerElement cell designer elements} parsed from
+   * xml.
+   */
+  private CellDesignerElementCollection elements;
 
-	/**
-	 * Default constructor. Model is required because some nodes require access to
-	 * other parts of the model.
-	 * 
-	 * @param elements
-	 *          collection of {@link CellDesignerElement cell designer elements}
-	 *          parsed from xml
-	 */
-	public GeneXmlParser(CellDesignerElementCollection elements) {
-		this.elements = elements;
-	}
+  /**
+   * Default constructor. Model is required because some nodes require access to
+   * other parts of the model.
+   * 
+   * @param elements
+   *          collection of {@link CellDesignerElement cell designer elements}
+   *          parsed from xml
+   */
+  public GeneXmlParser(CellDesignerElementCollection elements) {
+    this.elements = elements;
+  }
 
-	@Override
-	public Pair<String, CellDesignerGene> parseXmlElement(Node geneNode) throws InvalidXmlSchemaException {
-		CellDesignerGene gene = new CellDesignerGene();
-		String identifier = getNodeAttr("id", geneNode);
-		gene.setName(decodeName(getNodeAttr("name", geneNode)));
-		NodeList list = geneNode.getChildNodes();
-		for (int i = 0; i < list.getLength(); i++) {
-			Node node = list.item(i);
-			if (node.getNodeType() == Node.ELEMENT_NODE) {
-				if (node.getNodeName().equals("celldesigner:notes")) {
-					gene.setNotes(getRap().getNotes(node));
-				} else if (node.getNodeName().equals("celldesigner:listOfRegions")) {
-					NodeList residueList = node.getChildNodes();
-					for (int j = 0; j < residueList.getLength(); j++) {
-						Node residueNode = residueList.item(j);
-						if (residueNode.getNodeType() == Node.ELEMENT_NODE) {
-							if (residueNode.getNodeName().equalsIgnoreCase("celldesigner:region")) {
-								gene.addModificationResidue(getModificationResidue(residueNode));
-							} else {
-								throw new InvalidXmlSchemaException("Unknown element of celldesigner:listOfRegions " + residueNode.getNodeName());
-							}
-						}
-					}
-				} else {
-					throw new InvalidXmlSchemaException("Unknown element of celldesigner:gene " + node.getNodeName());
-				}
-			}
-		}
-		return new Pair<String, CellDesignerGene>(identifier, gene);
-	}
+  @Override
+  public Pair<String, CellDesignerGene> parseXmlElement(Node geneNode) throws InvalidXmlSchemaException {
+    CellDesignerGene gene = new CellDesignerGene();
+    String identifier = getNodeAttr("id", geneNode);
+    gene.setName(decodeName(getNodeAttr("name", geneNode)));
+    NodeList list = geneNode.getChildNodes();
+    for (int i = 0; i < list.getLength(); i++) {
+      Node node = list.item(i);
+      if (node.getNodeType() == Node.ELEMENT_NODE) {
+        if (node.getNodeName().equals("celldesigner:notes")) {
+          gene.setNotes(getRap().getNotes(node));
+        } else if (node.getNodeName().equals("celldesigner:listOfRegions")) {
+          NodeList residueList = node.getChildNodes();
+          for (int j = 0; j < residueList.getLength(); j++) {
+            Node residueNode = residueList.item(j);
+            if (residueNode.getNodeType() == Node.ELEMENT_NODE) {
+              if (residueNode.getNodeName().equalsIgnoreCase("celldesigner:region")) {
+                gene.addModificationResidue(getModificationResidue(residueNode));
+              } else {
+                throw new InvalidXmlSchemaException(
+                    "Unknown element of celldesigner:listOfRegions " + residueNode.getNodeName());
+              }
+            }
+          }
+        } else {
+          throw new InvalidXmlSchemaException("Unknown element of celldesigner:gene " + node.getNodeName());
+        }
+      }
+    }
+    return new Pair<String, CellDesignerGene>(identifier, gene);
+  }
 
-	/**
-	 * Parse modification for a gene.
-	 * 
-	 * @param residueNode
-	 *          source xml node
-	 * @return object representing modification
-	 * @throws InvalidXmlSchemaException
-	 *           thrown when input xml node doesn't follow defined schema
-	 */
-	CellDesignerModificationResidue getModificationResidue(Node residueNode) throws InvalidXmlSchemaException {
-		CellDesignerModificationResidue residue = new CellDesignerModificationResidue();
-		residue.setIdModificationResidue(getNodeAttr("id", residueNode));
-		residue.setName(getNodeAttr("name", residueNode));
-		residue.setSide(getNodeAttr("side", residueNode));
-		residue.setAngle(getNodeAttr("pos", residueNode));
-		NodeList list = residueNode.getChildNodes();
-		for (int i = 0; i < list.getLength(); i++) {
-			Node node = list.item(i);
-			if (node.getNodeType() == Node.ELEMENT_NODE) {
-				throw new InvalidXmlSchemaException("Unknown element of celldesigner:region " + node.getNodeName());
-			}
-		}
-		return residue;
-	}
+  /**
+   * Parse modification for a gene.
+   * 
+   * @param residueNode
+   *          source xml node
+   * @return object representing modification
+   * @throws InvalidXmlSchemaException
+   *           thrown when input xml node doesn't follow defined schema
+   */
+  CellDesignerModificationResidue getModificationResidue(Node residueNode) throws InvalidXmlSchemaException {
+    CellDesignerModificationResidue residue = new CellDesignerModificationResidue();
+    residue.setIdModificationResidue(getNodeAttr("id", residueNode));
+    residue.setName(getNodeAttr("name", residueNode));
+    residue.setSide(getNodeAttr("side", residueNode));
+    residue.setSize(getNodeAttr("size", residueNode));
+    residue.setActive(getNodeAttr("active", residueNode));
+    residue.setAngle(getNodeAttr("pos", residueNode));
+    String type = getNodeAttr("type", residueNode);
+    try {
+      residue.setModificationType(ModificationType.getByCellDesignerName(type));
+    } catch (InvalidArgumentException e) {
+      throw new InvalidXmlSchemaException(e);
+    }
+    NodeList list = residueNode.getChildNodes();
+    for (int i = 0; i < list.getLength(); i++) {
+      Node node = list.item(i);
+      if (node.getNodeType() == Node.ELEMENT_NODE) {
+        throw new InvalidXmlSchemaException("Unknown element of celldesigner:region " + node.getNodeName());
+      }
+    }
+    return residue;
+  }
 
-	@Override
-	public String toXml(Gene gene) {
-		String attributes = "";
-		String result = "";
-		attributes += " id=\"g_" + elements.getElementId(gene) + "\"";
-		if (!gene.getName().equals("")) {
-			attributes += " name=\"" + escapeXml(encodeName(gene.getName())) + "\"";
-		}
-		result += "<celldesigner:gene" + attributes + ">";
-		result += "<celldesigner:notes>";
-		result += "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title/></head><body>";
-		RestAnnotationParser rap = new RestAnnotationParser();
-		result += rap.createAnnotationString(gene);
-		result += gene.getNotes();
-		result += "</body></html>";
-		result += "</celldesigner:notes>";
+  @Override
+  public String toXml(Gene gene) {
+    String attributes = "";
+    String result = "";
+    attributes += " id=\"g_" + elements.getElementId(gene) + "\"";
+    if (!gene.getName().equals("")) {
+      attributes += " name=\"" + escapeXml(encodeName(gene.getName())) + "\"";
+    }
+    result += "<celldesigner:gene" + attributes + ">";
+    result += "<celldesigner:notes>";
+    result += "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title/></head><body>";
+    RestAnnotationParser rap = new RestAnnotationParser();
+    result += rap.createAnnotationString(gene);
+    result += gene.getNotes();
+    result += "</body></html>";
+    result += "</celldesigner:notes>";
 
-		if (gene.getModificationResidues().size() > 0) {
-			result += "<celldesigner:listOfRegions>\n";
-			for (ModificationResidue mr : gene.getModificationResidues()) {
-				result += toXml(mr);
-			}
-			result += "</celldesigner:listOfRegions>\n";
-		}
+    if (gene.getModificationResidues().size() > 0) {
+      result += "<celldesigner:listOfRegions>\n";
+      for (ModificationResidue mr : gene.getModificationResidues()) {
+        result += toXml(mr);
+      }
+      result += "</celldesigner:listOfRegions>\n";
+    }
 
-		result += "</celldesigner:gene>";
-		return result;
-	}
+    result += "</celldesigner:gene>";
+    return result;
+  }
 
-	/**
-	 * Generates CellDesigner xml for {@link CellDesignerModificationResidue}.
-	 * 
-	 * @param mr
-	 *          object to transform into xml
-	 * @return CellDesigner xml for {@link CellDesignerModificationResidue}
-	 */
-	String toXml(ModificationResidue mr) {
-		String result = "";
-		String attributes = "";
-		if (!mr.getIdModificationResidue().equals("")) {
-			attributes += " id=\"" + mr.getIdModificationResidue() + "\"";
-		}
-		if (!mr.getName().equals("")) {
-			attributes += " name=\"" + escapeXml(mr.getName()) + "\"";
-		}
-		if (!mr.getSide().equals("")) {
-			attributes += " side=\"" + mr.getSide() + "\"";
-		}
-		if (mr.getAngle() != null) {
-			attributes += " pos=\"" + mr.getAngle() + "\"";
-		}
-		result += "<celldesigner:region " + attributes + ">";
-		result += "</celldesigner:region>\n";
+  /**
+   * Generates CellDesigner xml for {@link CellDesignerModificationResidue}.
+   * 
+   * @param mr
+   *          object to transform into xml
+   * @return CellDesigner xml for {@link CellDesignerModificationResidue}
+   */
+  String toXml(ModificationResidue mr) {
+    CellDesignerModificationResidue cellDesignerModificationResidue = new CellDesignerModificationResidue(mr);
 
-		return result;
-	}
+    String result = "";
+    String attributes = "";
+    if (!mr.getIdModificationResidue().equals("")) {
+      attributes += " id=\"" + mr.getIdModificationResidue() + "\"";
+    }
+    if (!mr.getName().equals("")) {
+      attributes += " name=\"" + escapeXml(mr.getName()) + "\"";
+    }
+    String type = null;
+    if (mr instanceof ModificationSite) {
+      type = ModificationType.MODIFICATION_SITE.getCellDesignerName();
+    } else if (mr instanceof RegulatoryRegion) {
+      type = ModificationType.REGULATORY_REGION.getCellDesignerName();
+      attributes += " size=\"" + cellDesignerModificationResidue.getSize() + "\"";
+    } else if (mr instanceof CodingRegion) {
+      type = ModificationType.CODING_REGION.getCellDesignerName();
+      attributes += " size=\"" + cellDesignerModificationResidue.getSize() + "\"";
+    } else if (mr instanceof TranscriptionSite) {
+      TranscriptionSite transcriptionSite = (TranscriptionSite) mr;
+      if (transcriptionSite.getDirection().equals("RIGHT")) {
+        type = ModificationType.TRANSCRIPTION_SITE_RIGHT.getCellDesignerName();
+      } else {
+        type = ModificationType.TRANSCRIPTION_SITE_LEFT.getCellDesignerName();
+      }
+      attributes += " size=\"" + cellDesignerModificationResidue.getSize() + "\"";
+      attributes += " active=\"" + transcriptionSite.getActive() + "\"";
+    } else {
+      throw new InvalidArgumentException("Don't know how to handle: " + mr.getClass());
+    }
+    attributes += " type=\"" + type + "\"";
+    attributes += " pos=\"" + cellDesignerModificationResidue.getPos() + "\"";
+    result += "<celldesigner:region " + attributes + ">";
+    result += "</celldesigner:region>\n";
+
+    return result;
+  }
 
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/ProteinXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/ProteinXmlParser.java
index 68cd9af32aa18bae5cbbf1832c54febe80d4fef1..4f1e6d4cdc3a317b8f505dffdda898c45d3717c7 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/ProteinXmlParser.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/ProteinXmlParser.java
@@ -1,5 +1,8 @@
 package lcsb.mapviewer.converter.model.celldesigner.species;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.log4j.Logger;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -8,15 +11,19 @@ import lcsb.mapviewer.common.Pair;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
 import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.CellDesignerAliasConverter;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerElement;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerProtein;
 import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.ModificationType;
 import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.field.BindingRegion;
 import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.Residue;
 
 /**
- * Class that performs parsing of the CellDesigner xml for {@link CellDesignerProtein}
- * object.
+ * Class that performs parsing of the CellDesigner xml for
+ * {@link CellDesignerProtein} object.
  * 
  * @author Piotr Gawron
  * 
@@ -24,152 +31,237 @@ import lcsb.mapviewer.model.map.species.field.ModificationResidue;
 
 public class ProteinXmlParser extends AbstractElementXmlParser<CellDesignerProtein<?>, Protein> {
 
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private Logger								logger = Logger.getLogger(ProteinXmlParser.class.getName());
-
-	/**
-	 * Collection of {@link CellDesignerElement cell designer elements} parsed
-	 * from xml.
-	 */
-	private CellDesignerElementCollection	elements;
-
-	/**
-	 * Default constructor. Model is required because some nodes require access to
-	 * other parts of the model.
-	 * 
-	 * @param elements
-	 *          collection of {@link CellDesignerElement cell designer elements}
-	 *          parsed from xml
-	 */
-	public ProteinXmlParser(CellDesignerElementCollection elements) {
-		this.elements = elements;
-	}
-
-	@Override
-	public Pair<String, CellDesignerProtein<?>> parseXmlElement(Node proteinNode) throws InvalidXmlSchemaException {
-		CellDesignerProtein<?> protein = null;
-		String value = getNodeAttr("type", proteinNode);
-		ProteinMapping mapping = ProteinMapping.getMappingByString(value);
-		if (mapping != null) {
-			protein = mapping.createProtein();
-		} else {
-			throw new InvalidXmlSchemaException("Protein node in Sbml model is of unknown type: " + value);
-		}
-
-		String identifier = getNodeAttr("id", proteinNode);
-		protein.setName(decodeName(getNodeAttr("name", proteinNode)));
-		NodeList list = proteinNode.getChildNodes();
-		for (int i = 0; i < list.getLength(); i++) {
-			Node node = list.item(i);
-			if (node.getNodeType() == Node.ELEMENT_NODE) {
-				if (node.getNodeName().equals("celldesigner:listOfModificationResidues")) {
-					NodeList residueList = node.getChildNodes();
-					for (int j = 0; j < residueList.getLength(); j++) {
-						Node residueNode = residueList.item(j);
-						if (residueNode.getNodeType() == Node.ELEMENT_NODE) {
-							if (residueNode.getNodeName().equalsIgnoreCase("celldesigner:modificationResidue")) {
-								protein.addModificationResidue(getModificationResidue(residueNode));
-							} else {
-								throw new InvalidXmlSchemaException("Unknown element of celldesigner:listOfModificationResidues " + residueNode.getNodeName());
-							}
-						}
-					}
-				} else if (node.getNodeName().equals("celldesigner:notes")) {
-					protein.setNotes(getRap().getNotes(node));
-				} else {
-					throw new InvalidXmlSchemaException("Unknown element of celldesigner:protein " + node.getNodeName());
-				}
-			}
-		}
-
-		return new Pair<String, CellDesignerProtein<?>>(identifier, protein);
-	}
-
-	@Override
-	public String toXml(Protein protein) {
-		String attributes = "";
-		String result = "";
-		attributes += " id=\"p_" + elements.getElementId(protein) + "\"";
-		if (protein.getName() != null && !protein.getName().equals("")) {
-			attributes += " name=\"" + escapeXml(encodeName(protein.getName())) + "\"";
-		}
-		String type = null;
-		ProteinMapping mapping = ProteinMapping.getMappingByClass(protein.getClass());
-		if (mapping != null) {
-			type = mapping.getCellDesignerString();
-		} else {
-			throw new InvalidArgumentException("Invalid protein class type: " + protein.getClass().getName());
-		}
-		attributes += " type=\"" + type + "\"";
-		result += "<celldesigner:protein" + attributes + ">\n";
-		if (protein.getModificationResidues().size() > 0) {
-			result += "<celldesigner:listOfModificationResidues>";
-			for (ModificationResidue mr : protein.getModificationResidues()) {
-				result += toXml(mr);
-			}
-			result += "</celldesigner:listOfModificationResidues>\n";
-		}
-		// ignore notes - all notes will be stored in species
-		// result +=
-		// "<celldesigner:notes>"+protein.getNotes()+"</celldesigner:notes>";
-		result += "</celldesigner:protein>\n";
-		return result;
-	}
-
-	/**
-	 * Generates CellDesigner xml for {@link CellDesignerModificationResidue}.
-	 * 
-	 * @param mr
-	 *          object to transform into xml
-	 * @return CellDesigner xml for {@link CellDesignerModificationResidue}
-	 */
-	private String toXml(ModificationResidue mr) {
-		String result = "";
-		String attributes = "";
-		if (!mr.getIdModificationResidue().equals("")) {
-			attributes += " id=\"" + mr.getIdModificationResidue() + "\"";
-		}
-		if (!mr.getName().equals("")) {
-			attributes += " name=\"" + escapeXml(mr.getName()) + "\"";
-		}
-		if (!mr.getSide().equals("")) {
-			attributes += " side=\"" + mr.getSide() + "\"";
-		}
-		if (mr.getAngle() != null) {
-			attributes += " angle=\"" + mr.getAngle() + "\"";
-		}
-		result += "<celldesigner:modificationResidue " + attributes + ">";
-		result += "</celldesigner:modificationResidue>";
-
-		return result;
-	}
-
-	/**
-	 * Parses CellDesigner xml node for ModificationResidue.
-	 * 
-	 * @param residueNode
-	 *          xml node to parse
-	 * @return {@link CellDesignerModificationResidue} object created from the node
-	 * @throws InvalidXmlSchemaException
-	 *           thrown when input xml node doesn't follow defined schema
-	 */
-	private CellDesignerModificationResidue getModificationResidue(Node residueNode) throws InvalidXmlSchemaException {
-		CellDesignerModificationResidue residue = new CellDesignerModificationResidue();
-		residue.setIdModificationResidue(getNodeAttr("id", residueNode));
-		residue.setName(getNodeAttr("name", residueNode));
-		residue.setSide(getNodeAttr("side", residueNode));
-		residue.setAngle(getNodeAttr("angle", residueNode));
-		NodeList list = residueNode.getChildNodes();
-		for (int i = 0; i < list.getLength(); i++) {
-			Node node = list.item(i);
-			if (node.getNodeType() == Node.ELEMENT_NODE) {
-				throw new InvalidXmlSchemaException("Unknown element of celldesigner:modificationResidue " + node.getNodeName());
-			}
-		}
-		return residue;
-	}
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private Logger logger = Logger.getLogger(ProteinXmlParser.class.getName());
+
+  /**
+   * Collection of {@link CellDesignerElement cell designer elements} parsed from
+   * xml.
+   */
+  private CellDesignerElementCollection elements;
+
+  /**
+   * Default constructor. Model is required because some nodes require access to
+   * other parts of the model.
+   * 
+   * @param elements
+   *          collection of {@link CellDesignerElement cell designer elements}
+   *          parsed from xml
+   */
+  public ProteinXmlParser(CellDesignerElementCollection elements) {
+    this.elements = elements;
+  }
+
+  @Override
+  public Pair<String, CellDesignerProtein<?>> parseXmlElement(Node proteinNode) throws InvalidXmlSchemaException {
+    CellDesignerProtein<?> protein = null;
+    String value = getNodeAttr("type", proteinNode);
+    ProteinMapping mapping = ProteinMapping.getMappingByString(value);
+    if (mapping != null) {
+      protein = mapping.createProtein();
+    } else {
+      throw new InvalidXmlSchemaException("Protein node in Sbml model is of unknown type: " + value);
+    }
+
+    String identifier = getNodeAttr("id", proteinNode);
+    protein.setName(decodeName(getNodeAttr("name", proteinNode)));
+    NodeList list = proteinNode.getChildNodes();
+    for (int i = 0; i < list.getLength(); i++) {
+      Node node = list.item(i);
+      if (node.getNodeType() == Node.ELEMENT_NODE) {
+        if (node.getNodeName().equals("celldesigner:listOfModificationResidues")) {
+          NodeList residueList = node.getChildNodes();
+          for (int j = 0; j < residueList.getLength(); j++) {
+            Node residueNode = residueList.item(j);
+            if (residueNode.getNodeType() == Node.ELEMENT_NODE) {
+              if (residueNode.getNodeName().equalsIgnoreCase("celldesigner:modificationResidue")) {
+                protein.addModificationResidue(getModificationResidue(residueNode));
+              } else {
+                throw new InvalidXmlSchemaException(
+                    "Unknown element of celldesigner:listOfModificationResidues " + residueNode.getNodeName());
+              }
+            }
+          }
+        } else if (node.getNodeName().equals("celldesigner:listOfBindingRegions")) {
+          NodeList residueList = node.getChildNodes();
+          for (int j = 0; j < residueList.getLength(); j++) {
+            Node residueNode = residueList.item(j);
+            if (residueNode.getNodeType() == Node.ELEMENT_NODE) {
+              if (residueNode.getNodeName().equalsIgnoreCase("celldesigner:bindingRegion")) {
+                protein.addModificationResidue(getBindingRegion(residueNode));
+              } else {
+                throw new InvalidXmlSchemaException(
+                    "Unknown element of celldesigner:listOfModificationResidues " + residueNode.getNodeName());
+              }
+            }
+          }
+        } else if (node.getNodeName().equals("celldesigner:notes")) {
+          protein.setNotes(getRap().getNotes(node));
+        } else {
+          throw new InvalidXmlSchemaException("Unknown element of celldesigner:protein " + node.getNodeName());
+        }
+      }
+    }
+
+    return new Pair<String, CellDesignerProtein<?>>(identifier, protein);
+  }
+
+  @Override
+  public String toXml(Protein protein) {
+    String attributes = "";
+    String result = "";
+    attributes += " id=\"p_" + elements.getElementId(protein) + "\"";
+    if (protein.getName() != null && !protein.getName().equals("")) {
+      attributes += " name=\"" + escapeXml(encodeName(protein.getName())) + "\"";
+    }
+    String type = null;
+    ProteinMapping mapping = ProteinMapping.getMappingByClass(protein.getClass());
+    if (mapping != null) {
+      type = mapping.getCellDesignerString();
+    } else {
+      throw new InvalidArgumentException("Invalid protein class type: " + protein.getClass().getName());
+    }
+    attributes += " type=\"" + type + "\"";
+    result += "<celldesigner:protein" + attributes + ">\n";
+
+    List<Residue> residues = new ArrayList<>();
+    List<BindingRegion> bindingRegions = new ArrayList<>();
+    for (ModificationResidue mr : protein.getModificationResidues()) {
+      if (mr instanceof Residue) {
+        residues.add((Residue) mr);
+      } else if (mr instanceof BindingRegion) {
+        bindingRegions.add((BindingRegion) mr);
+      } else {
+        throw new InvalidArgumentException("Don't know how to handle: " + mr.getClass());
+      }
+    }
+    if (residues.size() > 0) {
+      result += "<celldesigner:listOfModificationResidues>";
+      for (Residue mr : residues) {
+        result += toXml(mr);
+      }
+      result += "</celldesigner:listOfModificationResidues>\n";
+    }
+    if (bindingRegions.size() > 0) {
+      result += "<celldesigner:listOfBindingRegions>";
+      for (BindingRegion mr : bindingRegions) {
+        result += toXml(mr);
+      }
+      result += "</celldesigner:listOfBindingRegions>\n";
+    }
+    // ignore notes - all notes will be stored in species
+    // result +=
+    // "<celldesigner:notes>"+protein.getNotes()+"</celldesigner:notes>";
+    result += "</celldesigner:protein>\n";
+    return result;
+  }
+
+  /**
+   * Generates CellDesigner xml for {@link Residue}.
+   * 
+   * @param mr
+   *          object to transform into xml
+   * @return CellDesigner xml for {@link Residue}
+   */
+  private String toXml(Residue mr) {
+    CellDesignerAliasConverter converter = new CellDesignerAliasConverter(mr.getSpecies(), false);
+
+    String result = "";
+    String attributes = "";
+    if (!mr.getIdModificationResidue().equals("")) {
+      attributes += " id=\"" + mr.getIdModificationResidue() + "\"";
+    }
+    if (!mr.getName().equals("")) {
+      attributes += " name=\"" + escapeXml(mr.getName()) + "\"";
+    }
+    attributes += " angle=\"" + converter.getAngleForPoint(mr.getSpecies(), mr.getPosition()) + "\"";
+    result += "<celldesigner:modificationResidue " + attributes + ">";
+    result += "</celldesigner:modificationResidue>";
+
+    return result;
+  }
+
+  /**
+   * Generates CellDesigner xml for {@link BindingRegion}.
+   * 
+   * @param mr
+   *          object to transform into xml
+   * @return CellDesigner xml for {@link BindingRegion}
+   */
+  private String toXml(BindingRegion mr) {
+
+    CellDesignerModificationResidue cellDesignerModificationResidue = new CellDesignerModificationResidue(mr);
+    String result = "";
+    String attributes = "";
+    if (!mr.getIdModificationResidue().equals("")) {
+      attributes += " id=\"" + mr.getIdModificationResidue() + "\"";
+    }
+    if (!mr.getName().equals("")) {
+      attributes += " name=\"" + escapeXml(mr.getName()) + "\"";
+    }
+    attributes += " angle=\"" + cellDesignerModificationResidue.getAngle() + "\"";
+    attributes += " size=\"" + cellDesignerModificationResidue.getSize() + "\"";
+    result += "<celldesigner:bindingRegion " + attributes + ">";
+    result += "</celldesigner:bindingRegion>";
+
+    return result;
+  }
+
+  /**
+   * Parses CellDesigner xml node for ModificationResidue.
+   * 
+   * @param residueNode
+   *          xml node to parse
+   * @return {@link CellDesignerModificationResidue} object created from the node
+   * @throws InvalidXmlSchemaException
+   *           thrown when input xml node doesn't follow defined schema
+   */
+  private CellDesignerModificationResidue getModificationResidue(Node residueNode) throws InvalidXmlSchemaException {
+    CellDesignerModificationResidue residue = new CellDesignerModificationResidue();
+    residue.setIdModificationResidue(getNodeAttr("id", residueNode));
+    residue.setName(getNodeAttr("name", residueNode));
+    residue.setSide(getNodeAttr("side", residueNode));
+    residue.setAngle(getNodeAttr("angle", residueNode));
+    residue.setModificationType(ModificationType.RESIDUE);
+    NodeList list = residueNode.getChildNodes();
+    for (int i = 0; i < list.getLength(); i++) {
+      Node node = list.item(i);
+      if (node.getNodeType() == Node.ELEMENT_NODE) {
+        throw new InvalidXmlSchemaException(
+            "Unknown element of celldesigner:modificationResidue " + node.getNodeName());
+      }
+    }
+    return residue;
+  }
+
+  /**
+   * Parses CellDesigner xml node for ModificationResidue.
+   * 
+   * @param residueNode
+   *          xml node to parse
+   * @return {@link CellDesignerModificationResidue} object created from the node
+   * @throws InvalidXmlSchemaException
+   *           thrown when input xml node doesn't follow defined schema
+   */
+  private CellDesignerModificationResidue getBindingRegion(Node residueNode) throws InvalidXmlSchemaException {
+    CellDesignerModificationResidue residue = new CellDesignerModificationResidue();
+    residue.setIdModificationResidue(getNodeAttr("id", residueNode));
+    residue.setName(getNodeAttr("name", residueNode));
+    residue.setSize(getNodeAttr("size", residueNode));
+    residue.setAngle(getNodeAttr("angle", residueNode));
+    residue.setModificationType(ModificationType.BINDING_REGION);
+    NodeList list = residueNode.getChildNodes();
+    for (int i = 0; i < list.getLength(); i++) {
+      Node node = list.item(i);
+      if (node.getNodeType() == Node.ELEMENT_NODE) {
+        throw new InvalidXmlSchemaException(
+            "Unknown element of celldesigner:modificationResidue " + node.getNodeName());
+      }
+    }
+    return residue;
+  }
 
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/RnaXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/RnaXmlParser.java
index 2febc38cc9615cff4420b7e0665521d27fe14817..1a8561939784facaba3ff978804574de184934e5 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/RnaXmlParser.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/RnaXmlParser.java
@@ -5,16 +5,24 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
 import lcsb.mapviewer.common.Pair;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
 import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
 import lcsb.mapviewer.converter.model.celldesigner.annotation.RestAnnotationParser;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.CellDesignerAliasConverter;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerElement;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerRna;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerRnaRegion;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.ModificationType;
 import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.ProteinBindingDomain;
 
 /**
- * Class that performs parsing of the CellDesigner xml for {@link CellDesignerRna} object.
+ * Class that performs parsing of the CellDesigner xml for
+ * {@link CellDesignerRna} object.
  * 
  * @author Piotr Gawron
  * 
@@ -22,105 +30,155 @@ import lcsb.mapviewer.model.map.species.Rna;
 
 public class RnaXmlParser extends AbstractElementXmlParser<CellDesignerRna, Rna> {
 
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private Logger								logger = Logger.getLogger(RnaXmlParser.class.getName());
-
-	/**
-	 * Collection of {@link CellDesignerElement cell designer elements} parsed
-	 * from xml.
-	 */
-	private CellDesignerElementCollection	elements;
-
-	/**
-	 * Default constructor. Model is required because some nodes require access to
-	 * other parts of the model.
-	 * 
-	 * @param elements
-	 *          collection of {@link CellDesignerElement cell designer elements}
-	 *          parsed from xml
-	 */
-	public RnaXmlParser(CellDesignerElementCollection elements) {
-		this.elements = elements;
-	}
-
-	@Override
-	public Pair<String, CellDesignerRna> parseXmlElement(Node rnaNode) throws InvalidXmlSchemaException {
-		CellDesignerRna rna = new CellDesignerRna();
-		String identifier = getNodeAttr("id", rnaNode);
-		rna.setName(decodeName(getNodeAttr("name", rnaNode)));
-		NodeList list = rnaNode.getChildNodes();
-		for (int i = 0; i < list.getLength(); i++) {
-			Node node = list.item(i);
-			if (node.getNodeType() == Node.ELEMENT_NODE) {
-				if (node.getNodeName().equals("celldesigner:notes")) {
-					rna.setNotes(getRap().getNotes(node));
-				} else if (node.getNodeName().equals("celldesigner:listOfRegions")) {
-					NodeList residueList = node.getChildNodes();
-					for (int j = 0; j < residueList.getLength(); j++) {
-						Node residueNode = residueList.item(j);
-						if (residueNode.getNodeType() == Node.ELEMENT_NODE) {
-							if (residueNode.getNodeName().equalsIgnoreCase("celldesigner:region")) {
-								rna.addRegion(getRnaRegion(residueNode));
-							} else {
-								throw new InvalidXmlSchemaException("Unknown element of celldesigner:listOfRegions " + residueNode.getNodeName());
-							}
-						}
-					}
-				} else {
-					throw new InvalidXmlSchemaException("Unknown element of celldesigner:rna " + node.getNodeName());
-				}
-			}
-		}
-		return new Pair<String, CellDesignerRna>(identifier, rna);
-	}
-
-	/**
-	 * Parses CellDesigner xml node for RnaRegion.
-	 * 
-	 * @param residueNode
-	 *          xml node to parse
-	 * @return {@link CellDesignerRnaRegion} object created from the node
-	 * @throws InvalidXmlSchemaException
-	 *           thrown when input xml node doesn't follow defined schema
-	 */
-	private CellDesignerRnaRegion getRnaRegion(Node residueNode) throws InvalidXmlSchemaException {
-		CellDesignerRnaRegion residue = new CellDesignerRnaRegion();
-		residue.setIdRnaRegion(getNodeAttr("id", residueNode));
-		residue.setSize(getNodeAttr("size", residueNode));
-		residue.setPos(getNodeAttr("pos", residueNode));
-		residue.setType(getNodeAttr("type", residueNode));
-		NodeList list = residueNode.getChildNodes();
-		for (int i = 0; i < list.getLength(); i++) {
-			Node node = list.item(i);
-			if (node.getNodeType() == Node.ELEMENT_NODE) {
-				throw new InvalidXmlSchemaException("Unknown element of celldesigner:region " + node.getNodeName());
-			}
-		}
-		return residue;
-	}
-
-	@Override
-	public String toXml(Rna rna) {
-		String attributes = "";
-		String result = "";
-		attributes += " id=\"r_" + elements.getElementId(rna) + "\"";
-		if (!rna.getName().equals("")) {
-			attributes += " name=\"" + escapeXml(encodeName(rna.getName())) + "\"";
-		}
-		result += "<celldesigner:RNA" + attributes + ">";
-		result += "<celldesigner:notes>";
-		result += "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title/></head><body>";
-		RestAnnotationParser rap = new RestAnnotationParser();
-		result += rap.createAnnotationString(rna);
-		result += rna.getNotes();
-		result += "</body></html>";
-		result += "</celldesigner:notes>";
-
-		result += "</celldesigner:RNA>";
-		return result;
-	}
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private Logger logger = Logger.getLogger(RnaXmlParser.class.getName());
+
+  /**
+   * Collection of {@link CellDesignerElement cell designer elements} parsed from
+   * xml.
+   */
+  private CellDesignerElementCollection elements;
+
+  /**
+   * Default constructor. Model is required because some nodes require access to
+   * other parts of the model.
+   * 
+   * @param elements
+   *          collection of {@link CellDesignerElement cell designer elements}
+   *          parsed from xml
+   */
+  public RnaXmlParser(CellDesignerElementCollection elements) {
+    this.elements = elements;
+  }
+
+  @Override
+  public Pair<String, CellDesignerRna> parseXmlElement(Node rnaNode) throws InvalidXmlSchemaException {
+    CellDesignerRna rna = new CellDesignerRna();
+    String identifier = getNodeAttr("id", rnaNode);
+    rna.setName(decodeName(getNodeAttr("name", rnaNode)));
+    NodeList list = rnaNode.getChildNodes();
+    for (int i = 0; i < list.getLength(); i++) {
+      Node node = list.item(i);
+      if (node.getNodeType() == Node.ELEMENT_NODE) {
+        if (node.getNodeName().equals("celldesigner:notes")) {
+          rna.setNotes(getRap().getNotes(node));
+        } else if (node.getNodeName().equals("celldesigner:listOfRegions")) {
+          NodeList residueList = node.getChildNodes();
+          for (int j = 0; j < residueList.getLength(); j++) {
+            Node residueNode = residueList.item(j);
+            if (residueNode.getNodeType() == Node.ELEMENT_NODE) {
+              if (residueNode.getNodeName().equalsIgnoreCase("celldesigner:region")) {
+                rna.addRegion(getRnaRegion(residueNode));
+              } else {
+                throw new InvalidXmlSchemaException(
+                    "Unknown element of celldesigner:listOfRegions " + residueNode.getNodeName());
+              }
+            }
+          }
+        } else {
+          throw new InvalidXmlSchemaException("Unknown element of celldesigner:rna " + node.getNodeName());
+        }
+      }
+    }
+    return new Pair<String, CellDesignerRna>(identifier, rna);
+  }
+
+  /**
+   * Parses CellDesigner xml node for RnaRegion.
+   * 
+   * @param residueNode
+   *          xml node to parse
+   * @return {@link CellDesignerRnaRegion} object created from the node
+   * @throws InvalidXmlSchemaException
+   *           thrown when input xml node doesn't follow defined schema
+   */
+  private CellDesignerModificationResidue getRnaRegion(Node residueNode) throws InvalidXmlSchemaException {
+    CellDesignerModificationResidue residue = new CellDesignerModificationResidue();
+    residue.setIdModificationResidue(getNodeAttr("id", residueNode));
+    residue.setSize(getNodeAttr("size", residueNode));
+    residue.setPos(getNodeAttr("pos", residueNode));
+    String typeString = getNodeAttr("type", residueNode);
+    if (typeString != null) {
+      residue.setModificationType(ModificationType.getByCellDesignerName(typeString));
+    }
+    NodeList list = residueNode.getChildNodes();
+    for (int i = 0; i < list.getLength(); i++) {
+      Node node = list.item(i);
+      if (node.getNodeType() == Node.ELEMENT_NODE) {
+        throw new InvalidXmlSchemaException("Unknown element of celldesigner:region " + node.getNodeName());
+      }
+    }
+    return residue;
+  }
+
+  @Override
+  public String toXml(Rna rna) {
+    String attributes = "";
+    String result = "";
+    attributes += " id=\"r_" + elements.getElementId(rna) + "\"";
+    if (!rna.getName().equals("")) {
+      attributes += " name=\"" + escapeXml(encodeName(rna.getName())) + "\"";
+    }
+    result += "<celldesigner:RNA" + attributes + ">";
+    result += "<celldesigner:notes>";
+    result += "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title/></head><body>";
+    RestAnnotationParser rap = new RestAnnotationParser();
+    result += rap.createAnnotationString(rna);
+    result += rna.getNotes();
+    result += "</body></html>";
+    result += "</celldesigner:notes>";
+
+    if (rna.getRegions().size() > 0) {
+      result += "<celldesigner:listOfRegions>";
+      for (ModificationResidue mr : rna.getRegions()) {
+        result += toXml(mr);
+      }
+      result += "</celldesigner:listOfRegions>";
+    }
+
+    result += "</celldesigner:RNA>";
+    return result;
+  }
+
+  /**
+   * Generates CellDesigner xml for {@link CellDesignerModificationResidue}.
+   * 
+   * @param mr
+   *          object to transform into xml
+   * @return CellDesigner xml for {@link CellDesignerModificationResidue}
+   */
+  String toXml(ModificationResidue mr) {
+    CellDesignerModificationResidue cellDesignerModificationResidue = new CellDesignerModificationResidue(mr);
+
+    String result = "";
+    String attributes = "";
+    if (!mr.getIdModificationResidue().equals("")) {
+      attributes += " id=\"" + mr.getIdModificationResidue() + "\"";
+    }
+    if (!mr.getName().equals("")) {
+      attributes += " name=\"" + escapeXml(mr.getName()) + "\"";
+    }
+    String type = null;
+    if (mr instanceof ModificationSite) {
+      type = ModificationType.MODIFICATION_SITE.getCellDesignerName();
+    } else if (mr instanceof CodingRegion) {
+      type = ModificationType.CODING_REGION.getCellDesignerName();
+      attributes += " size=\"" + cellDesignerModificationResidue.getSize() + "\"";
+    } else if (mr instanceof ProteinBindingDomain) {
+      type = ModificationType.PROTEIN_BINDING_DOMAIN.getCellDesignerName();
+      attributes += " size=\"" + cellDesignerModificationResidue.getSize() + "\"";
+    } else {
+      throw new InvalidArgumentException("Don't know how to handle: " + mr.getClass());
+    }
+    attributes += " type=\"" + type + "\"";
+    attributes += " pos=\"" + cellDesignerModificationResidue.getPos() + "\"";
+    result += "<celldesigner:region " + attributes + ">";
+    result += "</celldesigner:region>\n";
+
+    return result;
+  }
 
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParser.java
index c573707a2035ec14a6983048947b976a95f07799..a38a634c097cc21692fe90c3fa9b70cc4781bc78 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParser.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParser.java
@@ -20,9 +20,7 @@ import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerProtein
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerRna;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerSimpleMolecule;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerSpecies;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerAntisenseRnaRegion;
 import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerRnaRegion;
 import lcsb.mapviewer.converter.model.celldesigner.structure.fields.SpeciesState;
 import lcsb.mapviewer.model.map.compartment.Compartment;
 import lcsb.mapviewer.model.map.compartment.PathwayCompartment;
@@ -211,7 +209,8 @@ public class SpeciesSbmlParser extends AbstractElementXmlParser<CellDesignerSpec
       attributesBuilder.append(" constant=\"" + species.getConstant().toString().toLowerCase() + "\"");
     }
     if (species.getBoundaryCondition() != null) {
-      attributesBuilder.append(" boundaryCondition=\"" + species.getBoundaryCondition().toString().toLowerCase() + "\"");
+      attributesBuilder
+          .append(" boundaryCondition=\"" + species.getBoundaryCondition().toString().toLowerCase() + "\"");
     }
 
     Compartment comp = null;
@@ -459,7 +458,7 @@ public class SpeciesSbmlParser extends AbstractElementXmlParser<CellDesignerSpec
       }
 
       for (CellDesignerModificationResidue mr : state.getModifications()) {
-        rna.addRegion(createRnaRegion(mr));
+        rna.addRegion(mr);
       }
     } else if (species instanceof CellDesignerSimpleMolecule) {
       if (state.getStructuralState() != null && !state.getStructuralState().isEmpty()) {
@@ -476,8 +475,7 @@ public class SpeciesSbmlParser extends AbstractElementXmlParser<CellDesignerSpec
       }
 
       for (CellDesignerModificationResidue mr : state.getModifications()) {
-        CellDesignerAntisenseRnaRegion region = createAntisenseRnaRegion(mr);
-        antisenseRna.addRegion(region);
+        antisenseRna.addRegion(mr);
       }
     } else {
       if (state.getStructuralState() != null && !state.getStructuralState().isEmpty()) {
@@ -549,7 +547,8 @@ public class SpeciesSbmlParser extends AbstractElementXmlParser<CellDesignerSpec
   }
 
   /**
-   * Creates {@link CellDesignerModificationResidue} from the apropriate xml node.
+   * Creates {@link CellDesignerModificationResidue} from the appropriate xml
+   * node.
    * 
    * @param rootNode
    *          xml node
@@ -603,49 +602,4 @@ public class SpeciesSbmlParser extends AbstractElementXmlParser<CellDesignerSpec
     return "<celldesigner:modification residue=\"" + mr.getIdModificationResidue() + "\" state=\"" + state
         + "\"> </celldesigner:modification>\n";
   }
-
-  /**
-   * Creates {@link CellDesignerAntisenseRnaRegion} from
-   * {@link CellDesignerModificationResidue} description.
-   * 
-   * @param mr
-   *          object from which we create {@link CellDesignerAntisenseRnaRegion}
-   * @return {@link CellDesignerAntisenseRnaRegion} object created from param
-   */
-  CellDesignerAntisenseRnaRegion createAntisenseRnaRegion(CellDesignerModificationResidue mr) {
-    CellDesignerAntisenseRnaRegion region = new CellDesignerAntisenseRnaRegion();
-    region.setIdAntisenseRnaRegion(mr.getIdModificationResidue());
-    if (mr.getSize() != null) {
-      region.setSize(mr.getSize());
-    }
-    region.setState(mr.getState());
-    region.setName(mr.getName());
-    if (mr.getAngle() != null) {
-      region.setPos(mr.getAngle());
-    }
-    return region;
-  }
-
-  /**
-   * Creates {@link CellDesignerRnaRegion} from
-   * {@link CellDesignerModificationResidue} description.
-   * 
-   * @param mr
-   *          object from which we create {@link CellDesignerRnaRegion}
-   * @return {@link CellDesignerRnaRegion} object created from param
-   */
-  public CellDesignerRnaRegion createRnaRegion(CellDesignerModificationResidue mr) {
-    CellDesignerRnaRegion result = new CellDesignerRnaRegion();
-    result.setIdRnaRegion(mr.getIdModificationResidue());
-    if (mr.getSize() != null) {
-      result.setSize(mr.getSize());
-    }
-    result.setState(mr.getState());
-    result.setName(mr.getName());
-    if (mr.getAngle() != null) {
-      result.setPos(mr.getAngle());
-    }
-    return result;
-  }
-
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerAntisenseRna.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerAntisenseRna.java
index e3456b1c883be2e35b467ce847c334b709a798fa..9ad77efd72744ef067410592b646760e63baed5d 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerAntisenseRna.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerAntisenseRna.java
@@ -1,150 +1,149 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerAntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.AntisenseRna;
-
-/**
- * Class representing CellDesigner {@link AntisenseRna}.
- * 
- * @author Piotr Gawron
- * 
- */
-public class CellDesignerAntisenseRna extends CellDesignerSpecies<AntisenseRna> {
-
-	/**
-	 * 
-	 */
-	private static final long										 serialVersionUID	= 1L;
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger												 logger						= Logger.getLogger(CellDesignerAntisenseRna.class);
-
-	/**
-	 * List of antisense rna regions (some rna sequences) in this object.
-	 */
-	private List<CellDesignerAntisenseRnaRegion> regions					= new ArrayList<CellDesignerAntisenseRnaRegion>();
-
-	/**
-	 * Constructor that copies the data from species given in the argument.
-	 * 
-	 * @param species
-	 *          parent species from which we want to copy data
-	 */
-	public CellDesignerAntisenseRna(CellDesignerSpecies<?> species) {
-		super(species);
-		if (species instanceof CellDesignerAntisenseRna) {
-			CellDesignerAntisenseRna asRna = (CellDesignerAntisenseRna) species;
-			for (CellDesignerAntisenseRnaRegion region : asRna.getRegions()) {
-				addRegion(new CellDesignerAntisenseRnaRegion(region));
-			}
-		}
-	}
-
-	/**
-	 * Default constructor.
-	 */
-	public CellDesignerAntisenseRna() {
-		super();
-	}
-
-	@Override
-	public CellDesignerAntisenseRna copy() {
-		if (this.getClass() == CellDesignerAntisenseRna.class) {
-			return new CellDesignerAntisenseRna(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-	}
-
-	/**
-	 * Addd antisense rna region (part of rna sequence that has some meaning) to
-	 * the object. If the region with given id exists then the data of this region
-	 * is copied to the one that is already in the
-	 * {@link CellDesignerAntisenseRna}.
-	 * 
-	 * 
-	 * @param region
-	 *          region to add
-	 */
-	public void addRegion(CellDesignerAntisenseRnaRegion region) {
-		for (CellDesignerAntisenseRnaRegion region2 : regions) {
-			if (region2.getIdAntisenseRnaRegion().equals(region.getIdAntisenseRnaRegion())) {
-				region2.update(region);
-				return;
-			}
-		}
-
-		regions.add(region);
-		region.setSpecies(this);
-	}
-
-	@Override
-	public void update(CellDesignerSpecies<?> sp) {
-		super.update(sp);
-		if (sp instanceof CellDesignerAntisenseRna) {
-			CellDesignerAntisenseRna rna = (CellDesignerAntisenseRna) sp;
-			for (CellDesignerAntisenseRnaRegion mr : getRegions()) {
-				mr.setState(null);
-			}
-
-			for (CellDesignerAntisenseRnaRegion region : rna.getRegions()) {
-				updateRegion(region);
-			}
-		}
-	}
-
-	/**
-	 * Method update antisense rna region from the object in params (if the object
-	 * with the same id already exists). If there is no object with given id then
-	 * new object is added to antisense rna.
-	 * 
-	 * @param param
-	 *          - object with new data from where update should be performed
-	 */
-	private void updateRegion(CellDesignerAntisenseRnaRegion param) {
-		for (CellDesignerAntisenseRnaRegion region : regions) {
-			if (region.getIdAntisenseRnaRegion().equals(param.getIdAntisenseRnaRegion())) {
-				region.update(param);
-				return;
-			}
-		}
-		regions.add(param);
-	}
-
-	/**
-	 * @return the regions
-	 * @see #regions
-	 */
-	public List<CellDesignerAntisenseRnaRegion> getRegions() {
-		return regions;
-	}
-
-	/**
-	 * @param regions
-	 *          the regions to set
-	 * @see #regions
-	 */
-	public void setRegions(List<CellDesignerAntisenseRnaRegion> regions) {
-		this.regions = regions;
-	}
-
-	@Override
-	public AntisenseRna createModelElement(String aliasId) {
-		AntisenseRna result = new AntisenseRna(aliasId);
-		super.setModelObjectFields(result);
-		for (CellDesignerAntisenseRnaRegion region : regions) {
-			result.addRegion(region.createAntisenseRegionAlias());
-		}
-		return result;
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * Class representing CellDesigner {@link AntisenseRna}.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class CellDesignerAntisenseRna extends CellDesignerSpecies<AntisenseRna> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(CellDesignerAntisenseRna.class);
+
+  /**
+   * List of antisense rna regions (some rna sequences) in this object.
+   */
+  private List<CellDesignerModificationResidue> regions = new ArrayList<>();
+
+  /**
+   * Constructor that copies the data from species given in the argument.
+   * 
+   * @param species
+   *          parent species from which we want to copy data
+   */
+  public CellDesignerAntisenseRna(CellDesignerSpecies<?> species) {
+    super(species);
+    if (species instanceof CellDesignerAntisenseRna) {
+      CellDesignerAntisenseRna asRna = (CellDesignerAntisenseRna) species;
+      for (CellDesignerModificationResidue region : asRna.getRegions()) {
+        addRegion(new CellDesignerModificationResidue(region));
+      }
+    }
+  }
+
+  /**
+   * Default constructor.
+   */
+  public CellDesignerAntisenseRna() {
+    super();
+  }
+
+  @Override
+  public CellDesignerAntisenseRna copy() {
+    if (this.getClass() == CellDesignerAntisenseRna.class) {
+      return new CellDesignerAntisenseRna(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+  }
+
+  /**
+   * Add antisense rna region (part of rna sequence that has some meaning) to the
+   * object. If the region with given id exists then the data of this region is
+   * copied to the one that is already in the {@link CellDesignerAntisenseRna}.
+   * 
+   * 
+   * @param region
+   *          region to add
+   */
+  public void addRegion(CellDesignerModificationResidue region) {
+    for (CellDesignerModificationResidue region2 : regions) {
+      if (region2.getIdModificationResidue().equals(region.getIdModificationResidue())) {
+        region2.update(region);
+        return;
+      }
+    }
+    regions.add(region);
+    region.setSpecies(this);
+  }
+
+  @Override
+  public void update(CellDesignerSpecies<?> sp) {
+    super.update(sp);
+    if (sp instanceof CellDesignerAntisenseRna) {
+      CellDesignerAntisenseRna rna = (CellDesignerAntisenseRna) sp;
+      for (CellDesignerModificationResidue region : rna.getRegions()) {
+        updateRegion(region);
+      }
+    }
+  }
+
+  /**
+   * Method update antisense rna region from the object in params (if the object
+   * with the same id already exists). If there is no object with given id then
+   * new object is added to antisense rna.
+   * 
+   * @param param
+   *          - object with new data from where update should be performed
+   */
+  private void updateRegion(CellDesignerModificationResidue param) {
+    for (CellDesignerModificationResidue region : regions) {
+      if (region.getIdModificationResidue().equals(param.getIdModificationResidue())) {
+        region.update(param);
+        return;
+      }
+    }
+    regions.add(param);
+  }
+
+  /**
+   * @return the regions
+   * @see #regions
+   */
+  public List<CellDesignerModificationResidue> getRegions() {
+    return regions;
+  }
+
+  /**
+   * @param regions
+   *          the regions to set
+   * @see #regions
+   */
+  public void setRegions(List<CellDesignerModificationResidue> regions) {
+    this.regions = regions;
+  }
+
+  @Override
+  public AntisenseRna createModelElement(String aliasId) {
+    AntisenseRna result = new AntisenseRna(aliasId);
+    super.setModelObjectFields(result);
+    return result;
+  }
+
+  @Override
+  public void updateModelElementAfterLayoutAdded(Species element) {
+    for (CellDesignerModificationResidue region : regions) {
+      ((AntisenseRna) element).addRegion(region.createModificationResidue(element));
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerCompartment.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerCompartment.java
index e66ed1ca142def7e6f248a4a2a776e5b623132b9..c502500383a2e016d7c102f3d5e0467cfa6a07ab 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerCompartment.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerCompartment.java
@@ -1,152 +1,156 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.compartment.Compartment;
-
-/**
- * Class representing CellDesigner {@link Compartment}.
- * 
- * @author Piotr Gawron
- * 
- */
-public class CellDesignerCompartment extends CellDesignerElement<Compartment> implements Comparable<CellDesignerCompartment> {
-
-	/**
-	 * 
-	 */
-	private static final long						serialVersionUID = 1L;
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger								logger					 = Logger.getLogger(CellDesignerCompartment.class);
-
-	/**
-	 * Identifier of the compartment. Unique in the model
-	 */
-	private String											compartmentId		 = "";
-
-	/**
-	 * List of agregated elements.
-	 */
-	private Set<CellDesignerElement<?>>	elements				 = new HashSet<>();
-
-	/**
-	 * Default constructor with identifier given as a parameter.
-	 * 
-	 * @param id
-	 *          identifier of the compartment
-	 */
-	public CellDesignerCompartment(String id) {
-		compartmentId = id;
-		setName(id);
-	}
-
-	/**
-	 * Default constructor.
-	 */
-	public CellDesignerCompartment() {
-		super();
-	}
-
-	/**
-	 * Constructor that initialize the data using compartment given as a
-	 * parameter.
-	 * 
-	 * @param compartment
-	 *          object which is used for data intialization
-	 */
-	public CellDesignerCompartment(CellDesignerCompartment compartment) {
-		super(compartment);
-		setElementId(compartment.getElementId());
-		for (CellDesignerElement<?> element : compartment.getElements()) {
-			addElement(element.copy());
-		}
-	}
-
-	@Override
-	public int compareTo(CellDesignerCompartment param) {
-		if (param == null) {
-			return -1;
-		}
-		if (!compartmentId.equals(param.getElementId())) {
-			return compartmentId.compareTo(param.getElementId());
-		}
-		if (!getName().equals(param.getName())) {
-			return getName().compareTo(param.getName());
-		}
-		return 0;
-	}
-
-	@Override
-	public boolean equals(Object param) {
-		if (this == param) {
-			return true;
-		}
-		if (!(param instanceof CellDesignerCompartment)) {
-			return false;
-		}
-
-		return compareTo((CellDesignerCompartment) param) == 0;
-	}
-
-	@Override
-	public int hashCode() {
-		String result = compartmentId + "_" + getName();
-		return result.hashCode();
-	}
-
-	@Override
-	public CellDesignerCompartment copy() {
-		if (this.getClass() != CellDesignerCompartment.class) {
-			throw new NotImplementedException("this method should be overloaded");
-		}
-		return new CellDesignerCompartment(this);
-	}
-
-	@Override
-	public String getElementId() {
-		return compartmentId;
-	}
-
-	@Override
-	public void setElementId(String id) {
-		this.compartmentId = id;
-	}
-
-	/**
-	 * Adds element.
-	 * 
-	 * @param element
-	 *          element to add
-	 */
-	public void addElement(CellDesignerElement<?> element) {
-		elements.add(element);
-		element.setParent(this);
-	}
-
-	/**
-	 * 
-	 * @return {@link #elements}
-	 */
-	public Set<CellDesignerElement<?>> getElements() {
-		return elements;
-	}
-
-	@Override
-	public Compartment createModelElement(String aliasId) {
-		Compartment result = new Compartment(aliasId);
-		super.setModelObjectFields(result);
-		if (elements.size() > 0) {
-			throw new NotImplementedException();
-		}
-		return result;
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.compartment.Compartment;
+
+/**
+ * Class representing CellDesigner {@link Compartment}.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class CellDesignerCompartment extends CellDesignerElement<Compartment>
+    implements Comparable<CellDesignerCompartment> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(CellDesignerCompartment.class);
+
+  /**
+   * Identifier of the compartment. Unique in the model
+   */
+  private String compartmentId = "";
+
+  /**
+   * List of aggregated elements.
+   */
+  private Set<CellDesignerElement<?>> elements = new HashSet<>();
+
+  /**
+   * Default constructor with identifier given as a parameter.
+   * 
+   * @param id
+   *          identifier of the compartment
+   */
+  public CellDesignerCompartment(String id) {
+    compartmentId = id;
+    setName(id);
+  }
+
+  /**
+   * Default constructor.
+   */
+  public CellDesignerCompartment() {
+    super();
+  }
+
+  /**
+   * Constructor that initialize the data using compartment given as a parameter.
+   * 
+   * @param compartment
+   *          object which is used for data initialization
+   */
+  public CellDesignerCompartment(CellDesignerCompartment compartment) {
+    super(compartment);
+    setElementId(compartment.getElementId());
+    for (CellDesignerElement<?> element : compartment.getElements()) {
+      addElement(element.copy());
+    }
+  }
+
+  @Override
+  public int compareTo(CellDesignerCompartment param) {
+    if (param == null) {
+      return -1;
+    }
+    if (!compartmentId.equals(param.getElementId())) {
+      return compartmentId.compareTo(param.getElementId());
+    }
+    if (!getName().equals(param.getName())) {
+      return getName().compareTo(param.getName());
+    }
+    return 0;
+  }
+
+  @Override
+  public boolean equals(Object param) {
+    if (this == param) {
+      return true;
+    }
+    if (!(param instanceof CellDesignerCompartment)) {
+      return false;
+    }
+
+    return compareTo((CellDesignerCompartment) param) == 0;
+  }
+
+  @Override
+  public int hashCode() {
+    String result = compartmentId + "_" + getName();
+    return result.hashCode();
+  }
+
+  @Override
+  public CellDesignerCompartment copy() {
+    if (this.getClass() != CellDesignerCompartment.class) {
+      throw new NotImplementedException("this method should be overloaded");
+    }
+    return new CellDesignerCompartment(this);
+  }
+
+  @Override
+  public String getElementId() {
+    return compartmentId;
+  }
+
+  @Override
+  public void setElementId(String id) {
+    this.compartmentId = id;
+  }
+
+  /**
+   * Adds element.
+   * 
+   * @param element
+   *          element to add
+   */
+  public void addElement(CellDesignerElement<?> element) {
+    elements.add(element);
+    element.setParent(this);
+  }
+
+  /**
+   * 
+   * @return {@link #elements}
+   */
+  public Set<CellDesignerElement<?>> getElements() {
+    return elements;
+  }
+
+  @Override
+  public Compartment createModelElement(String aliasId) {
+    Compartment result = new Compartment(aliasId);
+    super.setModelObjectFields(result);
+    if (elements.size() > 0) {
+      throw new NotImplementedException();
+    }
+    return result;
+  }
+
+  @Override
+  public void updateModelElementAfterLayoutAdded(Compartment element) {
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerElement.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerElement.java
index 577844e96537028f07da499799ffbc5f63e5d6d1..5f2bf1910863679b298741261a0a5815d317322d 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerElement.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerElement.java
@@ -14,9 +14,9 @@ import lcsb.mapviewer.model.map.MiriamData;
 import lcsb.mapviewer.model.map.species.Element;
 
 /**
- * Generic CellDesigner element map. It is a root object in inheritance three for
- * every element ({@link CellDesignerSpecies} or {@link CellDesignerCompartment}
- * ).
+ * Generic CellDesigner element map. It is a root object in inheritance three
+ * for every element ({@link CellDesignerSpecies} or
+ * {@link CellDesignerCompartment} ).
  * 
  * @param <T>
  *          type of the {@link Element} in the model that is describe by this
@@ -26,423 +26,426 @@ import lcsb.mapviewer.model.map.species.Element;
  */
 public abstract class CellDesignerElement<T extends Element> implements Serializable {
 
-	/**
-	 * 
-	 */
-	private static final long					 serialVersionUID		= 1L;
-
-	/**
-	 * Maximum length of the valid synonym name.
-	 */
-	private static final int					 MAX_SYNONYM_LENGTH	= 255;
-
-	/**
-	 * Default class logger.
-	 */
-	private static Logger							 logger							= Logger.getLogger(CellDesignerElement.class);
-
-	/**
-	 * Notes describing this element.
-	 */
-	private String										 notes;
-
-	/**
-	 * Symbol of the element.
-	 */
-	private String										 symbol;
-
-	/**
-	 * Full name of the element.
-	 */
-	private String										 fullName;
-
-	/**
-	 * Abbreviation associated with the element.
-	 */
-	private String										 abbreviation;
-
-	/**
-	 * Formula associated with the element.
-	 */
-	private String										 formula;
-
-	/**
-	 * Short name of the element.
-	 */
-	private String										 name								= "";
-
-	/**
-	 * Lists of all synonyms used for describing this element.
-	 */
-	private List<String>							 synonyms						= new ArrayList<>();
-
-	/**
-	 * List of former symbols used to describe this element.
-	 */
-	private List<String>							 formerSymbols			= new ArrayList<>();
-
-	/**
-	 * Where this element lies on.
-	 */
-	private CellDesignerCompartment		 parent;
-
-	/**
-	 * In which complex this element is located.
-	 */
-	private CellDesignerComplexSpecies complex;
-
-	/**
-	 * Set of miriam annotations for this element.
-	 */
-	private Set<MiriamData>						 miriamData					= new HashSet<>();
-
-	/**
-	 * Default constructor that initialize the data with the information given in
-	 * the parameter.
-	 * 
-	 * @param element
-	 *          original object from which data should be initialized
-	 */
-	protected CellDesignerElement(CellDesignerElement<?> element) {
-		this.parent = element.parent;
-		this.complex = element.complex;
-		this.notes = element.notes;
-		this.symbol = element.symbol;
-		this.fullName = element.fullName;
-		this.name = element.getName();
-		this.getSynonyms().addAll(element.getSynonyms());
-		this.getFormerSymbols().addAll(element.getFormerSymbols());
-
-		for (MiriamData md : element.getMiriamData()) {
-			addMiriamData(new MiriamData(md));
-		}
-		this.abbreviation = element.getAbbreviation();
-		this.formula = element.getFormula();
-	}
-
-	/**
-	 * Default constructor.
-	 */
-	protected CellDesignerElement() {
-		this.notes = "";
-	}
-
-	/**
-	 * Adds set of {@link MiriamData} to the object.
-	 * 
-	 * @param miriamData
-	 *          objects to be added
-	 */
-	public void addMiriamData(Collection<MiriamData> miriamData) {
-		for (MiriamData md : miriamData) {
-			addMiriamData(md);
-		}
-	}
-
-	/**
-	 * Returns identifier of the species.
-	 * 
-	 * @return identifier of the species
-	 */
-	public abstract String getElementId();
-
-	/**
-	 * Adds {@link MiriamData} to the element.
-	 * 
-	 * @param md
-	 *          object to be added
-	 */
-	public void addMiriamData(MiriamData md) {
-		if (this.miriamData.contains(md)) {
-			logger.warn("Miriam data (" + md.getDataType() + ": " + md.getResource() + ") for " + getElementId() + " already exists. Ignoring...");
-		} else {
-			this.miriamData.add(md);
-		}
-
-	}
-
-	/**
-	 * Sets notes about the object.
-	 * 
-	 * @param notes
-	 *          new notes
-	 */
-	public void setNotes(String notes) {
-		if (notes != null) {
-			if (notes.contains("</html>")) {
-				throw new InvalidArgumentException("Notes cannot contain html tags...");
-			}
-		}
-		this.notes = notes;
-	}
-
-	/**
-	 * Makes a copy of the element.
-	 * 
-	 * @return copy of the object
-	 */
-	public abstract CellDesignerElement<T> copy();
-
-	/**
-	 * Adds synonyms to the element.
-	 * 
-	 * @param synonyms
-	 *          list of synonyms to be added
-	 */
-	public void addSynonyms(List<String> synonyms) {
-		for (String string : synonyms) {
-			if (string.length() > MAX_SYNONYM_LENGTH) {
-				String message = " <Synonym too long. Only " + MAX_SYNONYM_LENGTH + " characters are allowed>";
-				this.getSynonyms().add(string.substring(0, MAX_SYNONYM_LENGTH - message.length()) + message);
-			} else {
-				this.getSynonyms().add(string);
-			}
-		}
-
-	}
-
-	/**
-	 * Returns notes about the object.
-	 * 
-	 * @return notes about the object
-	 */
-	public String getNotes() {
-		return notes;
-	}
-
-	/**
-	 * Returns the symbol of the element.
-	 * 
-	 * @return the symbol of the element
-	 */
-	public String getSymbol() {
-		return symbol;
-	}
-
-	/**
-	 * Sets symbol of the element.
-	 * 
-	 * @param symbol
-	 *          new symbol
-	 */
-	public void setSymbol(String symbol) {
-		this.symbol = symbol;
-	}
-
-	/**
-	 * @return the fullName
-	 * @see #fullName
-	 */
-	public String getFullName() {
-		return fullName;
-	}
-
-	/**
-	 * @param fullName
-	 *          the fullName to set
-	 * @see #fullName
-	 */
-	public void setFullName(String fullName) {
-		this.fullName = fullName;
-	}
-
-	/**
-	 * Returns the name of the object.
-	 * 
-	 * @return name of the object
-	 * 
-	 */
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * @param name
-	 *          the name to set
-	 * @see #name
-	 */
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	/**
-	 * Get list of synonyms.
-	 * 
-	 * @return list of synonyms
-	 */
-	public List<String> getSynonyms() {
-		return synonyms;
-	}
-
-	/**
-	 * Sets list of synonyms to the element.
-	 * 
-	 * @param synonyms
-	 *          new list
-	 */
-	public void setSynonyms(List<String> synonyms) {
-		this.synonyms = synonyms;
-	}
-
-	/**
-	 * @return the formerSymbols
-	 * @see #formerSymbols
-	 */
-	public List<String> getFormerSymbols() {
-		return formerSymbols;
-	}
-
-	/**
-	 * @param formerSymbols
-	 *          the formerSymbols to set
-	 * @see #formerSymbols
-	 */
-	public void setFormerSymbols(List<String> formerSymbols) {
-		this.formerSymbols = formerSymbols;
-	}
-
-	/**
-	 * @return the parent
-	 * @see #parent
-	 */
-	public CellDesignerCompartment getParent() {
-		return parent;
-	}
-
-	/**
-	 * @param parent
-	 *          the parent to set
-	 * @see #parent
-	 */
-	public void setParent(CellDesignerCompartment parent) {
-		this.parent = parent;
-	}
-
-	/**
-	 * @return the complex
-	 * @see #complex
-	 */
-	public CellDesignerComplexSpecies getComplex() {
-		return complex;
-	}
-
-	/**
-	 * @param complex
-	 *          the complex to set
-	 * @see #complex
-	 */
-	public void setComplex(CellDesignerComplexSpecies complex) {
-		this.complex = complex;
-	}
-
-	/**
-	 * Returns list of {@link MiriamData annotations} for the object.
-	 * 
-	 * @return list of {@link MiriamData annotations} for the object
-	 */
-	public Set<MiriamData> getMiriamData() {
-		return miriamData;
-	}
-
-	/**
-	 * Returns the abbreviation.
-	 * 
-	 * @return the abbreviation
-	 */
-	public String getAbbreviation() {
-		return abbreviation;
-	}
-
-	/**
-	 * Sets abbreviation.
-	 * 
-	 * @param abbreviation
-	 *          new abbreviation
-	 */
-	public void setAbbreviation(String abbreviation) {
-		this.abbreviation = abbreviation;
-	}
-
-	/**
-	 * Returns the formula.
-	 * 
-	 * @return the formula
-	 */
-	public String getFormula() {
-		return formula;
-	}
-
-	/**
-	 * Sets formula.
-	 * 
-	 * @param formula
-	 *          new formula
-	 */
-	public void setFormula(String formula) {
-		this.formula = formula;
-	}
-
-	/**
-	 * Adds synonym.
-	 * 
-	 * @param synonym
-	 *          synonym to add
-	 */
-	public void addSynonym(String synonym) {
-		this.synonyms.add(synonym);
-	}
-
-	/**
-	 * Adds former symbol.
-	 * 
-	 * @param formerSymbol
-	 *          former symbol to add
-	 */
-	public void addFormerSymbol(String formerSymbol) {
-		this.formerSymbols.add(formerSymbol);
-	}
-
-	/**
-	 * Sets element identifier.
-	 * 
-	 * @param elementId
-	 *          element identifier
-	 */
-	public abstract void setElementId(String elementId);
-
-	/**
-	 * Creates model object from this celldesigner structure.
-	 * 
-	 * @return model object from this celldesigner structure
-	 */
-	public T createModelElement() {
-		return createModelElement(null);
-	}
-
-	/**
-	 * Creates model object from this celldesigner structure.
-	 * 
-	 * @param modelElementId
-	 *          identifier of new model object
-	 * @return model object from this celldesigner structure
-	 */
-	public abstract T createModelElement(String modelElementId);
-
-	/**
-	 * Sets values from this cell designer structure into model object.
-	 * 
-	 * @param result
-	 *          object to which values should be assigned
-	 */
-	protected void setModelObjectFields(T result) {
-		result.setNotes(notes);
-		result.setSymbol(symbol);
-		result.setFullName(fullName);
-		result.setAbbreviation(abbreviation);
-		result.setFormula(formula);
-		result.setName(name);
-		result.addSynonyms(synonyms);
-		result.addFormerSymbols(formerSymbols);
-		result.addMiriamData(miriamData);
-	}
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Maximum length of the valid synonym name.
+   */
+  private static final int MAX_SYNONYM_LENGTH = 255;
+
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(CellDesignerElement.class);
+
+  /**
+   * Notes describing this element.
+   */
+  private String notes;
+
+  /**
+   * Symbol of the element.
+   */
+  private String symbol;
+
+  /**
+   * Full name of the element.
+   */
+  private String fullName;
+
+  /**
+   * Abbreviation associated with the element.
+   */
+  private String abbreviation;
+
+  /**
+   * Formula associated with the element.
+   */
+  private String formula;
+
+  /**
+   * Short name of the element.
+   */
+  private String name = "";
+
+  /**
+   * Lists of all synonyms used for describing this element.
+   */
+  private List<String> synonyms = new ArrayList<>();
+
+  /**
+   * List of former symbols used to describe this element.
+   */
+  private List<String> formerSymbols = new ArrayList<>();
+
+  /**
+   * Where this element lies on.
+   */
+  private CellDesignerCompartment parent;
+
+  /**
+   * In which complex this element is located.
+   */
+  private CellDesignerComplexSpecies complex;
+
+  /**
+   * Set of miriam annotations for this element.
+   */
+  private Set<MiriamData> miriamData = new HashSet<>();
+
+  /**
+   * Default constructor that initialize the data with the information given in
+   * the parameter.
+   * 
+   * @param element
+   *          original object from which data should be initialized
+   */
+  protected CellDesignerElement(CellDesignerElement<?> element) {
+    this.parent = element.parent;
+    this.complex = element.complex;
+    this.notes = element.notes;
+    this.symbol = element.symbol;
+    this.fullName = element.fullName;
+    this.name = element.getName();
+    this.getSynonyms().addAll(element.getSynonyms());
+    this.getFormerSymbols().addAll(element.getFormerSymbols());
+
+    for (MiriamData md : element.getMiriamData()) {
+      addMiriamData(new MiriamData(md));
+    }
+    this.abbreviation = element.getAbbreviation();
+    this.formula = element.getFormula();
+  }
+
+  /**
+   * Default constructor.
+   */
+  protected CellDesignerElement() {
+    this.notes = "";
+  }
+
+  /**
+   * Adds set of {@link MiriamData} to the object.
+   * 
+   * @param miriamData
+   *          objects to be added
+   */
+  public void addMiriamData(Collection<MiriamData> miriamData) {
+    for (MiriamData md : miriamData) {
+      addMiriamData(md);
+    }
+  }
+
+  /**
+   * Returns identifier of the species.
+   * 
+   * @return identifier of the species
+   */
+  public abstract String getElementId();
+
+  /**
+   * Adds {@link MiriamData} to the element.
+   * 
+   * @param md
+   *          object to be added
+   */
+  public void addMiriamData(MiriamData md) {
+    if (this.miriamData.contains(md)) {
+      logger.warn("Miriam data (" + md.getDataType() + ": " + md.getResource() + ") for " + getElementId()
+          + " already exists. Ignoring...");
+    } else {
+      this.miriamData.add(md);
+    }
+
+  }
+
+  /**
+   * Sets notes about the object.
+   * 
+   * @param notes
+   *          new notes
+   */
+  public void setNotes(String notes) {
+    if (notes != null) {
+      if (notes.contains("</html>")) {
+        throw new InvalidArgumentException("Notes cannot contain html tags...");
+      }
+    }
+    this.notes = notes;
+  }
+
+  /**
+   * Makes a copy of the element.
+   * 
+   * @return copy of the object
+   */
+  public abstract CellDesignerElement<T> copy();
+
+  /**
+   * Adds synonyms to the element.
+   * 
+   * @param synonyms
+   *          list of synonyms to be added
+   */
+  public void addSynonyms(List<String> synonyms) {
+    for (String string : synonyms) {
+      if (string.length() > MAX_SYNONYM_LENGTH) {
+        String message = " <Synonym too long. Only " + MAX_SYNONYM_LENGTH + " characters are allowed>";
+        this.getSynonyms().add(string.substring(0, MAX_SYNONYM_LENGTH - message.length()) + message);
+      } else {
+        this.getSynonyms().add(string);
+      }
+    }
+
+  }
+
+  /**
+   * Returns notes about the object.
+   * 
+   * @return notes about the object
+   */
+  public String getNotes() {
+    return notes;
+  }
+
+  /**
+   * Returns the symbol of the element.
+   * 
+   * @return the symbol of the element
+   */
+  public String getSymbol() {
+    return symbol;
+  }
+
+  /**
+   * Sets symbol of the element.
+   * 
+   * @param symbol
+   *          new symbol
+   */
+  public void setSymbol(String symbol) {
+    this.symbol = symbol;
+  }
+
+  /**
+   * @return the fullName
+   * @see #fullName
+   */
+  public String getFullName() {
+    return fullName;
+  }
+
+  /**
+   * @param fullName
+   *          the fullName to set
+   * @see #fullName
+   */
+  public void setFullName(String fullName) {
+    this.fullName = fullName;
+  }
+
+  /**
+   * Returns the name of the object.
+   * 
+   * @return name of the object
+   * 
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * @param name
+   *          the name to set
+   * @see #name
+   */
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  /**
+   * Get list of synonyms.
+   * 
+   * @return list of synonyms
+   */
+  public List<String> getSynonyms() {
+    return synonyms;
+  }
+
+  /**
+   * Sets list of synonyms to the element.
+   * 
+   * @param synonyms
+   *          new list
+   */
+  public void setSynonyms(List<String> synonyms) {
+    this.synonyms = synonyms;
+  }
+
+  /**
+   * @return the formerSymbols
+   * @see #formerSymbols
+   */
+  public List<String> getFormerSymbols() {
+    return formerSymbols;
+  }
+
+  /**
+   * @param formerSymbols
+   *          the formerSymbols to set
+   * @see #formerSymbols
+   */
+  public void setFormerSymbols(List<String> formerSymbols) {
+    this.formerSymbols = formerSymbols;
+  }
+
+  /**
+   * @return the parent
+   * @see #parent
+   */
+  public CellDesignerCompartment getParent() {
+    return parent;
+  }
+
+  /**
+   * @param parent
+   *          the parent to set
+   * @see #parent
+   */
+  public void setParent(CellDesignerCompartment parent) {
+    this.parent = parent;
+  }
+
+  /**
+   * @return the complex
+   * @see #complex
+   */
+  public CellDesignerComplexSpecies getComplex() {
+    return complex;
+  }
+
+  /**
+   * @param complex
+   *          the complex to set
+   * @see #complex
+   */
+  public void setComplex(CellDesignerComplexSpecies complex) {
+    this.complex = complex;
+  }
+
+  /**
+   * Returns list of {@link MiriamData annotations} for the object.
+   * 
+   * @return list of {@link MiriamData annotations} for the object
+   */
+  public Set<MiriamData> getMiriamData() {
+    return miriamData;
+  }
+
+  /**
+   * Returns the abbreviation.
+   * 
+   * @return the abbreviation
+   */
+  public String getAbbreviation() {
+    return abbreviation;
+  }
+
+  /**
+   * Sets abbreviation.
+   * 
+   * @param abbreviation
+   *          new abbreviation
+   */
+  public void setAbbreviation(String abbreviation) {
+    this.abbreviation = abbreviation;
+  }
+
+  /**
+   * Returns the formula.
+   * 
+   * @return the formula
+   */
+  public String getFormula() {
+    return formula;
+  }
+
+  /**
+   * Sets formula.
+   * 
+   * @param formula
+   *          new formula
+   */
+  public void setFormula(String formula) {
+    this.formula = formula;
+  }
+
+  /**
+   * Adds synonym.
+   * 
+   * @param synonym
+   *          synonym to add
+   */
+  public void addSynonym(String synonym) {
+    this.synonyms.add(synonym);
+  }
+
+  /**
+   * Adds former symbol.
+   * 
+   * @param formerSymbol
+   *          former symbol to add
+   */
+  public void addFormerSymbol(String formerSymbol) {
+    this.formerSymbols.add(formerSymbol);
+  }
+
+  /**
+   * Sets element identifier.
+   * 
+   * @param elementId
+   *          element identifier
+   */
+  public abstract void setElementId(String elementId);
+
+  /**
+   * Creates model object from this CellDesigner structure.
+   * 
+   * @return model object from this CellDesigner structure
+   */
+  public T createModelElement() {
+    return createModelElement(null);
+  }
+
+  /**
+   * Creates model object from this CellDesigner structure.
+   * 
+   * @param modelElementId
+   *          identifier of new model object
+   * @return model object from this CellDesigner structure
+   */
+  public abstract T createModelElement(String modelElementId);
+
+  public abstract void updateModelElementAfterLayoutAdded(T element);
+
+  /**
+   * Sets values from this cell designer structure into model object.
+   * 
+   * @param result
+   *          object to which values should be assigned
+   */
+  protected void setModelObjectFields(T result) {
+    result.setNotes(notes);
+    result.setSymbol(symbol);
+    result.setFullName(fullName);
+    result.setAbbreviation(abbreviation);
+    result.setFormula(formula);
+    result.setName(name);
+    result.addSynonyms(synonyms);
+    result.addFormerSymbols(formerSymbols);
+    result.addMiriamData(miriamData);
+  }
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerGene.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerGene.java
index efc960c93ecf0b71b58863567529b7646be24847..7e485de81648c9a341e7c26f21983230751d4d40 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerGene.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerGene.java
@@ -6,6 +6,7 @@ import java.util.List;
 import lcsb.mapviewer.common.exception.NotImplementedException;
 import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
 import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Species;
 
 /**
  * Class representing CellDesigner {@link Gene}.
@@ -15,103 +16,107 @@ import lcsb.mapviewer.model.map.species.Gene;
  */
 public class CellDesignerGene extends CellDesignerSpecies<Gene> {
 
-	/**
-	 * 
-	 */
-	private static final long					serialVersionUID		 = 1L;
-
-	/**
-	 * List of modifications for the Gene.
-	 */
-	private List<CellDesignerModificationResidue>	modificationResidues = new ArrayList<>();
-
-	/**
-	 * Constructor that initializes gene with the data passed in the argument.
-	 * 
-	 * @param species
-	 *          original species used for data initialization
-	 */
-	public CellDesignerGene(CellDesignerSpecies<?> species) {
-		super(species);
-		if (species instanceof CellDesignerGene) {
-			CellDesignerGene gene = (CellDesignerGene) species;
-			for (CellDesignerModificationResidue mr : gene.getModificationResidues()) {
-				addModificationResidue(new CellDesignerModificationResidue(mr));
-			}
-		}
-	}
-
-	@Override
-	public void update(CellDesignerSpecies<?> species) {
-		super.update(species);
-		if (species instanceof CellDesignerGene) {
-			CellDesignerGene gene = (CellDesignerGene) species;
-
-			for (CellDesignerModificationResidue mr : gene.getModificationResidues()) {
-				addModificationResidue(mr);
-			}
-		}
-	}
-
-	/**
-	 * Default constructor.
-	 */
-	public CellDesignerGene() {
-		super();
-	}
-
-	@Override
-	public CellDesignerGene copy() {
-		if (this.getClass() == CellDesignerGene.class) {
-			return new CellDesignerGene(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-	}
-
-	/**
-	 * Adds modification to the gene.
-	 * 
-	 * @param modificationResidue
-	 *          modifiaction to add
-	 */
-	public void addModificationResidue(CellDesignerModificationResidue modificationResidue) {
-		for (CellDesignerModificationResidue mr : modificationResidues) {
-			if (mr.getIdModificationResidue().equals(modificationResidue.getIdModificationResidue())) {
-				mr.update(modificationResidue);
-				return;
-			}
-		}
-		modificationResidues.add(modificationResidue);
-		modificationResidue.setSpecies(this);
-
-	}
-
-	/**
-	 * @return the modificationResidues
-	 * @see #modificationResidues
-	 */
-	public List<CellDesignerModificationResidue> getModificationResidues() {
-		return modificationResidues;
-	}
-
-	/**
-	 * @param modificationResidues
-	 *          the modificationResidues to set
-	 * @see #modificationResidues
-	 */
-	public void setModificationResidues(List<CellDesignerModificationResidue> modificationResidues) {
-		this.modificationResidues = modificationResidues;
-	}
-
-	@Override
-	public Gene createModelElement(String aliasId) {
-		Gene result = new Gene(aliasId);
-		super.setModelObjectFields(result);
-		for (CellDesignerModificationResidue mr : modificationResidues) {
-			result.addModificationResidue(mr.createModificationResidueAlias());
-		}
-		return result;
-
-	}
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * List of modifications for the Gene.
+   */
+  private List<CellDesignerModificationResidue> modificationResidues = new ArrayList<>();
+
+  /**
+   * Constructor that initializes gene with the data passed in the argument.
+   * 
+   * @param species
+   *          original species used for data initialization
+   */
+  public CellDesignerGene(CellDesignerSpecies<?> species) {
+    super(species);
+    if (species instanceof CellDesignerGene) {
+      CellDesignerGene gene = (CellDesignerGene) species;
+      for (CellDesignerModificationResidue mr : gene.getModificationResidues()) {
+        addModificationResidue(new CellDesignerModificationResidue(mr));
+      }
+    }
+  }
+
+  @Override
+  public void update(CellDesignerSpecies<?> species) {
+    super.update(species);
+    if (species instanceof CellDesignerGene) {
+      CellDesignerGene gene = (CellDesignerGene) species;
+
+      for (CellDesignerModificationResidue mr : gene.getModificationResidues()) {
+        addModificationResidue(mr);
+      }
+    }
+  }
+
+  /**
+   * Default constructor.
+   */
+  public CellDesignerGene() {
+    super();
+  }
+
+  @Override
+  public CellDesignerGene copy() {
+    if (this.getClass() == CellDesignerGene.class) {
+      return new CellDesignerGene(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+  }
+
+  /**
+   * Adds modification to the gene.
+   * 
+   * @param modificationResidue
+   *          modification to add
+   */
+  public void addModificationResidue(CellDesignerModificationResidue modificationResidue) {
+    for (CellDesignerModificationResidue mr : modificationResidues) {
+      if (mr.getIdModificationResidue().equals(modificationResidue.getIdModificationResidue())) {
+        mr.update(modificationResidue);
+        return;
+      }
+    }
+    modificationResidues.add(modificationResidue);
+    modificationResidue.setSpecies(this);
+
+  }
+
+  /**
+   * @return the modificationResidues
+   * @see #modificationResidues
+   */
+  public List<CellDesignerModificationResidue> getModificationResidues() {
+    return modificationResidues;
+  }
+
+  /**
+   * @param modificationResidues
+   *          the modificationResidues to set
+   * @see #modificationResidues
+   */
+  public void setModificationResidues(List<CellDesignerModificationResidue> modificationResidues) {
+    this.modificationResidues = modificationResidues;
+  }
+
+  @Override
+  public Gene createModelElement(String aliasId) {
+    Gene result = new Gene(aliasId);
+    super.setModelObjectFields(result);
+    return result;
+  }
+
+  @Override
+  public void updateModelElementAfterLayoutAdded(Species element) {
+    for (CellDesignerModificationResidue region : modificationResidues) {
+      ((Gene) element).addModificationResidue(region.createModificationResidue(element));
+    }
+  }
+
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerIon.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerIon.java
index 31eb0cf621a5d2d86a08bdfd244facf0ad683196..cfd15dbf01463562f80203cffe7ff53d5c1cf62a 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerIon.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerIon.java
@@ -1,52 +1,51 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.Ion;
-
-/**
- * Class representing CellDesigner {@link Ion}.
- * 
- * @author Piotr Gawron
- * 
- */
-public class CellDesignerIon extends CellDesignerChemical<Ion> {
-
-	/**
-	 * 
-	 */
-	private static final long serialVersionUID = 1L;
-
-	/**
-	 * Constructor that initializes ion with the data passed in the argument.
-	 * 
-	 * @param species
-	 *          original species used for data initialization
-	 */
-	public CellDesignerIon(CellDesignerSpecies<?> species) {
-		super(species);
-	}
-
-	/**
-	 * Default constructor.
-	 */
-	public CellDesignerIon() {
-		super();
-	}
-
-	@Override
-	public CellDesignerIon copy() {
-		if (this.getClass() == CellDesignerIon.class) {
-			return new CellDesignerIon(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-	}
-
-	@Override
-	public Ion createModelElement(String aliasId) {
-		Ion result = new Ion(aliasId);
-		super.setModelObjectFields(result);
-		return result;
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.Ion;
+
+/**
+ * Class representing CellDesigner {@link Ion}.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class CellDesignerIon extends CellDesignerChemical<Ion> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Constructor that initializes ion with the data passed in the argument.
+   * 
+   * @param species
+   *          original species used for data initialization
+   */
+  public CellDesignerIon(CellDesignerSpecies<?> species) {
+    super(species);
+  }
+
+  /**
+   * Default constructor.
+   */
+  public CellDesignerIon() {
+    super();
+  }
+
+  @Override
+  public CellDesignerIon copy() {
+    if (this.getClass() == CellDesignerIon.class) {
+      return new CellDesignerIon(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+  }
+
+  @Override
+  public Ion createModelElement(String aliasId) {
+    Ion result = new Ion(aliasId);
+    super.setModelObjectFields(result);
+    return result;
+  }
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerProtein.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerProtein.java
index ae3677e954e3caf411d5af7276fedbabf42cfaf8..9fa15ca0dff3c18c82d4db90de02094f23bda405 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerProtein.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerProtein.java
@@ -1,153 +1,159 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
-import lcsb.mapviewer.model.map.species.Protein;
-
-/**
- * Class representing CellDesigner {@link Protein} object.
- * 
- * @param <T>
- *          type of a {@link Protein} modeled by this class
- * @author Piotr Gawron
- * 
- */
-public class CellDesignerProtein<T extends Protein> extends CellDesignerSpecies<T> {
-  /**
-   * 
-   */
-  private static final long serialVersionUID = 1L;
-
-  /**
-   * Default class logger.
-   */
-  private static Logger logger = Logger.getLogger(CellDesignerProtein.class.getName());
-
-  /**
-   * State of the protein.
-   */
-  private String structuralState = null;
-
-  /**
-   * List of modifications for the Protein.
-   */
-  private List<CellDesignerModificationResidue> modificationResidues = new ArrayList<CellDesignerModificationResidue>();
-
-  /**
-   * Constructor that initializes protein with the data passed in the argument.
-   * 
-   * @param species
-   *          original species used for data initialization
-   */
-  public CellDesignerProtein(CellDesignerSpecies<?> species) {
-    super(species);
-    if (species instanceof CellDesignerProtein) {
-      CellDesignerProtein<?> protein = (CellDesignerProtein<?>) species;
-      if (protein.getStructuralState() != null) {
-        setStructuralState(new String(protein.getStructuralState()));
-      }
-      for (CellDesignerModificationResidue mr : protein.getModificationResidues()) {
-        addModificationResidue(new CellDesignerModificationResidue(mr));
-      }
-    }
-  }
-
-  @Override
-  public void update(CellDesignerSpecies<?> species) {
-    super.update(species);
-    if (species instanceof CellDesignerProtein) {
-      CellDesignerProtein<?> protein = (CellDesignerProtein<?>) species;
-      if (getStructuralState() == null || getStructuralState().equals("")) {
-        setStructuralState(protein.getStructuralState());
-      }
-      for (CellDesignerModificationResidue mr : protein.getModificationResidues()) {
-        addModificationResidue(mr);
-      }
-    }
-  }
-
-  /**
-   * Default constructor.
-   */
-  public CellDesignerProtein() {
-    super();
-  }
-
-  @Override
-  public CellDesignerProtein<T> copy() {
-    if (this.getClass().equals(CellDesignerProtein.class)) {
-      return new CellDesignerProtein<T>(this);
-    } else {
-      throw new NotImplementedException("Copy method for " + this.getClass() + " class not implemented");
-    }
-  }
-
-  /**
-   * Adds modification to the protein.
-   * 
-   * @param modificationResidue
-   *          modification to add
-   */
-  public void addModificationResidue(CellDesignerModificationResidue modificationResidue) {
-    for (CellDesignerModificationResidue mr : modificationResidues) {
-      if (mr.getIdModificationResidue().equals(modificationResidue.getIdModificationResidue())) {
-        mr.update(modificationResidue);
-        return;
-      }
-    }
-    modificationResidues.add(modificationResidue);
-    modificationResidue.setSpecies(this);
-  }
-
-  /**
-   * @return the structuralState
-   * @see #structuralState
-   */
-  public String getStructuralState() {
-    return structuralState;
-  }
-
-  /**
-   * @param structuralState
-   *          the structuralState to set
-   * @see #structuralState
-   */
-  public void setStructuralState(String structuralState) {
-    if (this.structuralState != null && !this.structuralState.equals("")
-        && !this.structuralState.equals(structuralState)) {
-      logger.warn("replacing structural state, Old: " + this.structuralState + " into new: " + structuralState);
-    }
-    this.structuralState = structuralState;
-  }
-
-  /**
-   * @return the modificationResidues
-   * @see #modificationResidues
-   */
-  public List<CellDesignerModificationResidue> getModificationResidues() {
-    return modificationResidues;
-  }
-
-  /**
-   * @param modificationResidues
-   *          the modificationResidues to set
-   * @see #modificationResidues
-   */
-  public void setModificationResidues(List<CellDesignerModificationResidue> modificationResidues) {
-    this.modificationResidues = modificationResidues;
-  }
-
-  @Override
-  protected void setModelObjectFields(T result) {
-    super.setModelObjectFields(result);
-    result.setStructuralState(structuralState);
-    for (CellDesignerModificationResidue mr : modificationResidues) {
-      result.addModificationResidue(mr.createModificationResidueAlias());
-    }
-  }
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * Class representing CellDesigner {@link Protein} object.
+ * 
+ * @param <T>
+ *          type of a {@link Protein} modeled by this class
+ * @author Piotr Gawron
+ * 
+ */
+public class CellDesignerProtein<T extends Protein> extends CellDesignerSpecies<T> {
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(CellDesignerProtein.class.getName());
+
+  /**
+   * State of the protein.
+   */
+  private String structuralState = null;
+
+  /**
+   * List of modifications for the Protein.
+   */
+  private List<CellDesignerModificationResidue> modificationResidues = new ArrayList<CellDesignerModificationResidue>();
+
+  /**
+   * Constructor that initializes protein with the data passed in the argument.
+   * 
+   * @param species
+   *          original species used for data initialization
+   */
+  public CellDesignerProtein(CellDesignerSpecies<?> species) {
+    super(species);
+    if (species instanceof CellDesignerProtein) {
+      CellDesignerProtein<?> protein = (CellDesignerProtein<?>) species;
+      if (protein.getStructuralState() != null) {
+        setStructuralState(new String(protein.getStructuralState()));
+      }
+      for (CellDesignerModificationResidue mr : protein.getModificationResidues()) {
+        addModificationResidue(new CellDesignerModificationResidue(mr));
+      }
+    }
+  }
+
+  @Override
+  public void update(CellDesignerSpecies<?> species) {
+    super.update(species);
+    if (species instanceof CellDesignerProtein) {
+      CellDesignerProtein<?> protein = (CellDesignerProtein<?>) species;
+      if (getStructuralState() == null || getStructuralState().equals("")) {
+        setStructuralState(protein.getStructuralState());
+      }
+      for (CellDesignerModificationResidue mr : protein.getModificationResidues()) {
+        addModificationResidue(mr);
+      }
+    }
+  }
+
+  /**
+   * Default constructor.
+   */
+  public CellDesignerProtein() {
+    super();
+  }
+
+  @Override
+  public CellDesignerProtein<T> copy() {
+    if (this.getClass().equals(CellDesignerProtein.class)) {
+      return new CellDesignerProtein<T>(this);
+    } else {
+      throw new NotImplementedException("Copy method for " + this.getClass() + " class not implemented");
+    }
+  }
+
+  /**
+   * Adds modification to the protein.
+   * 
+   * @param modificationResidue
+   *          modification to add
+   */
+  public void addModificationResidue(CellDesignerModificationResidue modificationResidue) {
+    for (CellDesignerModificationResidue mr : modificationResidues) {
+      if (mr.getIdModificationResidue().equals(modificationResidue.getIdModificationResidue())) {
+        mr.update(modificationResidue);
+        return;
+      }
+    }
+    modificationResidues.add(modificationResidue);
+    modificationResidue.setSpecies(this);
+  }
+
+  /**
+   * @return the structuralState
+   * @see #structuralState
+   */
+  public String getStructuralState() {
+    return structuralState;
+  }
+
+  /**
+   * @param structuralState
+   *          the structuralState to set
+   * @see #structuralState
+   */
+  public void setStructuralState(String structuralState) {
+    if (this.structuralState != null && !this.structuralState.equals("")
+        && !this.structuralState.equals(structuralState)) {
+      logger.warn("replacing structural state, Old: " + this.structuralState + " into new: " + structuralState);
+    }
+    this.structuralState = structuralState;
+  }
+
+  /**
+   * @return the modificationResidues
+   * @see #modificationResidues
+   */
+  public List<CellDesignerModificationResidue> getModificationResidues() {
+    return modificationResidues;
+  }
+
+  /**
+   * @param modificationResidues
+   *          the modificationResidues to set
+   * @see #modificationResidues
+   */
+  public void setModificationResidues(List<CellDesignerModificationResidue> modificationResidues) {
+    this.modificationResidues = modificationResidues;
+  }
+
+  @Override
+  protected void setModelObjectFields(T result) {
+    super.setModelObjectFields(result);
+    result.setStructuralState(structuralState);
+  }
+
+  @Override
+  public void updateModelElementAfterLayoutAdded(Species element) {
+    for (CellDesignerModificationResidue mr : modificationResidues) {
+      ((Protein) element).addModificationResidue(mr.createModificationResidue(element));
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerRna.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerRna.java
index a1d476c3f02c9681fed20b53cf0bbd62b8d869ef..64e121ad9a3dd26675334a8e62feb267e7a1b0a2 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerRna.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerRna.java
@@ -1,147 +1,149 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerRnaRegion;
-import lcsb.mapviewer.model.map.species.Rna;
-
-/**
- * Class representing CellDesigner {@link Rna}.
- * 
- * @author Piotr Gawron
- * 
- */
-public class CellDesignerRna extends CellDesignerSpecies<Rna> {
-
-	/**
-	 * 
-	 */
-	private static final long						serialVersionUID = 1L;
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger								logger					 = Logger.getLogger(CellDesignerRna.class.getName());
-
-	/**
-	 * List of rna regions (some rna sequences) in this object.
-	 */
-	private List<CellDesignerRnaRegion>	regions					 = new ArrayList<>();
-
-	/**
-	 * Constructor that initializes rna with the data passed in the argument.
-	 * 
-	 * @param species
-	 *          original species used for data initialization
-	 */
-	public CellDesignerRna(CellDesignerSpecies<?> species) {
-		super(species);
-		if (species instanceof CellDesignerRna) {
-			CellDesignerRna rna = (CellDesignerRna) species;
-			for (CellDesignerRnaRegion region : rna.getRegions()) {
-				addRegion(new CellDesignerRnaRegion(region));
-			}
-		}
-	}
-
-	/**
-	 * Default constructor.
-	 */
-	public CellDesignerRna() {
-		super();
-	}
-
-	@Override
-	public CellDesignerRna copy() {
-		if (this.getClass() == CellDesignerRna.class) {
-			return new CellDesignerRna(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-	}
-
-	@Override
-	public void update(CellDesignerSpecies<?> species) {
-		super.update(species);
-		if (species instanceof CellDesignerRna) {
-			CellDesignerRna rna = (CellDesignerRna) species;
-			for (CellDesignerRnaRegion mr : getRegions()) {
-				mr.setState(null);
-			}
-
-			for (CellDesignerRnaRegion region : rna.getRegions()) {
-				updateRegion(region);
-			}
-		}
-	}
-
-	/**
-	 * Updates region in the rna. If region doesn't exist then it is added.
-	 * 
-	 * @param param
-	 *          region that with the data to update
-	 */
-	private void updateRegion(CellDesignerRnaRegion param) {
-		for (CellDesignerRnaRegion region : regions) {
-			if (region.getIdRnaRegion().equals(param.getIdRnaRegion())) {
-				region.update(param);
-				return;
-			}
-		}
-		addRegion(new CellDesignerRnaRegion(param));
-	}
-
-	/**
-	 * Adds region. If the region with given id exists then the data of this
-	 * region is copied to the one that is already in the {@link CellDesignerRna}.
-	 * 
-	 * @param rnaRegion
-	 *          region to add
-	 */
-	public void addRegion(CellDesignerRnaRegion rnaRegion) {
-		for (CellDesignerRnaRegion region2 : regions) {
-			if (region2.getIdRnaRegion().equals(rnaRegion.getIdRnaRegion())) {
-				region2.update(rnaRegion);
-				return;
-			}
-		}
-
-		regions.add(rnaRegion);
-		rnaRegion.setSpecies(this);
-
-	}
-
-	/**
-	 * @return the regions
-	 * @see #regions
-	 */
-	public List<CellDesignerRnaRegion> getRegions() {
-		return regions;
-	}
-
-	/**
-	 * @param regions
-	 *          the regions to set
-	 * @see #regions
-	 */
-	public void setRegions(List<CellDesignerRnaRegion> regions) {
-		this.regions = regions;
-	}
-
-	@Override
-	public Rna createModelElement(String aliasId) {
-		Rna result = new Rna(aliasId);
-		super.setModelObjectFields(result);
-		for (CellDesignerRnaRegion region : regions) {
-			result.addRegion(region.createRnaRegionAlias());
-		}
-
-		return result;
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * Class representing CellDesigner {@link Rna}.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class CellDesignerRna extends CellDesignerSpecies<Rna> {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(CellDesignerRna.class.getName());
+
+  /**
+   * List of rna regions (some rna sequences) in this object.
+   */
+  private List<CellDesignerModificationResidue> regions = new ArrayList<>();
+
+  /**
+   * Constructor that initializes rna with the data passed in the argument.
+   * 
+   * @param species
+   *          original species used for data initialization
+   */
+  public CellDesignerRna(CellDesignerSpecies<?> species) {
+    super(species);
+    if (species instanceof CellDesignerRna) {
+      CellDesignerRna rna = (CellDesignerRna) species;
+      for (CellDesignerModificationResidue region : rna.getRegions()) {
+        addRegion(new CellDesignerModificationResidue(region));
+      }
+    }
+  }
+
+  /**
+   * Default constructor.
+   */
+  public CellDesignerRna() {
+    super();
+  }
+
+  @Override
+  public CellDesignerRna copy() {
+    if (this.getClass() == CellDesignerRna.class) {
+      return new CellDesignerRna(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+  }
+
+  @Override
+  public void update(CellDesignerSpecies<?> species) {
+    super.update(species);
+    if (species instanceof CellDesignerRna) {
+      CellDesignerRna rna = (CellDesignerRna) species;
+
+      for (CellDesignerModificationResidue region : rna.getRegions()) {
+        updateRegion(region);
+      }
+    }
+  }
+
+  /**
+   * Updates region in the rna. If region doesn't exist then it is added.
+   * 
+   * @param param
+   *          region that with the data to update
+   */
+  private void updateRegion(CellDesignerModificationResidue param) {
+    for (CellDesignerModificationResidue region : regions) {
+      if (region.getIdModificationResidue().equals(param.getIdModificationResidue())) {
+        region.update(param);
+        return;
+      }
+    }
+    addRegion(new CellDesignerModificationResidue(param));
+  }
+
+  /**
+   * Adds region. If the region with given id exists then the data of this region
+   * is copied to the one that is already in the {@link CellDesignerRna}.
+   * 
+   * @param rnaRegion
+   *          region to add
+   */
+  public void addRegion(CellDesignerModificationResidue rnaRegion) {
+    for (CellDesignerModificationResidue region2 : regions) {
+      if (region2.getIdModificationResidue().equals(rnaRegion.getIdModificationResidue())) {
+        region2.update(rnaRegion);
+        return;
+      }
+    }
+
+    regions.add(rnaRegion);
+    rnaRegion.setSpecies(this);
+
+  }
+
+  /**
+   * @return the regions
+   * @see #regions
+   */
+  public List<CellDesignerModificationResidue> getRegions() {
+    return regions;
+  }
+
+  /**
+   * @param regions
+   *          the regions to set
+   * @see #regions
+   */
+  public void setRegions(List<CellDesignerModificationResidue> regions) {
+    this.regions = regions;
+  }
+
+  @Override
+  public Rna createModelElement(String aliasId) {
+    Rna result = new Rna(aliasId);
+    super.setModelObjectFields(result);
+    return result;
+  }
+
+  @Override
+  public void updateModelElementAfterLayoutAdded(Species element) {
+    for (CellDesignerModificationResidue region : regions) {
+      Rna rna = (Rna) element;
+      rna.addRegion(region.createModificationResidue(rna));
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java
index 4acada56476e594330adb6de81d9af2b2feccb49..189df358e98ebb9b6e05b3ea8c80cc22613e6950 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/CellDesignerSpecies.java
@@ -540,4 +540,8 @@ public class CellDesignerSpecies<T extends Species> extends CellDesignerElement<
     this.constant = constant;
   }
 
+  @Override
+  public void updateModelElementAfterLayoutAdded(Species element) {
+  }
+
 }
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerAntisenseRnaRegion.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerAntisenseRnaRegion.java
deleted file mode 100644
index 36decddc98a49f81ef86a92f4431a0349825d4c2..0000000000000000000000000000000000000000
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerAntisenseRnaRegion.java
+++ /dev/null
@@ -1,334 +0,0 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure.fields;
-
-import java.io.Serializable;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerAntisenseRna;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegionType;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-/**
- * This structure contains information about antisense rna region (rna fragment
- * of interest) for a specific
- * {@link lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerAntisenseRna
- * AntisenseRna}.
- * 
- * @author Piotr Gawron
- * 
- */
-public class CellDesignerAntisenseRnaRegion implements Serializable {
-
-	/**
-	 * 
-	 */
-	private static final long				 serialVersionUID			= 1L;
-
-	/**
-	 * Default size of the object (in graphical representation).
-	 */
-	private static final double			 DEFAULT_SIZE					= 0.1;
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger						 logger								= Logger.getLogger(CellDesignerAntisenseRnaRegion.class.getName());
-
-	/**
-	 * Unique identifier in the database.
-	 */
-	private int											 id;
-
-	/**
-	 * String identifier of the element. Unique in the model.
-	 */
-	private String									 idAntisenseRnaRegion	= "";
-
-	/**
-	 * Name of the region.
-	 */
-	private String									 name									= "";
-
-	/**
-	 * Defines a state of the region (for instance ubiquitinated etc).
-	 * 
-	 * @see ModificationState
-	 */
-	private ModificationState				 state								= null;
-
-	/**
-	 * Type of the region in the rna. There are three possible values:
-	 * <ul>
-	 * <li>Coding region,</li>
-	 * <li>Protein binding domain,</li>
-	 * <li>Modification site.</li>
-	 * </ul>
-	 */
-	private AntisenseRnaRegionType	 type;
-
-	/**
-	 * Size of the region in the graphic representation.
-	 */
-	private double									 size									= DEFAULT_SIZE;
-
-	/**
-	 * Position on the species in graphic representation.
-	 */
-	private Double									 pos;
-
-	/**
-	 * Defines a species where the region belongs to.
-	 */
-	private CellDesignerAntisenseRna species;
-
-	/**
-	 * Default constructor.
-	 */
-	public CellDesignerAntisenseRnaRegion() {
-
-	}
-
-	/**
-	 * Constructor that initialize object with the data from the parameter.
-	 * 
-	 * @param original
-	 *          object from which we initialize data
-	 */
-	public CellDesignerAntisenseRnaRegion(CellDesignerAntisenseRnaRegion original) {
-		this.idAntisenseRnaRegion = original.idAntisenseRnaRegion;
-		this.name = original.name;
-		this.size = original.size;
-		this.pos = original.pos;
-		this.type = original.type;
-	}
-
-	/**
-	 * Creates a copy of current object.
-	 * 
-	 * @return copy of the object
-	 */
-	public CellDesignerAntisenseRnaRegion copy() {
-		if (this.getClass() == CellDesignerAntisenseRnaRegion.class) {
-			return new CellDesignerAntisenseRnaRegion(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-
-	}
-
-	/**
-	 * Sets size from the string.
-	 * 
-	 * @param text
-	 *          size to parse and set
-	 * @see #size
-	 */
-	public void setSize(String text) {
-		try {
-			size = Double.parseDouble(text);
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid angle: " + text, e);
-		}
-	}
-
-	/**
-	 * Sets position from the string.
-	 * 
-	 * @param text
-	 *          position to parse and set
-	 * @see #pos
-	 */
-	public void setPos(String text) {
-		try {
-			pos = Double.parseDouble(text);
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid pos: " + text, e);
-		}
-	}
-
-	/**
-	 * Update data in this object from parameter (only if values in parameter
-	 * object are valid).
-	 * 
-	 * @param mr
-	 *          object from which we are updating data
-	 */
-	public void update(CellDesignerAntisenseRnaRegion mr) {
-		if (this.idAntisenseRnaRegion != null && !this.idAntisenseRnaRegion.equals("") && !this.idAntisenseRnaRegion.equals(mr.getIdAntisenseRnaRegion())) {
-			throw new InvalidArgumentException("Cannot update from mr with different id");
-		}
-		this.size = mr.getSize();
-		if (mr.getState() != null) {
-			this.state = mr.getState();
-		}
-		if (mr.getName() != null) {
-			this.name = mr.getName();
-		}
-		if (mr.getPos() != null) {
-			this.setPos(mr.getPos());
-		}
-
-	}
-
-	@Override
-	public String toString() {
-		String result = getIdAntisenseRnaRegion() + "," + getName() + "," + getType() + "," + getPos() + "," + getSize() + ",";
-		return result;
-	}
-
-	/**
-	 * @return the idAntisenseRnaRegion
-	 * @see #idAntisenseRnaRegion
-	 */
-	public String getIdAntisenseRnaRegion() {
-		return idAntisenseRnaRegion;
-	}
-
-	/**
-	 * @param idAntisenseRnaRegion
-	 *          the id to set
-	 * @see #idAntisenseRnaRegion
-	 */
-	public void setIdAntisenseRnaRegion(String idAntisenseRnaRegion) {
-		this.idAntisenseRnaRegion = idAntisenseRnaRegion;
-	}
-
-	/**
-	 * @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;
-	}
-
-	/**
-	 * @return the state
-	 * @see #state
-	 */
-	public ModificationState getState() {
-		return state;
-	}
-
-	/**
-	 * @param state
-	 *          the state to set
-	 * @see #state
-	 */
-	public void setState(ModificationState state) {
-		this.state = state;
-	}
-
-	/**
-	 * @return the type
-	 * @see #type
-	 */
-	public AntisenseRnaRegionType getType() {
-		return type;
-	}
-
-	/**
-	 * @param type
-	 *          the type to set
-	 * @see #type
-	 */
-	public void setType(AntisenseRnaRegionType type) {
-		this.type = type;
-	}
-
-	/**
-	 * @return the size
-	 * @see #size
-	 */
-	public double getSize() {
-		return size;
-	}
-
-	/**
-	 * @param size
-	 *          the size to set
-	 * @see #size
-	 */
-	public void setSize(double size) {
-		this.size = size;
-	}
-
-	/**
-	 * @return the pos
-	 * @see #pos
-	 */
-	public Double getPos() {
-		return pos;
-	}
-
-	/**
-	 * @param pos
-	 *          the pos to set
-	 * @see #pos
-	 */
-	public void setPos(Double pos) {
-		this.pos = pos;
-	}
-
-	/**
-	 * @return the species
-	 * @see #species
-	 */
-	public CellDesignerAntisenseRna getSpecies() {
-		return species;
-	}
-
-	/**
-	 * @param species
-	 *          the species to set
-	 * @see #species
-	 */
-	public void setSpecies(CellDesignerAntisenseRna species) {
-		this.species = species;
-	}
-
-	/**
-	 * @return the id
-	 * @see #id
-	 */
-	public int getId() {
-		return id;
-	}
-
-	/**
-	 * @param id
-	 *          the id to set
-	 * @see #id
-	 */
-	public void setId(int id) {
-		this.id = id;
-	}
-
-	/**
-	 * Creates model representation of {@link AntisenseRnaRegion}.
-	 * 
-	 * @return {@link AntisenseRnaRegion} representing this object in a model
-	 */
-	public AntisenseRnaRegion createAntisenseRegionAlias() {
-		AntisenseRnaRegion result = new AntisenseRnaRegion();
-		result.setIdAntisenseRnaRegion(idAntisenseRnaRegion);
-		result.setName(name);
-		result.setSize(size);
-		result.setPos(pos);
-		result.setType(type);
-		return result;
-	}
-
-}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerModificationResidue.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerModificationResidue.java
index 34bf5b75c4e47f0f21bb0c55b5f543b628dfa951..10789b0b509f5559600096ece698857338bec02f 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerModificationResidue.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerModificationResidue.java
@@ -1,333 +1,557 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure.fields;
-
-import java.io.Serializable;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerSpecies;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-/**
- * This class represent modification residue in protein and gene. However, it is
- * sometimes also used for storing information about AntisenseRna/Rna regions...
- * (due to CellDesigner xml strange structure).
- * 
- * @author Piotr Gawron
- * 
- */
-public class CellDesignerModificationResidue implements Serializable {
-
-	/**
-	 * 
-	 */
-	private static final long			 serialVersionUID			 = 1L;
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger					 logger								 = Logger.getLogger(CellDesignerModificationResidue.class.getName());
-
-	/**
-	 * Identifier of the modification. Must be unique in single map model.
-	 */
-	private String								 idModificationResidue = "";
-
-	/**
-	 * Name of the modification.
-	 */
-	private String								 name									 = "";
-
-	/**
-	 * Some strange param in CellDesigner. No idea what is it for.
-	 */
-	private String								 side									 = "";
-
-	/**
-	 * State in which this modification is.
-	 */
-	private ModificationState			 state								 = null;
-
-	/**
-	 * Where this modification is located (on which side of the border).
-	 */
-	private Double								 angle								 = null;
-
-	/**
-	 * How big is this modification (used only for some types of the
-	 * modification).
-	 */
-	private Double								 size									 = null;
-
-	/**
-	 * Species to which this modification belong to.
-	 */
-	private CellDesignerSpecies<?> species;
-
-	/**
-	 * Default constructor.
-	 */
-	public CellDesignerModificationResidue() {
-	}
-
-	/**
-	 * Constructor that initaize object with the data taken from the parameter.
-	 * 
-	 * @param mr
-	 *          original object from which data is taken
-	 */
-	public CellDesignerModificationResidue(CellDesignerModificationResidue mr) {
-		this.idModificationResidue = mr.idModificationResidue;
-		this.name = mr.name;
-		this.angle = mr.angle;
-		this.size = mr.size;
-		this.side = mr.side;
-		this.state = mr.state;
-	}
-
-	/**
-	 * Constructor that creates object from model representation of modification.
-	 * 
-	 * @param mr
-	 *          model represnation of {@link ModificationResidue}
-	 */
-	public CellDesignerModificationResidue(ModificationResidue mr) {
-		this.idModificationResidue = mr.getIdModificationResidue();
-		this.name = mr.getName();
-		this.angle = mr.getAngle();
-		this.size = mr.getSize();
-		this.side = mr.getSide();
-		this.state = mr.getState();
-	}
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param id
-	 *          identifier of the modificationr esidue
-	 */
-	public CellDesignerModificationResidue(String id) {
-		this.idModificationResidue = id;
-	}
-
-	/**
-	 * Updates fields in the object with the data given in the parameter
-	 * modification.
-	 * 
-	 * @param mr
-	 *          modification residue from which data will be used to update
-	 */
-	public void update(CellDesignerModificationResidue mr) {
-		if (mr.getName() != null && !mr.getName().equals("")) {
-			this.name = mr.name;
-		}
-		if (mr.getAngle() != null) {
-			this.angle = mr.angle;
-		}
-		if (mr.getSize() != null) {
-			this.size = mr.size;
-		}
-		if (mr.getSide() != null && !mr.getSide().equals("")) {
-			this.side = mr.side;
-		}
-		if (mr.getState() != null) {
-			this.state = mr.state;
-		}
-	}
-
-	@Override
-	public String toString() {
-		String result = getIdModificationResidue() + "," + getName() + "," + getState() + "," + getAngle() + "," + getSize() + "," + getSide() + ",";
-		return result;
-	}
-
-	/**
-	 * Creates copy of the object.
-	 * 
-	 * @return copy of the object.
-	 */
-	public CellDesignerModificationResidue copy() {
-		if (this.getClass() == CellDesignerModificationResidue.class) {
-			return new CellDesignerModificationResidue(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-	}
-
-	/**
-	 * Sets {@link #angle} .
-	 * 
-	 * @param text
-	 *          angle in text format
-	 */
-	public void setAngle(String text) {
-		try {
-			if (text != null && !text.equals("")) {
-				angle = Double.parseDouble(text);
-			} else {
-				angle = null;
-			}
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid angle: " + text, e);
-		}
-
-	}
-
-	/**
-	 * Sets {@link #size}.
-	 * 
-	 * @param text
-	 *          size in text format.
-	 */
-	public void setSize(String text) {
-		try {
-			if (text != null && !text.equals("")) {
-				size = Double.parseDouble(text);
-			} else {
-				size = null;
-			}
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid size: " + text, e);
-		}
-	}
-
-	/**
-	 * @return the id
-	 * @see #idModificationResidue
-	 */
-	public String getIdModificationResidue() {
-		return idModificationResidue;
-	}
-
-	/**
-	 * @param idModificationResidue
-	 *          the id to set
-	 * @see #idModificationResidue
-	 */
-	public void setIdModificationResidue(String idModificationResidue) {
-		this.idModificationResidue = idModificationResidue;
-	}
-
-	/**
-	 * @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;
-	}
-
-	/**
-	 * @return the side
-	 * @see #side
-	 */
-	public String getSide() {
-		return side;
-	}
-
-	/**
-	 * @param side
-	 *          the side to set
-	 * @see #side
-	 */
-	public void setSide(String side) {
-		this.side = side;
-	}
-
-	/**
-	 * @return the state
-	 * @see #state
-	 */
-	public ModificationState getState() {
-		return state;
-	}
-
-	/**
-	 * @param state
-	 *          the state to set
-	 * @see #state
-	 */
-	public void setState(ModificationState state) {
-		this.state = state;
-	}
-
-	/**
-	 * @return the angle
-	 * @see #angle
-	 */
-	public Double getAngle() {
-		return angle;
-	}
-
-	/**
-	 * @param angle
-	 *          the angle to set
-	 * @see #angle
-	 */
-	public void setAngle(Double angle) {
-		this.angle = angle;
-	}
-
-	/**
-	 * @return the size
-	 * @see #size
-	 */
-	public Double getSize() {
-		return size;
-	}
-
-	/**
-	 * @param size
-	 *          the size to set
-	 * @see #size
-	 */
-	public void setSize(Double size) {
-		this.size = size;
-	}
-
-	/**
-	 * @return the species
-	 * @see #species
-	 */
-	public CellDesignerSpecies<?> getSpecies() {
-		return species;
-	}
-
-	/**
-	 * @param species
-	 *          the species to set
-	 * @see #species
-	 */
-	public void setSpecies(CellDesignerSpecies<?> species) {
-		this.species = species;
-	}
-
-	/**
-	 * Creates model representation of {@link ModificationResidue}.
-	 * 
-	 * @return {@link ModificationResidue} representing this object in a model
-	 */
-	public ModificationResidue createModificationResidueAlias() {
-		ModificationResidue result = new ModificationResidue();
-
-		result.setIdModificationResidue(this.getIdModificationResidue());
-		result.setName(this.getName());
-		result.setAngle(this.getAngle());
-		result.setSize(this.getSize());
-		result.setSide(this.getSide());
-		result.setState(this.getState());
-		return result;
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure.fields;
+
+import java.io.Serializable;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.CellDesignerAliasConverter;
+import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerSpecies;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.field.BindingRegion;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+import lcsb.mapviewer.model.map.species.field.ProteinBindingDomain;
+import lcsb.mapviewer.model.map.species.field.RegulatoryRegion;
+import lcsb.mapviewer.model.map.species.field.Residue;
+import lcsb.mapviewer.model.map.species.field.TranscriptionSite;
+
+/**
+ * This class represent modification residue in a Species.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class CellDesignerModificationResidue implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(CellDesignerModificationResidue.class.getName());
+
+  /**
+   * Identifier of the modification. Must be unique in single map model.
+   */
+  private String idModificationResidue = "";
+
+  /**
+   * Name of the modification.
+   */
+  private String name = "";
+
+  private Boolean active = null;
+
+  private ModificationType modificationType;
+
+  /**
+   * Position on the species in graphic representation.
+   */
+  private Double pos;
+
+  /**
+   * Some strange parameter in CellDesigner. No idea what is it for.
+   */
+  private String side = "";
+
+  /**
+   * State in which this modification is.
+   */
+  private ModificationState state = null;
+
+  /**
+   * Where this modification is located (on which side of the border).
+   */
+  private Double angle = null;
+
+  /**
+   * How big is this modification (used only for some types of the modification).
+   */
+  private Double size = null;
+
+  /**
+   * Species to which this modification belong to.
+   */
+  private CellDesignerSpecies<?> species;
+
+  /**
+   * Default constructor.
+   */
+  public CellDesignerModificationResidue() {
+  }
+
+  /**
+   * Constructor that initialize object with the data taken from the parameter.
+   * 
+   * @param mr
+   *          original object from which data is taken
+   */
+  public CellDesignerModificationResidue(CellDesignerModificationResidue mr) {
+    this.idModificationResidue = mr.idModificationResidue;
+    this.name = mr.name;
+    this.angle = mr.angle;
+    this.active = mr.active;
+    this.size = mr.size;
+    this.side = mr.side;
+    this.pos = mr.pos;
+    this.state = mr.state;
+    this.modificationType = mr.modificationType;
+  }
+
+  /**
+   * Constructor that creates object from model representation of modification.
+   * 
+   * @param mr
+   *          model representation of {@link ModificationResidue}
+   */
+  public CellDesignerModificationResidue(ModificationResidue mr) {
+    CellDesignerAliasConverter converter = new CellDesignerAliasConverter(mr.getSpecies(), false);
+    this.idModificationResidue = mr.getIdModificationResidue();
+    this.name = mr.getName();
+    this.angle = converter.getAngleForPoint(mr.getSpecies(), mr.getPosition());
+    this.pos = converter.getCellDesignerPositionByCoordinates(mr);
+    if (mr instanceof Residue) {
+      this.modificationType = ModificationType.RESIDUE;
+      this.state = ((Residue) mr).getState();
+    } else if (mr instanceof ModificationSite) {
+      this.modificationType = ModificationType.MODIFICATION_SITE;
+      this.state = ((ModificationSite) mr).getState();
+    } else if (mr instanceof CodingRegion) {
+      this.size = converter.getCellDesignerSize(mr);
+      this.modificationType = ModificationType.CODING_REGION;
+    } else if (mr instanceof ProteinBindingDomain) {
+      this.size = converter.getCellDesignerSize(mr);
+      this.modificationType = ModificationType.PROTEIN_BINDING_DOMAIN;
+    } else if (mr instanceof RegulatoryRegion) {
+      this.size = converter.getCellDesignerSize(mr);
+      this.modificationType = ModificationType.REGULATORY_REGION;
+    } else if (mr instanceof TranscriptionSite) {
+      TranscriptionSite transcriptionSite = (TranscriptionSite) mr;
+      this.size = converter.getCellDesignerSize(mr);
+      this.active = transcriptionSite.getActive();
+      if (transcriptionSite.getDirection().equals("LEFT")) {
+        this.modificationType = ModificationType.TRANSCRIPTION_SITE_LEFT;
+      } else {
+        this.modificationType = ModificationType.TRANSCRIPTION_SITE_RIGHT;
+      }
+    } else if (mr instanceof BindingRegion) {
+      this.modificationType = ModificationType.BINDING_REGION;
+      if (Math.abs(mr.getPosition().getX() - mr.getSpecies().getX()) < Configuration.EPSILON) {
+        this.size = ((BindingRegion) mr).getHeight() / mr.getSpecies().getHeight();
+      } else if (Math
+          .abs(mr.getPosition().getX() - mr.getSpecies().getX() - mr.getSpecies().getWidth()) < Configuration.EPSILON) {
+        this.size = ((BindingRegion) mr).getHeight() / mr.getSpecies().getHeight();
+      } else {
+        this.size = ((BindingRegion) mr).getWidth() / mr.getSpecies().getWidth();
+      }
+
+    } else {
+      throw new InvalidArgumentException("Unknown modification type: " + mr.getClass());
+    }
+  }
+
+  /**
+   * Default constructor.
+   * 
+   * @param id
+   *          identifier of the modification residue
+   */
+  public CellDesignerModificationResidue(String id) {
+    this.idModificationResidue = id;
+  }
+
+  /**
+   * Updates fields in the object with the data given in the parameter
+   * modification.
+   * 
+   * @param mr
+   *          modification residue from which data will be used to update
+   */
+  public void update(CellDesignerModificationResidue mr) {
+    if (mr.getName() != null && !mr.getName().equals("")) {
+      this.name = mr.name;
+    }
+    if (mr.getAngle() != null) {
+      this.angle = mr.angle;
+    }
+    if (mr.getActive() != null) {
+      this.active = mr.active;
+    }
+    if (mr.getSize() != null) {
+      this.size = mr.size;
+    }
+    if (mr.getSide() != null && !mr.getSide().equals("")) {
+      this.side = mr.side;
+    }
+    if (mr.getState() != null) {
+      this.state = mr.state;
+    }
+    if (mr.getPos() != null) {
+      this.setPos(mr.getPos());
+    }
+    if (mr.getModificationType() != null) {
+      this.setModificationType(mr.modificationType);
+    }
+  }
+
+  @Override
+  public String toString() {
+    String result = getIdModificationResidue() + "," + getName() + "," + getState() + "," + getAngle() + "," + getSize()
+        + getPos() + "," + "," + getSide() + ",";
+    return result;
+  }
+
+  /**
+   * Creates copy of the object.
+   * 
+   * @return copy of the object.
+   */
+  public CellDesignerModificationResidue copy() {
+    if (this.getClass() == CellDesignerModificationResidue.class) {
+      return new CellDesignerModificationResidue(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+  }
+
+  /**
+   * Sets {@link #angle} .
+   * 
+   * @param text
+   *          angle in text format
+   */
+  public void setAngle(String text) {
+    try {
+      if (text != null && !text.equals("")) {
+        angle = Double.parseDouble(text);
+      } else {
+        angle = null;
+      }
+    } catch (NumberFormatException e) {
+      throw new InvalidArgumentException("Invalid angle: " + text, e);
+    }
+
+  }
+
+  /**
+   * Sets {@link #size}.
+   * 
+   * @param text
+   *          size in text format.
+   */
+  public void setSize(String text) {
+    try {
+      if (text != null && !text.equals("")) {
+        size = Double.parseDouble(text);
+      } else {
+        size = null;
+      }
+    } catch (NumberFormatException e) {
+      throw new InvalidArgumentException("Invalid size: " + text, e);
+    }
+  }
+
+  /**
+   * @return the id
+   * @see #idModificationResidue
+   */
+  public String getIdModificationResidue() {
+    return idModificationResidue;
+  }
+
+  /**
+   * @param idModificationResidue
+   *          the id to set
+   * @see #idModificationResidue
+   */
+  public void setIdModificationResidue(String idModificationResidue) {
+    this.idModificationResidue = idModificationResidue;
+  }
+
+  /**
+   * @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;
+  }
+
+  /**
+   * @return the side
+   * @see #side
+   */
+  public String getSide() {
+    return side;
+  }
+
+  /**
+   * @param side
+   *          the side to set
+   * @see #side
+   */
+  public void setSide(String side) {
+    this.side = side;
+  }
+
+  /**
+   * @return the state
+   * @see #state
+   */
+  public ModificationState getState() {
+    return state;
+  }
+
+  /**
+   * @param state
+   *          the state to set
+   * @see #state
+   */
+  public void setState(ModificationState state) {
+    this.state = state;
+  }
+
+  /**
+   * @return the angle
+   * @see #angle
+   */
+  public Double getAngle() {
+    return angle;
+  }
+
+  /**
+   * @param angle
+   *          the angle to set
+   * @see #angle
+   */
+  public void setAngle(Double angle) {
+    this.angle = angle;
+  }
+
+  /**
+   * @return the size
+   * @see #size
+   */
+  public Double getSize() {
+    return size;
+  }
+
+  /**
+   * @param size
+   *          the size to set
+   * @see #size
+   */
+  public void setSize(Double size) {
+    this.size = size;
+  }
+
+  /**
+   * @return the species
+   * @see #species
+   */
+  public CellDesignerSpecies<?> getSpecies() {
+    return species;
+  }
+
+  /**
+   * @param species
+   *          the species to set
+   * @see #species
+   */
+  public void setSpecies(CellDesignerSpecies<?> species) {
+    this.species = species;
+  }
+
+  /**
+   * Creates model representation of {@link ModificationResidue}.
+   * 
+   * @return {@link ModificationResidue} representing this object in a model
+   */
+  public ModificationResidue createModificationResidue(Element element) {
+    CellDesignerAliasConverter converter = new CellDesignerAliasConverter(element, false);
+
+    if (modificationType == null) {
+      throw new InvalidArgumentException("No type information for modification: " + idModificationResidue);
+    } else if (modificationType.equals(ModificationType.RESIDUE)) {
+      return createResidue(element, converter);
+    } else if (modificationType.equals(ModificationType.BINDING_REGION)) {
+      return createBindingRegion(element, converter);
+    } else if (modificationType.equals(ModificationType.MODIFICATION_SITE)) {
+      return createModificationSite(element, converter);
+    } else if (modificationType.equals(ModificationType.CODING_REGION)) {
+      return createCodingRegion(element, converter);
+    } else if (modificationType.equals(ModificationType.PROTEIN_BINDING_DOMAIN)) {
+      return createProteinBindingDomain(element, converter);
+    } else if (modificationType.equals(ModificationType.REGULATORY_REGION)) {
+      return createRegulatoryRegion(element, converter);
+    } else if (modificationType.equals(ModificationType.TRANSCRIPTION_SITE_LEFT)
+        || modificationType.equals(ModificationType.TRANSCRIPTION_SITE_RIGHT)) {
+      return createTranscriptionSite(element, converter);
+    } else {
+      throw new InvalidArgumentException("Unknown modification type: " + modificationType);
+    }
+
+  }
+
+  private ProteinBindingDomain createProteinBindingDomain(Element element, CellDesignerAliasConverter converter) {
+    ProteinBindingDomain result = new ProteinBindingDomain();
+    result.setWidth(converter.getWidthBySize(element, size));
+    result.setIdModificationResidue(idModificationResidue);
+    result.setName(name);
+    result.setPosition(converter.getCoordinatesByPosition(element, pos, result.getWidth()));
+    return result;
+  }
+
+  private BindingRegion createBindingRegion(Element element, CellDesignerAliasConverter converter) {
+    BindingRegion result = new BindingRegion();
+    result.setIdModificationResidue(idModificationResidue);
+    result.setName(name);
+    result.setPosition(converter.getResidueCoordinates(element, angle));
+    if (Math.abs(result.getPosition().getX() - element.getX()) < Configuration.EPSILON) {
+      result.setHeight(element.getHeight() * size);
+    } else if (Math.abs(result.getPosition().getX() - element.getX() - element.getWidth()) < Configuration.EPSILON) {
+      result.setHeight(element.getHeight() * size);
+    } else {
+      result.setWidth(element.getWidth() * size);
+    }
+    return result;
+  }
+
+  private CodingRegion createCodingRegion(Element element, CellDesignerAliasConverter converter) {
+    CodingRegion result = new CodingRegion();
+    result.setWidth(converter.getWidthBySize(element, size));
+    result.setIdModificationResidue(idModificationResidue);
+    result.setName(name);
+    if (pos == null) {
+      pos = angle;
+    }
+    result.setPosition(converter.getCoordinatesByPosition(element, pos, result.getWidth()));
+    return result;
+  }
+
+  private RegulatoryRegion createRegulatoryRegion(Element element, CellDesignerAliasConverter converter) {
+    RegulatoryRegion result = new RegulatoryRegion();
+    result.setWidth(converter.getWidthBySize(element, size));
+    result.setIdModificationResidue(idModificationResidue);
+    result.setName(name);
+    result.setPosition(converter.getCoordinatesByPosition(element, angle, result.getWidth()));
+    return result;
+  }
+
+  private TranscriptionSite createTranscriptionSite(Element element, CellDesignerAliasConverter converter) {
+    TranscriptionSite result = new TranscriptionSite();
+    result.setWidth(converter.getWidthBySize(element, size));
+    result.setIdModificationResidue(idModificationResidue);
+    result.setName(name);
+    result.setActive(active);
+    result.setPosition(converter.getCoordinatesByPosition(element, angle, result.getWidth()));
+    if (modificationType.equals(ModificationType.TRANSCRIPTION_SITE_LEFT)) {
+      result.setDirection("LEFT");
+    } else {
+      result.setDirection("RIGHT");
+    }
+    return result;
+  }
+
+  private ModificationSite createModificationSite(Element element, CellDesignerAliasConverter converter) {
+    ModificationSite result = new ModificationSite();
+    result.setState(this.getState());
+    result.setIdModificationResidue(this.getIdModificationResidue());
+    result.setName(this.getName());
+    if (angle == null) {
+      angle = pos;
+    }
+    if (angle == null) {
+      logger.warn("Angle is not defined using 0 as default");
+      angle = 0.0;
+    }
+    result.setPosition(converter.getCoordinatesByPosition(element, angle));
+    return result;
+  }
+
+  private Residue createResidue(Element element, CellDesignerAliasConverter converter) {
+    Residue result = new Residue();
+    result.setState(this.getState());
+    result.setIdModificationResidue(this.getIdModificationResidue());
+    result.setName(this.getName());
+    if (angle == null) {
+      logger.warn("Angle is not defined using 0 as default");
+      angle = 0.0;
+    }
+    result.setPosition(converter.getResidueCoordinates(element, angle));
+    return result;
+  }
+
+  public ModificationType getModificationType() {
+    return modificationType;
+  }
+
+  public void setModificationType(ModificationType modificationType) {
+    this.modificationType = modificationType;
+  }
+
+  /**
+   * Sets position from the string.
+   * 
+   * @param text
+   *          position to parse and set
+   * @see #pos
+   */
+  public void setPos(String text) {
+    try {
+      pos = Double.parseDouble(text);
+    } catch (NumberFormatException e) {
+      throw new InvalidArgumentException("Invalid pos: " + text, e);
+    }
+  }
+
+  /**
+   * @return the pos
+   * @see #pos
+   */
+  public Double getPos() {
+    return pos;
+  }
+
+  /**
+   * @param pos
+   *          the pos to set
+   * @see #pos
+   */
+  public void setPos(Double pos) {
+    this.pos = pos;
+  }
+
+  public Boolean getActive() {
+    return active;
+  }
+
+  public void setActive(Boolean active) {
+    this.active = active;
+  }
+
+  public void setActive(String text) {
+    if (text == null) {
+      this.active = null;
+    } else {
+      this.active = "true".equalsIgnoreCase(text);
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerRnaRegion.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerRnaRegion.java
deleted file mode 100644
index bbb44414758cd125082930ee1f9f62f290b94edd..0000000000000000000000000000000000000000
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerRnaRegion.java
+++ /dev/null
@@ -1,301 +0,0 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure.fields;
-
-import java.io.Serializable;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerRna;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
-
-/**
- * This structure contains information about rna region (rna fragment of
- * interest) for a specific
- * {@link lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerRna
- * Rna}.
- * 
- * @author Piotr Gawron
- * 
- */
-public class CellDesignerRnaRegion implements Serializable {
-
-	/**
-	 * 
-	 */
-	private static final long		serialVersionUID = 1L;
-
-	/**
-	 * Default {@link #size} of the region.
-	 */
-	private static final double	DEFAULT_SIZE		 = 0.1;
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger				logger					 = Logger.getLogger(CellDesignerRnaRegion.class.getName());
-
-	/**
-	 * Identifier of the region. Unique in the
-	 * {@link lcsb.mapviewer.model.map.model.Model}.
-	 */
-	private String							idRnaRegion			 = "";
-
-	/**
-	 * Type of the region in the rna. There are three possible values:
-	 * <ul>
-	 * <li>Coding region,</li>
-	 * <li>Protein binding domain,</li>
-	 * <li>Modification site.</li>
-	 * </ul>
-	 */
-	private String							type						 = "";
-
-	/**
-	 * Defines a state of the region (for instance ubiquitinated etc).
-	 * 
-	 * @see ModificationState
-	 */
-	private ModificationState		state						 = null;
-
-	/**
-	 * Name of the region.
-	 */
-	private String							name						 = "";
-
-	/**
-	 * Size of the region in the graphic representation.
-	 */
-	private double							size						 = DEFAULT_SIZE;
-
-	/**
-	 * Position on the species in graphic representation.
-	 */
-	private Double							pos;
-
-	/**
-	 * Defines a species where the region belongs to.
-	 */
-	private CellDesignerRna			species;
-
-	/**
-	 * Default constructor.
-	 */
-	public CellDesignerRnaRegion() {
-
-	}
-
-	/**
-	 * Creates object with the data taken from paramter region.
-	 * 
-	 * @param mr
-	 *          original {@link CellDesignerRnaRegion}
-	 */
-	public CellDesignerRnaRegion(CellDesignerRnaRegion mr) {
-		this.idRnaRegion = mr.idRnaRegion;
-		this.size = mr.size;
-		setPos(mr.getPos());
-		this.type = mr.type;
-		this.state = mr.state;
-		this.name = mr.name;
-	}
-
-	/**
-	 * Sets {@link #size}.
-	 * 
-	 * @param text
-	 *          new size value in string format
-	 */
-	public void setSize(String text) {
-		try {
-			size = Double.parseDouble(text);
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid angle: " + text, e);
-		}
-
-	}
-
-	/**
-	 * Sets {@link #pos}.
-	 * 
-	 * @param text
-	 *          new {@link #pos} value in string format
-	 */
-	public void setPos(String text) {
-		try {
-			setPos(Double.parseDouble(text));
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid pos: " + text, e);
-		}
-
-	}
-
-	/**
-	 * Updates fields in the object with the data given in the parameter rna
-	 * region.
-	 * 
-	 * @param mr
-	 *          {@link CellDesignerRnaRegion} from which data will be used to
-	 *          update
-	 */
-	public void update(CellDesignerRnaRegion mr) {
-		if (this.idRnaRegion != null && !this.idRnaRegion.equals("") && !this.idRnaRegion.equals(mr.getIdRnaRegion())) {
-			throw new InvalidArgumentException("Cannot update from mr with different id");
-		}
-		this.size = mr.getSize();
-		if (mr.getState() != null) {
-			this.state = mr.getState();
-		}
-		if (mr.getName() != null) {
-			this.name = mr.getName();
-		}
-		if (mr.getPos() != null) {
-			this.setPos(mr.getPos());
-		}
-
-	}
-
-	@Override
-	public String toString() {
-		String result = "" + getIdRnaRegion() + "," + getType() + "," + getPos() + "," + getSize() + "," + getState() + ",";
-		return result;
-
-	}
-
-	/**
-	 * @return the id
-	 * @see #id
-	 */
-	public String getIdRnaRegion() {
-		return idRnaRegion;
-	}
-
-	/**
-	 * @param id
-	 *          the id to set
-	 * @see #id
-	 */
-	public void setIdRnaRegion(String id) {
-		this.idRnaRegion = id;
-	}
-
-	/**
-	 * @return the type
-	 * @see #type
-	 */
-	public String getType() {
-		return type;
-	}
-
-	/**
-	 * @param type
-	 *          the type to set
-	 * @see #type
-	 */
-	public void setType(String type) {
-		this.type = type;
-	}
-
-	/**
-	 * @return the state
-	 * @see #state
-	 */
-	public ModificationState getState() {
-		return state;
-	}
-
-	/**
-	 * @param state
-	 *          the state to set
-	 * @see #state
-	 */
-	public void setState(ModificationState state) {
-		this.state = state;
-	}
-
-	/**
-	 * @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;
-	}
-
-	/**
-	 * @return the size
-	 * @see #size
-	 */
-	public double getSize() {
-		return size;
-	}
-
-	/**
-	 * @param size
-	 *          the size to set
-	 * @see #size
-	 */
-	public void setSize(double size) {
-		this.size = size;
-	}
-
-	/**
-	 * @return the pos
-	 * @see #pos
-	 */
-	public Double getPos() {
-		return pos;
-	}
-
-	/**
-	 * @param pos
-	 *          the pos to set
-	 * @see #pos
-	 */
-	public void setPos(Double pos) {
-		this.pos = pos;
-	}
-
-	/**
-	 * @return the species
-	 * @see #species
-	 */
-	public CellDesignerRna getSpecies() {
-		return species;
-	}
-
-	/**
-	 * @param species
-	 *          the species to set
-	 * @see #species
-	 */
-	public void setSpecies(CellDesignerRna species) {
-		this.species = species;
-	}
-
-	/**
-	 * Creates model representation of {@link RnaRegion}.
-	 * 
-	 * @return {@link RnaRegion} representing this object in a model
-	 */
-	public RnaRegion createRnaRegionAlias() {
-		RnaRegion result = new RnaRegion();
-		result.setIdRnaRegion(this.idRnaRegion);
-		result.setSize(this.size);
-		result.setPos(this.getPos());
-		result.setType(this.getType());
-		result.setState(this.state);
-		result.setName(this.name);
-		return result;
-	}
-
-}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/ModificationType.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/ModificationType.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca6bad57fea0d469996ef35f783add2a83a098ac
--- /dev/null
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/ModificationType.java
@@ -0,0 +1,33 @@
+package lcsb.mapviewer.converter.model.celldesigner.structure.fields;
+
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+
+public enum ModificationType {
+  BINDING_REGION(null), //
+  CODING_REGION("CodingRegion"), //
+  PROTEIN_BINDING_DOMAIN("proteinBindingDomain"), //
+  RESIDUE(null), //
+  REGULATORY_REGION("RegulatoryRegion"), //
+  TRANSCRIPTION_SITE_RIGHT("transcriptionStartingSiteR"), //
+  TRANSCRIPTION_SITE_LEFT("transcriptionStartingSiteL"), //
+  MODIFICATION_SITE("Modification Site");//
+
+  private String cellDesignerName;
+
+  ModificationType(String cellDesignerName) {
+    this.cellDesignerName = cellDesignerName;
+  }
+
+  public String getCellDesignerName() {
+    return cellDesignerName;
+  }
+
+  public static ModificationType getByCellDesignerName(String name) {
+    for (ModificationType type : ModificationType.values()) {
+      if (type.getCellDesignerName() != null && type.getCellDesignerName().equals(name)) {
+        return type;
+      }
+    }
+    throw new InvalidArgumentException("Unknown CellDesigner name: " + name);
+  }
+}
diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/SpeciesState.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/SpeciesState.java
index c6a42cda6e92d8b5083242f18163c373e5d0374f..2e9562224a93b787b2e21c676b552c2e88503108 100644
--- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/SpeciesState.java
+++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/SpeciesState.java
@@ -1,167 +1,170 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure.fields;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.Gene;
-import lcsb.mapviewer.model.map.species.Protein;
-import lcsb.mapviewer.model.map.species.Rna;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
-
-/**
- * Structure for storing the state of the Species in CellDesigner format.
- * 
- * @author Piotr Gawron
- * 
- */
-public class SpeciesState {
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private Logger										logger					= Logger.getLogger(SpeciesState.class.getName());
-
-	/**
-	 * How many dimers are in the species.
-	 */
-	private int												homodimer				= 1;
-
-	/**
-	 * String state description.
-	 */
-	private String										structuralState	= null;
-
-	/**
-	 * List of species modification.
-	 */
-	private List<CellDesignerModificationResidue>	modifications		= new ArrayList<CellDesignerModificationResidue>();
-
-	/**
-	 * Adds modification to the state.
-	 * 
-	 * @param modificationResidue
-	 *          modification to add
-	 */
-	public void addModificationResidue(CellDesignerModificationResidue modificationResidue) {
-		for (CellDesignerModificationResidue modification : modifications) {
-			if (modification.getIdModificationResidue().equals(modificationResidue.getIdModificationResidue())) {
-				modification.update(modificationResidue);
-				return;
-			}
-		}
-		modifications.add(modificationResidue);
-	}
-
-	/**
-	 * Default constructor.
-	 */
-	public SpeciesState() {
-	}
-
-	/**
-	 * Creates species state description from species element.
-	 * 
-	 * @param species
-	 *          object for which description is created
-	 */
-	public SpeciesState(Species species) {
-		if (species instanceof Protein) {
-			Protein protein = (Protein) species;
-			setStructuralState(protein.getStructuralState());
-			for (ModificationResidue mr : protein.getModificationResidues()) {
-				addModificationResidue(new CellDesignerModificationResidue(mr));
-			}
-
-		} else if (species instanceof Complex) {
-			Complex complex = (Complex) species;
-			setStructuralState(complex.getStructuralState());
-		} else if (species instanceof Rna) {
-			Rna rna = (Rna) species;
-			for (RnaRegion region : rna.getRegions()) {
-				CellDesignerModificationResidue mr = new CellDesignerModificationResidue();
-				mr.setIdModificationResidue(region.getIdRnaRegion());
-				mr.setSize(region.getSize());
-				mr.setState(region.getState());
-				addModificationResidue(mr);
-			}
-		} else if (species instanceof Gene) {
-			Gene gene = (Gene) species;
-			for (ModificationResidue mr : gene.getModificationResidues()) {
-				addModificationResidue(new CellDesignerModificationResidue(mr));
-			}
-		}
-		setHomodimer(species.getHomodimer());
-	}
-
-	/**
-	 * 
-	 * @param homodimer
-	 *          new {@link #homodimer} value to set (in string format)
-	 */
-	public void setHomodimer(String homodimer) {
-		try {
-			this.homodimer = Integer.parseInt(homodimer);
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid homodir value: " + homodimer);
-		}
-	}
-
-	/**
-	 * @return the homodimer
-	 * @see #homodimer
-	 */
-	public int getHomodimer() {
-		return homodimer;
-	}
-
-	/**
-	 * @param homodimer
-	 *          the homodimer to set
-	 * @see #homodimer
-	 */
-	public void setHomodimer(int homodimer) {
-		this.homodimer = homodimer;
-	}
-
-	/**
-	 * @return the structuralState
-	 * @see #structuralState
-	 */
-	public String getStructuralState() {
-		return structuralState;
-	}
-
-	/**
-	 * @param structuralState
-	 *          the structuralState to set
-	 * @see #structuralState
-	 */
-	public void setStructuralState(String structuralState) {
-		this.structuralState = structuralState;
-	}
-
-	/**
-	 * @return the modifications
-	 * @see #modifications
-	 */
-	public List<CellDesignerModificationResidue> getModifications() {
-		return modifications;
-	}
-
-	/**
-	 * @param modifications
-	 *          the modifications to set
-	 * @see #modifications
-	 */
-	public void setModifications(List<CellDesignerModificationResidue> modifications) {
-		this.modifications = modifications;
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure.fields;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * Structure for storing the state of the Species in CellDesigner format.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class SpeciesState {
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private Logger logger = Logger.getLogger(SpeciesState.class.getName());
+
+  /**
+   * How many dimers are in the species.
+   */
+  private int homodimer = 1;
+
+  /**
+   * String state description.
+   */
+  private String structuralState = null;
+
+  /**
+   * List of species modification.
+   */
+  private List<CellDesignerModificationResidue> modifications = new ArrayList<>();
+
+  /**
+   * Adds modification to the state.
+   * 
+   * @param modificationResidue
+   *          modification to add
+   */
+  public void addModificationResidue(CellDesignerModificationResidue modificationResidue) {
+    for (CellDesignerModificationResidue modification : modifications) {
+      if (modification.getIdModificationResidue().equals(modificationResidue.getIdModificationResidue())) {
+        modification.update(modificationResidue);
+        return;
+      }
+    }
+    modifications.add(modificationResidue);
+  }
+
+  /**
+   * Default constructor.
+   */
+  public SpeciesState() {
+  }
+
+  /**
+   * Creates species state description from species element.
+   * 
+   * @param species
+   *          object for which description is created
+   */
+  public SpeciesState(Species species) {
+    if (species instanceof Protein) {
+      Protein protein = (Protein) species;
+      setStructuralState(protein.getStructuralState());
+      for (ModificationResidue mr : protein.getModificationResidues()) {
+        addModificationResidue(new CellDesignerModificationResidue(mr));
+      }
+
+    } else if (species instanceof Complex) {
+      Complex complex = (Complex) species;
+      setStructuralState(complex.getStructuralState());
+    } else if (species instanceof Rna) {
+      Rna rna = (Rna) species;
+      for (ModificationResidue region : rna.getRegions()) {
+        CellDesignerModificationResidue mr = new CellDesignerModificationResidue(region);
+        addModificationResidue(mr);
+      }
+    } else if (species instanceof AntisenseRna) {
+      AntisenseRna rna = (AntisenseRna) species;
+      for (ModificationResidue region : rna.getRegions()) {
+        CellDesignerModificationResidue mr = new CellDesignerModificationResidue(region);
+        addModificationResidue(mr);
+      }
+    } else if (species instanceof Gene) {
+      Gene gene = (Gene) species;
+      for (ModificationResidue mr : gene.getModificationResidues()) {
+        addModificationResidue(new CellDesignerModificationResidue(mr));
+      }
+    }
+    setHomodimer(species.getHomodimer());
+  }
+
+  /**
+   * 
+   * @param homodimer
+   *          new {@link #homodimer} value to set (in string format)
+   */
+  public void setHomodimer(String homodimer) {
+    try {
+      this.homodimer = Integer.parseInt(homodimer);
+    } catch (NumberFormatException e) {
+      throw new InvalidArgumentException("Invalid homodir value: " + homodimer);
+    }
+  }
+
+  /**
+   * @return the homodimer
+   * @see #homodimer
+   */
+  public int getHomodimer() {
+    return homodimer;
+  }
+
+  /**
+   * @param homodimer
+   *          the homodimer to set
+   * @see #homodimer
+   */
+  public void setHomodimer(int homodimer) {
+    this.homodimer = homodimer;
+  }
+
+  /**
+   * @return the structuralState
+   * @see #structuralState
+   */
+  public String getStructuralState() {
+    return structuralState;
+  }
+
+  /**
+   * @param structuralState
+   *          the structuralState to set
+   * @see #structuralState
+   */
+  public void setStructuralState(String structuralState) {
+    this.structuralState = structuralState;
+  }
+
+  /**
+   * @return the modifications
+   * @see #modifications
+   */
+  public List<CellDesignerModificationResidue> getModifications() {
+    return modifications;
+  }
+
+  /**
+   * @param modifications
+   *          the modifications to set
+   * @see #modifications
+   */
+  public void setModifications(List<CellDesignerModificationResidue> modifications) {
+    this.modifications = modifications;
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/AllCellDesignerTests.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/AllCellDesignerTests.java
index d6dc3214fc927f4b37110b664eca7564438c4f8e..16b51dec9d76cb8896541fbfeea1492724f58d9b 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/AllCellDesignerTests.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/AllCellDesignerTests.java
@@ -34,6 +34,7 @@ import lcsb.mapviewer.converter.model.celldesigner.unit.UnitXmlParserTest;
     InvalidGroupExceptionTest.class, //
     LayerXmlParserTest.class, //
     NestedComplexParsingTests.class, //
+    ModificationTest.class, //
     ParameterXmlParserTest.class, //
     ReconDataInCellDesignerXmlParserTest.class, //
     UnitXmlParserTest.class,//
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java
index 6f97c0fbcdefd8a56ad20e1efcaa555006056e4d..a6f4b663a9292549d996eab2e7e4f1f33aef0abc 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerXmlParserTest.java
@@ -26,6 +26,7 @@ import org.junit.Test;
 import org.mockito.Mockito;
 
 import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
 import lcsb.mapviewer.converter.ConverterParams;
 import lcsb.mapviewer.converter.InvalidInputDataExecption;
@@ -120,8 +121,8 @@ public class CellDesignerXmlParserTest extends CellDesignerTestFunctions {
       CellDesignerXmlParser parser = new CellDesignerXmlParser();
       parser.createModel(new ConverterParams().filename("testFiles/invalid/sample10.xml"));
       fail("Exceptin expected");
-    } catch (InvalidInputDataExecption e) {
-      assertTrue(e.getMessage().contains("Unknown element of model/listOfReactions"));
+    } catch (InvalidArgumentException e) {
+      assertTrue(e.getMessage().contains("No type information for modification"));
     } catch (Exception e) {
       e.printStackTrace();
       throw e;
@@ -998,5 +999,4 @@ public class CellDesignerXmlParserTest extends CellDesignerTestFunctions {
       throw e;
     }
   }
-
 }
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ComplexParserTests.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ComplexParserTests.java
index d673a7a4e33416b980e8b7bb6f3554f81f22b69d..4df1c5bfb34dd918ef1e21c1aedd417bc53f5b61 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ComplexParserTests.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ComplexParserTests.java
@@ -33,8 +33,10 @@ import lcsb.mapviewer.model.map.species.GenericProtein;
 import lcsb.mapviewer.model.map.species.Protein;
 import lcsb.mapviewer.model.map.species.Rna;
 import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.AbstractSiteModification;
 import lcsb.mapviewer.model.map.species.field.ModificationResidue;
 import lcsb.mapviewer.model.map.species.field.ModificationState;
+import lcsb.mapviewer.model.map.species.field.Residue;
 import lcsb.mapviewer.modelutils.map.ElementUtils;
 
 public class ComplexParserTests extends CellDesignerTestFunctions {
@@ -99,7 +101,7 @@ public class ComplexParserTests extends CellDesignerTestFunctions {
     try {
       Model model = getModelForFile("testFiles/elements_with_kinetic_data.xml");
       model.setName(null);
-      
+
       String xml = new CellDesignerXmlParser().toXml(model);
       ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
       Model model2 = new CellDesignerXmlParser()
@@ -118,7 +120,7 @@ public class ComplexParserTests extends CellDesignerTestFunctions {
     try {
       Model model = getModelForFile("testFiles/reactions/kinetics.xml");
       model.setName(null);
-      
+
       String xml = new CellDesignerXmlParser().toXml(model);
       ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
       Model model2 = new CellDesignerXmlParser()
@@ -222,12 +224,14 @@ public class ComplexParserTests extends CellDesignerTestFunctions {
     try {
       model = getModelForFile("testFiles/problematic/acetyled_protein.xml");
 
-      Set<ModificationState> residues = new HashSet<ModificationState>();
+      Set<ModificationState> residues = new HashSet<>();
       for (Element element : model.getElements()) {
         if (element instanceof Species) {
-          Protein p = (Protein) element;
-          for (ModificationResidue mr : p.getModificationResidues()) {
-            residues.add(mr.getState());
+          Protein protein = (Protein) element;
+          for (ModificationResidue mr : protein.getModificationResidues()) {
+            if (mr instanceof AbstractSiteModification) {
+              residues.add(((AbstractSiteModification) mr).getState());
+            }
           }
         }
       }
@@ -235,8 +239,9 @@ public class ComplexParserTests extends CellDesignerTestFunctions {
       // of residues
       assertEquals(2, residues.size());
 
-      assertEquals(ModificationState.ACETYLATED,
-          ((Protein) model.getElementByElementId("sa2")).getModificationResidues().get(0).getState());
+      AbstractSiteModification modification = (AbstractSiteModification) ((Protein) model.getElementByElementId("sa2"))
+          .getModificationResidues().get(0);
+      assertEquals(ModificationState.ACETYLATED, modification.getState());
     } catch (Exception e) {
       e.printStackTrace();
       throw e;
@@ -278,8 +283,8 @@ public class ComplexParserTests extends CellDesignerTestFunctions {
       model = getModelForFile("testFiles/problematic/problematic_acetylation.xml");
       Protein p1 = (Protein) model.getElementByElementId("sa73");
       Protein p2 = (Protein) model.getElementByElementId("sa27");
-      assertEquals(ModificationState.ACETYLATED, p1.getModificationResidues().get(0).getState());
-      assertFalse(ModificationState.ACETYLATED.equals(p2.getModificationResidues().get(0).getState()));
+      assertEquals(ModificationState.ACETYLATED, ((Residue) p1.getModificationResidues().get(0)).getState());
+      assertFalse(ModificationState.ACETYLATED.equals(((Residue) p2.getModificationResidues().get(0)).getState()));
 
     } catch (Exception e) {
       e.printStackTrace();
@@ -417,60 +422,4 @@ public class ComplexParserTests extends CellDesignerTestFunctions {
     }
   }
 
-  @Test
-  public void testRnaWithRegion() throws Exception {
-    try {
-      Model model = getModelForFile("testFiles/rnaWithRegion.xml");
-      for (Element species : model.getNotComplexSpeciesList()) {
-        Rna rna = (Rna) species;
-        assertEquals(1, rna.getRegions().size());
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testProtinWithModifications() throws Exception {
-    try {
-      Model model = getModelForFile("testFiles/proteinWithEverPossibleModification.xml");
-      Protein protein = (Protein) model.getElementByElementId("sa1");
-      assertEquals(14, protein.getModificationResidues().size());
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testAntisenseRnaWithRegion() throws Exception {
-    try {
-      Model model = getModelForFile("testFiles/antisenseRnaWithRegion.xml");
-      for (Species species : model.getNotComplexSpeciesList()) {
-        AntisenseRna rna = (AntisenseRna) species;
-        assertEquals(1, rna.getRegions().size());
-      }
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testPhosporylatedProteinToXml() throws Exception {
-    try {
-      Model model = getModelForFile("testFiles/problematic/phosphorylated_protein.xml");
-      model.setName(null);
-      CellDesignerXmlParser p = new CellDesignerXmlParser();
-      String xml = p.toXml(model);
-      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-      Model model2 = p.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-      ModelComparator comparator = new ModelComparator();
-      assertEquals(0, comparator.compare(model, model2));
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
 }
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ModificationTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ModificationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bacc86fe1bd0cb526203cd376f465c01c1198e43
--- /dev/null
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ModificationTest.java
@@ -0,0 +1,264 @@
+package lcsb.mapviewer.converter.model.celldesigner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.converter.ConverterParams;
+import lcsb.mapviewer.converter.InvalidInputDataExecption;
+import lcsb.mapviewer.model.map.InconsistentModelException;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelComparator;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.field.BindingRegion;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+import lcsb.mapviewer.model.map.species.field.ProteinBindingDomain;
+import lcsb.mapviewer.model.map.species.field.RegulatoryRegion;
+import lcsb.mapviewer.model.map.species.field.Residue;
+import lcsb.mapviewer.model.map.species.field.TranscriptionSite;
+
+public class ModificationTest extends CellDesignerTestFunctions {
+  Logger logger = Logger.getLogger(ModificationTest.class);
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testBindingRegion() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/modifications/protein_with_binding_region.xml");
+      Protein protein = model.getElementByElementId("sa1");
+      assertEquals(1, protein.getModificationResidues().size());
+      ModificationResidue residue = protein.getModificationResidues().get(0);
+
+      assertTrue(residue instanceof BindingRegion);
+      BindingRegion bindingRegion = (BindingRegion) residue;
+      assertEquals(bindingRegion.getPosition().getX(), protein.getX(), Configuration.EPSILON);
+      assertTrue(bindingRegion.getWidth() < bindingRegion.getHeight());
+
+      testXmlSerialization(model);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private void testXmlSerialization(Model model)
+      throws InconsistentModelException, UnsupportedEncodingException, InvalidInputDataExecption {
+    CellDesignerXmlParser parser = new CellDesignerXmlParser();
+    String xml = parser.toXml(model);
+    InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8"));
+    Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+    model.setName(null);
+    ModelComparator comparator = new ModelComparator();
+    assertEquals(0, comparator.compare(model, model2));
+  }
+
+  @Test
+  public void testRegulatoryRegion() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/modifications/gene_with_regulatory_region.xml");
+      Gene gene = model.getElementByElementId("sa1");
+      assertEquals(1, gene.getModificationResidues().size());
+
+      ModificationResidue residue = gene.getModificationResidues().get(0);
+      assertTrue(residue instanceof RegulatoryRegion);
+      RegulatoryRegion bindingRegion = (RegulatoryRegion) residue;
+      assertEquals(bindingRegion.getPosition().getY(), gene.getY(), Configuration.EPSILON);
+      assertTrue(bindingRegion.getWidth() > bindingRegion.getHeight());
+
+      testXmlSerialization(model);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGeneCodingRegion() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/modifications/gene_with_coding_region.xml");
+      Gene gene = model.getElementByElementId("sa1");
+      assertEquals(1, gene.getModificationResidues().size());
+
+      ModificationResidue residue = gene.getModificationResidues().get(0);
+      assertTrue(residue instanceof CodingRegion);
+      CodingRegion bindingRegion = (CodingRegion) residue;
+      assertEquals(bindingRegion.getPosition().getY(), gene.getY(), Configuration.EPSILON);
+      assertTrue(bindingRegion.getWidth() > bindingRegion.getHeight());
+
+      testXmlSerialization(model);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGeneModificationSite() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/modifications/gene_with_modification_site.xml");
+      Gene gene = model.getElementByElementId("sa1");
+      assertEquals(1, gene.getModificationResidues().size());
+
+      ModificationResidue residue = gene.getModificationResidues().get(0);
+      assertTrue(residue instanceof ModificationSite);
+      ModificationSite bindingRegion = (ModificationSite) residue;
+      assertEquals(bindingRegion.getPosition().getY(), gene.getY(), Configuration.EPSILON);
+
+      testXmlSerialization(model);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRegulatoryTranscriptionSiteRight() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/modifications/gene_with_transcription_site_right.xml");
+      Gene gene = model.getElementByElementId("sa1");
+      assertEquals(1, gene.getModificationResidues().size());
+      ModificationResidue residue = gene.getModificationResidues().get(0);
+
+      assertTrue(residue instanceof TranscriptionSite);
+      TranscriptionSite transcriptionSite = (TranscriptionSite) residue;
+      assertEquals(transcriptionSite.getPosition().getY(), gene.getY(), Configuration.EPSILON);
+      assertEquals("RIGHT", transcriptionSite.getDirection());
+      assertTrue(transcriptionSite.getActive());
+
+      testXmlSerialization(model);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRegulatoryTranscriptionSiteLeft() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/modifications/gene_with_transcription_site_left.xml");
+      Gene gene = model.getElementByElementId("sa1");
+      assertEquals(1, gene.getModificationResidues().size());
+      ModificationResidue residue = gene.getModificationResidues().get(0);
+
+      assertTrue(residue instanceof TranscriptionSite);
+      TranscriptionSite transcriptionSite = (TranscriptionSite) residue;
+      assertEquals(transcriptionSite.getPosition().getY(), gene.getY(), Configuration.EPSILON);
+      assertEquals("LEFT", transcriptionSite.getDirection());
+      assertFalse(transcriptionSite.getActive());
+
+      testXmlSerialization(model);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testProtinWithResidues() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/modifications/protein_with_residues.xml");
+      Protein protein = (Protein) model.getElementByElementId("sa1");
+      assertEquals(14, protein.getModificationResidues().size());
+
+      ModificationResidue residue = protein.getModificationResidues().get(0);
+
+      assertTrue(residue instanceof Residue);
+
+      testXmlSerialization(model);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRnaWithRegion() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/modifications/rna_with_region.xml");
+      Rna rna = model.getElementByElementId("sa1");
+      assertEquals(1, rna.getRegions().size());
+      assertTrue(rna.getRegions().get(0) instanceof CodingRegion);
+
+      rna = model.getElementByElementId("sa2");
+      assertEquals(1, rna.getRegions().size());
+      assertTrue(rna.getRegions().get(0) instanceof ProteinBindingDomain);
+
+      rna = model.getElementByElementId("sa3");
+      assertEquals(1, rna.getRegions().size());
+      assertTrue(rna.getRegions().get(0) instanceof ModificationSite);
+
+      testXmlSerialization(model);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testAntisenseRnaWithRegion() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/modifications/antisense_rna_with_region.xml");
+      AntisenseRna rna = model.getElementByElementId("sa1");
+      assertEquals(1, rna.getRegions().size());
+      assertTrue(rna.getRegions().get(0) instanceof CodingRegion);
+
+      rna = model.getElementByElementId("sa2");
+      assertEquals(1, rna.getRegions().size());
+      assertTrue(rna.getRegions().get(0) instanceof ProteinBindingDomain);
+
+      rna = model.getElementByElementId("sa3");
+      assertEquals(1, rna.getRegions().size());
+      assertTrue(rna.getRegions().get(0) instanceof ModificationSite);
+
+      rna = model.getElementByElementId("sa4");
+      assertEquals(1, rna.getRegions().size());
+      assertTrue(rna.getRegions().get(0) instanceof ModificationSite);
+      ModificationSite modificationSite = (ModificationSite) rna.getRegions().get(0);
+      assertEquals(ModificationState.PHOSPHORYLATED, modificationSite.getState());
+
+      testXmlSerialization(model);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testPhosporylatedProteinToXml() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/problematic/phosphorylated_protein.xml");
+
+      testXmlSerialization(model);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AbstractCellDesignerAliasConverterTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AbstractCellDesignerAliasConverterTest.java
index 43901d78ddb32c72e15623045db96d523c8a8d63..a9e13b63447e44f04ffc5c13934f0814b9aa00ca 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AbstractCellDesignerAliasConverterTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/AbstractCellDesignerAliasConverterTest.java
@@ -11,6 +11,7 @@ import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.Test;
 
+import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.common.EventStorageLoggerAppender;
 import lcsb.mapviewer.common.geometry.LineTransformation;
 import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
@@ -22,60 +23,62 @@ import lcsb.mapviewer.model.map.species.Protein;
 import lcsb.mapviewer.model.map.species.Species;
 
 public class AbstractCellDesignerAliasConverterTest {
+  Logger logger = Logger.getLogger(AbstractCellDesignerAliasConverterTest.class);
 
-	AbstractCellDesignerAliasConverter<Species> converter = new AbstractCellDesignerAliasConverter<Species>(false) {
-		@Override
-		public Point2D getPointCoordinates(Species alias, CellDesignerAnchor anchor) {
-			return null;
-		}
-		@Override
-		protected PathIterator getBoundPathIterator(Species alias) {
-			return null;
-		}
-	};
+  AbstractCellDesignerAliasConverter<Species> converter = new AbstractCellDesignerAliasConverter<Species>(false) {
+    @Override
+    public Point2D getPointCoordinates(Species alias, CellDesignerAnchor anchor) {
+      return null;
+    }
 
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
+    @Override
+    protected PathIterator getBoundPathIterator(Species alias) {
+      return null;
+    }
+  };
 
-	@Before
-	public void setUp() throws Exception {
-	}
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+  }
 
-	@After
-	public void tearDown() throws Exception {
-	}
+  @Before
+  public void setUp() throws Exception {
+  }
 
-	@Test
-	public void testGetAnchorPointCoordinatesForInvalidImplementation() {
-		EventStorageLoggerAppender appender = new EventStorageLoggerAppender();
-		Logger.getRootLogger().addAppender(appender);
-		try {
-			Protein alias = new GenericProtein("id");
-			alias.setWidth(1);
-			alias.setHeight(1);
-			converter.getAnchorPointCoordinates(alias, 0);
-			assertEquals(1, appender.getWarnings().size());
-		} finally {
-			Logger.getRootLogger().removeAppender(appender);
-		}
-	}
+  @After
+  public void tearDown() throws Exception {
+  }
 
-	@Test
-	public void testGetters() {
-		CellDesignerEllipseTransformation ellipseTransformation = new CellDesignerEllipseTransformation();
-		LineTransformation lineTransformation = new LineTransformation();
-		CellDesignerPolygonTransformation polygonTransformation = new CellDesignerPolygonTransformation();
-		CellDesignerRectangleTransformation rectangleTransformation = new CellDesignerRectangleTransformation();
-		converter.setEllipseTransformation(ellipseTransformation);
-		converter.setLineTransformation(lineTransformation);
-		converter.setPolygonTransformation(polygonTransformation);
-		converter.setRectangleTransformation(rectangleTransformation);
+  @Test
+  public void testGetAnchorPointCoordinatesForInvalidImplementation() {
+    EventStorageLoggerAppender appender = new EventStorageLoggerAppender();
+    Logger.getRootLogger().addAppender(appender);
+    try {
+      Protein alias = new GenericProtein("id");
+      alias.setWidth(1);
+      alias.setHeight(1);
+      converter.getAnchorPointCoordinates(alias, 0);
+      assertEquals(1, appender.getWarnings().size());
+    } finally {
+      Logger.getRootLogger().removeAppender(appender);
+    }
+  }
 
-		assertEquals(ellipseTransformation, converter.getEllipseTransformation());
-		assertEquals(lineTransformation, converter.getLineTransformation());
-		assertEquals(polygonTransformation, converter.getPolygonTransformation());
-		assertEquals(rectangleTransformation, converter.getRectangleTransformation());
-	}
+  @Test
+  public void testGetters() {
+    CellDesignerEllipseTransformation ellipseTransformation = new CellDesignerEllipseTransformation();
+    LineTransformation lineTransformation = new LineTransformation();
+    CellDesignerPolygonTransformation polygonTransformation = new CellDesignerPolygonTransformation();
+    CellDesignerRectangleTransformation rectangleTransformation = new CellDesignerRectangleTransformation();
+    converter.setEllipseTransformation(ellipseTransformation);
+    converter.setLineTransformation(lineTransformation);
+    converter.setPolygonTransformation(polygonTransformation);
+    converter.setRectangleTransformation(rectangleTransformation);
+
+    assertEquals(ellipseTransformation, converter.getEllipseTransformation());
+    assertEquals(lineTransformation, converter.getLineTransformation());
+    assertEquals(polygonTransformation, converter.getPolygonTransformation());
+    assertEquals(rectangleTransformation, converter.getRectangleTransformation());
+  }
 
 }
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/GeneCellDesignerAliasConverterTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/GeneCellDesignerAliasConverterTest.java
index 270eafe9ce34158d15cf0e33013fd53237b18c1f..0ffe3ee44b73d7443d00770a5f8fa12c0e085de8 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/GeneCellDesignerAliasConverterTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/GeneCellDesignerAliasConverterTest.java
@@ -1,75 +1,74 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import static org.junit.Assert.assertNotNull;
-
-import java.awt.geom.PathIterator;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelFullIndexed;
-import lcsb.mapviewer.model.map.species.Gene;
-import lcsb.mapviewer.model.map.species.Species;
-
-public class GeneCellDesignerAliasConverterTest {
-
-	GeneCellDesignerAliasConverter converter = new GeneCellDesignerAliasConverter(false);
-
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testGetInvalidAliasPointCoordinates() {
-		Species alias = new Gene("id");
-		alias.setX(1);
-		alias.setY(12);
-		alias.setWidth(10);
-		alias.setHeight(10);
-		assertNotNull(converter.getPointCoordinates(alias, null));
-	}
-
-	@Test
-	public void testGetPath() {
-		Model model = new ModelFullIndexed(null);
-		Species alias = new Gene("id");
-		alias.setX(1);
-		alias.setY(12);
-		alias.setWidth(10);
-		alias.setHeight(10);
-
-		alias.setModel(model);
-		PathIterator path = converter.getBoundPathIterator(alias);
-
-		assertNotNull(path);
-	}
-
-	@Test
-	public void testGetPath2() {
-		GeneCellDesignerAliasConverter converter = new GeneCellDesignerAliasConverter(true);
-		
-		Model model = new ModelFullIndexed(null);
-		Species alias = new Gene("id");
-		alias.setX(1);
-		alias.setY(12);
-		alias.setWidth(10);
-		alias.setHeight(10);
-
-		alias.setModel(model);
-		PathIterator path = converter.getBoundPathIterator(alias);
-
-		assertNotNull(path);
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.awt.geom.PathIterator;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.model.map.species.Gene;
+
+public class GeneCellDesignerAliasConverterTest {
+
+  GeneCellDesignerAliasConverter converter = new GeneCellDesignerAliasConverter(false);
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+  }
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testGetInvalidAliasPointCoordinates() {
+    Gene alias = new Gene("id");
+    alias.setX(1);
+    alias.setY(12);
+    alias.setWidth(10);
+    alias.setHeight(10);
+    assertNotNull(converter.getPointCoordinates(alias, null));
+  }
+
+  @Test
+  public void testGetPath() {
+    Model model = new ModelFullIndexed(null);
+    Gene alias = new Gene("id");
+    alias.setX(1);
+    alias.setY(12);
+    alias.setWidth(10);
+    alias.setHeight(10);
+
+    alias.setModel(model);
+    PathIterator path = converter.getBoundPathIterator(alias);
+
+    assertNotNull(path);
+  }
+
+  @Test
+  public void testGetPath2() {
+    GeneCellDesignerAliasConverter converter = new GeneCellDesignerAliasConverter(true);
+
+    Model model = new ModelFullIndexed(null);
+    Gene alias = new Gene("id");
+    alias.setX(1);
+    alias.setY(12);
+    alias.setWidth(10);
+    alias.setHeight(10);
+
+    alias.setModel(model);
+    PathIterator path = converter.getBoundPathIterator(alias);
+
+    assertNotNull(path);
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/IonCellDesignerAliasConverterTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/IonCellDesignerAliasConverterTest.java
index a7f210b2f4ac4d5e1ad02aebf1a6c4a2c41f634b..c7cbcccba4e4ead4f6ee2bfcf59278362f525d02 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/IonCellDesignerAliasConverterTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/IonCellDesignerAliasConverterTest.java
@@ -1,57 +1,56 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.awt.geom.Point2D;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.Ion;
-import lcsb.mapviewer.model.map.species.Species;
-
-public class IonCellDesignerAliasConverterTest {
-
-	IonCellDesignerAliasConverter converter = new IonCellDesignerAliasConverter(false);
-
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testGetAnchorPointCoordinatesForInvalidAlias() {
-		Species alias = new Ion("id");
-		alias.setWidth(-1);
-		Point2D point = converter.getAnchorPointCoordinates(alias, 0);
-		assertNotNull(point);
-	}
-
-	@Test
-	public void testGetAnchorPointCoordinatesForInvalidAlias2() {
-		Species alias = new Ion("id");
-		Point2D point = converter.getAnchorPointCoordinates(alias, 0);
-		assertNotNull(point);
-	}
-
-	@Test
-	public void testNotImplementedMethod() {
-		try {
-			converter.getBoundPathIterator(null);
-		} catch (NotImplementedException e) {
-			assertTrue(e.getMessage().contains("This class doesn't have bound"));
-		}
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.geom.Point2D;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.Ion;
+
+public class IonCellDesignerAliasConverterTest {
+
+  IonCellDesignerAliasConverter converter = new IonCellDesignerAliasConverter(false);
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+  }
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testGetAnchorPointCoordinatesForInvalidAlias() {
+    Ion alias = new Ion("id");
+    alias.setWidth(-1);
+    Point2D point = converter.getAnchorPointCoordinates(alias, 0);
+    assertNotNull(point);
+  }
+
+  @Test
+  public void testGetAnchorPointCoordinatesForInvalidAlias2() {
+    Ion alias = new Ion("id");
+    Point2D point = converter.getAnchorPointCoordinates(alias, 0);
+    assertNotNull(point);
+  }
+
+  @Test
+  public void testNotImplementedMethod() {
+    try {
+      converter.getBoundPathIterator(null);
+    } catch (NotImplementedException e) {
+      assertTrue(e.getMessage().contains("This class doesn't have bound"));
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ProteinConverterTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ProteinConverterTest.java
index 4e8055b91cfd6533fa7fdc3b95c1e77e27d00725..e16751241a1f39ac4481125f94b0308193b257a3 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ProteinConverterTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/ProteinConverterTest.java
@@ -1,50 +1,96 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import static org.junit.Assert.assertEquals;
-
-import java.awt.geom.Point2D;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions;
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
-import lcsb.mapviewer.model.map.species.GenericProtein;
-
-public class ProteinConverterTest extends CellDesignerTestFunctions {
-	static Logger logger = Logger.getLogger(ProteinConverterTest.class);
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testGetAnchorForAlias() throws Exception {
-		try {
-
-			GenericProtein alias = new GenericProtein("id");
-			alias.setWidth(200);
-			alias.setHeight(300);
-			alias.setX(100.0);
-			alias.setY(50.0);
-
-			CellDesignerAliasConverter converter = new CellDesignerAliasConverter(alias, false);
-
-			for (CellDesignerAnchor anchor : CellDesignerAnchor.values()) {
-				Point2D point = converter.getPointCoordinates(alias, anchor);
-				CellDesignerAnchor newAnchor = converter.getAnchorForCoordinates(alias, point);
-				assertEquals(anchor, newAnchor);
-			}
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import static org.junit.Assert.assertEquals;
+
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.Protein;
+
+public class ProteinConverterTest extends CellDesignerTestFunctions {
+  static Logger logger = Logger.getLogger(ProteinConverterTest.class);
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testGetAnchorForAlias() throws Exception {
+    try {
+
+      GenericProtein alias = new GenericProtein("id");
+      alias.setWidth(200);
+      alias.setHeight(300);
+      alias.setX(100.0);
+      alias.setY(50.0);
+
+      CellDesignerAliasConverter converter = new CellDesignerAliasConverter(alias, false);
+
+      for (CellDesignerAnchor anchor : CellDesignerAnchor.values()) {
+        Point2D point = converter.getPointCoordinates(alias, anchor);
+        CellDesignerAnchor newAnchor = converter.getAnchorForCoordinates(alias, point);
+        assertEquals(anchor, newAnchor);
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testAngleConversion() {
+    Protein protein = new GenericProtein("id");
+    protein.setWidth(10);
+    protein.setHeight(60);
+    protein.setX(200);
+    protein.setY(500);
+
+    CellDesignerAliasConverter converter = new CellDesignerAliasConverter(protein, false);
+
+    for (double angle = 0.0; angle < Math.PI * 2; angle += 0.1) {
+      Point2D point = converter.getResidueCoordinates(protein, angle);
+      double angle2 = converter.getAngleForPoint(protein, point);
+      assertEquals(angle, angle2, Configuration.EPSILON);
+    }
+  }
+
+  @Test
+  public void testGetResidueCoords() throws Exception {
+    try {
+      GenericProtein protein = new GenericProtein("id");
+      protein.setX(135);
+      protein.setY(194.0);
+      protein.setWidth(130);
+      protein.setHeight(67);
+
+      CellDesignerAliasConverter conv = new CellDesignerAliasConverter(protein, false);
+      assertEquals(135.0, conv.getResidueCoordinates(protein, 3.141592653589793).getX(), 2);
+      assertEquals(265., conv.getResidueCoordinates(protein, 0.0).getX(), 2);
+      assertEquals(135.0, conv.getResidueCoordinates(protein, 2.41).getX(), 2);
+      assertEquals(194.0, conv.getResidueCoordinates(protein, 1.98).getY(), 2);
+      assertEquals(194.0, conv.getResidueCoordinates(protein, 1.59).getY(), 2);
+      assertEquals(265.0, conv.getResidueCoordinates(protein, 6.28).getX(), 2);
+      assertEquals(261.0, conv.getResidueCoordinates(protein, 4.13).getY(), 2);
+      assertEquals(261.0, conv.getResidueCoordinates(protein, 4.86).getY(), 2);
+      assertEquals(265.0, conv.getResidueCoordinates(protein, 5.69).getX(), 2);
+      assertEquals(194.0, conv.getResidueCoordinates(protein, 0.99).getY(), 2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/SimpleMoleculeCellDesignerAliasConverterTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/SimpleMoleculeCellDesignerAliasConverterTest.java
index efb1d2ed7e887d4dd40d462736d28da992b8e056..25479733a03204fbd77d8c713a8a4f742d4a02d5 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/SimpleMoleculeCellDesignerAliasConverterTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/SimpleMoleculeCellDesignerAliasConverterTest.java
@@ -1,99 +1,98 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import java.awt.geom.Point2D;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelFullIndexed;
-import lcsb.mapviewer.model.map.species.SimpleMolecule;
-import lcsb.mapviewer.model.map.species.Species;
-
-public class SimpleMoleculeCellDesignerAliasConverterTest {
-
-	SimpleMoleculeCellDesignerAliasConverter converter = new SimpleMoleculeCellDesignerAliasConverter(false);
-
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testPathIterator() {
-		try {
-			converter.getBoundPathIterator(null);
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-
-		}
-	}
-
-	@Test
-	public void testGetSbgnPointCoordinates() {
-		SimpleMoleculeCellDesignerAliasConverter converter = new SimpleMoleculeCellDesignerAliasConverter(true);
-
-		Model model = new ModelFullIndexed(null);
-		Species alias = new SimpleMolecule("id");
-		alias.setX(4);
-		alias.setY(5);
-		alias.setWidth(6);
-		alias.setHeight(7);
-		alias.setModel(model);
-
-		Point2D point = converter.getPointCoordinates(alias, CellDesignerAnchor.E);
-		assertNotNull(point);
-
-	}
-
-	@Test
-	public void testGetSbgnAnchorPointCoordinates() {
-		SimpleMoleculeCellDesignerAliasConverter converter = new SimpleMoleculeCellDesignerAliasConverter(true);
-
-		Model model = new ModelFullIndexed(null);
-		Species alias = new SimpleMolecule("id");
-		alias.setX(4);
-		alias.setY(5);
-		alias.setWidth(6);
-		alias.setHeight(7);
-		alias.setModel(model);
-
-		Point2D point = converter.getAnchorPointCoordinates(alias, 2);
-		assertNotNull(point);
-
-	}
-
-	@Test
-	public void testGetAnchorPointCoordinatesForEmptyAlias() {
-		SimpleMoleculeCellDesignerAliasConverter converter = new SimpleMoleculeCellDesignerAliasConverter(true);
-
-		Model model = new ModelFullIndexed(null);
-		Species alias = new SimpleMolecule("id");
-		alias.setX(4);
-		alias.setY(5);
-		alias.setWidth(0);
-		alias.setHeight(0);
-		alias.setModel(model);
-
-		Point2D point = converter.getAnchorPointCoordinates(alias, 2);
-		assertEquals(0.0, point.distance(new Point2D.Double(4, 5)), Configuration.EPSILON);
-
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.awt.geom.Point2D;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.helper.CellDesignerAnchor;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.model.map.species.SimpleMolecule;
+
+public class SimpleMoleculeCellDesignerAliasConverterTest {
+
+  SimpleMoleculeCellDesignerAliasConverter converter = new SimpleMoleculeCellDesignerAliasConverter(false);
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+  }
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testPathIterator() {
+    try {
+      converter.getBoundPathIterator(null);
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+
+    }
+  }
+
+  @Test
+  public void testGetSbgnPointCoordinates() {
+    SimpleMoleculeCellDesignerAliasConverter converter = new SimpleMoleculeCellDesignerAliasConverter(true);
+
+    Model model = new ModelFullIndexed(null);
+    SimpleMolecule alias = new SimpleMolecule("id");
+    alias.setX(4);
+    alias.setY(5);
+    alias.setWidth(6);
+    alias.setHeight(7);
+    alias.setModel(model);
+
+    Point2D point = converter.getPointCoordinates(alias, CellDesignerAnchor.E);
+    assertNotNull(point);
+
+  }
+
+  @Test
+  public void testGetSbgnAnchorPointCoordinates() {
+    SimpleMoleculeCellDesignerAliasConverter converter = new SimpleMoleculeCellDesignerAliasConverter(true);
+
+    Model model = new ModelFullIndexed(null);
+    SimpleMolecule alias = new SimpleMolecule("id");
+    alias.setX(4);
+    alias.setY(5);
+    alias.setWidth(6);
+    alias.setHeight(7);
+    alias.setModel(model);
+
+    Point2D point = converter.getAnchorPointCoordinates(alias, 2);
+    assertNotNull(point);
+
+  }
+
+  @Test
+  public void testGetAnchorPointCoordinatesForEmptyAlias() {
+    SimpleMoleculeCellDesignerAliasConverter converter = new SimpleMoleculeCellDesignerAliasConverter(true);
+
+    Model model = new ModelFullIndexed(null);
+    SimpleMolecule alias = new SimpleMolecule("id");
+    alias.setX(4);
+    alias.setY(5);
+    alias.setWidth(0);
+    alias.setHeight(0);
+    alias.setModel(model);
+
+    Point2D point = converter.getAnchorPointCoordinates(alias, 2);
+    assertEquals(0.0, point.distance(new Point2D.Double(4, 5)), Configuration.EPSILON);
+
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/UnknownCellDesignerAliasConverterTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/UnknownCellDesignerAliasConverterTest.java
index 3479f9ce228f0cbade97c71b91a0dbc5ed6bcc32..030765507000c2ce88f5e9e3ef8ebde8eebc8886 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/UnknownCellDesignerAliasConverterTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/geometry/UnknownCellDesignerAliasConverterTest.java
@@ -1,50 +1,49 @@
-package lcsb.mapviewer.converter.model.celldesigner.geometry;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.awt.geom.Point2D;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.GenericProtein;
-import lcsb.mapviewer.model.map.species.Species;
-
-public class UnknownCellDesignerAliasConverterTest {
-	UnknownCellDesignerAliasConverter converter = new UnknownCellDesignerAliasConverter(false);
-
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testGetBoundPathIterator() {
-		try {
-			converter.getBoundPathIterator(null);
-		} catch (NotImplementedException e) {
-			assertTrue(e.getMessage().contains("This class doesn't provide boundPath"));
-		}
-	}
-
-	@Test
-	public void testGetAnchorPointCoordinates() {
-		Species alias = new GenericProtein("id");
-		alias.setWidth(0);
-		alias.setHeight(0);
-		Point2D point = converter.getAnchorPointCoordinates(alias, 0);
-		assertNotNull(point);
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.geometry;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.geom.Point2D;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.Unknown;
+
+public class UnknownCellDesignerAliasConverterTest {
+  UnknownCellDesignerAliasConverter converter = new UnknownCellDesignerAliasConverter(false);
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+  }
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testGetBoundPathIterator() {
+    try {
+      converter.getBoundPathIterator(null);
+    } catch (NotImplementedException e) {
+      assertTrue(e.getMessage().contains("This class doesn't provide boundPath"));
+    }
+  }
+
+  @Test
+  public void testGetAnchorPointCoordinates() {
+    Unknown unknown = new Unknown("id");
+    unknown.setWidth(0);
+    unknown.setHeight(0);
+    Point2D point = converter.getAnchorPointCoordinates(unknown, 0);
+    assertNotNull(point);
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/AntisenseRnaXmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/AntisenseRnaXmlParserTest.java
index 9e5b0c45d076b0244c63c04c43a969dd0a6bc8dc..0bad270ff1b9f3502e87f12e58130ef484ffab93 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/AntisenseRnaXmlParserTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/AntisenseRnaXmlParserTest.java
@@ -22,138 +22,137 @@ import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
 import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
 import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerAntisenseRna;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerAntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegionType;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.ModificationType;
 
 public class AntisenseRnaXmlParserTest extends CellDesignerTestFunctions {
-	protected Logger							logger							 = Logger.getLogger(AntisenseRnaXmlParserTest.class.getName());
-
-	AntisenseRnaXmlParser					antisenseRnaParser;
-	String												testAntisenseRnaFile = "testFiles" + System.getProperty("file.separator") + "xmlNodeTestExamples"
-			+ System.getProperty("file.separator") + "antisense_rna.xml";
-	CellDesignerElementCollection	elements;
-
-	@Before
-	public void setUp() throws Exception {
-		elements = new CellDesignerElementCollection();
-		antisenseRnaParser = new AntisenseRnaXmlParser(elements);
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testParseXmlSpecies() throws Exception {
-		try {
-			String xmlString = readFile(testAntisenseRnaFile);
-			Pair<String, CellDesignerAntisenseRna> result = antisenseRnaParser.parseXmlElement(xmlString);
-			CellDesignerAntisenseRna antisenseRna = result.getRight();
-			assertEquals("arn1", result.getLeft());
-			assertEquals("s1", antisenseRna.getName());
-			assertTrue(antisenseRna.getNotes().contains("some notes"));
-			assertEquals(1, antisenseRna.getRegions().size());
-			CellDesignerAntisenseRnaRegion region = antisenseRna.getRegions().get(0);
-			assertEquals("tr1", region.getIdAntisenseRnaRegion());
-			assertEquals("zzz", region.getName());
-			assertEquals(0.3, region.getSize(), 1e-6);
-			assertEquals(0.29999999999999993, region.getPos(), 1e-6);
-			assertEquals(AntisenseRnaRegionType.CODING_REGION, region.getType());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXmlSpecies() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/antisense_rna.xml");
-			antisenseRnaParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Unknown element of celldesigner:listOfRegions"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXmlSpecies2() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/antisense_rna2.xml");
-			antisenseRnaParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Unknown element of celldesigner:antisenseRna"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXmlSpecies3() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/antisense_rna3.xml");
-			antisenseRnaParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Unknown antisense rna region type"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXmlSpecies4() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/antisense_rna4.xml");
-			antisenseRnaParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Unknown element of celldesigner:region"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testToXml() throws Exception {
-		try {
-			String xmlString = readFile(testAntisenseRnaFile);
-			Pair<String, CellDesignerAntisenseRna> result = antisenseRnaParser.parseXmlElement(xmlString);
-			CellDesignerAntisenseRna antisenseRna = result.getRight();
-
-			String transformedXml = antisenseRnaParser.toXml(antisenseRna.createModelElement());
-			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-			DocumentBuilder builder = factory.newDocumentBuilder();
-			InputSource is = new InputSource(new StringReader(transformedXml));
-			Document doc = builder.parse(is);
-			NodeList root = doc.getChildNodes();
-			assertEquals("celldesigner:AntisenseRNA", root.item(0).getNodeName());
-
-			Pair<String, CellDesignerAntisenseRna> result2 = antisenseRnaParser.parseXmlElement(xmlString);
-			CellDesignerAntisenseRna antisenseRna2 = result2.getRight();
-			assertEquals(result.getLeft(), result2.getLeft());
-			assertEquals(antisenseRna.getName(), antisenseRna2.getName());
-			assertEquals(antisenseRna.getNotes().trim(), antisenseRna2.getNotes().trim());
-
-			assertEquals(1, antisenseRna2.getRegions().size());
-			CellDesignerAntisenseRnaRegion region = antisenseRna.getRegions().get(0);
-			CellDesignerAntisenseRnaRegion region2 = antisenseRna2.getRegions().get(0);
-			assertEquals(region.getIdAntisenseRnaRegion(), region2.getIdAntisenseRnaRegion());
-			assertEquals(region.getName(), region2.getName());
-			assertEquals(region.getSize(), region2.getSize(), 1e-6);
-			assertEquals(region.getPos(), region2.getPos(), 1e-6);
-			assertEquals(region.getType(), region2.getType());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+  protected Logger logger = Logger.getLogger(AntisenseRnaXmlParserTest.class.getName());
+
+  AntisenseRnaXmlParser antisenseRnaParser;
+  String testAntisenseRnaFile = "testFiles" + System.getProperty("file.separator") + "xmlNodeTestExamples"
+      + System.getProperty("file.separator") + "antisense_rna.xml";
+  CellDesignerElementCollection elements;
+
+  @Before
+  public void setUp() throws Exception {
+    elements = new CellDesignerElementCollection();
+    antisenseRnaParser = new AntisenseRnaXmlParser(elements);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testParseXmlSpecies() throws Exception {
+    try {
+      String xmlString = readFile(testAntisenseRnaFile);
+      Pair<String, CellDesignerAntisenseRna> result = antisenseRnaParser.parseXmlElement(xmlString);
+      CellDesignerAntisenseRna antisenseRna = result.getRight();
+      assertEquals("arn1", result.getLeft());
+      assertEquals("s1", antisenseRna.getName());
+      assertTrue(antisenseRna.getNotes().contains("some notes"));
+      assertEquals(1, antisenseRna.getRegions().size());
+      CellDesignerModificationResidue region = antisenseRna.getRegions().get(0);
+      assertEquals("tr1", region.getIdModificationResidue());
+      assertEquals("zzz", region.getName());
+      assertEquals(0.3, region.getSize(), 1e-6);
+      assertEquals(0.29999999999999993, region.getPos(), 1e-6);
+      assertEquals(ModificationType.CODING_REGION, region.getModificationType());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXmlSpecies() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/antisense_rna.xml");
+      antisenseRnaParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+      assertTrue(e.getMessage().contains("Unknown element of celldesigner:listOfRegions"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXmlSpecies2() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/antisense_rna2.xml");
+      antisenseRnaParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+      assertTrue(e.getMessage().contains("Unknown element of celldesigner:antisenseRna"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXmlSpecies3() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/antisense_rna3.xml");
+      antisenseRnaParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXmlSpecies4() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/antisense_rna4.xml");
+      antisenseRnaParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+      assertTrue(e.getMessage().contains("Unknown element of celldesigner:region"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testToXml() throws Exception {
+    try {
+      String xmlString = readFile(testAntisenseRnaFile);
+      Pair<String, CellDesignerAntisenseRna> result = antisenseRnaParser.parseXmlElement(xmlString);
+      CellDesignerAntisenseRna antisenseRna = result.getRight();
+
+      String transformedXml = antisenseRnaParser.toXml(antisenseRna.createModelElement());
+      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+      DocumentBuilder builder = factory.newDocumentBuilder();
+      InputSource is = new InputSource(new StringReader(transformedXml));
+      Document doc = builder.parse(is);
+      NodeList root = doc.getChildNodes();
+      assertEquals("celldesigner:AntisenseRNA", root.item(0).getNodeName());
+
+      Pair<String, CellDesignerAntisenseRna> result2 = antisenseRnaParser.parseXmlElement(xmlString);
+      CellDesignerAntisenseRna antisenseRna2 = result2.getRight();
+      assertEquals(result.getLeft(), result2.getLeft());
+      assertEquals(antisenseRna.getName(), antisenseRna2.getName());
+      assertEquals(antisenseRna.getNotes().trim(), antisenseRna2.getNotes().trim());
+
+      assertEquals(1, antisenseRna2.getRegions().size());
+      CellDesignerModificationResidue region = antisenseRna.getRegions().get(0);
+      CellDesignerModificationResidue region2 = antisenseRna2.getRegions().get(0);
+      assertEquals(region.getIdModificationResidue(), region2.getIdModificationResidue());
+      assertEquals(region.getName(), region2.getName());
+      assertEquals(region.getSize(), region2.getSize(), 1e-6);
+      assertEquals(region.getPos(), region2.getPos(), 1e-6);
+      assertEquals(region.getModificationType(), region2.getModificationType());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 }
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/GeneXmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/GeneXmlParserTest.java
index 6a669466785baead3685bb12a3aa3f6c5890f2c9..c4c864b485e6fd2b397d287c2db5d960f4cad2a9 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/GeneXmlParserTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/GeneXmlParserTest.java
@@ -1,162 +1,171 @@
-package lcsb.mapviewer.converter.model.celldesigner.species;
-
-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 java.io.StringReader;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.w3c.dom.Document;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-
-import lcsb.mapviewer.common.Pair;
-import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions;
-import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerGene;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.species.Gene;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-public class GeneXmlParserTest extends CellDesignerTestFunctions {
-	Logger												logger			 = Logger.getLogger(GeneXmlParserTest.class.getName());
-
-	GeneXmlParser									geneParser;
-	String												testGeneFile = "testFiles" + System.getProperty("file.separator") + "xmlNodeTestExamples"
-			+ System.getProperty("file.separator") + "gene.xml";
-
-	CellDesignerElementCollection	elements;
-
-	@Before
-	public void setUp() throws Exception {
-		elements = new CellDesignerElementCollection();
-		geneParser = new GeneXmlParser(elements);
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testParseXmlSpecies() {
-		try {
-			String xmlString = readFile(testGeneFile);
-			Pair<String, CellDesignerGene> result = geneParser.parseXmlElement(xmlString);
-			CellDesignerGene gene = result.getRight();
-			assertEquals("gn3", result.getLeft());
-			assertEquals("BCL6", gene.getName());
-			assertTrue(gene.getNotes().contains("B-cell CLL/lymphoma 6"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			fail("Unexpected exception occured");
-		}
-	}
-
-	@Test
-	public void testToXml() throws Exception {
-		try {
-			String xmlString = readFile(testGeneFile);
-			Pair<String, CellDesignerGene> result = geneParser.parseXmlElement(xmlString);
-			CellDesignerGene gene = result.getRight();
-			String transformedXml = geneParser.toXml(gene.createModelElement());
-			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-			DocumentBuilder builder = factory.newDocumentBuilder();
-			InputSource is = new InputSource(new StringReader(transformedXml));
-			Document doc = builder.parse(is);
-			NodeList root = doc.getChildNodes();
-			assertEquals("celldesigner:gene", root.item(0).getNodeName());
-
-			Pair<String, CellDesignerGene> result2 = geneParser.parseXmlElement(geneParser.toXml(gene.createModelElement()));
-			CellDesignerGene gene2 = result2.getRight();
-			assertEquals(gene.getName(), gene2.getName());
-			assertTrue(gene2.getNotes().trim().contains(gene.getNotes().trim()));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParsePhosphorylatedGene() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/problematic/phosphorylated_gene.xml");
-			Gene gene = (Gene) model.getElementByElementId("sa1");
-			assertEquals(1, gene.getModificationResidues().size());
-			ModificationResidue residue = gene.getModificationResidues().get(0);
-			assertEquals(ModificationState.PHOSPHORYLATED, residue.getState());
-			assertEquals("some name", residue.getName());
-
-			// check xml transformation
-			String xml = geneParser.toXml(gene);
-			assertNotNull(xml);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidGeneInput() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/invalid_gene_1.xml");
-			geneParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidGeneInput2() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/invalid_gene_2.xml");
-			geneParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidModificationResidue() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/invalid_modification_residue.xml");
-			geneParser.getModificationResidue(getNodeFromXmlString(xmlString));
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testModificationResidueToXml() throws Exception {
-		try {
-			ModificationResidue mr = new ModificationResidue();
-			mr.setIdModificationResidue("i");
-			mr.setName("a");
-			mr.setSide("2");
-			mr.setAngle(3.0);
-			String xmlString = geneParser.toXml(mr);
-			assertNotNull(xmlString);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-}
+package lcsb.mapviewer.converter.model.celldesigner.species;
+
+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 java.awt.geom.Point2D;
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import lcsb.mapviewer.common.Pair;
+import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions;
+import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerGene;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+import lcsb.mapviewer.model.map.species.field.Residue;
+
+public class GeneXmlParserTest extends CellDesignerTestFunctions {
+  Logger logger = Logger.getLogger(GeneXmlParserTest.class.getName());
+
+  GeneXmlParser geneParser;
+  String testGeneFile = "testFiles" + System.getProperty("file.separator") + "xmlNodeTestExamples"
+      + System.getProperty("file.separator") + "gene.xml";
+
+  CellDesignerElementCollection elements;
+
+  @Before
+  public void setUp() throws Exception {
+    elements = new CellDesignerElementCollection();
+    geneParser = new GeneXmlParser(elements);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testParseXmlSpecies() {
+    try {
+      String xmlString = readFile(testGeneFile);
+      Pair<String, CellDesignerGene> result = geneParser.parseXmlElement(xmlString);
+      CellDesignerGene gene = result.getRight();
+      assertEquals("gn3", result.getLeft());
+      assertEquals("BCL6", gene.getName());
+      assertTrue(gene.getNotes().contains("B-cell CLL/lymphoma 6"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail("Unexpected exception occured");
+    }
+  }
+
+  @Test
+  public void testToXml() throws Exception {
+    try {
+      String xmlString = readFile(testGeneFile);
+      Pair<String, CellDesignerGene> result = geneParser.parseXmlElement(xmlString);
+      CellDesignerGene gene = result.getRight();
+      String transformedXml = geneParser.toXml(gene.createModelElement());
+      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+      DocumentBuilder builder = factory.newDocumentBuilder();
+      InputSource is = new InputSource(new StringReader(transformedXml));
+      Document doc = builder.parse(is);
+      NodeList root = doc.getChildNodes();
+      assertEquals("celldesigner:gene", root.item(0).getNodeName());
+
+      Pair<String, CellDesignerGene> result2 = geneParser.parseXmlElement(geneParser.toXml(gene.createModelElement()));
+      CellDesignerGene gene2 = result2.getRight();
+      assertEquals(gene.getName(), gene2.getName());
+      assertTrue(gene2.getNotes().trim().contains(gene.getNotes().trim()));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParsePhosphorylatedGene() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/problematic/phosphorylated_gene.xml");
+      Gene gene = (Gene) model.getElementByElementId("sa1");
+      assertEquals(1, gene.getModificationResidues().size());
+      ModificationSite residue = (ModificationSite) gene.getModificationResidues().get(0);
+      assertEquals(ModificationState.PHOSPHORYLATED, residue.getState());
+      assertEquals("some name", residue.getName());
+
+      // check xml transformation
+      String xml = geneParser.toXml(gene);
+      assertNotNull(xml);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidGeneInput() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/invalid_gene_1.xml");
+      geneParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidGeneInput2() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/invalid_gene_2.xml");
+      geneParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidModificationResidue() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/invalid_modification_residue.xml");
+      geneParser.getModificationResidue(getNodeFromXmlString(xmlString));
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testModificationResidueToXml() throws Exception {
+    try {
+      Gene protein = new Gene("id");
+      protein.setX(10);
+      protein.setY(10);
+      protein.setWidth(10);
+      protein.setHeight(10);
+      ModificationSite mr = new ModificationSite();
+      mr.setIdModificationResidue("i");
+      mr.setName("a");
+      mr.setPosition(new Point2D.Double(3.0, 2.0));
+      mr.setSpecies(protein);
+      String xmlString = geneParser.toXml(mr);
+      assertNotNull(xmlString);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/ProteinXmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/ProteinXmlParserTest.java
index fbca38d03ad44990cf3d380f77a92a5356eb7135..9c5ca3758170dd3a8f2e9e9fa08aca3ed459d826 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/ProteinXmlParserTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/ProteinXmlParserTest.java
@@ -1,173 +1,183 @@
-package lcsb.mapviewer.converter.model.celldesigner.species;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.StringReader;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.w3c.dom.Document;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-
-import lcsb.mapviewer.common.Pair;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions;
-import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerGenericProtein;
-import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerProtein;
-import lcsb.mapviewer.model.map.species.Protein;
-
-public class ProteinXmlParserTest extends CellDesignerTestFunctions {
-	Logger												logger					= Logger.getLogger(ProteinXmlParserTest.class.getName());
-
-	ProteinXmlParser							proteinParser;
-	String												testProteinFile	= "testFiles" + System.getProperty("file.separator") + "xmlNodeTestExamples"
-			+ System.getProperty("file.separator") + "protein.xml";
-
-	CellDesignerElementCollection	elements;
-
-	@Before
-	public void setUp() throws Exception {
-		elements = new CellDesignerElementCollection();
-		proteinParser = new ProteinXmlParser(elements);
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testParseXmlSpecies() throws Exception {
-		try {
-			String xmlString = readFile(testProteinFile);
-			Pair<String, CellDesignerProtein<?>> result = proteinParser.parseXmlElement(xmlString);
-			CellDesignerProtein<?> protein = result.getRight();
-			assertEquals("pr23", result.getLeft());
-			assertEquals("SDHA", protein.getName());
-			assertTrue(protein instanceof CellDesignerGenericProtein);
-			assertEquals(1, protein.getModificationResidues().size());
-			assertEquals("rs1", protein.getModificationResidues().get(0).getIdModificationResidue());
-			assertEquals("S176 bla bla", protein.getModificationResidues().get(0).getName());
-			assertEquals("Difference to big", 3.141592653589793, protein.getModificationResidues().get(0).getAngle(), 1e-6);
-			assertEquals("none", protein.getModificationResidues().get(0).getSide());
-			assertTrue(protein.getNotes().contains("UniProtKB	P31040	SDHA		GO:0005749	GO_REF:0000024"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testToXml() throws Exception {
-		try {
-			String xmlString = readFile(testProteinFile);
-
-			Pair<String, CellDesignerProtein<?>> result = proteinParser.parseXmlElement(xmlString);
-			CellDesignerProtein<?> protein = result.getRight();
-			String transformedXml = proteinParser.toXml(protein.createModelElement("id"));
-			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-			DocumentBuilder builder = factory.newDocumentBuilder();
-			InputSource is = new InputSource(new StringReader(transformedXml));
-			Document doc = builder.parse(is);
-			NodeList root = doc.getChildNodes();
-			assertEquals("celldesigner:protein", root.item(0).getNodeName());
-
-			Pair<String, CellDesignerProtein<?>> result2 = proteinParser.parseXmlElement(proteinParser.toXml(protein.createModelElement("id")));
-			CellDesignerProtein<?> protein2 = result2.getRight();
-			assertEquals(protein.getName(), protein2.getName());
-			assertEquals(protein.getClass(), protein2.getClass());
-			assertEquals(protein.getModificationResidues().size(), protein2.getModificationResidues().size());
-			assertEquals(protein.getModificationResidues().get(0).getIdModificationResidue(), protein2.getModificationResidues().get(0).getIdModificationResidue());
-			assertEquals(protein.getModificationResidues().get(0).getName(), protein2.getModificationResidues().get(0).getName());
-			assertEquals("Difference to big", protein.getModificationResidues().get(0).getAngle(), protein2.getModificationResidues().get(0).getAngle(), 1e-6);
-			assertEquals(protein.getModificationResidues().get(0).getSide(), protein2.getModificationResidues().get(0).getSide());
-
-			// proteins won't have notes because it makes the xml messy (everything
-			// will be in species notes)
-			// assertEquals(protein.getNotes().trim(), protein2.getNotes().trim());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXml() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/protein.xml");
-			proteinParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Protein node in Sbml model is of unknown type"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXml2() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/protein2.xml");
-			proteinParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Unknown element of celldesigner:listOfModificationResidues"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXml3() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/protein3.xml");
-			proteinParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Unknown element of celldesigner:protein"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXml4() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/protein4.xml");
-			proteinParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Unknown element of celldesigner:modificationResidue"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidProteinToXml() throws Exception {
-		try {
-			proteinParser.toXml(Mockito.mock(Protein.class));
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-			assertTrue(e.getMessage().contains("Invalid protein class type"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.species;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import lcsb.mapviewer.common.Pair;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions;
+import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerGenericProtein;
+import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerProtein;
+import lcsb.mapviewer.model.map.species.Protein;
+
+public class ProteinXmlParserTest extends CellDesignerTestFunctions {
+  Logger logger = Logger.getLogger(ProteinXmlParserTest.class.getName());
+
+  ProteinXmlParser proteinParser;
+  String testProteinFile = "testFiles" + System.getProperty("file.separator") + "xmlNodeTestExamples"
+      + System.getProperty("file.separator") + "protein.xml";
+
+  CellDesignerElementCollection elements;
+
+  @Before
+  public void setUp() throws Exception {
+    elements = new CellDesignerElementCollection();
+    proteinParser = new ProteinXmlParser(elements);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testParseXmlSpecies() throws Exception {
+    try {
+      String xmlString = readFile(testProteinFile);
+      Pair<String, CellDesignerProtein<?>> result = proteinParser.parseXmlElement(xmlString);
+      CellDesignerProtein<?> protein = result.getRight();
+      assertEquals("pr23", result.getLeft());
+      assertEquals("SDHA", protein.getName());
+      assertTrue(protein instanceof CellDesignerGenericProtein);
+      assertEquals(1, protein.getModificationResidues().size());
+      assertEquals("rs1", protein.getModificationResidues().get(0).getIdModificationResidue());
+      assertEquals("S176 bla bla", protein.getModificationResidues().get(0).getName());
+      assertEquals("Difference to big", 3.141592653589793, protein.getModificationResidues().get(0).getAngle(), 1e-6);
+      assertEquals("none", protein.getModificationResidues().get(0).getSide());
+      assertTrue(protein.getNotes().contains("UniProtKB	P31040	SDHA		GO:0005749	GO_REF:0000024"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testToXml() throws Exception {
+    try {
+      String xmlString = readFile(testProteinFile);
+
+      Pair<String, CellDesignerProtein<?>> result = proteinParser.parseXmlElement(xmlString);
+      CellDesignerProtein<?> protein = result.getRight();
+      String transformedXml = proteinParser.toXml(protein.createModelElement("id"));
+      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+      DocumentBuilder builder = factory.newDocumentBuilder();
+      InputSource is = new InputSource(new StringReader(transformedXml));
+      Document doc = builder.parse(is);
+      NodeList root = doc.getChildNodes();
+      assertEquals("celldesigner:protein", root.item(0).getNodeName());
+
+      elements = new CellDesignerElementCollection();
+      proteinParser = new ProteinXmlParser(elements);
+      Protein proteinWithLayout = protein.createModelElement("id");
+      proteinWithLayout.setWidth(10);
+      proteinWithLayout.setHeight(10);
+      protein.updateModelElementAfterLayoutAdded(proteinWithLayout);
+      Pair<String, CellDesignerProtein<?>> result2 = proteinParser
+          .parseXmlElement(proteinParser.toXml(proteinWithLayout));
+      
+      CellDesignerProtein<?> protein2 = result2.getRight();
+      assertEquals(protein.getName(), protein2.getName());
+      assertEquals(protein.getClass(), protein2.getClass());
+      assertEquals(protein.getModificationResidues().size(), protein2.getModificationResidues().size());
+      assertEquals(protein.getModificationResidues().get(0).getIdModificationResidue(),
+          protein2.getModificationResidues().get(0).getIdModificationResidue());
+      assertEquals(protein.getModificationResidues().get(0).getName(),
+          protein2.getModificationResidues().get(0).getName());
+      assertEquals("Difference to big", protein.getModificationResidues().get(0).getAngle(),
+          protein2.getModificationResidues().get(0).getAngle(), 1e-6);
+
+      // proteins won't have notes because it makes the xml messy (everything
+      // will be in species notes)
+      // assertEquals(protein.getNotes().trim(), protein2.getNotes().trim());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXml() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/protein.xml");
+      proteinParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+      assertTrue(e.getMessage().contains("Protein node in Sbml model is of unknown type"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXml2() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/protein2.xml");
+      proteinParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+      assertTrue(e.getMessage().contains("Unknown element of celldesigner:listOfModificationResidues"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXml3() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/protein3.xml");
+      proteinParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+      assertTrue(e.getMessage().contains("Unknown element of celldesigner:protein"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXml4() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/protein4.xml");
+      proteinParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+      assertTrue(e.getMessage().contains("Unknown element of celldesigner:modificationResidue"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidProteinToXml() throws Exception {
+    try {
+      proteinParser.toXml(Mockito.mock(Protein.class));
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+      assertTrue(e.getMessage().contains("Invalid protein class type"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/RnaXmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/RnaXmlParserTest.java
index 9e743299ad6ad5cdc65bba0bade4b0c171962ee9..dfc6456045a088430a8951941a1a20850ac05500 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/RnaXmlParserTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/RnaXmlParserTest.java
@@ -1,146 +1,146 @@
-package lcsb.mapviewer.converter.model.celldesigner.species;
-
-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 java.io.StringReader;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.w3c.dom.Document;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-
-import lcsb.mapviewer.common.Pair;
-import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions;
-import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerRna;
-
-public class RnaXmlParserTest extends CellDesignerTestFunctions {
-	protected Logger							logger			 = Logger.getLogger(RnaXmlParserTest.class.getName());
-
-	RnaXmlParser									rnaParser;
-	String												testRnaFile	 = "testFiles" + System.getProperty("file.separator") + "xmlNodeTestExamples"
-			+ System.getProperty("file.separator") + "rna.xml";
-	String												testRnaFile2 = "testFiles" + System.getProperty("file.separator") + "xmlNodeTestExamples"
-			+ System.getProperty("file.separator") + "rna_with_region.xml";
-
-	CellDesignerElementCollection	elements;
-
-	@Before
-	public void setUp() throws Exception {
-		elements = new CellDesignerElementCollection();
-		rnaParser = new RnaXmlParser(elements);
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testParseXmlSpecies() throws Exception {
-		try {
-			String xmlString = readFile(testRnaFile);
-			Pair<String, CellDesignerRna> result = rnaParser.parseXmlElement(xmlString);
-			CellDesignerRna rna = result.getRight();
-			assertEquals("rn36", result.getLeft());
-			assertEquals("BCL6", rna.getName());
-			assertTrue(rna.getNotes().contains("B-cell CLL/lymphoma "));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseXmlSpeciesWithRegion() throws Exception {
-		try {
-			String xmlString = readFile(testRnaFile2);
-			Pair<String, CellDesignerRna> result = rnaParser.parseXmlElement(xmlString);
-			CellDesignerRna rna = result.getRight();
-			assertNotNull(rna);
-			assertNotNull(rna.getRegions());
-			assertEquals(1, rna.getRegions().size());
-			assertEquals("tr1", rna.getRegions().get(0).getIdRnaRegion());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testToXml() throws Exception {
-		try {
-			String xmlString = readFile(testRnaFile);
-			Pair<String, CellDesignerRna> result = rnaParser.parseXmlElement(xmlString);
-			CellDesignerRna rna = result.getRight();
-
-			String transformedXml = rnaParser.toXml(rna.createModelElement("id"));
-			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-			DocumentBuilder builder = factory.newDocumentBuilder();
-			InputSource is = new InputSource(new StringReader(transformedXml));
-			Document doc = builder.parse(is);
-			NodeList root = doc.getChildNodes();
-			assertEquals("celldesigner:RNA", root.item(0).getNodeName());
-
-			Pair<String, CellDesignerRna> result2 = rnaParser.parseXmlElement(rnaParser.toXml(rna.createModelElement("id")));
-			CellDesignerRna rna2 = result2.getRight();
-			assertEquals(rna.getName(), rna2.getName());
-			assertTrue(rna2.getNotes().trim().contains(rna.getNotes().trim()));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXmlSpecies() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/rna.xml");
-			rnaParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Unknown element of celldesigner:listOfRegions"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXmlSpecies2() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/rna2.xml");
-			rnaParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Unknown element of celldesigner:rna"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParseInvalidXmlSpecies3() throws Exception {
-		try {
-			String xmlString = readFile("testFiles/invalid/rna3.xml");
-			rnaParser.parseXmlElement(xmlString);
-			fail("Exception expected");
-		} catch (InvalidXmlSchemaException e) {
-			assertTrue(e.getMessage().contains("Unknown element of celldesigner:region"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.species;
+
+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 java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import lcsb.mapviewer.common.Pair;
+import lcsb.mapviewer.common.exception.InvalidXmlSchemaException;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerElementCollection;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerTestFunctions;
+import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerRna;
+
+public class RnaXmlParserTest extends CellDesignerTestFunctions {
+  protected Logger logger = Logger.getLogger(RnaXmlParserTest.class.getName());
+
+  RnaXmlParser rnaParser;
+  String testRnaFile = "testFiles" + System.getProperty("file.separator") + "xmlNodeTestExamples"
+      + System.getProperty("file.separator") + "rna.xml";
+  String testRnaFile2 = "testFiles" + System.getProperty("file.separator") + "xmlNodeTestExamples"
+      + System.getProperty("file.separator") + "rna_with_region.xml";
+
+  CellDesignerElementCollection elements;
+
+  @Before
+  public void setUp() throws Exception {
+    elements = new CellDesignerElementCollection();
+    rnaParser = new RnaXmlParser(elements);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testParseXmlSpecies() throws Exception {
+    try {
+      String xmlString = readFile(testRnaFile);
+      Pair<String, CellDesignerRna> result = rnaParser.parseXmlElement(xmlString);
+      CellDesignerRna rna = result.getRight();
+      assertEquals("rn36", result.getLeft());
+      assertEquals("BCL6", rna.getName());
+      assertTrue(rna.getNotes().contains("B-cell CLL/lymphoma "));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseXmlSpeciesWithRegion() throws Exception {
+    try {
+      String xmlString = readFile(testRnaFile2);
+      Pair<String, CellDesignerRna> result = rnaParser.parseXmlElement(xmlString);
+      CellDesignerRna rna = result.getRight();
+      assertNotNull(rna);
+      assertNotNull(rna.getRegions());
+      assertEquals(1, rna.getRegions().size());
+      assertEquals("tr1", rna.getRegions().get(0).getIdModificationResidue());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testToXml() throws Exception {
+    try {
+      String xmlString = readFile(testRnaFile);
+      Pair<String, CellDesignerRna> result = rnaParser.parseXmlElement(xmlString);
+      CellDesignerRna rna = result.getRight();
+
+      String transformedXml = rnaParser.toXml(rna.createModelElement("id"));
+      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+      DocumentBuilder builder = factory.newDocumentBuilder();
+      InputSource is = new InputSource(new StringReader(transformedXml));
+      Document doc = builder.parse(is);
+      NodeList root = doc.getChildNodes();
+      assertEquals("celldesigner:RNA", root.item(0).getNodeName());
+
+      Pair<String, CellDesignerRna> result2 = rnaParser.parseXmlElement(rnaParser.toXml(rna.createModelElement("id")));
+      CellDesignerRna rna2 = result2.getRight();
+      assertEquals(rna.getName(), rna2.getName());
+      assertTrue(rna2.getNotes().trim().contains(rna.getNotes().trim()));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXmlSpecies() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/rna.xml");
+      rnaParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+      assertTrue(e.getMessage().contains("Unknown element of celldesigner:listOfRegions"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXmlSpecies2() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/rna2.xml");
+      rnaParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+      assertTrue(e.getMessage().contains("Unknown element of celldesigner:rna"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParseInvalidXmlSpecies3() throws Exception {
+    try {
+      String xmlString = readFile("testFiles/invalid/rna3.xml");
+      rnaParser.parseXmlElement(xmlString);
+      fail("Exception expected");
+    } catch (InvalidXmlSchemaException e) {
+      assertTrue(e.getMessage().contains("Unknown element of celldesigner:region"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParserTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParserTest.java
index 3d7c15ee19bf6537aca5cd461a8cc592adbb934b..786cd6cd4062b9ea122a2f0a67f8195fe51d5269 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParserTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/species/SpeciesSbmlParserTest.java
@@ -40,9 +40,7 @@ import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerRna;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerSimpleMolecule;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerSpecies;
 import lcsb.mapviewer.converter.model.celldesigner.structure.CellDesignerUnknown;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerAntisenseRnaRegion;
 import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerRnaRegion;
 import lcsb.mapviewer.converter.model.celldesigner.structure.fields.SpeciesState;
 import lcsb.mapviewer.model.map.kinetics.SbmlUnitType;
 import lcsb.mapviewer.model.map.species.Gene;
@@ -1142,36 +1140,4 @@ public class SpeciesSbmlParserTest extends CellDesignerTestFunctions {
     }
   }
 
-  @Test
-  public void testCreateRnaRegion() throws Exception {
-    try {
-      CellDesignerModificationResidue mr = new CellDesignerModificationResidue();
-      mr.setSize(1.0);
-      mr.setAngle(1.0);
-
-      CellDesignerRnaRegion region = parser.createRnaRegion(mr);
-      assertNotNull(region.getPos());
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testCreateAntisenseRnaRegion() throws Exception {
-    try {
-      CellDesignerModificationResidue mr = new CellDesignerModificationResidue();
-      mr.setSize(1.0);
-      mr.setAngle(1.0);
-
-      CellDesignerAntisenseRnaRegion region = parser.createAntisenseRnaRegion(mr);
-      assertNotNull(region.getPos());
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
 }
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AllStructureTests.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AllStructureTests.java
index 15e84c09a0fe585775018cb555f53a1619092c6c..6afe5cf8ea271e6816f6824ebb77240eeac0db31 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AllStructureTests.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AllStructureTests.java
@@ -8,7 +8,6 @@ import lcsb.mapviewer.converter.model.celldesigner.structure.fields.AllFieldsTes
 
 @RunWith(Suite.class)
 @SuiteClasses({ AllFieldsTests.class, //
-		AntisenseRnaRegionTest.class, //
 		AntisenseRnaTest.class, //
 		CellDesignerChemicalTest.class, //
 		CompartmentTest.class, //
@@ -26,7 +25,6 @@ import lcsb.mapviewer.converter.model.celldesigner.structure.fields.AllFieldsTes
 		PhenotypeTest.class, //
 		ProteinTest.class, //
 		ReceptorProteinTest.class, //
-		RnaRegionTest.class, //
 		RnaTest.class, //
 		SimpleMoleculeTest.class, //
 		SpeciesStateTest.class, //
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AntisenseRnaRegionTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AntisenseRnaRegionTest.java
deleted file mode 100644
index dc475ce8fdb30d22c30d4c618050393ffbafdd6a..0000000000000000000000000000000000000000
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AntisenseRnaRegionTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerAntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegionType;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-public class AntisenseRnaRegionTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new CellDesignerAntisenseRnaRegion());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor1() {
-		try {
-			CellDesignerAntisenseRnaRegion antisenseRna = new CellDesignerAntisenseRnaRegion();
-			CellDesignerAntisenseRnaRegion antisenseRna2 = new CellDesignerAntisenseRnaRegion(antisenseRna);
-			assertNotNull(antisenseRna2);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdate() {
-		try {
-			CellDesignerAntisenseRnaRegion antisenseRna = new CellDesignerAntisenseRnaRegion();
-			antisenseRna.setState(ModificationState.EMPTY);
-			antisenseRna.setName("as");
-			antisenseRna.setPos(3.0);
-			CellDesignerAntisenseRnaRegion antisenseRna2 = new CellDesignerAntisenseRnaRegion();
-			antisenseRna2.update(antisenseRna);
-			assertEquals(antisenseRna.getState(), antisenseRna2.getState());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidUpdate() {
-		try {
-			CellDesignerAntisenseRnaRegion antisenseRna = new CellDesignerAntisenseRnaRegion();
-			CellDesignerAntisenseRnaRegion antisenseRna2 = new CellDesignerAntisenseRnaRegion();
-			antisenseRna.setIdAntisenseRnaRegion("@1");
-			antisenseRna2.setIdAntisenseRnaRegion("@");
-			antisenseRna2.update(antisenseRna);
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			CellDesignerAntisenseRnaRegion region = new CellDesignerAntisenseRnaRegion(new CellDesignerAntisenseRnaRegion());
-			int id = 91;
-			CellDesignerAntisenseRna species = new CellDesignerAntisenseRna();
-			double pos = 4.6;
-			double size = 5.3;
-			AntisenseRnaRegionType type = AntisenseRnaRegionType.CODING_REGION;
-			String name = "nam";
-			String idAntisenseRnaRegion = "iddd";
-
-			region.setId(id);
-			region.setSpecies(species);
-			region.setPos(pos);
-			region.setSize(size);
-			region.setType(type);
-			region.setName(name);
-			region.setIdAntisenseRnaRegion(idAntisenseRnaRegion);
-			region.setState(ModificationState.ACETYLATED);
-
-			assertEquals(id, region.getId());
-			assertEquals(species, region.getSpecies());
-			assertEquals(pos, region.getPos(), Configuration.EPSILON);
-			assertEquals(size, region.getSize(), Configuration.EPSILON);
-			assertEquals(type, region.getType());
-			assertEquals(name, region.getName());
-			assertEquals(idAntisenseRnaRegion, region.getIdAntisenseRnaRegion());
-
-			assertEquals(ModificationState.ACETYLATED, region.getState());
-
-			try {
-				region.setSize("text");
-				fail("Exception expected");
-			} catch (InvalidArgumentException e) {
-			}
-
-			try {
-				region.setPos("text");
-				fail("Exception expected");
-			} catch (InvalidArgumentException e) {
-			}
-
-			region.setSize("1.0");
-			region.setPos("1.0");
-			assertEquals(1.0, region.getPos(), Configuration.EPSILON);
-			assertEquals(1.0, region.getSize(), Configuration.EPSILON);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testToString() {
-		try {
-			assertNotNull(new CellDesignerAntisenseRnaRegion().toString());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCopy() {
-		try {
-			CellDesignerAntisenseRnaRegion degraded = new CellDesignerAntisenseRnaRegion().copy();
-			assertNotNull(degraded);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		try {
-			new CellDesignerAntisenseRnaRegion() {
-
-				/**
-				 * 
-				 */
-				private static final long serialVersionUID = 1L;
-			}.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AntisenseRnaTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AntisenseRnaTest.java
index 98b0de4f63163d0347a47dc5acf0cdbd0e0e1bed..c9cd5cd3f3216ecfe0df7bb2958903555990951e 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AntisenseRnaTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/AntisenseRnaTest.java
@@ -1,159 +1,159 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-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 java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerAntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.AntisenseRna;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-public class AntisenseRnaTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new CellDesignerAntisenseRna());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor1() {
-		try {
-			CellDesignerAntisenseRna original = new CellDesignerAntisenseRna();
-			original.addRegion(new CellDesignerAntisenseRnaRegion());
-			CellDesignerAntisenseRna aRna = new CellDesignerAntisenseRna(original);
-			assertNotNull(aRna);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testAddRnaRegion() {
-		try {
-			CellDesignerAntisenseRna original = new CellDesignerAntisenseRna();
-			CellDesignerAntisenseRnaRegion region = new CellDesignerAntisenseRnaRegion();
-			region.setIdAntisenseRnaRegion("id1");
-			original.addRegion(region);
-
-			CellDesignerAntisenseRnaRegion region2 = new CellDesignerAntisenseRnaRegion();
-			region2.setIdAntisenseRnaRegion("id1");
-			region2.setName("nam");
-			original.addRegion(region2);
-
-			assertEquals(1, original.getRegions().size());
-
-			assertEquals("nam", original.getRegions().get(0).getName());
-
-			CellDesignerAntisenseRnaRegion region3 = new CellDesignerAntisenseRnaRegion();
-			region3.setIdAntisenseRnaRegion("id2");
-			region3.setName("nam");
-			original.addRegion(region3);
-
-			assertEquals(2, original.getRegions().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdate() {
-		try {
-			CellDesignerAntisenseRna original = new CellDesignerAntisenseRna();
-			CellDesignerAntisenseRnaRegion region2 = new CellDesignerAntisenseRnaRegion();
-			region2.setIdAntisenseRnaRegion("id1");
-			region2.setName("nam");
-			original.addRegion(region2);
-			CellDesignerAntisenseRnaRegion region3 = new CellDesignerAntisenseRnaRegion();
-			region3.setIdAntisenseRnaRegion("id2");
-			region3.setName("nam");
-			original.addRegion(region3);
-
-			CellDesignerAntisenseRna copy = new CellDesignerAntisenseRna(original);
-			copy.addRegion(new CellDesignerAntisenseRnaRegion());
-			copy.getRegions().get(0).setState(ModificationState.ACETYLATED);
-
-			original.update(copy);
-
-			boolean acetylatedFound = false;
-			for (CellDesignerAntisenseRnaRegion region : copy.getRegions()) {
-				if (ModificationState.ACETYLATED.equals(region.getState())) {
-					acetylatedFound = true;
-				}
-			}
-			assertTrue(acetylatedFound);
-			assertEquals(3, copy.getRegions().size());
-
-			original.update(new CellDesignerGenericProtein());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			CellDesignerAntisenseRna aRna = new CellDesignerAntisenseRna(new CellDesignerSpecies<AntisenseRna>());
-
-			List<CellDesignerAntisenseRnaRegion> regions = new ArrayList<>();
-
-			aRna.setRegions(regions);
-
-			assertEquals(regions, aRna.getRegions());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCopy() {
-		try {
-			CellDesignerAntisenseRna aRna = new CellDesignerAntisenseRna().copy();
-			assertNotNull(aRna);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		try {
-			CellDesignerAntisenseRna antisenseRna = Mockito.spy(CellDesignerAntisenseRna.class);
-			antisenseRna.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure;
+
+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 java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+
+public class AntisenseRnaTest {
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testSerialization() {
+    try {
+      SerializationUtils.serialize(new CellDesignerAntisenseRna());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor1() {
+    try {
+      CellDesignerAntisenseRna original = new CellDesignerAntisenseRna();
+      original.addRegion(new CellDesignerModificationResidue());
+      CellDesignerAntisenseRna aRna = new CellDesignerAntisenseRna(original);
+      assertNotNull(aRna);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testAddRnaRegion() {
+    try {
+      CellDesignerAntisenseRna original = new CellDesignerAntisenseRna();
+      CellDesignerModificationResidue region = new CellDesignerModificationResidue();
+      region.setIdModificationResidue("id1");
+      original.addRegion(region);
+
+      CellDesignerModificationResidue region2 = new CellDesignerModificationResidue();
+      region2.setIdModificationResidue("id1");
+      region2.setName("nam");
+      original.addRegion(region2);
+
+      assertEquals(1, original.getRegions().size());
+
+      assertEquals("nam", original.getRegions().get(0).getName());
+
+      CellDesignerModificationResidue region3 = new CellDesignerModificationResidue();
+      region3.setIdModificationResidue("id2");
+      region3.setName("nam");
+      original.addRegion(region3);
+
+      assertEquals(2, original.getRegions().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testUpdate() {
+    try {
+      CellDesignerAntisenseRna original = new CellDesignerAntisenseRna();
+      CellDesignerModificationResidue region2 = new CellDesignerModificationResidue();
+      region2.setIdModificationResidue("id1");
+      region2.setName("nam");
+      original.addRegion(region2);
+      CellDesignerModificationResidue region3 = new CellDesignerModificationResidue();
+      region3.setIdModificationResidue("id2");
+      region3.setName("nam");
+      original.addRegion(region3);
+
+      CellDesignerAntisenseRna copy = new CellDesignerAntisenseRna(original);
+      copy.addRegion(new CellDesignerModificationResidue());
+      copy.getRegions().get(0).setState(ModificationState.ACETYLATED);
+
+      original.update(copy);
+
+      boolean acetylatedFound = false;
+      for (CellDesignerModificationResidue region : copy.getRegions()) {
+        if (ModificationState.ACETYLATED.equals(region.getState())) {
+          acetylatedFound = true;
+        }
+      }
+      assertTrue(acetylatedFound);
+      assertEquals(3, copy.getRegions().size());
+
+      original.update(new CellDesignerGenericProtein());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetters() {
+    try {
+      CellDesignerAntisenseRna aRna = new CellDesignerAntisenseRna(new CellDesignerSpecies<AntisenseRna>());
+
+      List<CellDesignerModificationResidue> regions = new ArrayList<>();
+
+      aRna.setRegions(regions);
+
+      assertEquals(regions, aRna.getRegions());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCopy() {
+    try {
+      CellDesignerAntisenseRna aRna = new CellDesignerAntisenseRna().copy();
+      assertNotNull(aRna);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidCopy() {
+    try {
+      CellDesignerAntisenseRna antisenseRna = Mockito.spy(CellDesignerAntisenseRna.class);
+      antisenseRna.copy();
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/GeneTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/GeneTest.java
index d3ab45debf52ddc34a8c4a15b061cb51d6c91f83..766eeb156ebd85cf1b1c9eca3e0f3bd553a61428 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/GeneTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/GeneTest.java
@@ -1,128 +1,127 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
-import lcsb.mapviewer.model.map.species.Gene;
-
-public class GeneTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new CellDesignerGene());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor1() {
-		try {
-			CellDesignerGene original = new CellDesignerGene();
-			original.addModificationResidue(new CellDesignerModificationResidue());
-			CellDesignerGene gene = new CellDesignerGene(original);
-			assertNotNull(gene);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			List<CellDesignerModificationResidue> modificationResidues = new ArrayList<>();
-			CellDesignerGene gene = new CellDesignerGene(new CellDesignerSpecies<Gene>());
-			gene.setModificationResidues(modificationResidues);
-			assertEquals(modificationResidues, gene.getModificationResidues());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCopy() {
-		try {
-			CellDesignerGene degraded = new CellDesignerGene().copy();
-			assertNotNull(degraded);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		try {
-			CellDesignerGene gene = Mockito.spy(CellDesignerGene.class);
-			gene.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdate() {
-		try {
-			CellDesignerGene gene = new CellDesignerGene();
-			CellDesignerGene gene2 = new CellDesignerGene();
-			List<CellDesignerModificationResidue> residues = new ArrayList<>();
-			residues.add(new CellDesignerModificationResidue());
-
-			gene2.setModificationResidues(residues);
-
-			gene.update(gene2);
-			assertEquals(1, gene.getModificationResidues().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testAddModificationResidue() {
-		try {
-			CellDesignerGene gene = new CellDesignerGene();
-			CellDesignerModificationResidue mr = new CellDesignerModificationResidue("id1");
-			CellDesignerModificationResidue mr2 = new CellDesignerModificationResidue("id1");
-			CellDesignerModificationResidue mr3 = new CellDesignerModificationResidue("id2");
-
-			gene.addModificationResidue(mr);
-			assertEquals(1, gene.getModificationResidues().size());
-			gene.addModificationResidue(mr2);
-			assertEquals(1, gene.getModificationResidues().size());
-			gene.addModificationResidue(mr3);
-			assertEquals(2, gene.getModificationResidues().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+
+public class GeneTest {
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testSerialization() {
+    try {
+      SerializationUtils.serialize(new CellDesignerGene());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor1() {
+    try {
+      CellDesignerGene original = new CellDesignerGene();
+      original.addModificationResidue(new CellDesignerModificationResidue());
+      CellDesignerGene gene = new CellDesignerGene(original);
+      assertNotNull(gene);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetters() {
+    try {
+      List<CellDesignerModificationResidue> modificationResidues = new ArrayList<>();
+      CellDesignerGene gene = new CellDesignerGene(new CellDesignerSpecies<>());
+      gene.setModificationResidues(modificationResidues);
+      assertEquals(modificationResidues, gene.getModificationResidues());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCopy() {
+    try {
+      CellDesignerGene degraded = new CellDesignerGene().copy();
+      assertNotNull(degraded);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidCopy() {
+    try {
+      CellDesignerGene gene = Mockito.spy(CellDesignerGene.class);
+      gene.copy();
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testUpdate() {
+    try {
+      CellDesignerGene gene = new CellDesignerGene();
+      CellDesignerGene gene2 = new CellDesignerGene();
+      List<CellDesignerModificationResidue> residues = new ArrayList<>();
+      residues.add(new CellDesignerModificationResidue());
+
+      gene2.setModificationResidues(residues);
+
+      gene.update(gene2);
+      assertEquals(1, gene.getModificationResidues().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testAddModificationResidue() {
+    try {
+      CellDesignerGene gene = new CellDesignerGene();
+      CellDesignerModificationResidue mr = new CellDesignerModificationResidue("id1");
+      CellDesignerModificationResidue mr2 = new CellDesignerModificationResidue("id1");
+      CellDesignerModificationResidue mr3 = new CellDesignerModificationResidue("id2");
+
+      gene.addModificationResidue(mr);
+      assertEquals(1, gene.getModificationResidues().size());
+      gene.addModificationResidue(mr2);
+      assertEquals(1, gene.getModificationResidues().size());
+      gene.addModificationResidue(mr3);
+      assertEquals(2, gene.getModificationResidues().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/IonTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/IonTest.java
index a42eadbe87a04de39d955a0de6320bc74489389d..ac1641c2acc9101eb05eeee34f6f5d72afe3c926 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/IonTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/IonTest.java
@@ -1,70 +1,70 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.IonChannelProtein;
-
-public class IonTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new CellDesignerIon());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor1() {
-		try {
-			CellDesignerIon degraded = new CellDesignerIon(new CellDesignerSpecies<IonChannelProtein>());
-			assertNotNull(degraded);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCopy() {
-		try {
-			CellDesignerIon degraded = new CellDesignerIon().copy();
-			assertNotNull(degraded);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		try {
-			CellDesignerIon ion = Mockito.spy(CellDesignerIon.class);
-			ion.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.IonChannelProtein;
+
+public class IonTest {
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testSerialization() {
+    try {
+      SerializationUtils.serialize(new CellDesignerIon());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor1() {
+    try {
+      CellDesignerIon degraded = new CellDesignerIon(new CellDesignerSpecies<IonChannelProtein>());
+      assertNotNull(degraded);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCopy() {
+    try {
+      CellDesignerIon degraded = new CellDesignerIon().copy();
+      assertNotNull(degraded);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidCopy() {
+    try {
+      CellDesignerIon ion = Mockito.spy(CellDesignerIon.class);
+      ion.copy();
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/RnaRegionTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/RnaRegionTest.java
deleted file mode 100644
index 0ab0de88d9e272ff9f38d460d082d727e370e8d1..0000000000000000000000000000000000000000
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/RnaRegionTest.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerRnaRegion;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-public class RnaRegionTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new CellDesignerRnaRegion());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor() {
-		try {
-			CellDesignerRnaRegion region = new CellDesignerRnaRegion(new CellDesignerRnaRegion());
-			assertNotNull(region);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testSetSize() {
-		try {
-			CellDesignerRnaRegion region = new CellDesignerRnaRegion();
-			try {
-				region.setSize("as");
-				fail("Exception expected");
-			} catch (InvalidArgumentException e) {
-			}
-			region.setSize("0.0");
-			assertEquals(0.0, region.getSize(), Configuration.EPSILON);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testSetPos() {
-		try {
-			CellDesignerRnaRegion region = new CellDesignerRnaRegion();
-			try {
-				region.setPos("as");
-				fail("Exception expected");
-			} catch (InvalidArgumentException e) {
-			}
-			region.setPos("1.0");
-			assertEquals(1.0, region.getPos(), Configuration.EPSILON);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdate() {
-		try {
-			CellDesignerRnaRegion region = new CellDesignerRnaRegion();
-			CellDesignerRnaRegion region2 = new CellDesignerRnaRegion();
-			region2.setState(ModificationState.ACETYLATED);
-			region2.setName("asd");
-			region2.setPos(2.2);
-			region.update(region2);
-			assertEquals(region2.getName(), region.getName());
-			assertEquals(region2.getPos(), region.getPos());
-			assertEquals(region2.getState(), region.getState());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdate2() {
-		try {
-			CellDesignerRnaRegion region = new CellDesignerRnaRegion();
-			region.setIdRnaRegion("1");
-			CellDesignerRnaRegion region2 = new CellDesignerRnaRegion();
-			region2.setIdRnaRegion("2");
-			region.update(region2);
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			CellDesignerRnaRegion region = new CellDesignerRnaRegion();
-			double size = 2.5;
-			CellDesignerRna species = new CellDesignerRna();
-			region.setSize(size);
-			region.setSpecies(species);
-			assertEquals(size, region.getSize(), Configuration.EPSILON);
-			assertEquals(species, region.getSpecies());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/RnaTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/RnaTest.java
index 6cd1da2342857438181a8a639ffc677142238285..a4ae5659f7d94ffc28087b406297b6b225c7588f 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/RnaTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/RnaTest.java
@@ -1,161 +1,156 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-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 java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerRnaRegion;
-import lcsb.mapviewer.model.map.species.Rna;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-public class RnaTest {
-	Logger logger = Logger.getLogger(RnaTest.class);
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new CellDesignerRna());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor1() {
-		try {
-			CellDesignerRna rna = new CellDesignerRna(new CellDesignerSpecies<Rna>());
-			assertNotNull(rna);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			CellDesignerRna rna = new CellDesignerRna(new CellDesignerSpecies<Rna>());
-			List<CellDesignerRnaRegion> regions = new ArrayList<>();
-
-			rna.setRegions(regions);
-
-			assertEquals(regions, rna.getRegions());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCopy() {
-		try {
-			CellDesignerRna rna = new CellDesignerRna().copy();
-			assertNotNull(rna);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		try {
-			CellDesignerRna rna = Mockito.spy(CellDesignerRna.class);
-			rna.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testAddRnaRegion() {
-		try {
-			CellDesignerRna original = new CellDesignerRna();
-			CellDesignerRnaRegion region = new CellDesignerRnaRegion();
-			region.setIdRnaRegion("id1");
-			original.addRegion(region);
-
-			CellDesignerRnaRegion region2 = new CellDesignerRnaRegion();
-			region2.setIdRnaRegion("id1");
-			region2.setName("nam");
-			original.addRegion(region2);
-
-			assertEquals(1, original.getRegions().size());
-
-			assertEquals("nam", original.getRegions().get(0).getName());
-
-			CellDesignerRnaRegion region3 = new CellDesignerRnaRegion();
-			region3.setIdRnaRegion("id2");
-			region3.setName("nam");
-			original.addRegion(region3);
-
-			assertEquals(2, original.getRegions().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdate() {
-		try {
-			CellDesignerRna original = new CellDesignerRna();
-			CellDesignerRnaRegion region2 = new CellDesignerRnaRegion();
-			region2.setIdRnaRegion("id1");
-			region2.setName("nam");
-			original.addRegion(region2);
-			CellDesignerRnaRegion region3 = new CellDesignerRnaRegion();
-			region3.setIdRnaRegion("id2");
-			region3.setName("nam");
-			original.addRegion(region3);
-
-			CellDesignerRna copy = new CellDesignerRna(original);
-			copy.addRegion(new CellDesignerRnaRegion());
-			copy.getRegions().get(0).setState(ModificationState.ACETYLATED);
-
-			logger.debug(copy.getRegions().size());
-
-			original.update(copy);
-
-			boolean acetylatedFound = false;
-			for (CellDesignerRnaRegion region : copy.getRegions()) {
-				if (ModificationState.ACETYLATED.equals(region.getState())) {
-					acetylatedFound = true;
-				}
-			}
-			assertTrue(acetylatedFound);
-			assertEquals(3, original.getRegions().size());
-			assertEquals(3, copy.getRegions().size());
-
-			original.update(new CellDesignerGenericProtein());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure;
+
+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 java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+
+public class RnaTest {
+  Logger logger = Logger.getLogger(RnaTest.class);
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testSerialization() {
+    try {
+      SerializationUtils.serialize(new CellDesignerRna());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor1() {
+    try {
+      CellDesignerRna rna = new CellDesignerRna(new CellDesignerSpecies<Rna>());
+      assertNotNull(rna);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetters() {
+    try {
+      CellDesignerRna rna = new CellDesignerRna(new CellDesignerSpecies<Rna>());
+      List<CellDesignerModificationResidue> regions = new ArrayList<>();
+
+      rna.setRegions(regions);
+
+      assertEquals(regions, rna.getRegions());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCopy() {
+    try {
+      CellDesignerRna rna = new CellDesignerRna().copy();
+      assertNotNull(rna);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidCopy() {
+    try {
+      CellDesignerRna rna = Mockito.spy(CellDesignerRna.class);
+      rna.copy();
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testAddRnaRegion() {
+    try {
+      CellDesignerRna original = new CellDesignerRna();
+      CellDesignerModificationResidue region = new CellDesignerModificationResidue("id1");
+      original.addRegion(region);
+
+      CellDesignerModificationResidue region2 = new CellDesignerModificationResidue("id1");
+      region2.setName("nam");
+      original.addRegion(region2);
+
+      assertEquals(1, original.getRegions().size());
+
+      assertEquals("nam", original.getRegions().get(0).getName());
+
+      CellDesignerModificationResidue region3 = new CellDesignerModificationResidue("id2");
+      region3.setName("nam");
+      original.addRegion(region3);
+
+      assertEquals(2, original.getRegions().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testUpdate() {
+    try {
+      CellDesignerRna original = new CellDesignerRna();
+      CellDesignerModificationResidue region2 = new CellDesignerModificationResidue("id1");
+      region2.setName("nam");
+      original.addRegion(region2);
+      CellDesignerModificationResidue region3 = new CellDesignerModificationResidue("id2");
+      region3.setName("nam");
+      original.addRegion(region3);
+
+      CellDesignerRna copy = new CellDesignerRna(original);
+      copy.addRegion(new CellDesignerModificationResidue());
+      copy.getRegions().get(0).setState(ModificationState.ACETYLATED);
+
+      logger.debug(copy.getRegions().size());
+
+      original.update(copy);
+
+      boolean acetylatedFound = false;
+      for (CellDesignerModificationResidue region : copy.getRegions()) {
+        if (ModificationState.ACETYLATED.equals(region.getState())) {
+          acetylatedFound = true;
+        }
+      }
+      assertTrue(acetylatedFound);
+      assertEquals(3, original.getRegions().size());
+      assertEquals(3, copy.getRegions().size());
+
+      original.update(new CellDesignerGenericProtein());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/SpeciesStateTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/SpeciesStateTest.java
index b8814cdb37b451fa5d4708772d7588f460dbc8f5..5e24aa5ddb18578a19104fcb598e0a3daee9e618 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/SpeciesStateTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/SpeciesStateTest.java
@@ -1,78 +1,87 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
-import lcsb.mapviewer.converter.model.celldesigner.structure.fields.SpeciesState;
-import lcsb.mapviewer.model.map.species.Gene;
-import lcsb.mapviewer.model.map.species.Rna;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
-
-public class SpeciesStateTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testGetters() {
-		List<CellDesignerModificationResidue> modifications = new ArrayList<>();
-		SpeciesState state = new SpeciesState();
-		state.setModifications(modifications);
-		assertEquals(modifications, state.getModifications());
-	}
-
-	@Test
-	public void testSetHomodimer() {
-		try {
-			SpeciesState state = new SpeciesState();
-
-			state.setHomodimer("inv");
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-
-		}
-	}
-
-	@Test
-	public void testConstructorFromRna() {
-		Rna rna = new Rna("1");
-		rna.addRegion(new RnaRegion());
-		SpeciesState state = new SpeciesState(rna);
-		assertEquals(1, state.getModifications().size());
-	}
-
-	@Test
-	public void testConstructorFromGene() {
-		Gene gene = new Gene("2");
-		gene.addModificationResidue(new ModificationResidue());
-		SpeciesState state = new SpeciesState(gene);
-		assertEquals(1, state.getModifications().size());
-	}
-
-	@Test
-	public void testAddModifResidue() {
-		SpeciesState state = new SpeciesState();
-		state.addModificationResidue(new CellDesignerModificationResidue());
-		CellDesignerModificationResidue mr = new CellDesignerModificationResidue();
-		mr.setName("a");
-		state.addModificationResidue(mr);
-		assertEquals(1, state.getModifications().size());
-		assertEquals("a", state.getModifications().get(0).getName());
-	}
-
-}
+package lcsb.mapviewer.converter.model.celldesigner.structure;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.CellDesignerModificationResidue;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.SpeciesState;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+
+public class SpeciesStateTest {
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testGetters() {
+    List<CellDesignerModificationResidue> modifications = new ArrayList<>();
+    SpeciesState state = new SpeciesState();
+    state.setModifications(modifications);
+    assertEquals(modifications, state.getModifications());
+  }
+
+  @Test
+  public void testSetHomodimer() {
+    try {
+      SpeciesState state = new SpeciesState();
+
+      state.setHomodimer("inv");
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+
+    }
+  }
+
+  @Test
+  public void testConstructorFromRna() {
+    Rna rna = new Rna("1");
+    rna.setWidth(60);
+    rna.setHeight(10);
+    CodingRegion mr = new CodingRegion();
+    mr.setPosition(new Point2D.Double(10, 40));
+    rna.addRegion(mr);
+    SpeciesState state = new SpeciesState(rna);
+    assertEquals(1, state.getModifications().size());
+  }
+
+  @Test
+  public void testConstructorFromGene() {
+    Gene gene = new Gene("2");
+    gene.setWidth(60);
+    gene.setHeight(10);
+    ModificationSite mr = new ModificationSite();
+    mr.setPosition(new Point2D.Double(10, 40));
+    gene.addModificationResidue(mr);
+    SpeciesState state = new SpeciesState(gene);
+    assertEquals(1, state.getModifications().size());
+  }
+
+  @Test
+  public void testAddModifResidue() {
+    SpeciesState state = new SpeciesState();
+    state.addModificationResidue(new CellDesignerModificationResidue());
+    CellDesignerModificationResidue mr = new CellDesignerModificationResidue();
+    mr.setName("a");
+    state.addModificationResidue(mr);
+    assertEquals(1, state.getModifications().size());
+    assertEquals("a", state.getModifications().get(0).getName());
+  }
+
+}
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/AllFieldsTests.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/AllFieldsTests.java
index 7c08337d3f4a9fa2410a8c28b97781d81464519c..54887f8d0dc9c053aa0a906bd572ccdfe1e5e21b 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/AllFieldsTests.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/AllFieldsTests.java
@@ -6,7 +6,6 @@ import org.junit.runners.Suite.SuiteClasses;
 
 @RunWith(Suite.class)
 @SuiteClasses({ CellDesignerModificationResidueTest.class, //
-		CellDesignerRnaRegionTest.class,//
 })
 public class AllFieldsTests {
 
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerRnaRegionTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerRnaRegionTest.java
deleted file mode 100644
index f7e08b5a6855f3be58f1abe85af4107084b2b8b0..0000000000000000000000000000000000000000
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/structure/fields/CellDesignerRnaRegionTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package lcsb.mapviewer.converter.model.celldesigner.structure.fields;
-
-import static org.junit.Assert.assertNotNull;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-
-public class CellDesignerRnaRegionTest {
-
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testToString() {
-		CellDesignerRnaRegion region = new CellDesignerRnaRegion();
-		assertNotNull(region.toString());
-	}
-
-}
diff --git a/converter-CellDesigner/testFiles/gene_modifications.xml b/converter-CellDesigner/testFiles/gene_modifications.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0d9d681ce5a94a3c6f30f2943a448ecb2c70f6ee
--- /dev/null
+++ b/converter-CellDesigner/testFiles/gene_modifications.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4">
+<model metaid="untitled" id="untitled">
+<annotation>
+<celldesigner:extension>
+<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
+<celldesigner:modelDisplay sizeX="600" sizeY="400"/>
+<celldesigner:listOfCompartmentAliases/>
+<celldesigner:listOfComplexSpeciesAliases/>
+<celldesigner:listOfSpeciesAliases>
+<celldesigner:speciesAlias id="sa2" species="s2">
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="192.0" y="114.5" w="189.0" h="42.0"/>
+<celldesigner:font size="12"/>
+<celldesigner:view state="usual"/>
+<celldesigner:usualView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="189.0" height="42.0"/>
+<celldesigner:singleLine width="1.0"/>
+<celldesigner:paint color="ffffff66" scheme="Color"/>
+</celldesigner:usualView>
+<celldesigner:briefView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="60.0"/>
+<celldesigner:singleLine width="0.0"/>
+<celldesigner:paint color="3fff0000" scheme="Color"/>
+</celldesigner:briefView>
+<celldesigner:info state="empty" angle="-1.5707963267948966"/>
+</celldesigner:speciesAlias>
+</celldesigner:listOfSpeciesAliases>
+<celldesigner:listOfGroups/>
+<celldesigner:listOfProteins/>
+<celldesigner:listOfGenes>
+<celldesigner:gene id="gn1" name="s2" type="GENE">
+<celldesigner:listOfRegions>
+<celldesigner:region id="tr1" name="p1" size="0.0" pos="0.3" type="Modification Site" active="false"/>
+<celldesigner:region id="tr2" name="p2" size="0.1" pos="0.41000000000000003" type="CodingRegion" active="false"/>
+<celldesigner:region id="tr3" name="p3" size="0.1" pos="0.57" type="RegulatoryRegion" active="false"/>
+<celldesigner:region id="tr4" name="p4" size="0.1" pos="0.75" type="transcriptionStartingSiteL" active="true"/>
+<celldesigner:region id="tr5" name="p5" size="0.14" pos="0.8599999999999999" type="transcriptionStartingSiteR" active="false"/>
+</celldesigner:listOfRegions>
+</celldesigner:gene>
+</celldesigner:listOfGenes>
+<celldesigner:listOfRNAs/>
+<celldesigner:listOfAntisenseRNAs/>
+<celldesigner:listOfLayers/>
+<celldesigner:listOfBlockDiagrams/>
+</celldesigner:extension>
+</annotation>
+<listOfUnitDefinitions>
+<unitDefinition metaid="substance" id="substance" name="substance">
+<listOfUnits>
+<unit metaid="CDMT00001" kind="mole"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="volume" id="volume" name="volume">
+<listOfUnits>
+<unit metaid="CDMT00002" kind="litre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="area" id="area" name="area">
+<listOfUnits>
+<unit metaid="CDMT00003" kind="metre" exponent="2"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="length" id="length" name="length">
+<listOfUnits>
+<unit metaid="CDMT00004" kind="metre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="time" id="time" name="time">
+<listOfUnits>
+<unit metaid="CDMT00005" kind="second"/>
+</listOfUnits>
+</unitDefinition>
+</listOfUnitDefinitions>
+<listOfCompartments>
+<compartment metaid="default" id="default" size="1" units="volume"/>
+</listOfCompartments>
+<listOfSpecies>
+<species metaid="s2" id="s2" name="s2" compartment="default" initialAmount="0">
+<annotation>
+<celldesigner:extension>
+<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment>
+<celldesigner:speciesIdentity>
+<celldesigner:class>GENE</celldesigner:class>
+<celldesigner:geneReference>gn1</celldesigner:geneReference>
+</celldesigner:speciesIdentity>
+</celldesigner:extension>
+</annotation>
+</species>
+</listOfSpecies>
+</model>
+</sbml>
diff --git a/converter-CellDesigner/testFiles/antisenseRnaWithRegion.xml b/converter-CellDesigner/testFiles/modifications/antisense_rna_with_region.xml
similarity index 79%
rename from converter-CellDesigner/testFiles/antisenseRnaWithRegion.xml
rename to converter-CellDesigner/testFiles/modifications/antisense_rna_with_region.xml
index 91a7ef532f90c06d73ccca1838f9b614c6da0d32..1fe9f35b3629c6a645b4dd8149d238891b8f3c8a 100644
--- a/converter-CellDesigner/testFiles/antisenseRnaWithRegion.xml
+++ b/converter-CellDesigner/testFiles/modifications/antisense_rna_with_region.xml
@@ -22,7 +22,7 @@
 <celldesigner:briefView>
 <celldesigner:innerPosition x="0.0" y="0.0"/>
 <celldesigner:boxSize width="80.0" height="60.0"/>
-<celldesigner:singleLine width="0.0"/>
+<celldesigner:singleLine width="1.0"/>
 <celldesigner:paint color="3fff0000" scheme="Color"/>
 </celldesigner:briefView>
 <celldesigner:info state="empty" angle="-1.5707963267948966"/>
@@ -41,12 +41,12 @@
 <celldesigner:briefView>
 <celldesigner:innerPosition x="0.0" y="0.0"/>
 <celldesigner:boxSize width="80.0" height="60.0"/>
-<celldesigner:singleLine width="0.0"/>
+<celldesigner:singleLine width="1.0"/>
 <celldesigner:paint color="3fff0000" scheme="Color"/>
 </celldesigner:briefView>
 <celldesigner:info state="empty" angle="-1.5707963267948966"/>
 </celldesigner:speciesAlias>
-<celldesigner:speciesAlias id="sa3" species="s3">
+<celldesigner:speciesAlias id="sa3" species="s4">
 <celldesigner:activity>inactive</celldesigner:activity>
 <celldesigner:bounds x="192.0" y="247.5" w="90.0" h="25.0"/>
 <celldesigner:font size="12"/>
@@ -60,7 +60,26 @@
 <celldesigner:briefView>
 <celldesigner:innerPosition x="0.0" y="0.0"/>
 <celldesigner:boxSize width="80.0" height="60.0"/>
-<celldesigner:singleLine width="0.0"/>
+<celldesigner:singleLine width="1.0"/>
+<celldesigner:paint color="3fff0000" scheme="Color"/>
+</celldesigner:briefView>
+<celldesigner:info state="empty" angle="-1.5707963267948966"/>
+</celldesigner:speciesAlias>
+<celldesigner:speciesAlias id="sa4" species="s3">
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="300.0" y="207.0" w="90.0" h="25.0"/>
+<celldesigner:font size="12"/>
+<celldesigner:view state="usual"/>
+<celldesigner:usualView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="90.0" height="25.0"/>
+<celldesigner:singleLine width="1.0"/>
+<celldesigner:paint color="ffff6666" scheme="Color"/>
+</celldesigner:usualView>
+<celldesigner:briefView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="60.0"/>
+<celldesigner:singleLine width="1.0"/>
 <celldesigner:paint color="3fff0000" scheme="Color"/>
 </celldesigner:briefView>
 <celldesigner:info state="empty" angle="-1.5707963267948966"/>
@@ -151,6 +170,22 @@
 <celldesigner:speciesIdentity>
 <celldesigner:class>ANTISENSE_RNA</celldesigner:class>
 <celldesigner:antisensernaReference>arn3</celldesigner:antisensernaReference>
+<celldesigner:state>
+<celldesigner:listOfModifications>
+<celldesigner:modification residue="tr1" state="phosphorylated"/>
+</celldesigner:listOfModifications>
+</celldesigner:state>
+</celldesigner:speciesIdentity>
+</celldesigner:extension>
+</annotation>
+</species>
+<species metaid="s4" id="s4" name="s3" compartment="default" initialAmount="0">
+<annotation>
+<celldesigner:extension>
+<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment>
+<celldesigner:speciesIdentity>
+<celldesigner:class>ANTISENSE_RNA</celldesigner:class>
+<celldesigner:antisensernaReference>arn3</celldesigner:antisensernaReference>
 </celldesigner:speciesIdentity>
 </celldesigner:extension>
 </annotation>
diff --git a/converter-CellDesigner/testFiles/modifications/gene_with_coding_region.xml b/converter-CellDesigner/testFiles/modifications/gene_with_coding_region.xml
new file mode 100644
index 0000000000000000000000000000000000000000..74823057f625a7b537811c6239ac483311ec5714
--- /dev/null
+++ b/converter-CellDesigner/testFiles/modifications/gene_with_coding_region.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4">
+<model metaid="untitled" id="untitled">
+<annotation>
+<celldesigner:extension>
+<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
+<celldesigner:modelDisplay sizeX="600" sizeY="400"/>
+<celldesigner:listOfCompartmentAliases/>
+<celldesigner:listOfComplexSpeciesAliases/>
+<celldesigner:listOfSpeciesAliases>
+<celldesigner:speciesAlias id="sa1" species="s1">
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="291.0" y="217.5" w="70.0" h="25.0"/>
+<celldesigner:font size="12"/>
+<celldesigner:view state="usual"/>
+<celldesigner:usualView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="70.0" height="25.0"/>
+<celldesigner:singleLine width="1.0"/>
+<celldesigner:paint color="ffffff66" scheme="Color"/>
+</celldesigner:usualView>
+<celldesigner:briefView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="60.0"/>
+<celldesigner:singleLine width="0.0"/>
+<celldesigner:paint color="3fff0000" scheme="Color"/>
+</celldesigner:briefView>
+<celldesigner:info state="empty" angle="-1.5707963267948966"/>
+</celldesigner:speciesAlias>
+</celldesigner:listOfSpeciesAliases>
+<celldesigner:listOfGroups/>
+<celldesigner:listOfProteins/>
+<celldesigner:listOfGenes>
+<celldesigner:gene id="gn1" name="s1" type="GENE">
+<celldesigner:listOfRegions>
+<celldesigner:region id="tr1" name="xx" size="0.48" pos="0.14" type="CodingRegion" active="false"/>
+</celldesigner:listOfRegions>
+</celldesigner:gene>
+</celldesigner:listOfGenes>
+<celldesigner:listOfRNAs/>
+<celldesigner:listOfAntisenseRNAs/>
+<celldesigner:listOfLayers/>
+<celldesigner:listOfBlockDiagrams/>
+</celldesigner:extension>
+</annotation>
+<listOfUnitDefinitions>
+<unitDefinition metaid="substance" id="substance" name="substance">
+<listOfUnits>
+<unit metaid="CDMT00001" kind="mole"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="volume" id="volume" name="volume">
+<listOfUnits>
+<unit metaid="CDMT00002" kind="litre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="area" id="area" name="area">
+<listOfUnits>
+<unit metaid="CDMT00003" kind="metre" exponent="2"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="length" id="length" name="length">
+<listOfUnits>
+<unit metaid="CDMT00004" kind="metre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="time" id="time" name="time">
+<listOfUnits>
+<unit metaid="CDMT00005" kind="second"/>
+</listOfUnits>
+</unitDefinition>
+</listOfUnitDefinitions>
+<listOfCompartments>
+<compartment metaid="default" id="default" size="1" units="volume"/>
+</listOfCompartments>
+<listOfSpecies>
+<species metaid="s1" id="s1" name="s1" compartment="default" initialAmount="0">
+<annotation>
+<celldesigner:extension>
+<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment>
+<celldesigner:speciesIdentity>
+<celldesigner:class>GENE</celldesigner:class>
+<celldesigner:geneReference>gn1</celldesigner:geneReference>
+</celldesigner:speciesIdentity>
+</celldesigner:extension>
+</annotation>
+</species>
+</listOfSpecies>
+</model>
+</sbml>
diff --git a/converter-CellDesigner/testFiles/modifications/gene_with_modification_site.xml b/converter-CellDesigner/testFiles/modifications/gene_with_modification_site.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0069db65c5f247483fad3d090444318d115ce480
--- /dev/null
+++ b/converter-CellDesigner/testFiles/modifications/gene_with_modification_site.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4">
+<model metaid="untitled" id="untitled">
+<annotation>
+<celldesigner:extension>
+<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
+<celldesigner:modelDisplay sizeX="600" sizeY="400"/>
+<celldesigner:listOfCompartmentAliases/>
+<celldesigner:listOfComplexSpeciesAliases/>
+<celldesigner:listOfSpeciesAliases>
+<celldesigner:speciesAlias id="sa1" species="s1">
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="173.0" y="245.5" w="70.0" h="25.0"/>
+<celldesigner:font size="12"/>
+<celldesigner:view state="usual"/>
+<celldesigner:usualView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="70.0" height="25.0"/>
+<celldesigner:singleLine width="1.0"/>
+<celldesigner:paint color="ffffff66" scheme="Color"/>
+</celldesigner:usualView>
+<celldesigner:briefView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="60.0"/>
+<celldesigner:singleLine width="0.0"/>
+<celldesigner:paint color="3fff0000" scheme="Color"/>
+</celldesigner:briefView>
+<celldesigner:info state="empty" angle="-1.5707963267948966"/>
+</celldesigner:speciesAlias>
+</celldesigner:listOfSpeciesAliases>
+<celldesigner:listOfGroups/>
+<celldesigner:listOfProteins/>
+<celldesigner:listOfGenes>
+<celldesigner:gene id="gn1" name="s1" type="GENE">
+<celldesigner:listOfRegions>
+<celldesigner:region id="tr1" name="site" size="0.0" pos="0.62" type="Modification Site" active="false"/>
+</celldesigner:listOfRegions>
+</celldesigner:gene>
+</celldesigner:listOfGenes>
+<celldesigner:listOfRNAs/>
+<celldesigner:listOfAntisenseRNAs/>
+<celldesigner:listOfLayers/>
+<celldesigner:listOfBlockDiagrams/>
+</celldesigner:extension>
+</annotation>
+<listOfUnitDefinitions>
+<unitDefinition metaid="substance" id="substance" name="substance">
+<listOfUnits>
+<unit metaid="CDMT00001" kind="mole"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="volume" id="volume" name="volume">
+<listOfUnits>
+<unit metaid="CDMT00002" kind="litre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="area" id="area" name="area">
+<listOfUnits>
+<unit metaid="CDMT00003" kind="metre" exponent="2"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="length" id="length" name="length">
+<listOfUnits>
+<unit metaid="CDMT00004" kind="metre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="time" id="time" name="time">
+<listOfUnits>
+<unit metaid="CDMT00005" kind="second"/>
+</listOfUnits>
+</unitDefinition>
+</listOfUnitDefinitions>
+<listOfCompartments>
+<compartment metaid="default" id="default" size="1" units="volume"/>
+</listOfCompartments>
+<listOfSpecies>
+<species metaid="s1" id="s1" name="s1" compartment="default" initialAmount="0">
+<annotation>
+<celldesigner:extension>
+<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment>
+<celldesigner:speciesIdentity>
+<celldesigner:class>GENE</celldesigner:class>
+<celldesigner:geneReference>gn1</celldesigner:geneReference>
+<celldesigner:state>
+<celldesigner:listOfModifications>
+<celldesigner:modification residue="tr1" state="phosphorylated"/>
+</celldesigner:listOfModifications>
+</celldesigner:state>
+</celldesigner:speciesIdentity>
+</celldesigner:extension>
+</annotation>
+</species>
+</listOfSpecies>
+</model>
+</sbml>
diff --git a/converter-CellDesigner/testFiles/modifications/gene_with_regulatory_region.xml b/converter-CellDesigner/testFiles/modifications/gene_with_regulatory_region.xml
new file mode 100644
index 0000000000000000000000000000000000000000..aeaa0225240167c2c647aa552635d4060e1cd788
--- /dev/null
+++ b/converter-CellDesigner/testFiles/modifications/gene_with_regulatory_region.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4">
+<model metaid="untitled" id="untitled">
+<annotation>
+<celldesigner:extension>
+<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
+<celldesigner:modelDisplay sizeX="600" sizeY="400"/>
+<celldesigner:listOfCompartmentAliases/>
+<celldesigner:listOfComplexSpeciesAliases/>
+<celldesigner:listOfSpeciesAliases>
+<celldesigner:speciesAlias id="sa1" species="s1">
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="224.0" y="259.5" w="70.0" h="25.0"/>
+<celldesigner:font size="12"/>
+<celldesigner:view state="usual"/>
+<celldesigner:usualView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="70.0" height="25.0"/>
+<celldesigner:singleLine width="1.0"/>
+<celldesigner:paint color="ffffff66" scheme="Color"/>
+</celldesigner:usualView>
+<celldesigner:briefView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="60.0"/>
+<celldesigner:singleLine width="0.0"/>
+<celldesigner:paint color="3fff0000" scheme="Color"/>
+</celldesigner:briefView>
+<celldesigner:info state="empty" angle="-1.5707963267948966"/>
+</celldesigner:speciesAlias>
+</celldesigner:listOfSpeciesAliases>
+<celldesigner:listOfGroups/>
+<celldesigner:listOfProteins/>
+<celldesigner:listOfGenes>
+<celldesigner:gene id="gn1" name="s1" type="GENE">
+<celldesigner:listOfRegions>
+<celldesigner:region id="tr1" name="xx" size="0.78" pos="0.0" type="RegulatoryRegion" active="false"/>
+</celldesigner:listOfRegions>
+</celldesigner:gene>
+</celldesigner:listOfGenes>
+<celldesigner:listOfRNAs/>
+<celldesigner:listOfAntisenseRNAs/>
+<celldesigner:listOfLayers/>
+<celldesigner:listOfBlockDiagrams/>
+</celldesigner:extension>
+</annotation>
+<listOfUnitDefinitions>
+<unitDefinition metaid="substance" id="substance" name="substance">
+<listOfUnits>
+<unit metaid="CDMT00001" kind="mole"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="volume" id="volume" name="volume">
+<listOfUnits>
+<unit metaid="CDMT00002" kind="litre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="area" id="area" name="area">
+<listOfUnits>
+<unit metaid="CDMT00003" kind="metre" exponent="2"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="length" id="length" name="length">
+<listOfUnits>
+<unit metaid="CDMT00004" kind="metre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="time" id="time" name="time">
+<listOfUnits>
+<unit metaid="CDMT00005" kind="second"/>
+</listOfUnits>
+</unitDefinition>
+</listOfUnitDefinitions>
+<listOfCompartments>
+<compartment metaid="default" id="default" size="1" units="volume"/>
+</listOfCompartments>
+<listOfSpecies>
+<species metaid="s1" id="s1" name="s1" compartment="default" initialAmount="0">
+<annotation>
+<celldesigner:extension>
+<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment>
+<celldesigner:speciesIdentity>
+<celldesigner:class>GENE</celldesigner:class>
+<celldesigner:geneReference>gn1</celldesigner:geneReference>
+</celldesigner:speciesIdentity>
+</celldesigner:extension>
+</annotation>
+</species>
+</listOfSpecies>
+</model>
+</sbml>
diff --git a/converter-CellDesigner/testFiles/modifications/gene_with_transcription_site_left.xml b/converter-CellDesigner/testFiles/modifications/gene_with_transcription_site_left.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b22c0d9ebf37d9eaf023083ad4aba9b9efc59b1c
--- /dev/null
+++ b/converter-CellDesigner/testFiles/modifications/gene_with_transcription_site_left.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4">
+<model metaid="untitled" id="untitled">
+<annotation>
+<celldesigner:extension>
+<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
+<celldesigner:modelDisplay sizeX="600" sizeY="400"/>
+<celldesigner:listOfCompartmentAliases/>
+<celldesigner:listOfComplexSpeciesAliases/>
+<celldesigner:listOfSpeciesAliases>
+<celldesigner:speciesAlias id="sa1" species="s1">
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="197.0" y="177.5" w="70.0" h="25.0"/>
+<celldesigner:font size="12"/>
+<celldesigner:view state="usual"/>
+<celldesigner:usualView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="70.0" height="25.0"/>
+<celldesigner:singleLine width="1.0"/>
+<celldesigner:paint color="ffffff66" scheme="Color"/>
+</celldesigner:usualView>
+<celldesigner:briefView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="60.0"/>
+<celldesigner:singleLine width="0.0"/>
+<celldesigner:paint color="3fff0000" scheme="Color"/>
+</celldesigner:briefView>
+<celldesigner:info state="empty" angle="-1.5707963267948966"/>
+</celldesigner:speciesAlias>
+</celldesigner:listOfSpeciesAliases>
+<celldesigner:listOfGroups/>
+<celldesigner:listOfProteins/>
+<celldesigner:listOfGenes>
+<celldesigner:gene id="gn1" name="s1" type="GENE">
+<celldesigner:listOfRegions>
+<celldesigner:region id="tr1" size="0.38" pos="0.2" type="transcriptionStartingSiteL" active="false"/>
+</celldesigner:listOfRegions>
+</celldesigner:gene>
+</celldesigner:listOfGenes>
+<celldesigner:listOfRNAs/>
+<celldesigner:listOfAntisenseRNAs/>
+<celldesigner:listOfLayers/>
+<celldesigner:listOfBlockDiagrams/>
+</celldesigner:extension>
+</annotation>
+<listOfUnitDefinitions>
+<unitDefinition metaid="substance" id="substance" name="substance">
+<listOfUnits>
+<unit metaid="CDMT00001" kind="mole"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="volume" id="volume" name="volume">
+<listOfUnits>
+<unit metaid="CDMT00002" kind="litre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="area" id="area" name="area">
+<listOfUnits>
+<unit metaid="CDMT00003" kind="metre" exponent="2"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="length" id="length" name="length">
+<listOfUnits>
+<unit metaid="CDMT00004" kind="metre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="time" id="time" name="time">
+<listOfUnits>
+<unit metaid="CDMT00005" kind="second"/>
+</listOfUnits>
+</unitDefinition>
+</listOfUnitDefinitions>
+<listOfCompartments>
+<compartment metaid="default" id="default" size="1" units="volume"/>
+</listOfCompartments>
+<listOfSpecies>
+<species metaid="s1" id="s1" name="s1" compartment="default" initialAmount="0">
+<annotation>
+<celldesigner:extension>
+<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment>
+<celldesigner:speciesIdentity>
+<celldesigner:class>GENE</celldesigner:class>
+<celldesigner:geneReference>gn1</celldesigner:geneReference>
+</celldesigner:speciesIdentity>
+</celldesigner:extension>
+</annotation>
+</species>
+</listOfSpecies>
+</model>
+</sbml>
diff --git a/converter-CellDesigner/testFiles/modifications/gene_with_transcription_site_right.xml b/converter-CellDesigner/testFiles/modifications/gene_with_transcription_site_right.xml
new file mode 100644
index 0000000000000000000000000000000000000000..06a066d1c4ec627a2b0b1967efdf3dc750a48b67
--- /dev/null
+++ b/converter-CellDesigner/testFiles/modifications/gene_with_transcription_site_right.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4">
+<model metaid="untitled" id="untitled">
+<annotation>
+<celldesigner:extension>
+<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
+<celldesigner:modelDisplay sizeX="600" sizeY="400"/>
+<celldesigner:listOfCompartmentAliases/>
+<celldesigner:listOfComplexSpeciesAliases/>
+<celldesigner:listOfSpeciesAliases>
+<celldesigner:speciesAlias id="sa1" species="s1">
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="278.0" y="218.5" w="70.0" h="25.0"/>
+<celldesigner:font size="12"/>
+<celldesigner:view state="usual"/>
+<celldesigner:usualView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="70.0" height="25.0"/>
+<celldesigner:singleLine width="1.0"/>
+<celldesigner:paint color="ffffff66" scheme="Color"/>
+</celldesigner:usualView>
+<celldesigner:briefView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="60.0"/>
+<celldesigner:singleLine width="0.0"/>
+<celldesigner:paint color="3fff0000" scheme="Color"/>
+</celldesigner:briefView>
+<celldesigner:info state="empty" angle="-1.5707963267948966"/>
+</celldesigner:speciesAlias>
+</celldesigner:listOfSpeciesAliases>
+<celldesigner:listOfGroups/>
+<celldesigner:listOfProteins/>
+<celldesigner:listOfGenes>
+<celldesigner:gene id="gn1" name="s1" type="GENE">
+<celldesigner:listOfRegions>
+<celldesigner:region id="tr1" name="qwe" size="0.1" pos="0.25" type="transcriptionStartingSiteR" active="true"/>
+</celldesigner:listOfRegions>
+</celldesigner:gene>
+</celldesigner:listOfGenes>
+<celldesigner:listOfRNAs/>
+<celldesigner:listOfAntisenseRNAs/>
+<celldesigner:listOfLayers/>
+<celldesigner:listOfBlockDiagrams/>
+</celldesigner:extension>
+</annotation>
+<listOfUnitDefinitions>
+<unitDefinition metaid="substance" id="substance" name="substance">
+<listOfUnits>
+<unit metaid="CDMT00001" kind="mole"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="volume" id="volume" name="volume">
+<listOfUnits>
+<unit metaid="CDMT00002" kind="litre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="area" id="area" name="area">
+<listOfUnits>
+<unit metaid="CDMT00003" kind="metre" exponent="2"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="length" id="length" name="length">
+<listOfUnits>
+<unit metaid="CDMT00004" kind="metre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="time" id="time" name="time">
+<listOfUnits>
+<unit metaid="CDMT00005" kind="second"/>
+</listOfUnits>
+</unitDefinition>
+</listOfUnitDefinitions>
+<listOfCompartments>
+<compartment metaid="default" id="default" size="1" units="volume"/>
+</listOfCompartments>
+<listOfSpecies>
+<species metaid="s1" id="s1" name="s1" compartment="default" initialAmount="0">
+<annotation>
+<celldesigner:extension>
+<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment>
+<celldesigner:speciesIdentity>
+<celldesigner:class>GENE</celldesigner:class>
+<celldesigner:geneReference>gn1</celldesigner:geneReference>
+</celldesigner:speciesIdentity>
+</celldesigner:extension>
+</annotation>
+</species>
+</listOfSpecies>
+</model>
+</sbml>
diff --git a/converter-CellDesigner/testFiles/modifications/protein_with_binding_region.xml b/converter-CellDesigner/testFiles/modifications/protein_with_binding_region.xml
new file mode 100644
index 0000000000000000000000000000000000000000..87ded130833443025cdefd580dda92c5bc18237b
--- /dev/null
+++ b/converter-CellDesigner/testFiles/modifications/protein_with_binding_region.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<sbml xmlns="http://www.sbml.org/sbml/level2/version4" xmlns:celldesigner="http://www.sbml.org/2001/ns/celldesigner" level="2" version="4">
+<model metaid="untitled" id="untitled">
+<annotation>
+<celldesigner:extension>
+<celldesigner:modelVersion>4.0</celldesigner:modelVersion>
+<celldesigner:modelDisplay sizeX="600" sizeY="400"/>
+<celldesigner:listOfCompartmentAliases/>
+<celldesigner:listOfComplexSpeciesAliases/>
+<celldesigner:listOfSpeciesAliases>
+<celldesigner:speciesAlias id="sa1" species="s1">
+<celldesigner:activity>inactive</celldesigner:activity>
+<celldesigner:bounds x="238.0" y="123.0" w="80.0" h="40.0"/>
+<celldesigner:font size="12"/>
+<celldesigner:view state="usual"/>
+<celldesigner:usualView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="40.0"/>
+<celldesigner:singleLine width="1.0"/>
+<celldesigner:paint color="ffccffcc" scheme="Color"/>
+</celldesigner:usualView>
+<celldesigner:briefView>
+<celldesigner:innerPosition x="0.0" y="0.0"/>
+<celldesigner:boxSize width="80.0" height="60.0"/>
+<celldesigner:singleLine width="0.0"/>
+<celldesigner:paint color="3fff0000" scheme="Color"/>
+</celldesigner:briefView>
+<celldesigner:info state="empty" angle="-1.5707963267948966"/>
+</celldesigner:speciesAlias>
+</celldesigner:listOfSpeciesAliases>
+<celldesigner:listOfGroups/>
+<celldesigner:listOfProteins>
+<celldesigner:protein id="pr1" name="s1" type="GENERIC">
+<celldesigner:listOfBindingRegions>
+<celldesigner:bindingRegion angle="3.141592653589793" id="rs1" name="test" size="0.42"/>
+</celldesigner:listOfBindingRegions>
+</celldesigner:protein>
+</celldesigner:listOfProteins>
+<celldesigner:listOfGenes/>
+<celldesigner:listOfRNAs/>
+<celldesigner:listOfAntisenseRNAs/>
+<celldesigner:listOfLayers/>
+<celldesigner:listOfBlockDiagrams/>
+</celldesigner:extension>
+</annotation>
+<listOfUnitDefinitions>
+<unitDefinition metaid="substance" id="substance" name="substance">
+<listOfUnits>
+<unit metaid="CDMT00001" kind="mole"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="volume" id="volume" name="volume">
+<listOfUnits>
+<unit metaid="CDMT00002" kind="litre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="area" id="area" name="area">
+<listOfUnits>
+<unit metaid="CDMT00003" kind="metre" exponent="2"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="length" id="length" name="length">
+<listOfUnits>
+<unit metaid="CDMT00004" kind="metre"/>
+</listOfUnits>
+</unitDefinition>
+<unitDefinition metaid="time" id="time" name="time">
+<listOfUnits>
+<unit metaid="CDMT00005" kind="second"/>
+</listOfUnits>
+</unitDefinition>
+</listOfUnitDefinitions>
+<listOfCompartments>
+<compartment metaid="default" id="default" size="1" units="volume"/>
+</listOfCompartments>
+<listOfSpecies>
+<species metaid="s1" id="s1" name="s1" compartment="default" initialAmount="0">
+<annotation>
+<celldesigner:extension>
+<celldesigner:positionToCompartment>inside</celldesigner:positionToCompartment>
+<celldesigner:speciesIdentity>
+<celldesigner:class>PROTEIN</celldesigner:class>
+<celldesigner:proteinReference>pr1</celldesigner:proteinReference>
+</celldesigner:speciesIdentity>
+</celldesigner:extension>
+</annotation>
+</species>
+</listOfSpecies>
+</model>
+</sbml>
diff --git a/converter-CellDesigner/testFiles/proteinWithEverPossibleModification.xml b/converter-CellDesigner/testFiles/modifications/protein_with_residues.xml
similarity index 100%
rename from converter-CellDesigner/testFiles/proteinWithEverPossibleModification.xml
rename to converter-CellDesigner/testFiles/modifications/protein_with_residues.xml
diff --git a/converter-CellDesigner/testFiles/rnaWithRegion.xml b/converter-CellDesigner/testFiles/modifications/rna_with_region.xml
similarity index 100%
rename from converter-CellDesigner/testFiles/rnaWithRegion.xml
rename to converter-CellDesigner/testFiles/modifications/rna_with_region.xml
diff --git a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java
index c6d7b706742e0c5560469a846910d2ecf5059124..39b313a2589585494b053bd25fd6f23cf36cb1b6 100644
--- a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java
+++ b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlExporter.java
@@ -1,1028 +1,1019 @@
-package lcsb.mapviewer.converter.model.sbgnml;
-
-import java.awt.geom.Line2D;
-import java.awt.geom.Point2D;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import org.apache.commons.lang3.RandomStringUtils;
-import org.apache.log4j.Logger;
-import org.sbgn.ArcClazz;
-import org.sbgn.GlyphClazz;
-import org.sbgn.Language;
-import org.sbgn.bindings.Arc;
-import org.sbgn.bindings.Arc.End;
-import org.sbgn.bindings.Arc.Next;
-import org.sbgn.bindings.Arc.Start;
-import org.sbgn.bindings.Bbox;
-import org.sbgn.bindings.Glyph;
-import org.sbgn.bindings.Label;
-import org.sbgn.bindings.Map;
-import org.sbgn.bindings.Port;
-import org.sbgn.bindings.Sbgn;
-
-import lcsb.mapviewer.common.comparator.DoubleComparator;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.converter.graphics.bioEntity.reaction.ReactionConverter;
-import lcsb.mapviewer.model.graphics.ArrowType;
-import lcsb.mapviewer.model.map.compartment.Compartment;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.modifier.Catalysis;
-import lcsb.mapviewer.model.map.modifier.Inhibition;
-import lcsb.mapviewer.model.map.modifier.Modulation;
-import lcsb.mapviewer.model.map.modifier.PhysicalStimulation;
-import lcsb.mapviewer.model.map.modifier.Trigger;
-import lcsb.mapviewer.model.map.reaction.AbstractNode;
-import lcsb.mapviewer.model.map.reaction.AndOperator;
-import lcsb.mapviewer.model.map.reaction.AssociationOperator;
-import lcsb.mapviewer.model.map.reaction.DissociationOperator;
-import lcsb.mapviewer.model.map.reaction.Modifier;
-import lcsb.mapviewer.model.map.reaction.NodeOperator;
-import lcsb.mapviewer.model.map.reaction.OrOperator;
-import lcsb.mapviewer.model.map.reaction.Product;
-import lcsb.mapviewer.model.map.reaction.Reactant;
-import lcsb.mapviewer.model.map.reaction.Reaction;
-import lcsb.mapviewer.model.map.reaction.SplitOperator;
-import lcsb.mapviewer.model.map.reaction.type.DissociationReaction;
-import lcsb.mapviewer.model.map.reaction.type.HeterodimerAssociationReaction;
-import lcsb.mapviewer.model.map.reaction.type.KnownTransitionOmittedReaction;
-import lcsb.mapviewer.model.map.reaction.type.NegativeInfluenceReaction;
-import lcsb.mapviewer.model.map.reaction.type.ReducedModulationReaction;
-import lcsb.mapviewer.model.map.reaction.type.ReducedPhysicalStimulationReaction;
-import lcsb.mapviewer.model.map.reaction.type.ReducedTriggerReaction;
-import lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction;
-import lcsb.mapviewer.model.map.reaction.type.UnknownTransitionReaction;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.AntisenseRna;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.Degraded;
-import lcsb.mapviewer.model.map.species.Gene;
-import lcsb.mapviewer.model.map.species.Ion;
-import lcsb.mapviewer.model.map.species.Phenotype;
-import lcsb.mapviewer.model.map.species.Protein;
-import lcsb.mapviewer.model.map.species.Rna;
-import lcsb.mapviewer.model.map.species.SimpleMolecule;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.TruncatedProtein;
-import lcsb.mapviewer.model.map.species.Unknown;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.modelutils.map.ElementUtils;
-
-/**
- * Class used to export SBGN-ML files from the model.
- * 
- * @author Michał Kuźma
- *
- */
-public class SbgnmlXmlExporter {
-
-	/**
-	 * Helps in providing human readable identifiers of elements for logging.
-	 */
-	private ElementUtils												eu												 = new ElementUtils();
-
-	/**
-	 * Default class logger.
-	 */
-	private Logger															logger										 = Logger.getLogger(SbgnmlXmlExporter.class.getName());
-
-	/**
-	 * Counter of the arcs parsed so far, used in generating arc's id.
-	 */
-	private int																	arcCounter;
-
-	/**
-	 * Set of all the operators parsed so far, used in generating operator's id.
-	 */
-	private Set<NodeOperator>										parsedOperators;
-
-	/**
-	 * Map of operator IDs used when parsing arcs targeting an operator.
-	 */
-	private java.util.Map<NodeOperator, String>	operatorIds;
-
-	/**
-	 * Map of all glyphs and ports generated so far with id as key.
-	 */
-	private java.util.Map<String, Object>				sourceTargetMap;
-
-	/**
-	 * Side margin for units of information.
-	 */
-	private static final double									UNIT_OF_INFORMATION_MARGIN = 10.0;
-
-	/**
-	 * Height of generated units of information.
-	 */
-	private static final double									UNIT_OF_INFORMATION_HEIGHT = 12.0;
-
-	/**
-	 * Height and width of generated operators.
-	 */
-	private static final double									OPERATOR_SIZE							 = 40.0;
-
-	/**
-	 * Distance between operator circle and port point.
-	 */
-	private static final double									OPERATOR_PORT_DISTANCE		 = 20.0;
-
-	/**
-	 * Distance between process glyph and port point.
-	 */
-	private static final double									PROCESS_PORT_DISTANCE			 = 10.0;
-
-	/**
-	 * Length of random alphabetic string added in the begining of ID, if it is a
-	 * number. SBGN-ML doesn't accept numbers as ID.
-	 */
-	private static final int										ID_RANDOM_STRING_LENGTH		 = 5;
-
-	/**
-	 * Transforms model into SBGN-ML xml.
-	 * 
-	 * @param model
-	 *          model that should be transformed
-	 * @return SBGM-ML xml string for the model
-	 */
-	public Sbgn toSbgnml(Model model) {
-		// Reset global variables
-		arcCounter = 0;
-		parsedOperators = new HashSet<>();
-		operatorIds = new HashMap<>();
-		sourceTargetMap = new HashMap<>();
-
-		Map map = new Map();
-		map.setLanguage(Language.PD.getName());
-		Sbgn sbgnData = new Sbgn();
-
-		List<Species> aliases = model.getSpeciesList();
-
-		for (Species a : aliases) {
-			if (a.getComplex() == null) {
-				Glyph newGlyph = aliasToGlyph(a);
-				map.getGlyph().add(newGlyph);
-			}
-		}
-
-		for (Reaction reaction : model.getReactions()) {
-			try {
-				map.getGlyph().add(getProcessGlyphFromReaction(reaction));
-			} catch (InvalidArgumentException ex) {
-				// Reduced notation
-				try {
-					map.getArc().add(getArcFromReducedReaction(reaction));
-				} catch (InvalidArgumentException e) {
-					logger.warn(
-							"Invalid arc type." + " Reduced notation reaction found of type that is not compliant with SBGN-ML format." + " Reaction: "
-									+ reaction.getIdReaction());
-				}
-				continue;
-			}
-			map.getArc().addAll(getArcsFromReaction(reaction, map.getGlyph()));
-		}
-
-		sbgnData.setMap(map);
-
-		return sbgnData;
-	}
-
-	/**
-	 * Creates new glyph element with all parameters from given alias.
-	 * 
-	 * @param alias
-	 *          alias with all parameters for the glyph
-	 * @return newly created glyph
-	 */
-	private Glyph aliasToGlyph(Element alias) {
-		Glyph newGlyph = new Glyph();
-		boolean idIsANumber = true;
-		try {
-			Integer.parseInt(alias.getElementId().substring(0, 1));
-		} catch (NumberFormatException e) {
-			idIsANumber = false;
-		}
-		if (idIsANumber) {
-			newGlyph.setId(RandomStringUtils.randomAlphabetic(ID_RANDOM_STRING_LENGTH).concat(alias.getElementId()));
-		} else {
-			newGlyph.setId(alias.getElementId());
-		}
-		newGlyph.setClazz(getGlyphClazzFromElement(alias).getClazz());
-		newGlyph.setLabel(getGlyphLabelFromAlias(alias));
-
-		Bbox bbox = new Bbox();
-		bbox.setX(alias.getX().floatValue());
-		bbox.setY(alias.getY().floatValue());
-		bbox.setW(alias.getWidth().floatValue());
-		bbox.setH(alias.getHeight().floatValue());
-		newGlyph.setBbox(bbox);
-
-		if (GlyphClazz.fromClazz(newGlyph.getClazz()).equals(GlyphClazz.MACROMOLECULE)
-				|| GlyphClazz.fromClazz(newGlyph.getClazz()).equals(GlyphClazz.MACROMOLECULE_MULTIMER)) {
-			Protein protein = (Protein) alias;
-			for (ModificationResidue mr : protein.getModificationResidues()) {
-				Glyph stateVariableGlyph = parseStateVariable(mr, newGlyph);
-				stateVariableGlyph.setId(newGlyph.getId().concat("-").concat(stateVariableGlyph.getId()));
-				newGlyph.getGlyph().add(stateVariableGlyph);
-			}
-		}
-
-		Glyph unitOfInformationGlyph = getUnitOfInformationGlyph(alias);
-		if (unitOfInformationGlyph != null) {
-			newGlyph.getGlyph().add(unitOfInformationGlyph);
-		}
-
-		if (alias instanceof Complex) {
-			Complex complexAlias = (Complex) alias;
-			for (Species a : complexAlias.getElements()) {
-				Glyph childGlyph = aliasToGlyph(a);
-				newGlyph.getGlyph().add(childGlyph);
-			}
-		}
-
-		sourceTargetMap.put(newGlyph.getId(), newGlyph);
-		return newGlyph;
-	}
-
-	/**
-	 * Creates new glyph element with all parameters from given operator.
-	 * 
-	 * @param operator
-	 *          operator with all parameters for the glyph
-	 * @return newly created glyph
-	 */
-	private Glyph operatorToGlyph(NodeOperator operator) {
-		Glyph newGlyph = new Glyph();
-		newGlyph.setId("operator".concat(Integer.toString(parsedOperators.size())));
-		parsedOperators.add(operator);
-		operatorIds.put(operator, newGlyph.getId());
-		if (operator instanceof AndOperator) {
-			newGlyph.setClazz(GlyphClazz.AND.getClazz());
-		} else if (operator instanceof OrOperator) {
-			newGlyph.setClazz(GlyphClazz.OR.getClazz());
-		}
-
-		Bbox bbox = new Bbox();
-		bbox.setX((float) (operator.getLine().getPoints().get(0).getX() - OPERATOR_SIZE / 2));
-		bbox.setY((float) (operator.getLine().getPoints().get(0).getY() - OPERATOR_SIZE / 2));
-		bbox.setW((float) OPERATOR_SIZE);
-		bbox.setH((float) OPERATOR_SIZE);
-		newGlyph.setBbox(bbox);
-
-		Port port2 = new Port();
-		port2.setId(newGlyph.getId().concat(".2"));
-		Point2D centerPoint = operator.getLine().getPoints().get(0);
-		Point2D nextPoint = operator.getLine().getPoints().get(1);
-		double dx = nextPoint.getX() - centerPoint.getX();
-		double dy = nextPoint.getY() - centerPoint.getY();
-		double portToCenterDistance = OPERATOR_SIZE / 2 + OPERATOR_PORT_DISTANCE;
-
-		double dx2, dy2;
-		if (dx != 0) {
-			dx2 = Math.sqrt(Math.pow(portToCenterDistance, 2) / (1 + Math.pow(dy / dx, 2)));
-			dy2 = dx2 * dy / dx;
-		} else {
-			dx2 = 0;
-			if (dy > 0) {
-				dy2 = portToCenterDistance;
-			} else {
-				dy2 = -portToCenterDistance;
-			}
-		}
-
-		port2.setX((float) (centerPoint.getX() + dx2));
-		port2.setY((float) (centerPoint.getY() + dy2));
-		sourceTargetMap.put(port2.getId(), port2);
-		newGlyph.getPort().add(port2);
-
-		Port port1 = new Port();
-		port1.setId(newGlyph.getId().concat(".1"));
-		Point2D portPoint1 = new Point2D.Double(2 * centerPoint.getX() - port2.getX(), 2 * centerPoint.getY() - port2.getY());
-		port1.setX((float) portPoint1.getX());
-		port1.setY((float) portPoint1.getY());
-		sourceTargetMap.put(port1.getId(), port1);
-		newGlyph.getPort().add(port1);
-
-		sourceTargetMap.put(newGlyph.getId(), newGlyph);
-
-		return newGlyph;
-	}
-
-	/**
-	 * Returns GlyphClazz adequate for given element, based on it's class.
-	 * 
-	 * @param element
-	 *          element to extract GlyphCLazz from
-	 * @return GlyphClazz adequate for given alias
-	 */
-	private GlyphClazz getGlyphClazzFromElement(Element element) {
-		if (element instanceof Protein) {
-			Protein protein = (Protein) element;
-			if (protein.getHomodimer() == 1) {
-				return GlyphClazz.MACROMOLECULE;
-			} else {
-				return GlyphClazz.MACROMOLECULE_MULTIMER;
-			}
-		}
-
-		if (element instanceof SimpleMolecule) {
-			SimpleMolecule simpleMolecule = (SimpleMolecule) element;
-			if (simpleMolecule.getHomodimer() == 1) {
-				return GlyphClazz.SIMPLE_CHEMICAL;
-			} else {
-				return GlyphClazz.SIMPLE_CHEMICAL_MULTIMER;
-			}
-		}
-
-		if (element instanceof Ion) {
-			Ion ion = (Ion) element;
-			if (ion.getHomodimer() == 1) {
-				return GlyphClazz.SIMPLE_CHEMICAL;
-			} else {
-				return GlyphClazz.SIMPLE_CHEMICAL_MULTIMER;
-			}
-		}
-
-		if (element instanceof Gene) {
-			Gene gene = (Gene) element;
-			if (gene.getHomodimer() == 1) {
-				return GlyphClazz.NUCLEIC_ACID_FEATURE;
-			} else {
-				return GlyphClazz.NUCLEIC_ACID_FEATURE_MULTIMER;
-			}
-		}
-
-		if (element instanceof Rna) {
-			Rna rna = (Rna) element;
-			if (rna.getHomodimer() == 1) {
-				return GlyphClazz.NUCLEIC_ACID_FEATURE;
-			} else {
-				return GlyphClazz.NUCLEIC_ACID_FEATURE_MULTIMER;
-			}
-		}
-
-		if (element instanceof AntisenseRna) {
-			AntisenseRna rna = (AntisenseRna) element;
-			if (rna.getHomodimer() == 1) {
-				return GlyphClazz.NUCLEIC_ACID_FEATURE;
-			} else {
-				return GlyphClazz.NUCLEIC_ACID_FEATURE_MULTIMER;
-			}
-		}
-
-		if (element instanceof Complex) {
-			Complex complexSpecies = (Complex) element;
-			if (complexSpecies.getHomodimer() == 1) {
-				return GlyphClazz.COMPLEX;
-			} else {
-				return GlyphClazz.COMPLEX_MULTIMER;
-			}
-		}
-
-		if (element instanceof Degraded) {
-			return GlyphClazz.SOURCE_AND_SINK;
-		}
-
-		if (element instanceof Phenotype) {
-			return GlyphClazz.PHENOTYPE;
-		}
-
-		if (element instanceof Compartment) {
-			return GlyphClazz.COMPARTMENT;
-		}
-		if (element instanceof Unknown) {
-			return GlyphClazz.UNSPECIFIED_ENTITY;
-		}
-
-		logger.warn(eu.getElementTag(element) + "Element type is not supported by SBGN-ML format. Unspecified Entity type assigned.");
-		return GlyphClazz.UNSPECIFIED_ENTITY;
-	}
-
-	/**
-	 * Returns label for a glyph with name extracted from given element.
-	 * 
-	 * @param element
-	 *          element with the name
-	 * @return label for a glyph
-	 */
-	private Label getGlyphLabelFromAlias(Element element) {
-		Label label = new Label();
-		label.setText(element.getName());
-		return label;
-	}
-
-	/**
-	 * Returns state variable glyph parsed from {@link ModificationResidue}.
-	 * 
-	 * @param mr
-	 *          {@link ModificationResidue} to be parsed
-	 * @param parentGlyph
-	 *          parent glyph for the state variable
-	 * @return state variable glyph
-	 */
-	private Glyph parseStateVariable(ModificationResidue mr, Glyph parentGlyph) {
-		Glyph glyph = new Glyph();
-		glyph.setId(mr.getIdModificationResidue());
-		glyph.setClazz(GlyphClazz.STATE_VARIABLE.getClazz());
-
-		if (mr.getState() != null) {
-			Glyph.State state = new Glyph.State();
-			state.setValue(mr.getState().getAbbreviation());
-			state.setVariable(mr.getName());
-			glyph.setState(state);
-		}
-
-		Bbox bbox = new Bbox();
-
-		final float filledWidth = 70.0f;
-		final float filledHeight = 28.0f;
-		final float emptyWidth = 20.0f;
-		final float emptyHeight = 22.0f;
-		if (glyph.getState() != null) {
-			bbox.setH(filledHeight);
-			bbox.setW(filledWidth);
-		} else {
-			bbox.setH(emptyHeight);
-			bbox.setW(emptyWidth);
-		}
-
-		float angle = mr.getAngle().floatValue();
-		angle /= Math.PI;
-
-		final float rightBorderLimit = 0.25f;
-		final float topBorderLimit = 0.75f;
-		final float leftBorderLimit = 1.25f;
-		float svCenterX, svCenterY;
-		if (angle < rightBorderLimit) {
-			svCenterX = parentGlyph.getBbox().getW();
-			svCenterY = parentGlyph.getBbox().getH() / 2 - (angle * 2 * parentGlyph.getBbox().getH());
-		} else if (angle < topBorderLimit) {
-			svCenterX = parentGlyph.getBbox().getW() * (1.0f - 2 * (angle - rightBorderLimit));
-			svCenterY = 0;
-		} else if (angle < leftBorderLimit) {
-			svCenterX = 0;
-			svCenterY = parentGlyph.getBbox().getH() * 2 * (angle - topBorderLimit);
-		} else {
-			svCenterX = parentGlyph.getBbox().getW() * 2 * (angle - leftBorderLimit);
-			svCenterY = parentGlyph.getBbox().getH();
-		}
-
-		bbox.setX(svCenterX - bbox.getW() / 2.0f + parentGlyph.getBbox().getX());
-		bbox.setY(svCenterY - bbox.getH() / 2.0f + parentGlyph.getBbox().getY());
-
-		glyph.setBbox(bbox);
-
-		return glyph;
-	}
-
-	/**
-	 * Returns glyph with unit of information extracted from the alias or null if
-	 * no unit of information was found.
-	 * 
-	 * @param alias
-	 *          input alias
-	 * @return glyph with unit of information extracted from the alias or null if
-	 *         no unit of information was found
-	 */
-	private Glyph getUnitOfInformationGlyph(Element alias) {
-		Glyph uoiGlyph = null;
-
-		String uoiText = "";
-		if (alias instanceof Species) {
-			Species species = (Species) alias;
-			int homodir = species.getHomodimer();
-			if (homodir > 1) {
-				uoiText = "N:".concat(Integer.toString(homodir));
-			}
-		}
-
-		if (alias instanceof TruncatedProtein) {
-			if (!uoiText.equals("")) {
-				uoiText = uoiText.concat("; ");
-			}
-			uoiText = uoiText.concat("ct:truncatedProtein");
-		}
-
-		if (alias instanceof Species) {
-			Species speciesAlias = (Species) alias;
-			if ((speciesAlias.getStateLabel() != null) && (speciesAlias.getStatePrefix() != null)) {
-				if (!uoiText.equals("")) {
-					uoiText = uoiText.concat("; ");
-				}
-				if (!speciesAlias.getStatePrefix().equals("free input")) {
-					uoiText = uoiText.concat(speciesAlias.getStatePrefix()).concat(":");
-				}
-				uoiText = uoiText.concat(speciesAlias.getStateLabel());
-			}
-		}
-
-		if (!uoiText.contains("ct:")) {
-			if (alias instanceof Rna) {
-				if (!uoiText.equals("")) {
-					uoiText = uoiText.concat("; ");
-				}
-				uoiText = uoiText.concat("ct:RNA");
-			}
-			if (alias instanceof AntisenseRna) {
-				if (!uoiText.equals("")) {
-					uoiText = uoiText.concat("; ");
-				}
-				uoiText = uoiText.concat("ct:antisenseRNA");
-			}
-			if (alias instanceof Gene) {
-				if (!uoiText.equals("")) {
-					uoiText = uoiText.concat("; ");
-				}
-				uoiText = uoiText.concat("ct:gene");
-			}
-		}
-
-		if (!uoiText.equals("")) {
-			uoiGlyph = new Glyph();
-			uoiGlyph.setClazz(GlyphClazz.UNIT_OF_INFORMATION.getClazz());
-			uoiGlyph.setId(alias.getElementId().concat("uoi"));
-
-			Label label = new Label();
-			label.setText(uoiText);
-			uoiGlyph.setLabel(label);
-
-			Bbox bbox = new Bbox();
-			bbox.setX((float) (alias.getX() + UNIT_OF_INFORMATION_MARGIN));
-			bbox.setY((float) (alias.getY() - UNIT_OF_INFORMATION_HEIGHT / 2));
-			bbox.setH((float) UNIT_OF_INFORMATION_HEIGHT);
-			bbox.setW((float) (alias.getWidth() - 2 * UNIT_OF_INFORMATION_MARGIN));
-			uoiGlyph.setBbox(bbox);
-		}
-
-		return uoiGlyph;
-	}
-
-	/**
-	 * Returns process glyph created based on reaction's center point.
-	 * 
-	 * @param reaction
-	 *          reaction to be parsed
-	 * @return process glyph for given reaction
-	 */
-	private Glyph getProcessGlyphFromReaction(Reaction reaction) {
-		Glyph processGlyph = new Glyph();
-		processGlyph.setId(reaction.getIdReaction());
-		processGlyph.setClazz(getGlyphClazzFromReaction(reaction).getClazz());
-		Bbox bbox = new Bbox();
-
-		Line2D line = reaction.getCenterLine();
-		Point2D startPoint = line.getP1();
-		Point2D endPoint = line.getP2();
-
-		double pointX = (startPoint.getX() + endPoint.getX()) / 2;
-		double pointY = (startPoint.getY() + endPoint.getY()) / 2;
-		Point2D pointNW = new Point2D.Double(pointX - ReactionConverter.RECT_SIZE / 2, pointY - ReactionConverter.RECT_SIZE / 2);
-		bbox.setX((float) pointNW.getX());
-		bbox.setY((float) pointNW.getY());
-		bbox.setH((float) ReactionConverter.RECT_SIZE);
-		bbox.setW((float) ReactionConverter.RECT_SIZE);
-
-		processGlyph.setBbox(bbox);
-
-		Port reactantPort = new Port();
-		reactantPort.setId(reaction.getIdReaction().concat(".1"));
-		sourceTargetMap.put(reactantPort.getId(), reactantPort);
-
-		Port productPort = new Port();
-		productPort.setId(reaction.getIdReaction().concat(".2"));
-		sourceTargetMap.put(productPort.getId(), productPort);
-
-		// Set glyph orientation and ports' coordinates.
-		double reactantDxAverage = 0.0;
-		double reactantDyAverage = 0.0;
-		double productDxAverage = 0.0;
-		double productDyAverage = 0.0;
-
-		for (Reactant r : reaction.getReactants()) {
-			Point2D reactantPoint;
-			List<Point2D> reactantArcPoints = r.getLine().getPoints();
-			if (reaction instanceof HeterodimerAssociationReaction) {
-				reactantPoint = reactantArcPoints.get(reactantArcPoints.size() - 1);
-			} else {
-				reactantPoint = reactantArcPoints.get(reactantArcPoints.size() - 2);
-			}
-			reactantDxAverage += reactantPoint.getX() - pointX;
-			reactantDyAverage += reactantPoint.getY() - pointY;
-		}
-		reactantDxAverage /= reaction.getReactants().size();
-		reactantDyAverage /= reaction.getReactants().size();
-
-		for (Product p : reaction.getProducts()) {
-			List<Point2D> productArcPoints = p.getLine().getPoints();
-			Point2D productPoint;
-			if (reaction instanceof DissociationReaction) {
-				productPoint = productArcPoints.get(0);
-			} else {
-				productPoint = productArcPoints.get(1);
-			}
-			productDxAverage += productPoint.getX() - pointX;
-			productDyAverage += productPoint.getY() - pointY;
-		}
-		productDxAverage /= reaction.getProducts().size();
-		productDyAverage /= reaction.getProducts().size();
-
-		boolean horizontalOrientation;
-		if ((reactantDxAverage * productDxAverage < 0) && (reactantDyAverage * productDyAverage < 0)) {
-			horizontalOrientation = (Math.abs(productDxAverage - reactantDxAverage) > Math.abs(productDyAverage - reactantDyAverage));
-		} else {
-			horizontalOrientation = (reactantDxAverage * productDxAverage < 0);
-		}
-		if (horizontalOrientation) {
-			processGlyph.setOrientation("horizontal");
-			reactantPort.setY((float) pointY);
-			productPort.setY((float) pointY);
-			if (reactantDxAverage < 0) {
-				reactantPort.setX((float) (pointX - PROCESS_PORT_DISTANCE));
-				productPort.setX((float) (pointX + PROCESS_PORT_DISTANCE));
-			} else {
-				reactantPort.setX((float) (pointX + PROCESS_PORT_DISTANCE));
-				productPort.setX((float) (pointX - PROCESS_PORT_DISTANCE));
-			}
-		} else {
-			reactantPort.setX((float) pointX);
-			productPort.setX((float) pointX);
-			if (reactantDyAverage < 0) {
-				reactantPort.setY((float) (pointY - PROCESS_PORT_DISTANCE));
-				productPort.setY((float) (pointY + PROCESS_PORT_DISTANCE));
-			} else {
-				reactantPort.setY((float) (pointY + PROCESS_PORT_DISTANCE));
-				productPort.setY((float) (pointY - PROCESS_PORT_DISTANCE));
-			}
-			processGlyph.setOrientation("vertical");
-		}
-
-		processGlyph.getPort().add(reactantPort);
-		processGlyph.getPort().add(productPort);
-
-		sourceTargetMap.put(processGlyph.getId(), processGlyph);
-
-		return processGlyph;
-	}
-
-	/**
-	 * Returns {@link GlyphClazz} appropriate to given reaction.
-	 * 
-	 * @param reaction
-	 *          {@link Reaction} to extract {@link GlyphClazz} from
-	 * @return {@link GlyphClazz} appropriate to given reaction
-	 */
-	private GlyphClazz getGlyphClazzFromReaction(Reaction reaction) {
-		if (reaction instanceof StateTransitionReaction) {
-			return GlyphClazz.PROCESS;
-		}
-		if (reaction instanceof HeterodimerAssociationReaction) {
-			return GlyphClazz.ASSOCIATION;
-		}
-		if (reaction instanceof DissociationReaction) {
-			return GlyphClazz.DISSOCIATION;
-		}
-		if (reaction instanceof KnownTransitionOmittedReaction) {
-			return GlyphClazz.OMITTED_PROCESS;
-		}
-		if (reaction instanceof UnknownTransitionReaction) {
-			return GlyphClazz.UNCERTAIN_PROCESS;
-		}
-		throw new InvalidArgumentException();
-	}
-
-	/**
-	 * Returns arc extracted from given reduced notation reaction.
-	 * 
-	 * @param reaction
-	 *          reduced notation reaction
-	 * @return arc extracted from given reduced notation reaction
-	 */
-	private Arc getArcFromReducedReaction(Reaction reaction) {
-		if ((reaction.getReactants().size() != 1) || (reaction.getProducts().size() != 1)) {
-			throw new InvalidArgumentException();
-		}
-		Arc arc = new Arc();
-		arc.setId(reaction.getIdReaction());
-
-		if (reaction instanceof NegativeInfluenceReaction) {
-			arc.setClazz(ArcClazz.INHIBITION.getClazz());
-		} else if (reaction instanceof ReducedModulationReaction) {
-			arc.setClazz(ArcClazz.MODULATION.getClazz());
-		} else if (reaction instanceof ReducedTriggerReaction) {
-			arc.setClazz(ArcClazz.NECESSARY_STIMULATION.getClazz());
-		} else if (reaction instanceof ReducedPhysicalStimulationReaction) {
-			arc.setClazz(ArcClazz.STIMULATION.getClazz());
-		} else {
-			throw new InvalidArgumentException();
-		}
-
-		if (reaction.getProducts().get(0).getElement() instanceof Phenotype) {
-			logger.warn("Found Phenotype being a reactant in process. That is discouraged");
-		}
-
-		arc.setSource(sourceTargetMap.get(reaction.getReactants().get(0).getElement().getElementId()));
-		arc.setTarget(sourceTargetMap.get(reaction.getProducts().get(0).getElement().getElementId()));
-
-		List<Point2D> pointList = reaction.getReactants().get(0).getLine().getPoints();
-		pointList.addAll(reaction.getProducts().get(0).getLine().getPoints());
-
-		removeRedundantPoints(pointList);
-
-		Start start = new Start();
-		start.setX((float) pointList.get(0).getX());
-		start.setY((float) pointList.get(0).getY());
-		arc.setStart(start);
-
-		End end = new End();
-		end.setX((float) pointList.get(pointList.size() - 1).getX());
-		end.setY((float) pointList.get(pointList.size() - 1).getY());
-		arc.setEnd(end);
-
-		for (int i = 1; i < pointList.size() - 1; i++) {
-			Point2D nextPoint = pointList.get(i);
-			Next next = new Next();
-			next.setX((float) nextPoint.getX());
-			next.setY((float) nextPoint.getY());
-			arc.getNext().add(next);
-		}
-
-		return arc;
-	}
-
-	/**
-	 * Removes redundant points from the list.
-	 * 
-	 * @param pointList
-	 *          list of points to be fixed
-	 */
-	private void removeRedundantPoints(List<Point2D> pointList) {
-		boolean allDone = false;
-		while (!allDone) {
-			allDone = true;
-			for (int i = 1; i < pointList.size() - 1; i++) {
-				double dx1 = pointList.get(i).getX() - pointList.get(i - 1).getX();
-				double dy1 = pointList.get(i).getY() - pointList.get(i - 1).getY();
-				double dx2 = pointList.get(i + 1).getX() - pointList.get(i).getX();
-				double dy2 = pointList.get(i + 1).getY() - pointList.get(i).getY();
-
-				DoubleComparator doubleComparator = new DoubleComparator();
-				if (((doubleComparator.compare(dy1 / dx1, dy2 / dx2) == 0)
-						|| (pointList.get(i - 1).getY() == pointList.get(i).getY()) && (pointList.get(i).getY() == pointList.get(i + 1).getY()))
-						&& between(pointList.get(i).getX(), pointList.get(i - 1).getX(), pointList.get(i + 1).getX())) {
-					pointList.remove(i);
-					allDone = false;
-				}
-			}
-		}
-	}
-
-	/**
-	 * Checks if argument x is between s1 and s2.
-	 * 
-	 * @param x
-	 *          number to checked if it is in the middle
-	 * @param s1
-	 *          one side argument
-	 * @param s2
-	 *          second side argument
-	 * @return true if x is between s1 and s2
-	 */
-	private boolean between(double x, double s1, double s2) {
-		if ((x >= s1) && (x <= s2)) {
-			return true;
-		}
-		if ((x <= s1) && (x >= s2)) {
-			return true;
-		}
-		return false;
-	}
-
-	/**
-	 * Returns set of all arcs used in the reaction.
-	 * 
-	 * @param reaction
-	 *          the reaction to extract arcs from
-	 * @param glyphList
-	 *          list of all glyphs in the map; used only for parsing operators
-	 * @return set of all arcs used in the reaction
-	 */
-	private List<Arc> getArcsFromReaction(Reaction reaction, List<Glyph> glyphList) {
-		List<Arc> arcList = new ArrayList<>();
-
-		// Parse all nodes except NodeOperators
-		for (AbstractNode node : reaction.getNodes().stream().filter(n -> !(n instanceof NodeOperator)).collect(Collectors.toList())) {
-			try {
-				arcList.add(getArcFromNode(node, glyphList));
-			} catch (InvalidArgumentException ex) {
-				logger.warn("Node skipped in export process, since it is not compliant with SBGN-ML format: " + node.getClass().getName());
-				continue;
-			}
-		}
-
-		// Now parse NodeOperators
-		for (AbstractNode node : reaction.getOperators().stream().filter(o -> {
-			if (o.getInputs().stream().filter(i -> i instanceof Reactant).count() > 0) {
-				return false;
-			}
-			if (o instanceof SplitOperator || o instanceof AssociationOperator || o instanceof DissociationOperator) {
-				return false;
-			}
-			return true;
-		}).collect(Collectors.toList())) {
-			try {
-				arcList.add(getArcFromNode(node, glyphList));
-			} catch (InvalidArgumentException ex) {
-				logger.warn("Node skipped in export process, since it is not compliant with SBGN-ML format: " + node.getClass().getName());
-				continue;
-			}
-		}
-
-		return arcList;
-
-	}
-
-	/**
-	 * Returns arc for given node.
-	 * 
-	 * @param node
-	 *          node to parse arc from
-	 * @param glyphList
-	 *          list of all glyphs in the map; used only for parsing operators
-	 * @return SBGN-ML arc for given node
-	 */
-	private Arc getArcFromNode(AbstractNode node, List<Glyph> glyphList) {
-		Arc arc = new Arc();
-		arc.setId("arc".concat(Integer.toString(arcCounter)));
-		arcCounter += 1;
-
-		boolean logicArc = false;
-		if (node instanceof Modifier) {
-			for (NodeOperator operator : node.getReaction().getOperators()) {
-				if (operator.getInputs().contains(node)) {
-					logicArc = true;
-				}
-			}
-		}
-		if (logicArc) {
-			arc.setClazz(ArcClazz.LOGIC_ARC.getClazz());
-		} else {
-			arc.setClazz(getArcClazzFromNode(node));
-		}
-
-		if (node instanceof Reactant) {
-			arc.setSource(sourceTargetMap.get(((Reactant) node).getElement().getElementId()));
-			arc.setTarget(sourceTargetMap.get(node.getReaction().getIdReaction().concat(".1")));
-		} else if (node instanceof Product) {
-			arc.setSource(sourceTargetMap.get(node.getReaction().getIdReaction().concat(".2")));
-			arc.setTarget(sourceTargetMap.get(((Product) node).getElement().getElementId()));
-		} else if (node instanceof Modifier) {
-			arc.setSource(sourceTargetMap.get(((Modifier) node).getElement().getElementId()));
-			if (!node.getLine().getEndAtd().getArrowType().equals(ArrowType.NONE)) {
-				arc.setTarget(sourceTargetMap.get(node.getReaction().getIdReaction()));
-			} else {
-				for (NodeOperator operator : node.getReaction().getOperators()) {
-					if (operator.getInputs().contains(node)) {
-						if (!parsedOperators.contains(operator)) {
-							Glyph newOperator = operatorToGlyph(operator);
-							glyphList.add(newOperator);
-						}
-						arc.setTarget(sourceTargetMap.get(operatorIds.get(operator).concat(".1")));
-					}
-				}
-			}
-		} else if (node instanceof NodeOperator) {
-			if ((node instanceof DissociationOperator) || (node instanceof AssociationOperator)) {
-				throw new InvalidArgumentException();
-			}
-			arc.setSource(sourceTargetMap.get(operatorIds.get(node).concat(".2")));
-			if (!node.getLine().getEndAtd().getArrowType().equals(ArrowType.NONE)) {
-				arc.setTarget(sourceTargetMap.get(node.getReaction().getIdReaction()));
-			} else {
-				for (NodeOperator operator : node.getReaction().getOperators()) {
-					if (operator.getInputs().contains(node)) {
-						if (!parsedOperators.contains(operator)) {
-							Glyph newOperator = operatorToGlyph(operator);
-							glyphList.add(newOperator);
-						}
-						arc.setTarget(sourceTargetMap.get(operatorIds.get(operator).concat(".1")));
-					}
-				}
-			}
-		}
-
-		List<Point2D> arcPoints = node.getLine().getPoints();
-		Start start = new Start();
-		if ((node instanceof Product) || (node instanceof NodeOperator)) {
-			Port sourcePort = (Port) arc.getSource();
-			start.setX(sourcePort.getX());
-			start.setY(sourcePort.getY());
-		} else {
-			start.setX((float) arcPoints.get(0).getX());
-			start.setY((float) arcPoints.get(0).getY());
-		}
-		arc.setStart(start);
-
-		End end = new End();
-		if ((node instanceof Reactant) || ((node instanceof Modifier) && (arc.getTarget() instanceof Port))) {
-			Port targetPort = (Port) arc.getTarget();
-			end.setX(targetPort.getX());
-			end.setY(targetPort.getY());
-		} else {
-			Point2D lastPoint = arcPoints.get(arcPoints.size() - 1);
-			end.setX((float) lastPoint.getX());
-			end.setY((float) lastPoint.getY());
-		}
-		arc.setEnd(end);
-
-		if ((node instanceof Product) && (node.getReaction() instanceof DissociationReaction)) {
-			Point2D nextPoint = arcPoints.get(0);
-			Next next = new Next();
-			next.setX((float) nextPoint.getX());
-			next.setY((float) nextPoint.getY());
-			arc.getNext().add(next);
-		}
-
-		DoubleComparator doubleComparator = new DoubleComparator();
-		for (int i = 1; i < arcPoints.size() - 1; i++) {
-			Point2D nextPoint = arcPoints.get(i);
-			if ((doubleComparator.compare(nextPoint.getX(), new Double(start.getX())) == 0)
-					&& (doubleComparator.compare(nextPoint.getY(), new Double(start.getY())) == 0)) {
-				arc.getNext().clear();
-				continue;
-			}
-			if ((doubleComparator.compare(nextPoint.getX(), new Double(end.getX())) == 0)
-					&& (doubleComparator.compare(nextPoint.getY(), new Double(end.getY())) == 0)) {
-				break;
-			}
-			Next next = new Next();
-			next.setX((float) nextPoint.getX());
-			next.setY((float) nextPoint.getY());
-			arc.getNext().add(next);
-		}
-
-		if ((node instanceof Reactant) && (node.getReaction() instanceof HeterodimerAssociationReaction)) {
-			Point2D nextPoint = arcPoints.get(arcPoints.size() - 1);
-			Next next = new Next();
-			next.setX((float) nextPoint.getX());
-			next.setY((float) nextPoint.getY());
-			arc.getNext().add(next);
-		}
-
-		return arc;
-	}
-
-	/**
-	 * Returns {@link ArcClazz} for given node.
-	 * 
-	 * @param node
-	 *          Node to extract {@link ArcClazz} from
-	 * @return {@link ArcClazz} for given node
-	 */
-	private String getArcClazzFromNode(AbstractNode node) {
-		if (node instanceof Reactant) {
-			return ArcClazz.CONSUMPTION.getClazz();
-		}
-		if (node instanceof Product) {
-			return ArcClazz.PRODUCTION.getClazz();
-		}
-		if (node instanceof Catalysis) {
-			return ArcClazz.CATALYSIS.getClazz();
-		}
-		if (node instanceof Inhibition) {
-			return ArcClazz.INHIBITION.getClazz();
-		}
-		if (node instanceof Modulation) {
-			return ArcClazz.MODULATION.getClazz();
-		}
-		if (node instanceof Trigger) {
-			return ArcClazz.NECESSARY_STIMULATION.getClazz();
-		}
-		if (node instanceof PhysicalStimulation) {
-			return ArcClazz.STIMULATION.getClazz();
-		}
-		if (node instanceof NodeOperator) {
-			ArrowType arrowType = node.getLine().getEndAtd().getArrowType();
-			switch (arrowType) {
-				case BLANK:
-					return ArcClazz.STIMULATION.getClazz();
-				case BLANK_CROSSBAR:
-					return ArcClazz.NECESSARY_STIMULATION.getClazz();
-				case CIRCLE:
-					return ArcClazz.CATALYSIS.getClazz();
-				case CROSSBAR:
-					return ArcClazz.INHIBITION.getClazz();
-				case DIAMOND:
-					return ArcClazz.MODULATION.getClazz();
-				case NONE:
-					return ArcClazz.LOGIC_ARC.getClazz();
-				default:
-					throw new InvalidArgumentException();
-
-			}
-		}
-		throw new InvalidArgumentException();
-	}
-}
+package lcsb.mapviewer.converter.model.sbgnml;
+
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.log4j.Logger;
+import org.sbgn.ArcClazz;
+import org.sbgn.GlyphClazz;
+import org.sbgn.Language;
+import org.sbgn.bindings.Arc;
+import org.sbgn.bindings.Arc.End;
+import org.sbgn.bindings.Arc.Next;
+import org.sbgn.bindings.Arc.Start;
+import org.sbgn.bindings.Bbox;
+import org.sbgn.bindings.Glyph;
+import org.sbgn.bindings.Label;
+import org.sbgn.bindings.Map;
+import org.sbgn.bindings.Port;
+import org.sbgn.bindings.Sbgn;
+
+import lcsb.mapviewer.common.comparator.DoubleComparator;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.converter.graphics.bioEntity.reaction.ReactionConverter;
+import lcsb.mapviewer.model.graphics.ArrowType;
+import lcsb.mapviewer.model.map.compartment.Compartment;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.modifier.Catalysis;
+import lcsb.mapviewer.model.map.modifier.Inhibition;
+import lcsb.mapviewer.model.map.modifier.Modulation;
+import lcsb.mapviewer.model.map.modifier.PhysicalStimulation;
+import lcsb.mapviewer.model.map.modifier.Trigger;
+import lcsb.mapviewer.model.map.reaction.AbstractNode;
+import lcsb.mapviewer.model.map.reaction.AndOperator;
+import lcsb.mapviewer.model.map.reaction.AssociationOperator;
+import lcsb.mapviewer.model.map.reaction.DissociationOperator;
+import lcsb.mapviewer.model.map.reaction.Modifier;
+import lcsb.mapviewer.model.map.reaction.NodeOperator;
+import lcsb.mapviewer.model.map.reaction.OrOperator;
+import lcsb.mapviewer.model.map.reaction.Product;
+import lcsb.mapviewer.model.map.reaction.Reactant;
+import lcsb.mapviewer.model.map.reaction.Reaction;
+import lcsb.mapviewer.model.map.reaction.SplitOperator;
+import lcsb.mapviewer.model.map.reaction.type.DissociationReaction;
+import lcsb.mapviewer.model.map.reaction.type.HeterodimerAssociationReaction;
+import lcsb.mapviewer.model.map.reaction.type.KnownTransitionOmittedReaction;
+import lcsb.mapviewer.model.map.reaction.type.NegativeInfluenceReaction;
+import lcsb.mapviewer.model.map.reaction.type.ReducedModulationReaction;
+import lcsb.mapviewer.model.map.reaction.type.ReducedPhysicalStimulationReaction;
+import lcsb.mapviewer.model.map.reaction.type.ReducedTriggerReaction;
+import lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction;
+import lcsb.mapviewer.model.map.reaction.type.UnknownTransitionReaction;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.Degraded;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Ion;
+import lcsb.mapviewer.model.map.species.Phenotype;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.SimpleMolecule;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.TruncatedProtein;
+import lcsb.mapviewer.model.map.species.Unknown;
+import lcsb.mapviewer.model.map.species.field.AbstractSiteModification;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.modelutils.map.ElementUtils;
+
+/**
+ * Class used to export SBGN-ML files from the model.
+ * 
+ * @author Michał Kuźma
+ *
+ */
+public class SbgnmlXmlExporter {
+
+  /**
+   * Helps in providing human readable identifiers of elements for logging.
+   */
+  private ElementUtils eu = new ElementUtils();
+
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(SbgnmlXmlExporter.class.getName());
+
+  /**
+   * Counter of the arcs parsed so far, used in generating arc's id.
+   */
+  private int arcCounter;
+
+  /**
+   * Set of all the operators parsed so far, used in generating operator's id.
+   */
+  private Set<NodeOperator> parsedOperators;
+
+  /**
+   * Map of operator IDs used when parsing arcs targeting an operator.
+   */
+  private java.util.Map<NodeOperator, String> operatorIds;
+
+  /**
+   * Map of all glyphs and ports generated so far with id as key.
+   */
+  private java.util.Map<String, Object> sourceTargetMap;
+
+  /**
+   * Side margin for units of information.
+   */
+  private static final double UNIT_OF_INFORMATION_MARGIN = 10.0;
+
+  /**
+   * Height of generated units of information.
+   */
+  private static final double UNIT_OF_INFORMATION_HEIGHT = 12.0;
+
+  /**
+   * Height and width of generated operators.
+   */
+  private static final double OPERATOR_SIZE = 40.0;
+
+  /**
+   * Distance between operator circle and port point.
+   */
+  private static final double OPERATOR_PORT_DISTANCE = 20.0;
+
+  /**
+   * Distance between process glyph and port point.
+   */
+  private static final double PROCESS_PORT_DISTANCE = 10.0;
+
+  /**
+   * Length of random alphabetic string added in the begining of ID, if it is a
+   * number. SBGN-ML doesn't accept numbers as ID.
+   */
+  private static final int ID_RANDOM_STRING_LENGTH = 5;
+
+  /**
+   * Transforms model into SBGN-ML xml.
+   * 
+   * @param model
+   *          model that should be transformed
+   * @return SBGM-ML xml string for the model
+   */
+  public Sbgn toSbgnml(Model model) {
+    // Reset global variables
+    arcCounter = 0;
+    parsedOperators = new HashSet<>();
+    operatorIds = new HashMap<>();
+    sourceTargetMap = new HashMap<>();
+
+    Map map = new Map();
+    map.setLanguage(Language.PD.getName());
+    Sbgn sbgnData = new Sbgn();
+
+    List<Species> aliases = model.getSpeciesList();
+
+    for (Species a : aliases) {
+      if (a.getComplex() == null) {
+        Glyph newGlyph = aliasToGlyph(a);
+        map.getGlyph().add(newGlyph);
+      }
+    }
+
+    for (Reaction reaction : model.getReactions()) {
+      try {
+        map.getGlyph().add(getProcessGlyphFromReaction(reaction));
+      } catch (InvalidArgumentException ex) {
+        // Reduced notation
+        try {
+          map.getArc().add(getArcFromReducedReaction(reaction));
+        } catch (InvalidArgumentException e) {
+          logger.warn("Invalid arc type."
+              + " Reduced notation reaction found of type that is not compliant with SBGN-ML format." + " Reaction: "
+              + reaction.getIdReaction());
+        }
+        continue;
+      }
+      map.getArc().addAll(getArcsFromReaction(reaction, map.getGlyph()));
+    }
+
+    sbgnData.setMap(map);
+
+    return sbgnData;
+  }
+
+  /**
+   * Creates new glyph element with all parameters from given alias.
+   * 
+   * @param alias
+   *          alias with all parameters for the glyph
+   * @return newly created glyph
+   */
+  private Glyph aliasToGlyph(Element alias) {
+    Glyph newGlyph = new Glyph();
+    boolean idIsANumber = true;
+    try {
+      Integer.parseInt(alias.getElementId().substring(0, 1));
+    } catch (NumberFormatException e) {
+      idIsANumber = false;
+    }
+    if (idIsANumber) {
+      newGlyph.setId(RandomStringUtils.randomAlphabetic(ID_RANDOM_STRING_LENGTH).concat(alias.getElementId()));
+    } else {
+      newGlyph.setId(alias.getElementId());
+    }
+    newGlyph.setClazz(getGlyphClazzFromElement(alias).getClazz());
+    newGlyph.setLabel(getGlyphLabelFromAlias(alias));
+
+    Bbox bbox = new Bbox();
+    bbox.setX(alias.getX().floatValue());
+    bbox.setY(alias.getY().floatValue());
+    bbox.setW(alias.getWidth().floatValue());
+    bbox.setH(alias.getHeight().floatValue());
+    newGlyph.setBbox(bbox);
+
+    if (GlyphClazz.fromClazz(newGlyph.getClazz()).equals(GlyphClazz.MACROMOLECULE)
+        || GlyphClazz.fromClazz(newGlyph.getClazz()).equals(GlyphClazz.MACROMOLECULE_MULTIMER)) {
+      Protein protein = (Protein) alias;
+      for (ModificationResidue mr : protein.getModificationResidues()) {
+        Glyph stateVariableGlyph = parseStateVariable(mr, newGlyph);
+        stateVariableGlyph.setId(newGlyph.getId().concat("-").concat(stateVariableGlyph.getId()));
+        newGlyph.getGlyph().add(stateVariableGlyph);
+      }
+    }
+
+    Glyph unitOfInformationGlyph = getUnitOfInformationGlyph(alias);
+    if (unitOfInformationGlyph != null) {
+      newGlyph.getGlyph().add(unitOfInformationGlyph);
+    }
+
+    if (alias instanceof Complex) {
+      Complex complexAlias = (Complex) alias;
+      for (Species a : complexAlias.getElements()) {
+        Glyph childGlyph = aliasToGlyph(a);
+        newGlyph.getGlyph().add(childGlyph);
+      }
+    }
+
+    sourceTargetMap.put(newGlyph.getId(), newGlyph);
+    return newGlyph;
+  }
+
+  /**
+   * Creates new glyph element with all parameters from given operator.
+   * 
+   * @param operator
+   *          operator with all parameters for the glyph
+   * @return newly created glyph
+   */
+  private Glyph operatorToGlyph(NodeOperator operator) {
+    Glyph newGlyph = new Glyph();
+    newGlyph.setId("operator".concat(Integer.toString(parsedOperators.size())));
+    parsedOperators.add(operator);
+    operatorIds.put(operator, newGlyph.getId());
+    if (operator instanceof AndOperator) {
+      newGlyph.setClazz(GlyphClazz.AND.getClazz());
+    } else if (operator instanceof OrOperator) {
+      newGlyph.setClazz(GlyphClazz.OR.getClazz());
+    }
+
+    Bbox bbox = new Bbox();
+    bbox.setX((float) (operator.getLine().getPoints().get(0).getX() - OPERATOR_SIZE / 2));
+    bbox.setY((float) (operator.getLine().getPoints().get(0).getY() - OPERATOR_SIZE / 2));
+    bbox.setW((float) OPERATOR_SIZE);
+    bbox.setH((float) OPERATOR_SIZE);
+    newGlyph.setBbox(bbox);
+
+    Port port2 = new Port();
+    port2.setId(newGlyph.getId().concat(".2"));
+    Point2D centerPoint = operator.getLine().getPoints().get(0);
+    Point2D nextPoint = operator.getLine().getPoints().get(1);
+    double dx = nextPoint.getX() - centerPoint.getX();
+    double dy = nextPoint.getY() - centerPoint.getY();
+    double portToCenterDistance = OPERATOR_SIZE / 2 + OPERATOR_PORT_DISTANCE;
+
+    double dx2, dy2;
+    if (dx != 0) {
+      dx2 = Math.sqrt(Math.pow(portToCenterDistance, 2) / (1 + Math.pow(dy / dx, 2)));
+      dy2 = dx2 * dy / dx;
+    } else {
+      dx2 = 0;
+      if (dy > 0) {
+        dy2 = portToCenterDistance;
+      } else {
+        dy2 = -portToCenterDistance;
+      }
+    }
+
+    port2.setX((float) (centerPoint.getX() + dx2));
+    port2.setY((float) (centerPoint.getY() + dy2));
+    sourceTargetMap.put(port2.getId(), port2);
+    newGlyph.getPort().add(port2);
+
+    Port port1 = new Port();
+    port1.setId(newGlyph.getId().concat(".1"));
+    Point2D portPoint1 = new Point2D.Double(2 * centerPoint.getX() - port2.getX(),
+        2 * centerPoint.getY() - port2.getY());
+    port1.setX((float) portPoint1.getX());
+    port1.setY((float) portPoint1.getY());
+    sourceTargetMap.put(port1.getId(), port1);
+    newGlyph.getPort().add(port1);
+
+    sourceTargetMap.put(newGlyph.getId(), newGlyph);
+
+    return newGlyph;
+  }
+
+  /**
+   * Returns GlyphClazz adequate for given element, based on it's class.
+   * 
+   * @param element
+   *          element to extract GlyphCLazz from
+   * @return GlyphClazz adequate for given alias
+   */
+  private GlyphClazz getGlyphClazzFromElement(Element element) {
+    if (element instanceof Protein) {
+      Protein protein = (Protein) element;
+      if (protein.getHomodimer() == 1) {
+        return GlyphClazz.MACROMOLECULE;
+      } else {
+        return GlyphClazz.MACROMOLECULE_MULTIMER;
+      }
+    }
+
+    if (element instanceof SimpleMolecule) {
+      SimpleMolecule simpleMolecule = (SimpleMolecule) element;
+      if (simpleMolecule.getHomodimer() == 1) {
+        return GlyphClazz.SIMPLE_CHEMICAL;
+      } else {
+        return GlyphClazz.SIMPLE_CHEMICAL_MULTIMER;
+      }
+    }
+
+    if (element instanceof Ion) {
+      Ion ion = (Ion) element;
+      if (ion.getHomodimer() == 1) {
+        return GlyphClazz.SIMPLE_CHEMICAL;
+      } else {
+        return GlyphClazz.SIMPLE_CHEMICAL_MULTIMER;
+      }
+    }
+
+    if (element instanceof Gene) {
+      Gene gene = (Gene) element;
+      if (gene.getHomodimer() == 1) {
+        return GlyphClazz.NUCLEIC_ACID_FEATURE;
+      } else {
+        return GlyphClazz.NUCLEIC_ACID_FEATURE_MULTIMER;
+      }
+    }
+
+    if (element instanceof Rna) {
+      Rna rna = (Rna) element;
+      if (rna.getHomodimer() == 1) {
+        return GlyphClazz.NUCLEIC_ACID_FEATURE;
+      } else {
+        return GlyphClazz.NUCLEIC_ACID_FEATURE_MULTIMER;
+      }
+    }
+
+    if (element instanceof AntisenseRna) {
+      AntisenseRna rna = (AntisenseRna) element;
+      if (rna.getHomodimer() == 1) {
+        return GlyphClazz.NUCLEIC_ACID_FEATURE;
+      } else {
+        return GlyphClazz.NUCLEIC_ACID_FEATURE_MULTIMER;
+      }
+    }
+
+    if (element instanceof Complex) {
+      Complex complexSpecies = (Complex) element;
+      if (complexSpecies.getHomodimer() == 1) {
+        return GlyphClazz.COMPLEX;
+      } else {
+        return GlyphClazz.COMPLEX_MULTIMER;
+      }
+    }
+
+    if (element instanceof Degraded) {
+      return GlyphClazz.SOURCE_AND_SINK;
+    }
+
+    if (element instanceof Phenotype) {
+      return GlyphClazz.PHENOTYPE;
+    }
+
+    if (element instanceof Compartment) {
+      return GlyphClazz.COMPARTMENT;
+    }
+    if (element instanceof Unknown) {
+      return GlyphClazz.UNSPECIFIED_ENTITY;
+    }
+
+    logger.warn(eu.getElementTag(element)
+        + "Element type is not supported by SBGN-ML format. Unspecified Entity type assigned.");
+    return GlyphClazz.UNSPECIFIED_ENTITY;
+  }
+
+  /**
+   * Returns label for a glyph with name extracted from given element.
+   * 
+   * @param element
+   *          element with the name
+   * @return label for a glyph
+   */
+  private Label getGlyphLabelFromAlias(Element element) {
+    Label label = new Label();
+    label.setText(element.getName());
+    return label;
+  }
+
+  /**
+   * Returns state variable glyph parsed from {@link ModificationResidue}.
+   * 
+   * @param mr
+   *          {@link ModificationResidue} to be parsed
+   * @param parentGlyph
+   *          parent glyph for the state variable
+   * @return state variable glyph
+   */
+  private Glyph parseStateVariable(ModificationResidue mr, Glyph parentGlyph) {
+    Glyph glyph = new Glyph();
+    glyph.setId(mr.getIdModificationResidue());
+    glyph.setClazz(GlyphClazz.STATE_VARIABLE.getClazz());
+
+    if (mr instanceof AbstractSiteModification) {
+      AbstractSiteModification modification = (AbstractSiteModification) mr;
+      if (modification.getState() != null) {
+        Glyph.State state = new Glyph.State();
+        state.setValue(modification.getState().getAbbreviation());
+        state.setVariable(mr.getName());
+        glyph.setState(state);
+      }
+    }
+
+    Bbox bbox = new Bbox();
+
+    final float filledWidth = 70.0f;
+    final float filledHeight = 28.0f;
+    final float emptyWidth = 20.0f;
+    final float emptyHeight = 22.0f;
+    if (glyph.getState() != null) {
+      bbox.setH(filledHeight);
+      bbox.setW(filledWidth);
+    } else {
+      bbox.setH(emptyHeight);
+      bbox.setW(emptyWidth);
+    }
+
+    bbox.setX((float) mr.getPosition().getX());
+    bbox.setY((float) mr.getPosition().getY());
+
+    glyph.setBbox(bbox);
+
+    return glyph;
+  }
+
+  /**
+   * Returns glyph with unit of information extracted from the alias or null if no
+   * unit of information was found.
+   * 
+   * @param alias
+   *          input alias
+   * @return glyph with unit of information extracted from the alias or null if no
+   *         unit of information was found
+   */
+  private Glyph getUnitOfInformationGlyph(Element alias) {
+    Glyph uoiGlyph = null;
+
+    String uoiText = "";
+    if (alias instanceof Species) {
+      Species species = (Species) alias;
+      int homodir = species.getHomodimer();
+      if (homodir > 1) {
+        uoiText = "N:".concat(Integer.toString(homodir));
+      }
+    }
+
+    if (alias instanceof TruncatedProtein) {
+      if (!uoiText.equals("")) {
+        uoiText = uoiText.concat("; ");
+      }
+      uoiText = uoiText.concat("ct:truncatedProtein");
+    }
+
+    if (alias instanceof Species) {
+      Species speciesAlias = (Species) alias;
+      if ((speciesAlias.getStateLabel() != null) && (speciesAlias.getStatePrefix() != null)) {
+        if (!uoiText.equals("")) {
+          uoiText = uoiText.concat("; ");
+        }
+        if (!speciesAlias.getStatePrefix().equals("free input")) {
+          uoiText = uoiText.concat(speciesAlias.getStatePrefix()).concat(":");
+        }
+        uoiText = uoiText.concat(speciesAlias.getStateLabel());
+      }
+    }
+
+    if (!uoiText.contains("ct:")) {
+      if (alias instanceof Rna) {
+        if (!uoiText.equals("")) {
+          uoiText = uoiText.concat("; ");
+        }
+        uoiText = uoiText.concat("ct:RNA");
+      }
+      if (alias instanceof AntisenseRna) {
+        if (!uoiText.equals("")) {
+          uoiText = uoiText.concat("; ");
+        }
+        uoiText = uoiText.concat("ct:antisenseRNA");
+      }
+      if (alias instanceof Gene) {
+        if (!uoiText.equals("")) {
+          uoiText = uoiText.concat("; ");
+        }
+        uoiText = uoiText.concat("ct:gene");
+      }
+    }
+
+    if (!uoiText.equals("")) {
+      uoiGlyph = new Glyph();
+      uoiGlyph.setClazz(GlyphClazz.UNIT_OF_INFORMATION.getClazz());
+      uoiGlyph.setId(alias.getElementId().concat("uoi"));
+
+      Label label = new Label();
+      label.setText(uoiText);
+      uoiGlyph.setLabel(label);
+
+      Bbox bbox = new Bbox();
+      bbox.setX((float) (alias.getX() + UNIT_OF_INFORMATION_MARGIN));
+      bbox.setY((float) (alias.getY() - UNIT_OF_INFORMATION_HEIGHT / 2));
+      bbox.setH((float) UNIT_OF_INFORMATION_HEIGHT);
+      bbox.setW((float) (alias.getWidth() - 2 * UNIT_OF_INFORMATION_MARGIN));
+      uoiGlyph.setBbox(bbox);
+    }
+
+    return uoiGlyph;
+  }
+
+  /**
+   * Returns process glyph created based on reaction's center point.
+   * 
+   * @param reaction
+   *          reaction to be parsed
+   * @return process glyph for given reaction
+   */
+  private Glyph getProcessGlyphFromReaction(Reaction reaction) {
+    Glyph processGlyph = new Glyph();
+    processGlyph.setId(reaction.getIdReaction());
+    processGlyph.setClazz(getGlyphClazzFromReaction(reaction).getClazz());
+    Bbox bbox = new Bbox();
+
+    Line2D line = reaction.getCenterLine();
+    Point2D startPoint = line.getP1();
+    Point2D endPoint = line.getP2();
+
+    double pointX = (startPoint.getX() + endPoint.getX()) / 2;
+    double pointY = (startPoint.getY() + endPoint.getY()) / 2;
+    Point2D pointNW = new Point2D.Double(pointX - ReactionConverter.RECT_SIZE / 2,
+        pointY - ReactionConverter.RECT_SIZE / 2);
+    bbox.setX((float) pointNW.getX());
+    bbox.setY((float) pointNW.getY());
+    bbox.setH((float) ReactionConverter.RECT_SIZE);
+    bbox.setW((float) ReactionConverter.RECT_SIZE);
+
+    processGlyph.setBbox(bbox);
+
+    Port reactantPort = new Port();
+    reactantPort.setId(reaction.getIdReaction().concat(".1"));
+    sourceTargetMap.put(reactantPort.getId(), reactantPort);
+
+    Port productPort = new Port();
+    productPort.setId(reaction.getIdReaction().concat(".2"));
+    sourceTargetMap.put(productPort.getId(), productPort);
+
+    // Set glyph orientation and ports' coordinates.
+    double reactantDxAverage = 0.0;
+    double reactantDyAverage = 0.0;
+    double productDxAverage = 0.0;
+    double productDyAverage = 0.0;
+
+    for (Reactant r : reaction.getReactants()) {
+      Point2D reactantPoint;
+      List<Point2D> reactantArcPoints = r.getLine().getPoints();
+      if (reaction instanceof HeterodimerAssociationReaction) {
+        reactantPoint = reactantArcPoints.get(reactantArcPoints.size() - 1);
+      } else {
+        reactantPoint = reactantArcPoints.get(reactantArcPoints.size() - 2);
+      }
+      reactantDxAverage += reactantPoint.getX() - pointX;
+      reactantDyAverage += reactantPoint.getY() - pointY;
+    }
+    reactantDxAverage /= reaction.getReactants().size();
+    reactantDyAverage /= reaction.getReactants().size();
+
+    for (Product p : reaction.getProducts()) {
+      List<Point2D> productArcPoints = p.getLine().getPoints();
+      Point2D productPoint;
+      if (reaction instanceof DissociationReaction) {
+        productPoint = productArcPoints.get(0);
+      } else {
+        productPoint = productArcPoints.get(1);
+      }
+      productDxAverage += productPoint.getX() - pointX;
+      productDyAverage += productPoint.getY() - pointY;
+    }
+    productDxAverage /= reaction.getProducts().size();
+    productDyAverage /= reaction.getProducts().size();
+
+    boolean horizontalOrientation;
+    if ((reactantDxAverage * productDxAverage < 0) && (reactantDyAverage * productDyAverage < 0)) {
+      horizontalOrientation = (Math.abs(productDxAverage - reactantDxAverage) > Math
+          .abs(productDyAverage - reactantDyAverage));
+    } else {
+      horizontalOrientation = (reactantDxAverage * productDxAverage < 0);
+    }
+    if (horizontalOrientation) {
+      processGlyph.setOrientation("horizontal");
+      reactantPort.setY((float) pointY);
+      productPort.setY((float) pointY);
+      if (reactantDxAverage < 0) {
+        reactantPort.setX((float) (pointX - PROCESS_PORT_DISTANCE));
+        productPort.setX((float) (pointX + PROCESS_PORT_DISTANCE));
+      } else {
+        reactantPort.setX((float) (pointX + PROCESS_PORT_DISTANCE));
+        productPort.setX((float) (pointX - PROCESS_PORT_DISTANCE));
+      }
+    } else {
+      reactantPort.setX((float) pointX);
+      productPort.setX((float) pointX);
+      if (reactantDyAverage < 0) {
+        reactantPort.setY((float) (pointY - PROCESS_PORT_DISTANCE));
+        productPort.setY((float) (pointY + PROCESS_PORT_DISTANCE));
+      } else {
+        reactantPort.setY((float) (pointY + PROCESS_PORT_DISTANCE));
+        productPort.setY((float) (pointY - PROCESS_PORT_DISTANCE));
+      }
+      processGlyph.setOrientation("vertical");
+    }
+
+    processGlyph.getPort().add(reactantPort);
+    processGlyph.getPort().add(productPort);
+
+    sourceTargetMap.put(processGlyph.getId(), processGlyph);
+
+    return processGlyph;
+  }
+
+  /**
+   * Returns {@link GlyphClazz} appropriate to given reaction.
+   * 
+   * @param reaction
+   *          {@link Reaction} to extract {@link GlyphClazz} from
+   * @return {@link GlyphClazz} appropriate to given reaction
+   */
+  private GlyphClazz getGlyphClazzFromReaction(Reaction reaction) {
+    if (reaction instanceof StateTransitionReaction) {
+      return GlyphClazz.PROCESS;
+    }
+    if (reaction instanceof HeterodimerAssociationReaction) {
+      return GlyphClazz.ASSOCIATION;
+    }
+    if (reaction instanceof DissociationReaction) {
+      return GlyphClazz.DISSOCIATION;
+    }
+    if (reaction instanceof KnownTransitionOmittedReaction) {
+      return GlyphClazz.OMITTED_PROCESS;
+    }
+    if (reaction instanceof UnknownTransitionReaction) {
+      return GlyphClazz.UNCERTAIN_PROCESS;
+    }
+    throw new InvalidArgumentException();
+  }
+
+  /**
+   * Returns arc extracted from given reduced notation reaction.
+   * 
+   * @param reaction
+   *          reduced notation reaction
+   * @return arc extracted from given reduced notation reaction
+   */
+  private Arc getArcFromReducedReaction(Reaction reaction) {
+    if ((reaction.getReactants().size() != 1) || (reaction.getProducts().size() != 1)) {
+      throw new InvalidArgumentException();
+    }
+    Arc arc = new Arc();
+    arc.setId(reaction.getIdReaction());
+
+    if (reaction instanceof NegativeInfluenceReaction) {
+      arc.setClazz(ArcClazz.INHIBITION.getClazz());
+    } else if (reaction instanceof ReducedModulationReaction) {
+      arc.setClazz(ArcClazz.MODULATION.getClazz());
+    } else if (reaction instanceof ReducedTriggerReaction) {
+      arc.setClazz(ArcClazz.NECESSARY_STIMULATION.getClazz());
+    } else if (reaction instanceof ReducedPhysicalStimulationReaction) {
+      arc.setClazz(ArcClazz.STIMULATION.getClazz());
+    } else {
+      throw new InvalidArgumentException();
+    }
+
+    if (reaction.getProducts().get(0).getElement() instanceof Phenotype) {
+      logger.warn("Found Phenotype being a reactant in process. That is discouraged");
+    }
+
+    arc.setSource(sourceTargetMap.get(reaction.getReactants().get(0).getElement().getElementId()));
+    arc.setTarget(sourceTargetMap.get(reaction.getProducts().get(0).getElement().getElementId()));
+
+    List<Point2D> pointList = reaction.getReactants().get(0).getLine().getPoints();
+    pointList.addAll(reaction.getProducts().get(0).getLine().getPoints());
+
+    removeRedundantPoints(pointList);
+
+    Start start = new Start();
+    start.setX((float) pointList.get(0).getX());
+    start.setY((float) pointList.get(0).getY());
+    arc.setStart(start);
+
+    End end = new End();
+    end.setX((float) pointList.get(pointList.size() - 1).getX());
+    end.setY((float) pointList.get(pointList.size() - 1).getY());
+    arc.setEnd(end);
+
+    for (int i = 1; i < pointList.size() - 1; i++) {
+      Point2D nextPoint = pointList.get(i);
+      Next next = new Next();
+      next.setX((float) nextPoint.getX());
+      next.setY((float) nextPoint.getY());
+      arc.getNext().add(next);
+    }
+
+    return arc;
+  }
+
+  /**
+   * Removes redundant points from the list.
+   * 
+   * @param pointList
+   *          list of points to be fixed
+   */
+  private void removeRedundantPoints(List<Point2D> pointList) {
+    boolean allDone = false;
+    while (!allDone) {
+      allDone = true;
+      for (int i = 1; i < pointList.size() - 1; i++) {
+        double dx1 = pointList.get(i).getX() - pointList.get(i - 1).getX();
+        double dy1 = pointList.get(i).getY() - pointList.get(i - 1).getY();
+        double dx2 = pointList.get(i + 1).getX() - pointList.get(i).getX();
+        double dy2 = pointList.get(i + 1).getY() - pointList.get(i).getY();
+
+        DoubleComparator doubleComparator = new DoubleComparator();
+        if (((doubleComparator.compare(dy1 / dx1, dy2 / dx2) == 0)
+            || (pointList.get(i - 1).getY() == pointList.get(i).getY())
+                && (pointList.get(i).getY() == pointList.get(i + 1).getY()))
+            && between(pointList.get(i).getX(), pointList.get(i - 1).getX(), pointList.get(i + 1).getX())) {
+          pointList.remove(i);
+          allDone = false;
+        }
+      }
+    }
+  }
+
+  /**
+   * Checks if argument x is between s1 and s2.
+   * 
+   * @param x
+   *          number to checked if it is in the middle
+   * @param s1
+   *          one side argument
+   * @param s2
+   *          second side argument
+   * @return true if x is between s1 and s2
+   */
+  private boolean between(double x, double s1, double s2) {
+    if ((x >= s1) && (x <= s2)) {
+      return true;
+    }
+    if ((x <= s1) && (x >= s2)) {
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * Returns set of all arcs used in the reaction.
+   * 
+   * @param reaction
+   *          the reaction to extract arcs from
+   * @param glyphList
+   *          list of all glyphs in the map; used only for parsing operators
+   * @return set of all arcs used in the reaction
+   */
+  private List<Arc> getArcsFromReaction(Reaction reaction, List<Glyph> glyphList) {
+    List<Arc> arcList = new ArrayList<>();
+
+    // Parse all nodes except NodeOperators
+    for (AbstractNode node : reaction.getNodes().stream().filter(n -> !(n instanceof NodeOperator))
+        .collect(Collectors.toList())) {
+      try {
+        arcList.add(getArcFromNode(node, glyphList));
+      } catch (InvalidArgumentException ex) {
+        logger.warn("Node skipped in export process, since it is not compliant with SBGN-ML format: "
+            + node.getClass().getName());
+        continue;
+      }
+    }
+
+    // Now parse NodeOperators
+    for (AbstractNode node : reaction.getOperators().stream().filter(o -> {
+      if (o.getInputs().stream().filter(i -> i instanceof Reactant).count() > 0) {
+        return false;
+      }
+      if (o instanceof SplitOperator || o instanceof AssociationOperator || o instanceof DissociationOperator) {
+        return false;
+      }
+      return true;
+    }).collect(Collectors.toList())) {
+      try {
+        arcList.add(getArcFromNode(node, glyphList));
+      } catch (InvalidArgumentException ex) {
+        logger.warn("Node skipped in export process, since it is not compliant with SBGN-ML format: "
+            + node.getClass().getName());
+        continue;
+      }
+    }
+
+    return arcList;
+
+  }
+
+  /**
+   * Returns arc for given node.
+   * 
+   * @param node
+   *          node to parse arc from
+   * @param glyphList
+   *          list of all glyphs in the map; used only for parsing operators
+   * @return SBGN-ML arc for given node
+   */
+  private Arc getArcFromNode(AbstractNode node, List<Glyph> glyphList) {
+    Arc arc = new Arc();
+    arc.setId("arc".concat(Integer.toString(arcCounter)));
+    arcCounter += 1;
+
+    boolean logicArc = false;
+    if (node instanceof Modifier) {
+      for (NodeOperator operator : node.getReaction().getOperators()) {
+        if (operator.getInputs().contains(node)) {
+          logicArc = true;
+        }
+      }
+    }
+    if (logicArc) {
+      arc.setClazz(ArcClazz.LOGIC_ARC.getClazz());
+    } else {
+      arc.setClazz(getArcClazzFromNode(node));
+    }
+
+    if (node instanceof Reactant) {
+      arc.setSource(sourceTargetMap.get(((Reactant) node).getElement().getElementId()));
+      arc.setTarget(sourceTargetMap.get(node.getReaction().getIdReaction().concat(".1")));
+    } else if (node instanceof Product) {
+      arc.setSource(sourceTargetMap.get(node.getReaction().getIdReaction().concat(".2")));
+      arc.setTarget(sourceTargetMap.get(((Product) node).getElement().getElementId()));
+    } else if (node instanceof Modifier) {
+      arc.setSource(sourceTargetMap.get(((Modifier) node).getElement().getElementId()));
+      if (!node.getLine().getEndAtd().getArrowType().equals(ArrowType.NONE)) {
+        arc.setTarget(sourceTargetMap.get(node.getReaction().getIdReaction()));
+      } else {
+        for (NodeOperator operator : node.getReaction().getOperators()) {
+          if (operator.getInputs().contains(node)) {
+            if (!parsedOperators.contains(operator)) {
+              Glyph newOperator = operatorToGlyph(operator);
+              glyphList.add(newOperator);
+            }
+            arc.setTarget(sourceTargetMap.get(operatorIds.get(operator).concat(".1")));
+          }
+        }
+      }
+    } else if (node instanceof NodeOperator) {
+      if ((node instanceof DissociationOperator) || (node instanceof AssociationOperator)) {
+        throw new InvalidArgumentException();
+      }
+      arc.setSource(sourceTargetMap.get(operatorIds.get(node).concat(".2")));
+      if (!node.getLine().getEndAtd().getArrowType().equals(ArrowType.NONE)) {
+        arc.setTarget(sourceTargetMap.get(node.getReaction().getIdReaction()));
+      } else {
+        for (NodeOperator operator : node.getReaction().getOperators()) {
+          if (operator.getInputs().contains(node)) {
+            if (!parsedOperators.contains(operator)) {
+              Glyph newOperator = operatorToGlyph(operator);
+              glyphList.add(newOperator);
+            }
+            arc.setTarget(sourceTargetMap.get(operatorIds.get(operator).concat(".1")));
+          }
+        }
+      }
+    }
+
+    List<Point2D> arcPoints = node.getLine().getPoints();
+    Start start = new Start();
+    if ((node instanceof Product) || (node instanceof NodeOperator)) {
+      Port sourcePort = (Port) arc.getSource();
+      start.setX(sourcePort.getX());
+      start.setY(sourcePort.getY());
+    } else {
+      start.setX((float) arcPoints.get(0).getX());
+      start.setY((float) arcPoints.get(0).getY());
+    }
+    arc.setStart(start);
+
+    End end = new End();
+    if ((node instanceof Reactant) || ((node instanceof Modifier) && (arc.getTarget() instanceof Port))) {
+      Port targetPort = (Port) arc.getTarget();
+      end.setX(targetPort.getX());
+      end.setY(targetPort.getY());
+    } else {
+      Point2D lastPoint = arcPoints.get(arcPoints.size() - 1);
+      end.setX((float) lastPoint.getX());
+      end.setY((float) lastPoint.getY());
+    }
+    arc.setEnd(end);
+
+    if ((node instanceof Product) && (node.getReaction() instanceof DissociationReaction)) {
+      Point2D nextPoint = arcPoints.get(0);
+      Next next = new Next();
+      next.setX((float) nextPoint.getX());
+      next.setY((float) nextPoint.getY());
+      arc.getNext().add(next);
+    }
+
+    DoubleComparator doubleComparator = new DoubleComparator();
+    for (int i = 1; i < arcPoints.size() - 1; i++) {
+      Point2D nextPoint = arcPoints.get(i);
+      if ((doubleComparator.compare(nextPoint.getX(), new Double(start.getX())) == 0)
+          && (doubleComparator.compare(nextPoint.getY(), new Double(start.getY())) == 0)) {
+        arc.getNext().clear();
+        continue;
+      }
+      if ((doubleComparator.compare(nextPoint.getX(), new Double(end.getX())) == 0)
+          && (doubleComparator.compare(nextPoint.getY(), new Double(end.getY())) == 0)) {
+        break;
+      }
+      Next next = new Next();
+      next.setX((float) nextPoint.getX());
+      next.setY((float) nextPoint.getY());
+      arc.getNext().add(next);
+    }
+
+    if ((node instanceof Reactant) && (node.getReaction() instanceof HeterodimerAssociationReaction)) {
+      Point2D nextPoint = arcPoints.get(arcPoints.size() - 1);
+      Next next = new Next();
+      next.setX((float) nextPoint.getX());
+      next.setY((float) nextPoint.getY());
+      arc.getNext().add(next);
+    }
+
+    return arc;
+  }
+
+  /**
+   * Returns {@link ArcClazz} for given node.
+   * 
+   * @param node
+   *          Node to extract {@link ArcClazz} from
+   * @return {@link ArcClazz} for given node
+   */
+  private String getArcClazzFromNode(AbstractNode node) {
+    if (node instanceof Reactant) {
+      return ArcClazz.CONSUMPTION.getClazz();
+    }
+    if (node instanceof Product) {
+      return ArcClazz.PRODUCTION.getClazz();
+    }
+    if (node instanceof Catalysis) {
+      return ArcClazz.CATALYSIS.getClazz();
+    }
+    if (node instanceof Inhibition) {
+      return ArcClazz.INHIBITION.getClazz();
+    }
+    if (node instanceof Modulation) {
+      return ArcClazz.MODULATION.getClazz();
+    }
+    if (node instanceof Trigger) {
+      return ArcClazz.NECESSARY_STIMULATION.getClazz();
+    }
+    if (node instanceof PhysicalStimulation) {
+      return ArcClazz.STIMULATION.getClazz();
+    }
+    if (node instanceof NodeOperator) {
+      ArrowType arrowType = node.getLine().getEndAtd().getArrowType();
+      switch (arrowType) {
+      case BLANK:
+        return ArcClazz.STIMULATION.getClazz();
+      case BLANK_CROSSBAR:
+        return ArcClazz.NECESSARY_STIMULATION.getClazz();
+      case CIRCLE:
+        return ArcClazz.CATALYSIS.getClazz();
+      case CROSSBAR:
+        return ArcClazz.INHIBITION.getClazz();
+      case DIAMOND:
+        return ArcClazz.MODULATION.getClazz();
+      case NONE:
+        return ArcClazz.LOGIC_ARC.getClazz();
+      default:
+        throw new InvalidArgumentException();
+
+      }
+    }
+    throw new InvalidArgumentException();
+  }
+}
diff --git a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java
index 3733c04f545ddf0b3ee7bfc46508dcc1750c2634..c38a6e2e9482a7509ab690f8e0306f6303f6a03c 100644
--- a/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java
+++ b/converter-SBGNML/src/main/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParser.java
@@ -1,1535 +1,1550 @@
-package lcsb.mapviewer.converter.model.sbgnml;
-
-import java.awt.Color;
-import java.awt.geom.Line2D;
-import java.awt.geom.Point2D;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.log4j.Logger;
-import org.sbgn.ArcClazz;
-import org.sbgn.GlyphClazz;
-import org.sbgn.SbgnUtil;
-import org.sbgn.bindings.Arc;
-import org.sbgn.bindings.Arc.End;
-import org.sbgn.bindings.Arc.Next;
-import org.sbgn.bindings.Arc.Start;
-import org.sbgn.bindings.Bbox;
-import org.sbgn.bindings.Glyph;
-import org.sbgn.bindings.Map;
-import org.sbgn.bindings.Port;
-import org.sbgn.bindings.Sbgn;
-
-import lcsb.mapviewer.common.comparator.DoubleComparator;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.converter.ConverterParams;
-import lcsb.mapviewer.converter.InvalidInputDataExecption;
-import lcsb.mapviewer.converter.graphics.bioEntity.element.species.SpeciesConverter;
-import lcsb.mapviewer.converter.model.celldesigner.types.ModifierType;
-import lcsb.mapviewer.converter.model.celldesigner.types.ModifierTypeUtils;
-import lcsb.mapviewer.converter.model.sbgnml.structures.Process;
-import lcsb.mapviewer.model.graphics.ArrowType;
-import lcsb.mapviewer.model.graphics.ArrowTypeData;
-import lcsb.mapviewer.model.graphics.LineType;
-import lcsb.mapviewer.model.graphics.PolylineData;
-import lcsb.mapviewer.model.map.compartment.Compartment;
-import lcsb.mapviewer.model.map.compartment.SquareCompartment;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelFullIndexed;
-import lcsb.mapviewer.model.map.modifier.Catalysis;
-import lcsb.mapviewer.model.map.modifier.Inhibition;
-import lcsb.mapviewer.model.map.modifier.Modulation;
-import lcsb.mapviewer.model.map.modifier.PhysicalStimulation;
-import lcsb.mapviewer.model.map.modifier.Trigger;
-import lcsb.mapviewer.model.map.reaction.AndOperator;
-import lcsb.mapviewer.model.map.reaction.Modifier;
-import lcsb.mapviewer.model.map.reaction.NodeOperator;
-import lcsb.mapviewer.model.map.reaction.OrOperator;
-import lcsb.mapviewer.model.map.reaction.Product;
-import lcsb.mapviewer.model.map.reaction.Reactant;
-import lcsb.mapviewer.model.map.reaction.Reaction;
-import lcsb.mapviewer.model.map.reaction.SplitOperator;
-import lcsb.mapviewer.model.map.reaction.type.KnownTransitionOmittedReaction;
-import lcsb.mapviewer.model.map.reaction.type.NegativeInfluenceReaction;
-import lcsb.mapviewer.model.map.reaction.type.ReducedModulationReaction;
-import lcsb.mapviewer.model.map.reaction.type.ReducedPhysicalStimulationReaction;
-import lcsb.mapviewer.model.map.reaction.type.ReducedTriggerReaction;
-import lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction;
-import lcsb.mapviewer.model.map.reaction.type.UnknownTransitionReaction;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.Degraded;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.Gene;
-import lcsb.mapviewer.model.map.species.GenericProtein;
-import lcsb.mapviewer.model.map.species.Phenotype;
-import lcsb.mapviewer.model.map.species.Protein;
-import lcsb.mapviewer.model.map.species.Rna;
-import lcsb.mapviewer.model.map.species.SimpleMolecule;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.Unknown;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-/**
- * This class is a parser for SBGN-ML files.
- * 
- * @author Michał Kuźma
- *
- */
-public class SbgnmlXmlParser {
-
-	/**
-	 * Default class logger.
-	 */
-	private Logger							logger										 = Logger.getLogger(SbgnmlXmlParser.class.getName());
-
-	/**
-	 * List of all processes to be parsed.
-	 */
-	private List<Process>				processes									 = new ArrayList<Process>();
-
-	/**
-	 * List of all logic operator glyphs parsed so far.
-	 */
-	private List<Glyph>					logicOperators						 = new ArrayList<Glyph>();
-
-	/**
-	 * List of all logic arcs parsed so far.
-	 */
-	private List<Arc>						logicArcs									 = new ArrayList<Arc>();
-
-	/**
-	 * Default margin for container name.
-	 */
-	private static final double	CONTAINER_NAME_MARGIN			 = 5.0;
-
-	/**
-	 * Part of height of the line used to cross degraded circle that goes behind
-	 * this circle.
-	 */
-	private static final int		CROSS_LINE_EXTENDED_LENGTH = 7;
-
-	/**
-	 * Default color for parsed compartments.
-	 */
-	private static final Color	COMPARTMENT_COLOR					 = new Color(0.5f, 0.5f, 1.0f);
-
-	/**
-	 * Method used to create a model from SBGN-ML file.
-	 * 
-	 * @param params
-	 *          parameters needed for parsing file and creating a model
-	 * @return valid model parsed from the file
-	 * @throws InvalidInputDataExecption
-	 *           thrown when input file is invalid
-	 */
-	public Model createModel(ConverterParams params) throws InvalidInputDataExecption {
-
-		Model model = new ModelFullIndexed(null);
-		model.setIdModel(params.getFilename());
-
-		// Input file
-		File inputSbgnmlFile = inputStreamToFile(params.getInputStream());
-
-		Sbgn sbgnData;
-		// Check if input file has valid SBGN-ML data
-		try {
-			if (!SbgnUtil.isValid(inputSbgnmlFile)) {
-				throw new InvalidInputDataExecption("Given input is not a valid SBGN-ML file.");
-			}
-
-			// Read data from file
-			sbgnData = SbgnUtil.readFromFile(inputSbgnmlFile);
-		} catch (InvalidInputDataExecption ex) {
-			throw ex;
-		} catch (Exception ex) {
-			throw new InvalidInputDataExecption("Unable to read given file.", ex);
-		}
-
-		// Extract map with all the glyphs and arcs
-		Map map = sbgnData.getMap();
-
-		adjustSizeOfElements(map);
-
-		setModelSize(map, model);
-
-		// Iterate over every glyph
-		for (Glyph g : map.getGlyph()) {
-			parseGlyph(g, model);
-		}
-
-		// Iterate over every arc in the map
-		for (Arc a : map.getArc()) {
-			parseArc(a, model);
-		}
-
-		// Parse all processes created before
-		for (Process p : processes) {
-			try {
-				parseProcess(p, model);
-			} catch (Exception e) {
-				logger.warn("Unable to parse the process: " + p.getCentralPoint().getId());
-			}
-		}
-
-		return model;
-	}
-
-	/**
-	 * Writes input stream into a File.
-	 * 
-	 * @param inputStream
-	 *          Input stream to be written to File
-	 * @return File handle
-	 */
-	private File inputStreamToFile(InputStream inputStream) {
-		File tempFile = null;
-		try {
-			tempFile = File.createTempFile("stream2file", ".tmp");
-			tempFile.deleteOnExit();
-			try (FileOutputStream out = new FileOutputStream(tempFile)) {
-				IOUtils.copy(inputStream, out);
-			}
-		} catch (Exception ex) {
-			logger.debug("Unable to create temporary file.");
-			return null;
-		}
-		return tempFile;
-	}
-
-	/**
-	 * Method used to adjust the size of elements that have their size represented
-	 * different in the SBGN-ML file. Adjusted elements: Source and Sink /
-	 * Degraded elements, Multimers.
-	 * 
-	 * @param map
-	 *          Map parsed from SBGN-ML file
-	 */
-	private void adjustSizeOfElements(Map map) {
-		for (Glyph g : map.getGlyph()) {
-			GlyphClazz glyphClazz = GlyphClazz.fromClazz(g.getClazz());
-			switch (glyphClazz) {
-				case SOURCE_AND_SINK:
-					g.getBbox().setH(g.getBbox().getH() + 2 * CROSS_LINE_EXTENDED_LENGTH);
-					g.getBbox().setW(g.getBbox().getW() + 2 * CROSS_LINE_EXTENDED_LENGTH);
-					g.getBbox().setX(g.getBbox().getX() - CROSS_LINE_EXTENDED_LENGTH);
-					g.getBbox().setY(g.getBbox().getY() - CROSS_LINE_EXTENDED_LENGTH);
-					break;
-				case COMPLEX_MULTIMER:
-				case MACROMOLECULE_MULTIMER:
-				case NUCLEIC_ACID_FEATURE_MULTIMER:
-				case SIMPLE_CHEMICAL_MULTIMER:
-					int cardinality;
-					try {
-						cardinality = getMultimerCardinality(g);
-					} catch (Exception ex) {
-						cardinality = 2;
-						logger.warn(ex.getMessage() + " Set the default value of 2.");
-					}
-					g.getBbox().setW(g.getBbox().getW() + (cardinality - 1) * SpeciesConverter.HOMODIMER_OFFSET);
-					g.getBbox().setH(g.getBbox().getH() + (cardinality - 1) * SpeciesConverter.HOMODIMER_OFFSET);
-					break;
-				default:
-					break;
-			}
-		}
-	}
-
-	/**
-	 * Method used to compute height and width of the model.
-	 * 
-	 * @param map
-	 *          Map parsed from SBGN-ML file
-	 * @param model
-	 *          Model to be updated
-	 */
-	private void setModelSize(Map map, Model model) {
-		double minX = Double.MAX_VALUE;
-		double minY = Double.MAX_VALUE;
-		double maxX = 0;
-		double maxY = 0;
-
-		// Iterate over every glyph
-		for (Glyph g : map.getGlyph()) {
-			if (GlyphClazz.fromClazz(g.getClazz()).equals(GlyphClazz.ANNOTATION) || GlyphClazz.fromClazz(g.getClazz()).equals(GlyphClazz.TAG)) {
-				continue;
-			}
-			Bbox bbox = g.getBbox();
-			if (bbox != null) {
-				if (bbox.getX() < minX) {
-					minX = bbox.getX();
-				}
-				if (bbox.getY() < minY) {
-					minY = bbox.getY();
-				}
-				if (bbox.getX() + bbox.getW() > maxX) {
-					maxX = bbox.getX() + bbox.getW();
-				}
-				if (bbox.getY() + bbox.getH() > maxY) {
-					maxY = bbox.getY() + bbox.getH();
-				}
-			}
-		}
-
-		// Iterate over every arc
-		for (Arc a : map.getArc()) {
-			// Since submaps are not yet supported, the arcs connecting them or
-			// tags cannot be used when computing width and height of the model.
-			boolean connectsTagOrSubmap = false;
-			if (a.getSource() instanceof Glyph) {
-				Glyph sourceGlyph = (Glyph) a.getSource();
-				if (GlyphClazz.fromClazz(sourceGlyph.getClazz()).equals(GlyphClazz.TAG) || GlyphClazz.fromClazz(sourceGlyph.getClazz()).equals(GlyphClazz.SUBMAP)) {
-					connectsTagOrSubmap = true;
-				}
-			}
-			if (a.getTarget() instanceof Glyph) {
-				Glyph targetGlyph = (Glyph) a.getTarget();
-				if (GlyphClazz.fromClazz(targetGlyph.getClazz()).equals(GlyphClazz.TAG) || GlyphClazz.fromClazz(targetGlyph.getClazz()).equals(GlyphClazz.SUBMAP)) {
-					connectsTagOrSubmap = true;
-				}
-			}
-			// If the arc is not connecting a submap or a tag, check it's points
-			if (!connectsTagOrSubmap) {
-				Start aStart = a.getStart();
-				if (aStart.getX() < minX) {
-					minX = aStart.getX();
-				}
-				if (aStart.getX() > maxX) {
-					maxX = aStart.getX();
-				}
-				if (aStart.getY() < minY) {
-					minY = aStart.getY();
-				}
-				if (aStart.getY() > maxY) {
-					maxY = aStart.getY();
-				}
-				End aEnd = a.getEnd();
-				if (aEnd.getX() < minX) {
-					minX = aEnd.getX();
-				}
-				if (aEnd.getX() > maxX) {
-					maxX = aEnd.getX();
-				}
-				if (aEnd.getY() < minY) {
-					minY = aEnd.getY();
-				}
-				if (aEnd.getY() > maxY) {
-					maxY = aEnd.getY();
-				}
-				for (Next aNext : a.getNext()) {
-					if (aNext.getX() < minX) {
-						minX = aNext.getX();
-					}
-					if (aNext.getX() > maxX) {
-						maxX = aNext.getX();
-					}
-					if (aNext.getY() < minY) {
-						minY = aNext.getY();
-					}
-					if (aNext.getY() > maxY) {
-						maxY = aNext.getY();
-					}
-				}
-			}
-		}
-
-		model.setWidth(maxX + minX);
-		model.setHeight(maxY + minY);
-	}
-
-	/**
-	 * Method used to parse a single glyph.
-	 * 
-	 * @param g
-	 *          glyph to be parsed
-	 * @param model
-	 *          model to be updated
-	 * @throws Exception
-	 */
-	private void parseGlyph(Glyph g, Model model) {
-		Species newSpecies = null;
-		switch (GlyphClazz.fromClazz(g.getClazz())) {
-			case AND:
-			case NOT:
-			case OR:
-				logicOperators.add(g);
-				break;
-			case COMPARTMENT:
-				parseCompartment(g, model);
-				break;
-			case COMPLEX:
-				parseComplex(g, null, true, model);
-				break;
-			case COMPLEX_MULTIMER:
-				parseComplex(g, null, false, model);
-				break;
-			case MACROMOLECULE:
-				newSpecies = new GenericProtein(g.getId());
-				parseSpecies(g, newSpecies, true, model);
-				break;
-			case MACROMOLECULE_MULTIMER:
-				newSpecies = new GenericProtein(g.getId());
-				parseSpecies(g, newSpecies, false, model);
-				break;
-			case NUCLEIC_ACID_FEATURE:
-				if (isRNA(g)) {
-					newSpecies = new Rna(g.getId());
-				} else {
-					newSpecies = new Gene(g.getId());
-				}
-				parseSpecies(g, newSpecies, true, model);
-				break;
-			case NUCLEIC_ACID_FEATURE_MULTIMER:
-				if (isRNA(g)) {
-					newSpecies = new Rna(g.getId());
-				} else {
-					newSpecies = new Gene(g.getId());
-				}
-				parseSpecies(g, newSpecies, false, model);
-				break;
-			case PERTURBING_AGENT:
-				newSpecies = new Phenotype(g.getId());
-				parseSpecies(g, newSpecies, true, model);
-				break;
-			case PHENOTYPE:
-				newSpecies = new Phenotype(g.getId());
-				parseSpecies(g, newSpecies, true, model);
-				break;
-			case ASSOCIATION:
-			case DISSOCIATION:
-			case OMITTED_PROCESS:
-			case PROCESS:
-			case UNCERTAIN_PROCESS:
-				processes.add(new Process(g));
-				break;
-			case SIMPLE_CHEMICAL:
-				newSpecies = new SimpleMolecule(g.getId());
-				parseSpecies(g, newSpecies, true, model);
-				break;
-			case SIMPLE_CHEMICAL_MULTIMER:
-				newSpecies = new SimpleMolecule(g.getId());
-				parseSpecies(g, newSpecies, false, model);
-				break;
-			case SOURCE_AND_SINK:
-				newSpecies = new Degraded(g.getId());
-				parseSpecies(g, newSpecies, true, model);
-				break;
-			case TAG:
-			case SUBMAP:
-				logger.warn("Submaps are not supported. Glyph: " + g.getId() + " has not been parsed.");
-			case UNSPECIFIED_ENTITY:
-				newSpecies = new Unknown(g.getId());
-				parseSpecies(g, newSpecies, true, model);
-				break;
-			default:
-				logger.warn("The glyph " + g.getId() + " of class " + g.getClazz() + " has not been parsed, since it is invalid for SBGN PD map.");
-				break;
-		}
-	}
-
-	/**
-	 * Method used to parse a single arc.
-	 * 
-	 * @param a
-	 *          arc to be parsed
-	 * @param model
-	 *          model to be updated
-	 */
-	private void parseArc(Arc a, Model model) {
-		switch (ArcClazz.fromClazz(a.getClazz())) {
-			case CONSUMPTION:
-				Port arcTargetPort = (Port) a.getTarget();
-				for (Process p : processes) {
-					if (p.getCentralPoint().getPort().contains(arcTargetPort)) {
-						p.addReagentArc(a);
-						break;
-					}
-				}
-				break;
-			case PRODUCTION:
-				Port arcSourcePort = (Port) a.getSource();
-				for (Process p : processes) {
-					if (p.getCentralPoint().getPort().contains(arcSourcePort)) {
-						p.addProductArc(a);
-						break;
-					}
-				}
-				break;
-			case EQUIVALENCE_ARC:
-				logger.warn("Submaps are not supported. Equivalence arc: " + a.getId() + " has not been parsed.");
-				break;
-			case LOGIC_ARC:
-				logicArcs.add(a);
-				break;
-			case CATALYSIS:
-			case INHIBITION:
-			case MODULATION:
-			case NECESSARY_STIMULATION:
-			case STIMULATION:
-				Glyph targetGlyph = (Glyph) a.getTarget();
-				if (GlyphClazz.fromClazz(targetGlyph.getClazz()).equals(GlyphClazz.PHENOTYPE)) {
-					if (!(a.getSource() instanceof Glyph)) {
-						logger.warn("Invalid phenotype arc: " + a.getId());
-						break;
-					}
-					try {
-						parsePhenotypeArc(a, model);
-					} catch (Exception ex) {
-						logger.warn(ex.getMessage());
-					}
-					break;
-				}
-				if (a.getSource() instanceof Glyph) {
-					Glyph sourceGlyph = (Glyph) a.getSource();
-					if (GlyphClazz.fromClazz(sourceGlyph.getClazz()).equals(GlyphClazz.PHENOTYPE)
-							&& (model.getElementByElementId(targetGlyph.getId()) instanceof Species)) {
-						try {
-							parsePhenotypeArc(a, model);
-						} catch (InvalidArgumentException ex) {
-							logger.warn("The arc " + a.getId() + " of class " + a.getClazz() + " is not a valid reduced notation arc.");
-						}
-						break;
-					}
-				}
-				for (Process p : processes) {
-					if (p.getCentralPoint().getId().equals(targetGlyph.getId())) {
-						p.addInfluenceArc(a);
-						break;
-					}
-				}
-				break;
-			default:
-				logger.warn("The arc " + a.getId() + " of class " + a.getClazz() + " has not been parsed, since it is invalid for SBGN PD map.");
-		}
-	}
-
-	/**
-	 * Method used to parse arc going to or from a phenotype.
-	 * 
-	 * @param a
-	 *          arc to be parsed
-	 * @param model
-	 *          model to be updated
-	 */
-	private void parsePhenotypeArc(Arc a, Model model) {
-		Reaction reaction;
-
-		switch (ArcClazz.fromClazz(a.getClazz())) {
-
-			case INHIBITION:
-				reaction = new NegativeInfluenceReaction();
-				break;
-			case MODULATION:
-				reaction = new ReducedModulationReaction();
-				break;
-			case NECESSARY_STIMULATION:
-				reaction = new ReducedTriggerReaction();
-				break;
-			case STIMULATION:
-				reaction = new ReducedPhysicalStimulationReaction();
-				break;
-			default:
-				throw new InvalidArgumentException();
-		}
-
-		reaction.setIdReaction(a.getId());
-		reaction.setModel(model);
-
-		Reactant reactant = new Reactant();
-		reactant.setReaction(reaction);
-		Glyph source = (Glyph) a.getSource();
-		reactant.setElement(model.getElementByElementId(source.getId()));
-		List<Point2D> reactantPointList = new ArrayList<>();
-		reactantPointList.add(new Point2D.Double(a.getStart().getX(), a.getStart().getY()));
-		reactantPointList.add(new Point2D.Double(a.getStart().getX(), a.getStart().getY()));
-		PolylineData reactantLine = new PolylineData(reactantPointList);
-		ArrowTypeData atd = new ArrowTypeData();
-		atd.setArrowType(ArrowType.NONE);
-		atd.setArrowLineType(LineType.SOLID);
-		reactantLine.setEndAtd(atd);
-		reactant.setLine(reactantLine);
-		reaction.addReactant(reactant);
-
-		Product product = new Product();
-		product.setReaction(reaction);
-		Glyph target = (Glyph) a.getTarget();
-		product.setElement(model.getElementByElementId(target.getId()));
-		List<Point2D> productPointList = getLinePoints(a);
-		PolylineData productLine = parseLine(a, productPointList);
-		product.setLine(productLine);
-		reaction.addProduct(product);
-
-		model.addReaction(reaction);
-	}
-
-	/**
-	 * Method used to parse a single species.
-	 * 
-	 * @param g
-	 *          SBGN-ML glyph representing the species
-	 * @param newSpecies
-	 *          species to be parsed
-	 * @param isHomodimer
-	 *          true if parsed species is not multimer
-	 * @param model
-	 *          model to be updated
-	 */
-	private void parseSpecies(Glyph g, Species newSpecies, boolean isHomodimer, Model model) {
-		newSpecies.setModel(model);
-		// If Glyph has label with a name, set it as Species name. If not, set
-		// Id as name.
-		if (g.getLabel() != null) {
-			newSpecies.setName(g.getLabel().getText());
-		} else {
-			newSpecies.setName(g.getId());
-		}
-		// Add species to parent complex if there is one
-		if (newSpecies.getComplex() != null) {
-			newSpecies.getComplex().addSpecies(newSpecies);
-		}
-		// If the species is a multimer, set it's cardinality.
-		if (!isHomodimer) {
-			try {
-				newSpecies.setHomodimer(getMultimerCardinality(g));
-			} catch (Exception ex) {
-				newSpecies.setHomodimer(2);
-				logger.warn(ex.getMessage() + " Set the default value of 2.");
-			}
-		}
-
-		List<Glyph> children = g.getGlyph();
-		for (Glyph child : children) {
-			if (GlyphClazz.fromClazz(child.getClazz()).equals(GlyphClazz.STATE_VARIABLE)) {
-				if (child.getState() == null || child.getState().getVariable() != null) {
-					try {
-						parseStateVariable(child, g, newSpecies);
-					} catch (Exception ex) {
-						logger.warn(ex.getMessage());
-					}
-				} else {
-					String structuralState = child.getState().getValue();
-					if (newSpecies instanceof Protein) {
-						Protein protein = (Protein) newSpecies;
-						protein.setStructuralState(structuralState);
-					} else if (newSpecies instanceof Complex) {
-						Complex complex = (Complex) newSpecies;
-						complex.setStructuralState(structuralState);
-					}
-				}
-			}
-		}
-
-		parseSpecies(g, newSpecies, model);
-	}
-
-	/**
-	 * Method used to create a new alias from SBGN-ML glyph.
-	 * 
-	 * @param glyph
-	 *          SBGN-ML glyph representing the alias
-	 * @param species
-	 *          species of the alias
-	 * @param model
-	 *          model to be updated
-	 */
-	private void parseSpecies(Glyph glyph, Species species, Model model) {
-		species.setHeight(new Double(glyph.getBbox().getH()));
-		species.setWidth(new Double(glyph.getBbox().getW()));
-		species.setX(new Double(glyph.getBbox().getX()));
-		species.setY(new Double(glyph.getBbox().getY()));
-
-		Compartment parentCompartment = null;
-		if (glyph.getCompartmentRef() != null) {
-			Glyph compartmentGlyph = (Glyph) glyph.getCompartmentRef();
-			parentCompartment = model.getElementByElementId(compartmentGlyph.getId());
-		} else if (species.getComplex() == null) {
-			parentCompartment = findParentCompartment(species, model);
-		}
-		if (parentCompartment != null) {
-			species.setCompartment(parentCompartment);
-			parentCompartment.addElement(species);
-		}
-
-		// Parse units of information
-		for (Glyph child : glyph.getGlyph()) {
-			if (GlyphClazz.fromClazz(child.getClazz()).equals(GlyphClazz.UNIT_OF_INFORMATION)) {
-				parseUnitOfInformation(child, species);
-			}
-		}
-
-		model.addElement(species);
-	}
-
-	/**
-	 * Finds a compartment where element should be located (base on the
-	 * coordinates).
-	 * 
-	 * @param child
-	 *          {@link Element} for which we want to find compartment
-	 * @param model
-	 *          {@link Model} where we look for a compartment
-	 * @return parent {@link Compartment}
-	 */
-	private Compartment findParentCompartment(Element child, Model model) {
-		Compartment nullParent = new Compartment("null");
-		nullParent.setWidth(Double.MAX_VALUE);
-		nullParent.setHeight(Double.MAX_VALUE);
-		nullParent.setX(0.0);
-		nullParent.setY(0.0);
-		Compartment parent = nullParent;
-		for (Compartment potentialParent : model.getCompartments()) {
-			if (potentialParent.contains(child)) {
-				if (parent.getSize() > potentialParent.getSize()) {
-					parent = potentialParent;
-				}
-			}
-		}
-		if (parent != nullParent) {
-			return parent;
-		} else {
-			return null;
-		}
-	}
-
-	/**
-	 * Method used to retrieve multimer cardinality from a multimer glyph.
-	 * 
-	 * @param g
-	 *          multimer glyph
-	 * @return multimer cardinality
-	 * @throws Exception
-	 *           Exception is thrown if no proper unit of information with
-	 *           cardinality was found
-	 */
-	private int getMultimerCardinality(Glyph g) throws Exception {
-		int multimerCardinality = 0;
-		// Check all the children nodes looking for unit of information with
-		// cardinality
-		List<Glyph> children = g.getGlyph();
-		for (Glyph child : children) {
-			if (GlyphClazz.fromClazz(child.getClazz()) == GlyphClazz.UNIT_OF_INFORMATION) {
-				String[] splitLabel = child.getLabel().getText().split(":");
-				multimerCardinality = Integer.parseInt(splitLabel[1]);
-			}
-		}
-		// If no unit of information was found, or the cardinality is invalid,
-		// raise exception
-		if (multimerCardinality <= 0) {
-			throw new Exception("No proper unit of information with multimer cardinality was found." + " Glyph: " + g.getId());
-		}
-
-		return multimerCardinality;
-	}
-
-	/**
-	 * Method used to decide if Nucleic-acid feature should be translated to RNA.
-	 * 
-	 * @param g
-	 *          Nucleic-acid feature glyph
-	 * @return true if input is RNA
-	 */
-	private boolean isRNA(Glyph g) {
-		boolean rna = false;
-		// Check all the children nodes looking for unit of information
-		List<Glyph> children = g.getGlyph();
-		for (Glyph child : children) {
-			if (GlyphClazz.fromClazz(child.getClazz()) == GlyphClazz.UNIT_OF_INFORMATION) {
-				if (child.getLabel().getText().toLowerCase().contains("rna")) {
-					rna = true;
-				}
-			}
-		}
-
-		return rna;
-	}
-
-	/**
-	 * Method used to parse state variable.
-	 * 
-	 * @param unitOfInformationGlyph
-	 *          unit of information glyph from sbgn-ml file
-	 * @param speciesGlyph
-	 *          glyph that the unit of information considers
-	 * @param newSpecies
-	 *          species that the unit of information considers
-	 * @throws Exception
-	 *           Exception is thrown if state variable is parsed for species other
-	 *           than Protein
-	 */
-	private void parseStateVariable(Glyph unitOfInformationGlyph, Glyph speciesGlyph, Species newSpecies) throws Exception {
-		if (!(newSpecies instanceof Protein)) {
-			throw new Exception("Only macromolecule elements can have state variables.");
-		}
-		Protein protein = (Protein) newSpecies;
-		ModificationResidue mr = new ModificationResidue();
-
-		mr.setSpecies(protein);
-		mr.setIdModificationResidue(unitOfInformationGlyph.getId());
-		if (unitOfInformationGlyph.getState() != null) {
-			// If State variable consists of value and variable
-			mr.setName(unitOfInformationGlyph.getState().getVariable());
-			for (ModificationState ms : ModificationState.values()) {
-				if (ms.getAbbreviation().equals(unitOfInformationGlyph.getState().getValue())) {
-					mr.setState(ms);
-				}
-			}
-		}
-
-		// Compute the angle from coordinates and dimensions
-		Double stateVarX = new Double(unitOfInformationGlyph.getBbox().getX() + unitOfInformationGlyph.getBbox().getW() / 2 - speciesGlyph.getBbox().getX());
-		Double stateVarY = new Double(unitOfInformationGlyph.getBbox().getY() + unitOfInformationGlyph.getBbox().getH() / 2 - speciesGlyph.getBbox().getY());
-
-		// Angle difference between endpoints of glyph's edge (divided by Pi)
-		final double edgeAngle = 0.5;
-
-		// Starting angle (top-right corner)
-		final double startingAngle = 0.25;
-
-		// Angle of the state variable
-		Double angle = startingAngle;
-
-		double leftSideDif = Math.abs(stateVarX);
-		double rightSideDif = Math.abs(speciesGlyph.getBbox().getW() - stateVarX);
-		double topSideDif = Math.abs(stateVarY);
-		double bottomSideDif = Math.abs(speciesGlyph.getBbox().getH() - stateVarY);
-		double minDif = Math.min(Math.min(leftSideDif, rightSideDif), Math.min(topSideDif, bottomSideDif));
-
-		if (minDif == leftSideDif) {
-			// State variable is located on glyph's left edge
-			angle += edgeAngle + (stateVarY / speciesGlyph.getBbox().getH()) * edgeAngle;
-		} else if (minDif == rightSideDif) {
-			// State variable is located on glyph's right edge
-			angle -= (stateVarY / speciesGlyph.getBbox().getH()) * edgeAngle;
-		} else if (minDif == topSideDif) {
-			// State variable is located on glyph's top edge
-			angle += edgeAngle - (stateVarX / speciesGlyph.getBbox().getW()) * edgeAngle;
-		} else if (minDif == bottomSideDif) {
-			// State variable is located on glyph's bottom edge
-			angle += 2 * edgeAngle + (stateVarX / speciesGlyph.getBbox().getW()) * edgeAngle;
-		}
-
-		mr.setAngle(angle * Math.PI);
-
-		protein.addModificationResidue(mr);
-	}
-
-	/**
-	 * Method used for parsing units of information.
-	 * 
-	 * @param unitOfInformationGlyph
-	 *          unit of information glyph from sbgn-ml file
-	 * @param alias
-	 *          alias that the unit of information concerns
-	 */
-	private void parseUnitOfInformation(Glyph unitOfInformationGlyph, Species alias) {
-		String unitOfInformationText = unitOfInformationGlyph.getLabel().getText();
-		if (unitOfInformationText.contains(":") && !unitOfInformationText.startsWith("N:")) {
-			String unitOfInformationPrefix = unitOfInformationText.substring(0, unitOfInformationText.indexOf(':'));
-			String unitOfInformationSuffix = unitOfInformationText.substring(unitOfInformationText.indexOf(':') + 1);
-			alias.setStatePrefix(unitOfInformationPrefix);
-			alias.setStateLabel(unitOfInformationSuffix);
-		} else if (!unitOfInformationText.startsWith("N:")) {
-			alias.setStateLabel(unitOfInformationText);
-			alias.setStatePrefix("free input");
-		}
-	}
-
-	/**
-	 * Method used for parsing complex species.
-	 * 
-	 * @param complexGlyph
-	 *          complex species glyph from sbgn-ml file
-	 * @param parentComplexSpecies
-	 *          parent complex species
-	 * @param isHomodimer
-	 *          set if the complex is a homodimer
-	 * @param model
-	 *          model to update with the parsed complex species
-	 */
-	private void parseComplex(Glyph complexGlyph, Complex parentComplexSpecies, boolean isHomodimer, Model model) {
-		Complex complexSpecies = new Complex(complexGlyph.getId());
-		if (parentComplexSpecies != null) {
-			complexSpecies.setComplex(parentComplexSpecies);
-		}
-		parseSpecies(complexGlyph, complexSpecies, isHomodimer, model);
-
-		Complex complexAlias = model.getElementByElementId(complexGlyph.getId());
-		for (Glyph child : complexGlyph.getGlyph()) {
-			Species newSpecies;
-			switch (GlyphClazz.fromClazz(child.getClazz())) {
-				case UNSPECIFIED_ENTITY:
-					newSpecies = new Unknown(child.getId());
-					newSpecies.setComplex(complexSpecies);
-					parseSpecies(child, newSpecies, true, model);
-					break;
-				case SIMPLE_CHEMICAL:
-					newSpecies = new SimpleMolecule(child.getId());
-					newSpecies.setComplex(complexSpecies);
-					parseSpecies(child, newSpecies, true, model);
-					break;
-				case MACROMOLECULE:
-					newSpecies = new GenericProtein(child.getId());
-					newSpecies.setComplex(complexSpecies);
-					parseSpecies(child, newSpecies, true, model);
-					break;
-				case NUCLEIC_ACID_FEATURE:
-					newSpecies = new Gene(child.getId());
-					newSpecies.setComplex(complexSpecies);
-					parseSpecies(child, newSpecies, true, model);
-					break;
-				case SIMPLE_CHEMICAL_MULTIMER:
-					newSpecies = new SimpleMolecule(child.getId());
-					newSpecies.setComplex(complexSpecies);
-					parseSpecies(child, newSpecies, false, model);
-					break;
-				case MACROMOLECULE_MULTIMER:
-					newSpecies = new GenericProtein(child.getId());
-					newSpecies.setComplex(complexSpecies);
-					parseSpecies(child, newSpecies, false, model);
-					break;
-				case NUCLEIC_ACID_FEATURE_MULTIMER:
-					newSpecies = new Gene(child.getId());
-					newSpecies.setComplex(complexSpecies);
-					parseSpecies(child, newSpecies, false, model);
-					break;
-				case COMPLEX:
-					parseComplex(child, complexSpecies, true, model);
-					break;
-				case COMPLEX_MULTIMER:
-					parseComplex(child, complexSpecies, false, model);
-					break;
-				default:
-					break;
-			}
-			Species newAlias = model.getElementByElementId(child.getId());
-			if (newAlias != null) {
-				newAlias.setComplex(complexAlias);
-				complexAlias.addSpecies((Species) newAlias);
-			}
-		}
-	}
-
-	/**
-	 * Method used to compute end point for modifier line.
-	 * 
-	 * @param a
-	 *          SBGN-ML modifier arc
-	 * @param reaction
-	 *          reaction to which the arc points
-	 * @return end point for modifier line
-	 */
-	private Point2D getModifierEndPoint(Arc a, Reaction reaction) {
-		ModifierTypeUtils utils = new ModifierTypeUtils();
-		Point2D result;
-
-		Line2D centerLine = reaction.getCenterLine();
-		double dx = centerLine.getX2() - centerLine.getX1();
-		double dy = centerLine.getY2() - centerLine.getY1();
-		double centerLineAngle = Math.atan2(dy, dx);
-
-		Point2D centerPoint = new Point2D.Double(centerLine.getX1() + dx / 2, centerLine.getY1() + dy / 2);
-
-		// Retrieve second last point from the arc
-		Point2D secondLast;
-		if (a.getNext().isEmpty()) {
-			secondLast = new Point2D.Double(a.getStart().getX(), a.getStart().getY());
-		} else {
-			Next temp = a.getNext().get(a.getNext().size() - 1);
-			secondLast = new Point2D.Double(temp.getX(), temp.getY());
-		}
-
-		double dx2 = secondLast.getX() - centerPoint.getX();
-		double dy2 = secondLast.getY() - centerPoint.getY();
-		double modifierAngle = Math.atan2(dy2, dx2);
-
-		double finalAngle = modifierAngle - centerLineAngle;
-		while (finalAngle < -Math.PI) {
-			finalAngle += 2 * Math.PI;
-		}
-		while (finalAngle > Math.PI) {
-			finalAngle -= 2 * Math.PI;
-		}
-		String lineConnectionType = null;
-
-		// CHECKSTYLE:OFF
-		if (finalAngle < -Math.PI / 3 * 2) {
-			lineConnectionType = "0,4";
-		} else if (finalAngle < -Math.PI / 3) {
-			lineConnectionType = "0,2";
-		} else if (finalAngle < 0) {
-			lineConnectionType = "0,5";
-		} else if (finalAngle < Math.PI / 3) {
-			lineConnectionType = "0,7";
-		} else if (finalAngle < Math.PI / 3 * 2) {
-			lineConnectionType = "0,3";
-		} else {
-			lineConnectionType = "0,6";
-		}
-		// CHECKSTYLE:ON
-
-		result = utils.getAnchorPointOnReactionRect(reaction, lineConnectionType);
-
-		return result;
-	}
-
-	/**
-	 * Method used to parse line points from SBGN-ML arc.
-	 * 
-	 * @param a
-	 *          SBGN-ML arc
-	 * @return list of line points
-	 */
-	private List<Point2D> getLinePoints(Arc a) {
-		List<Point2D> pointList = new ArrayList<>();
-		Point2D startPoint = new Point2D.Double(a.getStart().getX(), a.getStart().getY());
-		Point2D endPoint = new Point2D.Double(a.getEnd().getX(), a.getEnd().getY());
-		pointList.add(startPoint);
-		for (Next nextPoint : a.getNext()) {
-			pointList.add(new Point2D.Double(nextPoint.getX(), nextPoint.getY()));
-		}
-		pointList.add(endPoint);
-		return pointList;
-	}
-
-	/**
-	 * Method used for parsing lines from sbgn-ml arcs.
-	 * 
-	 * @param a
-	 *          SBGN-ML arc
-	 * @param pointList
-	 *          list of points for the line
-	 * @return line parsed from SBGN-ML arc
-	 */
-	private PolylineData parseLine(Arc a, List<Point2D> pointList) {
-		PolylineData line = new PolylineData(pointList);
-		ArrowTypeData atd = new ArrowTypeData();
-
-		switch (ArcClazz.fromClazz(a.getClazz())) {
-			case CATALYSIS:
-				atd = ModifierType.CATALYSIS.getAtd();
-				break;
-			case CONSUMPTION:
-				atd.setArrowType(ArrowType.NONE);
-				break;
-			case INHIBITION:
-				atd = ModifierType.INHIBITION.getAtd();
-				break;
-			case MODULATION:
-				atd = ModifierType.MODULATION_STRING.getAtd();
-				break;
-			case NECESSARY_STIMULATION:
-				atd = ModifierType.TRIGGER_STRING.getAtd();
-				break;
-			case PRODUCTION:
-				atd.setArrowType(ArrowType.FULL);
-				break;
-			case STIMULATION:
-				atd = ModifierType.PHYSICAL_STIMULATION.getAtd();
-				break;
-			case LOGIC_ARC:
-				atd.setArrowType(ArrowType.NONE);
-				break;
-			default:
-				throw new InvalidArgumentException("Wrong arc class.");
-		}
-		atd.setArrowLineType(LineType.SOLID);
-		line.setEndAtd(atd.copy());
-		return line;
-	}
-
-	/**
-	 * Returns {@link AndOperator} for the reaction's reagents port.
-	 * 
-	 * @param p
-	 *          process of the reaction
-	 * @return operator for the reaction port
-	 */
-	private AndOperator getReactionPortAndOperator(Process p) {
-		AndOperator andOperator = new AndOperator();
-		Glyph centralPoint = p.getCentralPoint();
-		Double centralPointX = new Double(centralPoint.getBbox().getX() + centralPoint.getBbox().getW() / 2);
-		Double centralPointY = new Double(centralPoint.getBbox().getY() + centralPoint.getBbox().getH() / 2);
-		Point2D centerOfReactionPoint = new Point2D.Double(centralPointX, centralPointY);
-		Point2D portPoint;
-		if (p.getReagentArcs().size() > 1) {
-			portPoint = new Point2D.Double(p.getReagentArcs().get(0).getEnd().getX(), p.getReagentArcs().get(0).getEnd().getY());
-		} else {
-			portPoint = new Point2D.Double(p.getRevReagentArcs().get(0).getStart().getX(), p.getRevReagentArcs().get(0).getStart().getY());
-		}
-		PolylineData line = new PolylineData(portPoint, centerOfReactionPoint);
-		ArrowTypeData atd = new ArrowTypeData();
-		atd.setArrowType(ArrowType.NONE);
-		atd.setArrowLineType(LineType.SOLID);
-		line.setEndAtd(atd);
-		andOperator.setLine(line);
-		return andOperator;
-	}
-
-	/**
-	 * Returns {@link SplitOperator} for the reaction's products port.
-	 * 
-	 * @param p
-	 *          process of the reaction
-	 * @return operator for the reaction port
-	 */
-	private SplitOperator getReactionPortSplitOperator(Process p) {
-		SplitOperator splitOperator = new SplitOperator();
-		Glyph centralPoint = p.getCentralPoint();
-		Double centralPointX = new Double(centralPoint.getBbox().getX() + centralPoint.getBbox().getW() / 2);
-		Double centralPointY = new Double(centralPoint.getBbox().getY() + centralPoint.getBbox().getH() / 2);
-		Point2D centerOfReactionPoint = new Point2D.Double(centralPointX, centralPointY);
-		Point2D portPoint;
-		if (!p.isReversible()) {
-			portPoint = new Point2D.Double(p.getProductArcs().get(0).getStart().getX(), p.getProductArcs().get(0).getStart().getY());
-		} else {
-			portPoint = new Point2D.Double(p.getRevProductArcs().get(0).getStart().getX(), p.getRevProductArcs().get(0).getStart().getY());
-		}
-		PolylineData line = new PolylineData(centerOfReactionPoint, portPoint);
-		ArrowTypeData atd = new ArrowTypeData();
-		atd.setArrowType(ArrowType.NONE);
-		atd.setArrowLineType(LineType.SOLID);
-		line.setEndAtd(atd);
-		splitOperator.setLine(line);
-		return splitOperator;
-	}
-
-	/**
-	 * Returns instance of {@link Modifier} based on given {@link ArcClazz}.
-	 * 
-	 * @param ac
-	 *          {@link ArcClazz} defining the result
-	 * @return {@link Modifier} of class adequate to given ac
-	 * @throws Exception
-	 *           thrown when no adequate Modifier has been found
-	 */
-	private Modifier getModifierFromArcClazz(ArcClazz ac) throws Exception {
-		switch (ac) {
-			case CATALYSIS:
-				return new Catalysis();
-			case INHIBITION:
-				return new Inhibition();
-			case MODULATION:
-				return new Modulation();
-			case NECESSARY_STIMULATION:
-				return new Trigger();
-			case STIMULATION:
-				return new PhysicalStimulation();
-			default:
-				logger.warn("Modifier arc of invalid class.");
-				throw new Exception("Wrong arc class.");
-		}
-	}
-
-	/**
-	 * Returns center point for given process.
-	 * 
-	 * @param p
-	 *          completely parsed process to compute center point from
-	 * @return center point for given process
-	 */
-	private Point2D getCenterPointFromProcess(Process p) {
-		Double centralPointX = new Double(p.getCentralPoint().getBbox().getX() + p.getCentralPoint().getBbox().getW() / 2);
-		Double centralPointY = new Double(p.getCentralPoint().getBbox().getY() + p.getCentralPoint().getBbox().getH() / 2);
-		Point2D centerOfReactionPoint = new Point2D.Double(centralPointX, centralPointY);
-		return centerOfReactionPoint;
-	}
-
-	/**
-	 * Returns proper Reaction object based on given glyph clazz.
-	 * 
-	 * @param glyphClazz
-	 *          clazz of the process glyph
-	 * @return Reaction object based on given glyph clazz
-	 */
-	private Reaction getReactionFromProcessGlyphClazz(String glyphClazz) {
-		switch (GlyphClazz.fromClazz(glyphClazz)) {
-			case ASSOCIATION:
-			case DISSOCIATION:
-			case PROCESS:
-				return new StateTransitionReaction();
-			case OMITTED_PROCESS:
-				return new KnownTransitionOmittedReaction();
-			case UNCERTAIN_PROCESS:
-				return new UnknownTransitionReaction();
-			default:
-				throw new InvalidArgumentException();
-
-		}
-	}
-
-	/**
-	 * Method used for parsing processes into reactions.
-	 * 
-	 * @param p
-	 *          process to be parsed
-	 * @param model
-	 *          model to be updated with the parsed reaction
-	 * @throws Exception
-	 *           thrown when the process was invalid
-	 */
-	private void parseProcess(Process p, Model model) throws Exception {
-		if (p.getProductArcs().isEmpty()) {
-			throw new Exception(p.getCentralPoint().getId() + ": The process must have at least one outgoing arc.");
-		}
-		p.setProductsPort((Port) p.getProductArcs().get(0).getSource());
-		for (Arc productArc : p.getProductArcs()) {
-			if (!((Port) productArc.getSource()).equals(p.getProductsPort())) {
-				p.setReversible(true);
-				p.setReagentsPort((Port) productArc.getSource());
-			}
-		}
-		if (p.getReagentsPort() == null && !p.getReagentArcs().isEmpty()) {
-			p.setReagentsPort((Port) p.getReagentArcs().get(0).getTarget());
-		}
-
-		if ((p.getReagentArcs().isEmpty() && !p.isReversible()) || (p.getRevReagentArcs().isEmpty() && p.isReversible())) {
-			throw new Exception(p.getCentralPoint().getId() + ": The process must have at least one incoming arc.");
-		}
-
-		Reaction reaction;
-		if (p.getCentralPoint() == null) {
-			throw new Exception("Process has no central point.");
-		}
-		reaction = getReactionFromProcessGlyphClazz(p.getCentralPoint().getClazz());
-		reaction.setIdReaction(p.getCentralPoint().getId());
-		reaction.setModel(model);
-
-		reaction.setReversible(p.isReversible());
-
-		// If there are multiple inputs, add "AND" operator
-		AndOperator andOperator = null;
-		if (p.getReagentArcs().size() > 1 || p.getRevReagentArcs().size() > 1) {
-			andOperator = getReactionPortAndOperator(p);
-			andOperator.setReaction(reaction);
-			reaction.addNode(andOperator);
-		}
-
-		// If there are multiple outputs, add Split operator
-		SplitOperator splitOperator = null;
-		if ((p.getProductArcs().size() > 1 && !p.isReversible()) || (p.isReversible() && p.getRevProductArcs().size() > 1)) {
-			splitOperator = getReactionPortSplitOperator(p);
-			splitOperator.setReaction(reaction);
-			reaction.addNode(splitOperator);
-		}
-
-		for (Arc a : p.getReagentArcs()) {
-			Reactant reactant = new Reactant();
-			reactant.setReaction(reaction);
-			Glyph source = (Glyph) a.getSource();
-			reactant.setElement(model.getElementByElementId(source.getId()));
-			List<Point2D> pointList = getLinePoints(a);
-			if (p.getReagentArcs().size() == 1) {
-				pointList.add(getCenterPointFromProcess(p));
-			} else {
-				pointList.add(pointList.get(pointList.size() - 1));
-			}
-			PolylineData line = parseLine(a, pointList);
-			reactant.setLine(line);
-			if (andOperator != null) {
-				andOperator.addInput(reactant);
-			}
-
-			reaction.addReactant(reactant);
-		}
-
-		for (Arc a : p.getProductArcs()) {
-			if (((Port) a.getSource()).equals(p.getProductsPort())) {
-				Product product = new Product();
-				product.setReaction(reaction);
-				Glyph target = (Glyph) a.getTarget();
-				product.setElement(model.getElementByElementId(target.getId()));
-				List<Point2D> pointList = getLinePoints(a);
-				if (p.getRevProductArcs().size() >= 1) {
-					pointList.add(0, getCenterPointFromProcess(p));
-				} else {
-					pointList.add(0, pointList.get(0));
-				}
-				PolylineData line = parseLine(a, pointList);
-				product.setLine(line);
-				if (splitOperator != null) {
-					splitOperator.addOutput(product);
-				}
-
-				reaction.addProduct(product);
-			} else {
-				Reactant reactant = new Reactant();
-				reactant.setReaction(reaction);
-				Glyph source = (Glyph) a.getTarget();
-				reactant.setElement(model.getElementByElementId(source.getId()));
-				List<Point2D> pointList = getLinePoints(a);
-				if (p.getRevReagentArcs().size() <= 1) {
-					pointList.add(0, getCenterPointFromProcess(p));
-				} else {
-					pointList.add(0, pointList.get(0));
-				}
-				PolylineData line = parseLine(a, pointList);
-				line = line.reverse();
-				reactant.setLine(line);
-				if (andOperator != null) {
-					andOperator.addInput(reactant);
-				}
-
-				reaction.addReactant(reactant);
-			}
-		}
-		for (Arc a : p.getModifierArcs()) {
-			Modifier modifier = null;
-			try {
-				modifier = getModifierFromArcClazz(ArcClazz.fromClazz(a.getClazz()));
-			} catch (Exception ex) {
-				logger.warn("Unable to add modifier");
-				continue;
-			}
-			if (a.getSource() instanceof Glyph) {
-				Glyph sourceGlyph = (Glyph) a.getSource();
-				Species modifierAlias = (Species) model.getElementByElementId(sourceGlyph.getId());
-				modifier.setElement(modifierAlias);
-				List<Point2D> pointList = getLinePoints(a);
-				pointList.remove(pointList.size() - 1);
-				pointList.add(getModifierEndPoint(a, reaction));
-				PolylineData line = parseLine(a, pointList);
-				modifier.setLine(line);
-
-				reaction.addModifier(modifier);
-			} else if (a.getSource() instanceof Port) {
-				// Logic operator
-				try {
-					parseLogicOperator(a, reaction, ArcClazz.fromClazz(a.getClazz()), null, model);
-				} catch (Exception ex) {
-					logger.warn(ex.getMessage());
-				}
-			}
-
-		}
-
-		model.addReaction(reaction);
-	}
-
-	/**
-	 * Returns {@link ArrowTypeData} based on given {@link ArcClazz}.
-	 * 
-	 * @param ac
-	 *          input arc class
-	 * @return ArrowTypeData based on input arrow class
-	 * @throws Exception
-	 *           thrown when invalid arc class was given on input
-	 */
-	private ArrowTypeData getAtdFromArcClazz(ArcClazz ac) throws Exception {
-		ArrowTypeData atd = new ArrowTypeData();
-		switch (ac) {
-			case CATALYSIS:
-				atd = ModifierType.CATALYSIS.getAtd();
-				break;
-			case CONSUMPTION:
-				atd.setArrowType(ArrowType.NONE);
-				break;
-			case INHIBITION:
-				atd = ModifierType.INHIBITION.getAtd();
-				break;
-			case MODULATION:
-				atd = ModifierType.MODULATION_STRING.getAtd();
-				break;
-			case NECESSARY_STIMULATION:
-				atd = ModifierType.TRIGGER_STRING.getAtd();
-				break;
-			case PRODUCTION:
-				atd.setArrowType(ArrowType.FULL);
-				break;
-			case STIMULATION:
-				atd = ModifierType.PHYSICAL_STIMULATION.getAtd();
-				break;
-			case LOGIC_ARC:
-				atd.setArrowType(ArrowType.NONE);
-				break;
-			default:
-				throw new Exception("Wrong arc class.");
-		}
-		return atd.copy();
-	}
-
-	/**
-	 * Method used for parsing logic operators.
-	 * 
-	 * @param arc
-	 *          arc with a starting point in the logic operator
-	 * @param reaction
-	 *          reaction that the logic operator is a part of
-	 * @param modifierClass
-	 *          determines type of source species
-	 * @param targetOperator
-	 *          target logic operator
-	 * @param model
-	 *          model of the map
-	 * @throws Exception
-	 *           thrown when parsed logic operator is invalid
-	 */
-	private void parseLogicOperator(Arc arc, Reaction reaction, ArcClazz modifierClass, NodeOperator targetOperator, Model model) throws Exception {
-		Port operatorPort = (Port) arc.getSource();
-		Glyph logicOperator = null;
-		for (Glyph lo : logicOperators) {
-			if (lo.getPort().contains(operatorPort)) {
-				logicOperator = lo;
-			}
-		}
-		if (logicOperator == null) {
-			throw new Exception("Missing logic operator for logic arc: " + arc.getId());
-		}
-
-		// LogicOperator is valid for CellDesigner only if it has exactly 2
-		// inputs of Species
-		final Glyph tempLogicOperator = logicOperator;
-		boolean isCellDesignerValidLogicOperator = logicArcs
-				.stream().filter(a -> tempLogicOperator.getPort().contains(a.getTarget()) && !(a.getSource() instanceof Port)).count() == 2;
-		if (!isCellDesignerValidLogicOperator) {
-			throw new Exception("Parsed operator is not valid for CellDesigner: " + logicOperator.getId());
-		}
-
-		NodeOperator operator;
-		switch (GlyphClazz.fromClazz(logicOperator.getClazz())) {
-			case AND:
-				operator = new AndOperator();
-				break;
-			case OR:
-				operator = new OrOperator();
-				break;
-			case NOT:
-				logger.warn("NOT gates are not implemented in the platform. Glyph: " + logicOperator.getId() + " has not been parsed.");
-				return;
-			default:
-				throw new Exception("Wrong logic operator class.");
-		}
-
-		// Parse line from arc and operator glyph
-		Point2D operatorCenterPoint = new Point2D.Double(
-				logicOperator.getBbox().getX() + logicOperator.getBbox().getW() / 2, logicOperator.getBbox().getY() + logicOperator.getBbox().getH() / 2);
-
-		List<Point2D> linePoints = getLinePoints(arc);
-		new ArrayList<Point2D>();
-
-		if (targetOperator == null) {
-			linePoints.remove(linePoints.size() - 1);
-			linePoints.add(getModifierEndPoint(arc, reaction));
-		}
-
-		// Check if operator port is in the line from center point of the
-		// operator. If so, remove that redundant point.
-		double dx, dy;
-		dx = linePoints.get(0).getX() - operatorCenterPoint.getX();
-		dy = linePoints.get(0).getY() - operatorCenterPoint.getY();
-		double dx2, dy2;
-		if (arc.getNext().isEmpty()) {
-			dx2 = linePoints.get(linePoints.size() - 1).getX() - linePoints.get(0).getX();
-			dy2 = linePoints.get(linePoints.size() - 1).getY() - linePoints.get(0).getY();
-		} else {
-			dx2 = arc.getNext().get(0).getX() - linePoints.get(0).getX();
-			dy2 = arc.getNext().get(0).getY() - linePoints.get(0).getY();
-		}
-		DoubleComparator doubleComparator = new DoubleComparator();
-		if (doubleComparator.compare(dy / dx, dy2 / dx2) == 0) {
-			linePoints.remove(0);
-		}
-		linePoints.add(0, operatorCenterPoint);
-
-		PolylineData line = new PolylineData(linePoints);
-		ArrowTypeData atd = getAtdFromArcClazz(ArcClazz.fromClazz(arc.getClazz()));
-
-		atd.setArrowLineType(LineType.SOLID);
-		line.setEndAtd(atd);
-
-		operator.setLine(line);
-		operator.setReaction(reaction);
-
-		if (targetOperator != null) {
-			operator.addOutput(targetOperator);
-			targetOperator.addInput(operator);
-		}
-
-		for (Arc logicArc : logicArcs) {
-			if (logicOperator.getPort().contains(logicArc.getTarget())) {
-				if (logicArc.getSource() instanceof Port) {
-					// The arc has source in logic operator
-					logger.warn("Logic operators trees are not compatible with CellDesigner. Therefore they are not supported.");
-					continue;
-					// parseLogicOperator(logicArc, reaction, modifierClass,
-					// operator, model);
-				} else {
-					Modifier modifier;
-
-					switch (modifierClass) {
-						case CATALYSIS:
-							modifier = new Catalysis();
-							break;
-						case INHIBITION:
-							modifier = new Inhibition();
-							break;
-						case MODULATION:
-							modifier = new Modulation();
-							break;
-						case NECESSARY_STIMULATION:
-							modifier = new Trigger();
-							break;
-						case STIMULATION:
-							modifier = new PhysicalStimulation();
-							break;
-						default:
-							throw new Exception("Wrong arc class.");
-					}
-
-					Glyph sourceGlyph = (Glyph) logicArc.getSource();
-					Species modifierAlias = (Species) model.getElementByElementId(sourceGlyph.getId());
-					modifier.setElement(modifierAlias);
-					List<Point2D> pointList = getLinePoints(logicArc);
-					pointList.add(operatorCenterPoint);
-					PolylineData newLine = parseLine(logicArc, pointList);
-					modifier.setLine(newLine);
-
-					operator.addInput(modifier);
-
-					reaction.addModifier(modifier);
-				}
-			}
-		}
-		reaction.addNode(operator);
-	}
-
-	/**
-	 * Method used for parsing compartments.
-	 * 
-	 * @param glyph
-	 *          compartment glyph from sbgn-ml file
-	 * @param model
-	 *          model to be updated with the parsed compartment
-	 */
-	private void parseCompartment(Glyph glyph, Model model) {
-
-		Compartment compartment = new SquareCompartment(glyph.getId());
-		if (glyph.getLabel() != null) {
-			compartment.setName(glyph.getLabel().getText());
-		}
-		compartment.setModel(model);
-		compartment.setHeight(new Double(glyph.getBbox().getH()));
-		compartment.setWidth(new Double(glyph.getBbox().getW()));
-		compartment.setX(new Double(glyph.getBbox().getX()));
-		compartment.setY(new Double(glyph.getBbox().getY()));
-		compartment.setThickness(1.0);
-		compartment.setColor(COMPARTMENT_COLOR);
-
-		if (glyph.getLabel() != null && glyph.getLabel().getBbox() != null) {
-			compartment.setNamePoint(glyph.getLabel().getBbox().getX(), glyph.getLabel().getBbox().getY());
-		} else {
-			compartment.setNamePoint(
-					compartment.getX() + compartment.getThickness() + CONTAINER_NAME_MARGIN, compartment.getY() + compartment.getThickness() + CONTAINER_NAME_MARGIN);
-		}
-		Compartment parent = findParentCompartment(compartment, model);
-		if (parent != null) {
-			compartment.setCompartment(parent);
-			parent.addElement(compartment);
-		}
-
-		model.addElement(compartment);
-	}
-}
+package lcsb.mapviewer.converter.model.sbgnml;
+
+import java.awt.Color;
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.log4j.Logger;
+import org.sbgn.ArcClazz;
+import org.sbgn.GlyphClazz;
+import org.sbgn.SbgnUtil;
+import org.sbgn.bindings.Arc;
+import org.sbgn.bindings.Arc.End;
+import org.sbgn.bindings.Arc.Next;
+import org.sbgn.bindings.Arc.Start;
+import org.sbgn.bindings.Bbox;
+import org.sbgn.bindings.Glyph;
+import org.sbgn.bindings.Map;
+import org.sbgn.bindings.Port;
+import org.sbgn.bindings.Sbgn;
+
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.common.comparator.DoubleComparator;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.converter.ConverterParams;
+import lcsb.mapviewer.converter.InvalidInputDataExecption;
+import lcsb.mapviewer.converter.graphics.bioEntity.element.species.SpeciesConverter;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.CellDesignerAliasConverter;
+import lcsb.mapviewer.converter.model.celldesigner.types.ModifierType;
+import lcsb.mapviewer.converter.model.celldesigner.types.ModifierTypeUtils;
+import lcsb.mapviewer.converter.model.sbgnml.structures.Process;
+import lcsb.mapviewer.model.graphics.ArrowType;
+import lcsb.mapviewer.model.graphics.ArrowTypeData;
+import lcsb.mapviewer.model.graphics.LineType;
+import lcsb.mapviewer.model.graphics.PolylineData;
+import lcsb.mapviewer.model.map.compartment.Compartment;
+import lcsb.mapviewer.model.map.compartment.SquareCompartment;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.model.map.modifier.Catalysis;
+import lcsb.mapviewer.model.map.modifier.Inhibition;
+import lcsb.mapviewer.model.map.modifier.Modulation;
+import lcsb.mapviewer.model.map.modifier.PhysicalStimulation;
+import lcsb.mapviewer.model.map.modifier.Trigger;
+import lcsb.mapviewer.model.map.reaction.AndOperator;
+import lcsb.mapviewer.model.map.reaction.Modifier;
+import lcsb.mapviewer.model.map.reaction.NodeOperator;
+import lcsb.mapviewer.model.map.reaction.OrOperator;
+import lcsb.mapviewer.model.map.reaction.Product;
+import lcsb.mapviewer.model.map.reaction.Reactant;
+import lcsb.mapviewer.model.map.reaction.Reaction;
+import lcsb.mapviewer.model.map.reaction.SplitOperator;
+import lcsb.mapviewer.model.map.reaction.type.KnownTransitionOmittedReaction;
+import lcsb.mapviewer.model.map.reaction.type.NegativeInfluenceReaction;
+import lcsb.mapviewer.model.map.reaction.type.ReducedModulationReaction;
+import lcsb.mapviewer.model.map.reaction.type.ReducedPhysicalStimulationReaction;
+import lcsb.mapviewer.model.map.reaction.type.ReducedTriggerReaction;
+import lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction;
+import lcsb.mapviewer.model.map.reaction.type.UnknownTransitionReaction;
+import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.Degraded;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.Phenotype;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.SimpleMolecule;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.Unknown;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+import lcsb.mapviewer.model.map.species.field.Residue;
+
+/**
+ * This class is a parser for SBGN-ML files.
+ * 
+ * @author Michał Kuźma
+ *
+ */
+public class SbgnmlXmlParser {
+
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(SbgnmlXmlParser.class.getName());
+
+  /**
+   * List of all processes to be parsed.
+   */
+  private List<Process> processes = new ArrayList<Process>();
+
+  /**
+   * List of all logic operator glyphs parsed so far.
+   */
+  private List<Glyph> logicOperators = new ArrayList<Glyph>();
+
+  /**
+   * List of all logic arcs parsed so far.
+   */
+  private List<Arc> logicArcs = new ArrayList<Arc>();
+
+  /**
+   * Default margin for container name.
+   */
+  private static final double CONTAINER_NAME_MARGIN = 5.0;
+
+  /**
+   * Part of height of the line used to cross degraded circle that goes behind
+   * this circle.
+   */
+  private static final int CROSS_LINE_EXTENDED_LENGTH = 7;
+
+  /**
+   * Default color for parsed compartments.
+   */
+  private static final Color COMPARTMENT_COLOR = new Color(0.5f, 0.5f, 1.0f);
+
+  /**
+   * Method used to create a model from SBGN-ML file.
+   * 
+   * @param params
+   *          parameters needed for parsing file and creating a model
+   * @return valid model parsed from the file
+   * @throws InvalidInputDataExecption
+   *           thrown when input file is invalid
+   */
+  public Model createModel(ConverterParams params) throws InvalidInputDataExecption {
+
+    Model model = new ModelFullIndexed(null);
+    model.setIdModel(params.getFilename());
+
+    // Input file
+    File inputSbgnmlFile = inputStreamToFile(params.getInputStream());
+
+    Sbgn sbgnData;
+    // Check if input file has valid SBGN-ML data
+    try {
+      if (!SbgnUtil.isValid(inputSbgnmlFile)) {
+        throw new InvalidInputDataExecption("Given input is not a valid SBGN-ML file.");
+      }
+
+      // Read data from file
+      sbgnData = SbgnUtil.readFromFile(inputSbgnmlFile);
+    } catch (InvalidInputDataExecption ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new InvalidInputDataExecption("Unable to read given file.", ex);
+    }
+
+    // Extract map with all the glyphs and arcs
+    Map map = sbgnData.getMap();
+
+    adjustSizeOfElements(map);
+
+    setModelSize(map, model);
+
+    // Iterate over every glyph
+    for (Glyph g : map.getGlyph()) {
+      parseGlyph(g, model);
+    }
+
+    // Iterate over every arc in the map
+    for (Arc a : map.getArc()) {
+      parseArc(a, model);
+    }
+
+    // Parse all processes created before
+    for (Process p : processes) {
+      try {
+        parseProcess(p, model);
+      } catch (Exception e) {
+        logger.warn("Unable to parse the process: " + p.getCentralPoint().getId());
+      }
+    }
+
+    return model;
+  }
+
+  /**
+   * Writes input stream into a File.
+   * 
+   * @param inputStream
+   *          Input stream to be written to File
+   * @return File handle
+   */
+  private File inputStreamToFile(InputStream inputStream) {
+    File tempFile = null;
+    try {
+      tempFile = File.createTempFile("stream2file", ".tmp");
+      tempFile.deleteOnExit();
+      try (FileOutputStream out = new FileOutputStream(tempFile)) {
+        IOUtils.copy(inputStream, out);
+      }
+    } catch (Exception ex) {
+      logger.debug("Unable to create temporary file.");
+      return null;
+    }
+    return tempFile;
+  }
+
+  /**
+   * Method used to adjust the size of elements that have their size represented
+   * different in the SBGN-ML file. Adjusted elements: Source and Sink / Degraded
+   * elements, Multimers.
+   * 
+   * @param map
+   *          Map parsed from SBGN-ML file
+   */
+  private void adjustSizeOfElements(Map map) {
+    for (Glyph g : map.getGlyph()) {
+      GlyphClazz glyphClazz = GlyphClazz.fromClazz(g.getClazz());
+      switch (glyphClazz) {
+      case SOURCE_AND_SINK:
+        g.getBbox().setH(g.getBbox().getH() + 2 * CROSS_LINE_EXTENDED_LENGTH);
+        g.getBbox().setW(g.getBbox().getW() + 2 * CROSS_LINE_EXTENDED_LENGTH);
+        g.getBbox().setX(g.getBbox().getX() - CROSS_LINE_EXTENDED_LENGTH);
+        g.getBbox().setY(g.getBbox().getY() - CROSS_LINE_EXTENDED_LENGTH);
+        break;
+      case COMPLEX_MULTIMER:
+      case MACROMOLECULE_MULTIMER:
+      case NUCLEIC_ACID_FEATURE_MULTIMER:
+      case SIMPLE_CHEMICAL_MULTIMER:
+        int cardinality;
+        try {
+          cardinality = getMultimerCardinality(g);
+        } catch (Exception ex) {
+          cardinality = 2;
+          logger.warn(ex.getMessage() + " Set the default value of 2.");
+        }
+        g.getBbox().setW(g.getBbox().getW() + (cardinality - 1) * SpeciesConverter.HOMODIMER_OFFSET);
+        g.getBbox().setH(g.getBbox().getH() + (cardinality - 1) * SpeciesConverter.HOMODIMER_OFFSET);
+        break;
+      default:
+        break;
+      }
+    }
+  }
+
+  /**
+   * Method used to compute height and width of the model.
+   * 
+   * @param map
+   *          Map parsed from SBGN-ML file
+   * @param model
+   *          Model to be updated
+   */
+  private void setModelSize(Map map, Model model) {
+    double minX = Double.MAX_VALUE;
+    double minY = Double.MAX_VALUE;
+    double maxX = 0;
+    double maxY = 0;
+
+    // Iterate over every glyph
+    for (Glyph g : map.getGlyph()) {
+      if (GlyphClazz.fromClazz(g.getClazz()).equals(GlyphClazz.ANNOTATION)
+          || GlyphClazz.fromClazz(g.getClazz()).equals(GlyphClazz.TAG)) {
+        continue;
+      }
+      Bbox bbox = g.getBbox();
+      if (bbox != null) {
+        if (bbox.getX() < minX) {
+          minX = bbox.getX();
+        }
+        if (bbox.getY() < minY) {
+          minY = bbox.getY();
+        }
+        if (bbox.getX() + bbox.getW() > maxX) {
+          maxX = bbox.getX() + bbox.getW();
+        }
+        if (bbox.getY() + bbox.getH() > maxY) {
+          maxY = bbox.getY() + bbox.getH();
+        }
+      }
+    }
+
+    // Iterate over every arc
+    for (Arc a : map.getArc()) {
+      // Since submaps are not yet supported, the arcs connecting them or
+      // tags cannot be used when computing width and height of the model.
+      boolean connectsTagOrSubmap = false;
+      if (a.getSource() instanceof Glyph) {
+        Glyph sourceGlyph = (Glyph) a.getSource();
+        if (GlyphClazz.fromClazz(sourceGlyph.getClazz()).equals(GlyphClazz.TAG)
+            || GlyphClazz.fromClazz(sourceGlyph.getClazz()).equals(GlyphClazz.SUBMAP)) {
+          connectsTagOrSubmap = true;
+        }
+      }
+      if (a.getTarget() instanceof Glyph) {
+        Glyph targetGlyph = (Glyph) a.getTarget();
+        if (GlyphClazz.fromClazz(targetGlyph.getClazz()).equals(GlyphClazz.TAG)
+            || GlyphClazz.fromClazz(targetGlyph.getClazz()).equals(GlyphClazz.SUBMAP)) {
+          connectsTagOrSubmap = true;
+        }
+      }
+      // If the arc is not connecting a submap or a tag, check it's points
+      if (!connectsTagOrSubmap) {
+        Start aStart = a.getStart();
+        if (aStart.getX() < minX) {
+          minX = aStart.getX();
+        }
+        if (aStart.getX() > maxX) {
+          maxX = aStart.getX();
+        }
+        if (aStart.getY() < minY) {
+          minY = aStart.getY();
+        }
+        if (aStart.getY() > maxY) {
+          maxY = aStart.getY();
+        }
+        End aEnd = a.getEnd();
+        if (aEnd.getX() < minX) {
+          minX = aEnd.getX();
+        }
+        if (aEnd.getX() > maxX) {
+          maxX = aEnd.getX();
+        }
+        if (aEnd.getY() < minY) {
+          minY = aEnd.getY();
+        }
+        if (aEnd.getY() > maxY) {
+          maxY = aEnd.getY();
+        }
+        for (Next aNext : a.getNext()) {
+          if (aNext.getX() < minX) {
+            minX = aNext.getX();
+          }
+          if (aNext.getX() > maxX) {
+            maxX = aNext.getX();
+          }
+          if (aNext.getY() < minY) {
+            minY = aNext.getY();
+          }
+          if (aNext.getY() > maxY) {
+            maxY = aNext.getY();
+          }
+        }
+      }
+    }
+
+    model.setWidth(maxX + minX);
+    model.setHeight(maxY + minY);
+  }
+
+  /**
+   * Method used to parse a single glyph.
+   * 
+   * @param g
+   *          glyph to be parsed
+   * @param model
+   *          model to be updated
+   * @throws Exception
+   */
+  private void parseGlyph(Glyph g, Model model) {
+    Species newSpecies = null;
+    switch (GlyphClazz.fromClazz(g.getClazz())) {
+    case AND:
+    case NOT:
+    case OR:
+      logicOperators.add(g);
+      break;
+    case COMPARTMENT:
+      parseCompartment(g, model);
+      break;
+    case COMPLEX:
+      parseComplex(g, null, true, model);
+      break;
+    case COMPLEX_MULTIMER:
+      parseComplex(g, null, false, model);
+      break;
+    case MACROMOLECULE:
+      newSpecies = new GenericProtein(g.getId());
+      parseSpecies(g, newSpecies, true, model);
+      break;
+    case MACROMOLECULE_MULTIMER:
+      newSpecies = new GenericProtein(g.getId());
+      parseSpecies(g, newSpecies, false, model);
+      break;
+    case NUCLEIC_ACID_FEATURE:
+      if (isRNA(g)) {
+        newSpecies = new Rna(g.getId());
+      } else {
+        newSpecies = new Gene(g.getId());
+      }
+      parseSpecies(g, newSpecies, true, model);
+      break;
+    case NUCLEIC_ACID_FEATURE_MULTIMER:
+      if (isRNA(g)) {
+        newSpecies = new Rna(g.getId());
+      } else {
+        newSpecies = new Gene(g.getId());
+      }
+      parseSpecies(g, newSpecies, false, model);
+      break;
+    case PERTURBING_AGENT:
+      newSpecies = new Phenotype(g.getId());
+      parseSpecies(g, newSpecies, true, model);
+      break;
+    case PHENOTYPE:
+      newSpecies = new Phenotype(g.getId());
+      parseSpecies(g, newSpecies, true, model);
+      break;
+    case ASSOCIATION:
+    case DISSOCIATION:
+    case OMITTED_PROCESS:
+    case PROCESS:
+    case UNCERTAIN_PROCESS:
+      processes.add(new Process(g));
+      break;
+    case SIMPLE_CHEMICAL:
+      newSpecies = new SimpleMolecule(g.getId());
+      parseSpecies(g, newSpecies, true, model);
+      break;
+    case SIMPLE_CHEMICAL_MULTIMER:
+      newSpecies = new SimpleMolecule(g.getId());
+      parseSpecies(g, newSpecies, false, model);
+      break;
+    case SOURCE_AND_SINK:
+      newSpecies = new Degraded(g.getId());
+      parseSpecies(g, newSpecies, true, model);
+      break;
+    case TAG:
+    case SUBMAP:
+      logger.warn("Submaps are not supported. Glyph: " + g.getId() + " has not been parsed.");
+    case UNSPECIFIED_ENTITY:
+      newSpecies = new Unknown(g.getId());
+      parseSpecies(g, newSpecies, true, model);
+      break;
+    default:
+      logger.warn("The glyph " + g.getId() + " of class " + g.getClazz()
+          + " has not been parsed, since it is invalid for SBGN PD map.");
+      break;
+    }
+  }
+
+  /**
+   * Method used to parse a single arc.
+   * 
+   * @param a
+   *          arc to be parsed
+   * @param model
+   *          model to be updated
+   */
+  private void parseArc(Arc a, Model model) {
+    switch (ArcClazz.fromClazz(a.getClazz())) {
+    case CONSUMPTION:
+      Port arcTargetPort = (Port) a.getTarget();
+      for (Process p : processes) {
+        if (p.getCentralPoint().getPort().contains(arcTargetPort)) {
+          p.addReagentArc(a);
+          break;
+        }
+      }
+      break;
+    case PRODUCTION:
+      Port arcSourcePort = (Port) a.getSource();
+      for (Process p : processes) {
+        if (p.getCentralPoint().getPort().contains(arcSourcePort)) {
+          p.addProductArc(a);
+          break;
+        }
+      }
+      break;
+    case EQUIVALENCE_ARC:
+      logger.warn("Submaps are not supported. Equivalence arc: " + a.getId() + " has not been parsed.");
+      break;
+    case LOGIC_ARC:
+      logicArcs.add(a);
+      break;
+    case CATALYSIS:
+    case INHIBITION:
+    case MODULATION:
+    case NECESSARY_STIMULATION:
+    case STIMULATION:
+      Glyph targetGlyph = (Glyph) a.getTarget();
+      if (GlyphClazz.fromClazz(targetGlyph.getClazz()).equals(GlyphClazz.PHENOTYPE)) {
+        if (!(a.getSource() instanceof Glyph)) {
+          logger.warn("Invalid phenotype arc: " + a.getId());
+          break;
+        }
+        try {
+          parsePhenotypeArc(a, model);
+        } catch (Exception ex) {
+          logger.warn(ex.getMessage());
+        }
+        break;
+      }
+      if (a.getSource() instanceof Glyph) {
+        Glyph sourceGlyph = (Glyph) a.getSource();
+        if (GlyphClazz.fromClazz(sourceGlyph.getClazz()).equals(GlyphClazz.PHENOTYPE)
+            && (model.getElementByElementId(targetGlyph.getId()) instanceof Species)) {
+          try {
+            parsePhenotypeArc(a, model);
+          } catch (InvalidArgumentException ex) {
+            logger.warn("The arc " + a.getId() + " of class " + a.getClazz() + " is not a valid reduced notation arc.");
+          }
+          break;
+        }
+      }
+      for (Process p : processes) {
+        if (p.getCentralPoint().getId().equals(targetGlyph.getId())) {
+          p.addInfluenceArc(a);
+          break;
+        }
+      }
+      break;
+    default:
+      logger.warn("The arc " + a.getId() + " of class " + a.getClazz()
+          + " has not been parsed, since it is invalid for SBGN PD map.");
+    }
+  }
+
+  /**
+   * Method used to parse arc going to or from a phenotype.
+   * 
+   * @param a
+   *          arc to be parsed
+   * @param model
+   *          model to be updated
+   */
+  private void parsePhenotypeArc(Arc a, Model model) {
+    Reaction reaction;
+
+    switch (ArcClazz.fromClazz(a.getClazz())) {
+
+    case INHIBITION:
+      reaction = new NegativeInfluenceReaction();
+      break;
+    case MODULATION:
+      reaction = new ReducedModulationReaction();
+      break;
+    case NECESSARY_STIMULATION:
+      reaction = new ReducedTriggerReaction();
+      break;
+    case STIMULATION:
+      reaction = new ReducedPhysicalStimulationReaction();
+      break;
+    default:
+      throw new InvalidArgumentException();
+    }
+
+    reaction.setIdReaction(a.getId());
+    reaction.setModel(model);
+
+    Reactant reactant = new Reactant();
+    reactant.setReaction(reaction);
+    Glyph source = (Glyph) a.getSource();
+    reactant.setElement(model.getElementByElementId(source.getId()));
+    List<Point2D> reactantPointList = new ArrayList<>();
+    reactantPointList.add(new Point2D.Double(a.getStart().getX(), a.getStart().getY()));
+    reactantPointList.add(new Point2D.Double(a.getStart().getX(), a.getStart().getY()));
+    PolylineData reactantLine = new PolylineData(reactantPointList);
+    ArrowTypeData atd = new ArrowTypeData();
+    atd.setArrowType(ArrowType.NONE);
+    atd.setArrowLineType(LineType.SOLID);
+    reactantLine.setEndAtd(atd);
+    reactant.setLine(reactantLine);
+    reaction.addReactant(reactant);
+
+    Product product = new Product();
+    product.setReaction(reaction);
+    Glyph target = (Glyph) a.getTarget();
+    product.setElement(model.getElementByElementId(target.getId()));
+    List<Point2D> productPointList = getLinePoints(a);
+    PolylineData productLine = parseLine(a, productPointList);
+    product.setLine(productLine);
+    reaction.addProduct(product);
+
+    model.addReaction(reaction);
+  }
+
+  /**
+   * Method used to parse a single species.
+   * 
+   * @param g
+   *          SBGN-ML glyph representing the species
+   * @param newSpecies
+   *          species to be parsed
+   * @param isHomodimer
+   *          true if parsed species is not multimer
+   * @param model
+   *          model to be updated
+   */
+  private void parseSpecies(Glyph g, Species newSpecies, boolean isHomodimer, Model model) {
+    newSpecies.setModel(model);
+    // If Glyph has label with a name, set it as Species name. If not, set
+    // Id as name.
+    if (g.getLabel() != null) {
+      newSpecies.setName(g.getLabel().getText());
+    } else {
+      newSpecies.setName(g.getId());
+    }
+    // Add species to parent complex if there is one
+    if (newSpecies.getComplex() != null) {
+      newSpecies.getComplex().addSpecies(newSpecies);
+    }
+    // If the species is a multimer, set it's cardinality.
+    if (!isHomodimer) {
+      try {
+        newSpecies.setHomodimer(getMultimerCardinality(g));
+      } catch (Exception ex) {
+        newSpecies.setHomodimer(2);
+        logger.warn(ex.getMessage() + " Set the default value of 2.");
+      }
+    }
+
+    List<Glyph> children = g.getGlyph();
+    for (Glyph child : children) {
+      if (GlyphClazz.fromClazz(child.getClazz()).equals(GlyphClazz.STATE_VARIABLE)) {
+        if (child.getState() == null || child.getState().getVariable() != null) {
+          try {
+            parseStateVariable(child, g, newSpecies);
+          } catch (Exception ex) {
+            logger.warn(ex.getMessage());
+          }
+        } else {
+          String structuralState = child.getState().getValue();
+          if (newSpecies instanceof Protein) {
+            Protein protein = (Protein) newSpecies;
+            protein.setStructuralState(structuralState);
+          } else if (newSpecies instanceof Complex) {
+            Complex complex = (Complex) newSpecies;
+            complex.setStructuralState(structuralState);
+          }
+        }
+      }
+    }
+
+    parseSpecies(g, newSpecies, model);
+
+    adjustModificationCoordinates(newSpecies);
+
+  }
+
+  /**
+   * {@link ModificationResidue} in element might have slightly off coordinates
+   * (due to different symbol shapes). For that we need to align them to match our
+   * model.
+   * 
+   * @param species
+   */
+  protected void adjustModificationCoordinates(Species species) {
+    if (species instanceof Protein) {
+      Protein protein = (Protein) species;
+      if (protein.getModificationResidues().size() > 0) {
+        CellDesignerAliasConverter converter = new CellDesignerAliasConverter(species, true);
+        for (ModificationResidue mr : protein.getModificationResidues()) {
+          double angle = converter.getAngleForPoint(species, mr.getPosition());
+          mr.setPosition(converter.getResidueCoordinates(species, angle));
+        }
+      }
+
+    }
+  }
+
+  /**
+   * Method used to create a new alias from SBGN-ML glyph.
+   * 
+   * @param glyph
+   *          SBGN-ML glyph representing the alias
+   * @param species
+   *          species of the alias
+   * @param model
+   *          model to be updated
+   */
+  private void parseSpecies(Glyph glyph, Species species, Model model) {
+    species.setHeight(new Double(glyph.getBbox().getH()));
+    species.setWidth(new Double(glyph.getBbox().getW()));
+    species.setX(new Double(glyph.getBbox().getX()));
+    species.setY(new Double(glyph.getBbox().getY()));
+
+    Compartment parentCompartment = null;
+    if (glyph.getCompartmentRef() != null) {
+      Glyph compartmentGlyph = (Glyph) glyph.getCompartmentRef();
+      parentCompartment = model.getElementByElementId(compartmentGlyph.getId());
+    } else if (species.getComplex() == null) {
+      parentCompartment = findParentCompartment(species, model);
+    }
+    if (parentCompartment != null) {
+      species.setCompartment(parentCompartment);
+      parentCompartment.addElement(species);
+    }
+
+    // Parse units of information
+    for (Glyph child : glyph.getGlyph()) {
+      if (GlyphClazz.fromClazz(child.getClazz()).equals(GlyphClazz.UNIT_OF_INFORMATION)) {
+        parseUnitOfInformation(child, species);
+      }
+    }
+
+    model.addElement(species);
+  }
+
+  /**
+   * Finds a compartment where element should be located (base on the
+   * coordinates).
+   * 
+   * @param child
+   *          {@link Element} for which we want to find compartment
+   * @param model
+   *          {@link Model} where we look for a compartment
+   * @return parent {@link Compartment}
+   */
+  private Compartment findParentCompartment(Element child, Model model) {
+    Compartment nullParent = new Compartment("null");
+    nullParent.setWidth(Double.MAX_VALUE);
+    nullParent.setHeight(Double.MAX_VALUE);
+    nullParent.setX(0.0);
+    nullParent.setY(0.0);
+    Compartment parent = nullParent;
+    for (Compartment potentialParent : model.getCompartments()) {
+      if (potentialParent.contains(child)) {
+        if (parent.getSize() > potentialParent.getSize()) {
+          parent = potentialParent;
+        }
+      }
+    }
+    if (parent != nullParent) {
+      return parent;
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * Method used to retrieve multimer cardinality from a multimer glyph.
+   * 
+   * @param g
+   *          multimer glyph
+   * @return multimer cardinality
+   * @throws Exception
+   *           Exception is thrown if no proper unit of information with
+   *           cardinality was found
+   */
+  private int getMultimerCardinality(Glyph g) throws Exception {
+    int multimerCardinality = 0;
+    // Check all the children nodes looking for unit of information with
+    // cardinality
+    List<Glyph> children = g.getGlyph();
+    for (Glyph child : children) {
+      if (GlyphClazz.fromClazz(child.getClazz()) == GlyphClazz.UNIT_OF_INFORMATION) {
+        String[] splitLabel = child.getLabel().getText().split(":");
+        multimerCardinality = Integer.parseInt(splitLabel[1]);
+      }
+    }
+    // If no unit of information was found, or the cardinality is invalid,
+    // raise exception
+    if (multimerCardinality <= 0) {
+      throw new Exception(
+          "No proper unit of information with multimer cardinality was found." + " Glyph: " + g.getId());
+    }
+
+    return multimerCardinality;
+  }
+
+  /**
+   * Method used to decide if Nucleic-acid feature should be translated to RNA.
+   * 
+   * @param g
+   *          Nucleic-acid feature glyph
+   * @return true if input is RNA
+   */
+  private boolean isRNA(Glyph g) {
+    boolean rna = false;
+    // Check all the children nodes looking for unit of information
+    List<Glyph> children = g.getGlyph();
+    for (Glyph child : children) {
+      if (GlyphClazz.fromClazz(child.getClazz()) == GlyphClazz.UNIT_OF_INFORMATION) {
+        if (child.getLabel().getText().toLowerCase().contains("rna")) {
+          rna = true;
+        }
+      }
+    }
+
+    return rna;
+  }
+
+  /**
+   * Method used to parse state variable.
+   * 
+   * @param unitOfInformationGlyph
+   *          unit of information glyph from sbgn-ml file
+   * @param speciesGlyph
+   *          glyph that the unit of information considers
+   * @param newSpecies
+   *          species that the unit of information considers
+   * @throws Exception
+   *           Exception is thrown if state variable is parsed for species other
+   *           than Protein
+   */
+  private void parseStateVariable(Glyph unitOfInformationGlyph, Glyph speciesGlyph, Species newSpecies)
+      throws Exception {
+    if (!(newSpecies instanceof Protein)) {
+      throw new Exception("Only macromolecule elements can have state variables.");
+    }
+    Protein protein = (Protein) newSpecies;
+    Residue mr = new Residue();
+
+    mr.setSpecies(protein);
+    mr.setIdModificationResidue(unitOfInformationGlyph.getId());
+    if (unitOfInformationGlyph.getState() != null) {
+      // If State variable consists of value and variable
+      mr.setName(unitOfInformationGlyph.getState().getVariable());
+      for (ModificationState ms : ModificationState.values()) {
+        if (ms.getAbbreviation().equals(unitOfInformationGlyph.getState().getValue())) {
+          mr.setState(ms);
+        }
+      }
+    }
+
+    // Compute the angle from coordinates and dimensions
+    double x = unitOfInformationGlyph.getBbox().getX() + unitOfInformationGlyph.getBbox().getW() / 2;
+    double y = unitOfInformationGlyph.getBbox().getY() + unitOfInformationGlyph.getBbox().getH() / 2;
+
+    mr.setPosition(new Point2D.Double(x, y));
+
+    protein.addModificationResidue(mr);
+  }
+
+  /**
+   * Method used for parsing units of information.
+   * 
+   * @param unitOfInformationGlyph
+   *          unit of information glyph from sbgn-ml file
+   * @param alias
+   *          alias that the unit of information concerns
+   */
+  private void parseUnitOfInformation(Glyph unitOfInformationGlyph, Species alias) {
+    String unitOfInformationText = unitOfInformationGlyph.getLabel().getText();
+    if (unitOfInformationText.contains(":") && !unitOfInformationText.startsWith("N:")) {
+      String unitOfInformationPrefix = unitOfInformationText.substring(0, unitOfInformationText.indexOf(':'));
+      String unitOfInformationSuffix = unitOfInformationText.substring(unitOfInformationText.indexOf(':') + 1);
+      alias.setStatePrefix(unitOfInformationPrefix);
+      alias.setStateLabel(unitOfInformationSuffix);
+    } else if (!unitOfInformationText.startsWith("N:")) {
+      alias.setStateLabel(unitOfInformationText);
+      alias.setStatePrefix("free input");
+    }
+  }
+
+  /**
+   * Method used for parsing complex species.
+   * 
+   * @param complexGlyph
+   *          complex species glyph from sbgn-ml file
+   * @param parentComplexSpecies
+   *          parent complex species
+   * @param isHomodimer
+   *          set if the complex is a homodimer
+   * @param model
+   *          model to update with the parsed complex species
+   */
+  private void parseComplex(Glyph complexGlyph, Complex parentComplexSpecies, boolean isHomodimer, Model model) {
+    Complex complexSpecies = new Complex(complexGlyph.getId());
+    if (parentComplexSpecies != null) {
+      complexSpecies.setComplex(parentComplexSpecies);
+    }
+    parseSpecies(complexGlyph, complexSpecies, isHomodimer, model);
+
+    Complex complexAlias = model.getElementByElementId(complexGlyph.getId());
+    for (Glyph child : complexGlyph.getGlyph()) {
+      Species newSpecies;
+      switch (GlyphClazz.fromClazz(child.getClazz())) {
+      case UNSPECIFIED_ENTITY:
+        newSpecies = new Unknown(child.getId());
+        newSpecies.setComplex(complexSpecies);
+        parseSpecies(child, newSpecies, true, model);
+        break;
+      case SIMPLE_CHEMICAL:
+        newSpecies = new SimpleMolecule(child.getId());
+        newSpecies.setComplex(complexSpecies);
+        parseSpecies(child, newSpecies, true, model);
+        break;
+      case MACROMOLECULE:
+        newSpecies = new GenericProtein(child.getId());
+        newSpecies.setComplex(complexSpecies);
+        parseSpecies(child, newSpecies, true, model);
+        break;
+      case NUCLEIC_ACID_FEATURE:
+        newSpecies = new Gene(child.getId());
+        newSpecies.setComplex(complexSpecies);
+        parseSpecies(child, newSpecies, true, model);
+        break;
+      case SIMPLE_CHEMICAL_MULTIMER:
+        newSpecies = new SimpleMolecule(child.getId());
+        newSpecies.setComplex(complexSpecies);
+        parseSpecies(child, newSpecies, false, model);
+        break;
+      case MACROMOLECULE_MULTIMER:
+        newSpecies = new GenericProtein(child.getId());
+        newSpecies.setComplex(complexSpecies);
+        parseSpecies(child, newSpecies, false, model);
+        break;
+      case NUCLEIC_ACID_FEATURE_MULTIMER:
+        newSpecies = new Gene(child.getId());
+        newSpecies.setComplex(complexSpecies);
+        parseSpecies(child, newSpecies, false, model);
+        break;
+      case COMPLEX:
+        parseComplex(child, complexSpecies, true, model);
+        break;
+      case COMPLEX_MULTIMER:
+        parseComplex(child, complexSpecies, false, model);
+        break;
+      default:
+        break;
+      }
+      Species newAlias = model.getElementByElementId(child.getId());
+      if (newAlias != null) {
+        newAlias.setComplex(complexAlias);
+        complexAlias.addSpecies((Species) newAlias);
+      }
+    }
+  }
+
+  /**
+   * Method used to compute end point for modifier line.
+   * 
+   * @param a
+   *          SBGN-ML modifier arc
+   * @param reaction
+   *          reaction to which the arc points
+   * @return end point for modifier line
+   */
+  private Point2D getModifierEndPoint(Arc a, Reaction reaction) {
+    ModifierTypeUtils utils = new ModifierTypeUtils();
+    Point2D result;
+
+    Line2D centerLine = reaction.getCenterLine();
+    double dx = centerLine.getX2() - centerLine.getX1();
+    double dy = centerLine.getY2() - centerLine.getY1();
+    double centerLineAngle = Math.atan2(dy, dx);
+
+    Point2D centerPoint = new Point2D.Double(centerLine.getX1() + dx / 2, centerLine.getY1() + dy / 2);
+
+    // Retrieve second last point from the arc
+    Point2D secondLast;
+    if (a.getNext().isEmpty()) {
+      secondLast = new Point2D.Double(a.getStart().getX(), a.getStart().getY());
+    } else {
+      Next temp = a.getNext().get(a.getNext().size() - 1);
+      secondLast = new Point2D.Double(temp.getX(), temp.getY());
+    }
+
+    double dx2 = secondLast.getX() - centerPoint.getX();
+    double dy2 = secondLast.getY() - centerPoint.getY();
+    double modifierAngle = Math.atan2(dy2, dx2);
+
+    double finalAngle = modifierAngle - centerLineAngle;
+    while (finalAngle < -Math.PI) {
+      finalAngle += 2 * Math.PI;
+    }
+    while (finalAngle > Math.PI) {
+      finalAngle -= 2 * Math.PI;
+    }
+    String lineConnectionType = null;
+
+    // CHECKSTYLE:OFF
+    if (finalAngle < -Math.PI / 3 * 2) {
+      lineConnectionType = "0,4";
+    } else if (finalAngle < -Math.PI / 3) {
+      lineConnectionType = "0,2";
+    } else if (finalAngle < 0) {
+      lineConnectionType = "0,5";
+    } else if (finalAngle < Math.PI / 3) {
+      lineConnectionType = "0,7";
+    } else if (finalAngle < Math.PI / 3 * 2) {
+      lineConnectionType = "0,3";
+    } else {
+      lineConnectionType = "0,6";
+    }
+    // CHECKSTYLE:ON
+
+    result = utils.getAnchorPointOnReactionRect(reaction, lineConnectionType);
+
+    return result;
+  }
+
+  /**
+   * Method used to parse line points from SBGN-ML arc.
+   * 
+   * @param a
+   *          SBGN-ML arc
+   * @return list of line points
+   */
+  private List<Point2D> getLinePoints(Arc a) {
+    List<Point2D> pointList = new ArrayList<>();
+    Point2D startPoint = new Point2D.Double(a.getStart().getX(), a.getStart().getY());
+    Point2D endPoint = new Point2D.Double(a.getEnd().getX(), a.getEnd().getY());
+    pointList.add(startPoint);
+    for (Next nextPoint : a.getNext()) {
+      pointList.add(new Point2D.Double(nextPoint.getX(), nextPoint.getY()));
+    }
+    pointList.add(endPoint);
+    return pointList;
+  }
+
+  /**
+   * Method used for parsing lines from sbgn-ml arcs.
+   * 
+   * @param a
+   *          SBGN-ML arc
+   * @param pointList
+   *          list of points for the line
+   * @return line parsed from SBGN-ML arc
+   */
+  private PolylineData parseLine(Arc a, List<Point2D> pointList) {
+    PolylineData line = new PolylineData(pointList);
+    ArrowTypeData atd = new ArrowTypeData();
+
+    switch (ArcClazz.fromClazz(a.getClazz())) {
+    case CATALYSIS:
+      atd = ModifierType.CATALYSIS.getAtd();
+      break;
+    case CONSUMPTION:
+      atd.setArrowType(ArrowType.NONE);
+      break;
+    case INHIBITION:
+      atd = ModifierType.INHIBITION.getAtd();
+      break;
+    case MODULATION:
+      atd = ModifierType.MODULATION_STRING.getAtd();
+      break;
+    case NECESSARY_STIMULATION:
+      atd = ModifierType.TRIGGER_STRING.getAtd();
+      break;
+    case PRODUCTION:
+      atd.setArrowType(ArrowType.FULL);
+      break;
+    case STIMULATION:
+      atd = ModifierType.PHYSICAL_STIMULATION.getAtd();
+      break;
+    case LOGIC_ARC:
+      atd.setArrowType(ArrowType.NONE);
+      break;
+    default:
+      throw new InvalidArgumentException("Wrong arc class.");
+    }
+    atd.setArrowLineType(LineType.SOLID);
+    line.setEndAtd(atd.copy());
+    return line;
+  }
+
+  /**
+   * Returns {@link AndOperator} for the reaction's reagents port.
+   * 
+   * @param p
+   *          process of the reaction
+   * @return operator for the reaction port
+   */
+  private AndOperator getReactionPortAndOperator(Process p) {
+    AndOperator andOperator = new AndOperator();
+    Glyph centralPoint = p.getCentralPoint();
+    Double centralPointX = new Double(centralPoint.getBbox().getX() + centralPoint.getBbox().getW() / 2);
+    Double centralPointY = new Double(centralPoint.getBbox().getY() + centralPoint.getBbox().getH() / 2);
+    Point2D centerOfReactionPoint = new Point2D.Double(centralPointX, centralPointY);
+    Point2D portPoint;
+    if (p.getReagentArcs().size() > 1) {
+      portPoint = new Point2D.Double(p.getReagentArcs().get(0).getEnd().getX(),
+          p.getReagentArcs().get(0).getEnd().getY());
+    } else {
+      portPoint = new Point2D.Double(p.getRevReagentArcs().get(0).getStart().getX(),
+          p.getRevReagentArcs().get(0).getStart().getY());
+    }
+    PolylineData line = new PolylineData(portPoint, centerOfReactionPoint);
+    ArrowTypeData atd = new ArrowTypeData();
+    atd.setArrowType(ArrowType.NONE);
+    atd.setArrowLineType(LineType.SOLID);
+    line.setEndAtd(atd);
+    andOperator.setLine(line);
+    return andOperator;
+  }
+
+  /**
+   * Returns {@link SplitOperator} for the reaction's products port.
+   * 
+   * @param p
+   *          process of the reaction
+   * @return operator for the reaction port
+   */
+  private SplitOperator getReactionPortSplitOperator(Process p) {
+    SplitOperator splitOperator = new SplitOperator();
+    Glyph centralPoint = p.getCentralPoint();
+    Double centralPointX = new Double(centralPoint.getBbox().getX() + centralPoint.getBbox().getW() / 2);
+    Double centralPointY = new Double(centralPoint.getBbox().getY() + centralPoint.getBbox().getH() / 2);
+    Point2D centerOfReactionPoint = new Point2D.Double(centralPointX, centralPointY);
+    Point2D portPoint;
+    if (!p.isReversible()) {
+      portPoint = new Point2D.Double(p.getProductArcs().get(0).getStart().getX(),
+          p.getProductArcs().get(0).getStart().getY());
+    } else {
+      portPoint = new Point2D.Double(p.getRevProductArcs().get(0).getStart().getX(),
+          p.getRevProductArcs().get(0).getStart().getY());
+    }
+    PolylineData line = new PolylineData(centerOfReactionPoint, portPoint);
+    ArrowTypeData atd = new ArrowTypeData();
+    atd.setArrowType(ArrowType.NONE);
+    atd.setArrowLineType(LineType.SOLID);
+    line.setEndAtd(atd);
+    splitOperator.setLine(line);
+    return splitOperator;
+  }
+
+  /**
+   * Returns instance of {@link Modifier} based on given {@link ArcClazz}.
+   * 
+   * @param ac
+   *          {@link ArcClazz} defining the result
+   * @return {@link Modifier} of class adequate to given ac
+   * @throws Exception
+   *           thrown when no adequate Modifier has been found
+   */
+  private Modifier getModifierFromArcClazz(ArcClazz ac) throws Exception {
+    switch (ac) {
+    case CATALYSIS:
+      return new Catalysis();
+    case INHIBITION:
+      return new Inhibition();
+    case MODULATION:
+      return new Modulation();
+    case NECESSARY_STIMULATION:
+      return new Trigger();
+    case STIMULATION:
+      return new PhysicalStimulation();
+    default:
+      logger.warn("Modifier arc of invalid class.");
+      throw new Exception("Wrong arc class.");
+    }
+  }
+
+  /**
+   * Returns center point for given process.
+   * 
+   * @param p
+   *          completely parsed process to compute center point from
+   * @return center point for given process
+   */
+  private Point2D getCenterPointFromProcess(Process p) {
+    Double centralPointX = new Double(p.getCentralPoint().getBbox().getX() + p.getCentralPoint().getBbox().getW() / 2);
+    Double centralPointY = new Double(p.getCentralPoint().getBbox().getY() + p.getCentralPoint().getBbox().getH() / 2);
+    Point2D centerOfReactionPoint = new Point2D.Double(centralPointX, centralPointY);
+    return centerOfReactionPoint;
+  }
+
+  /**
+   * Returns proper Reaction object based on given glyph clazz.
+   * 
+   * @param glyphClazz
+   *          clazz of the process glyph
+   * @return Reaction object based on given glyph clazz
+   */
+  private Reaction getReactionFromProcessGlyphClazz(String glyphClazz) {
+    switch (GlyphClazz.fromClazz(glyphClazz)) {
+    case ASSOCIATION:
+    case DISSOCIATION:
+    case PROCESS:
+      return new StateTransitionReaction();
+    case OMITTED_PROCESS:
+      return new KnownTransitionOmittedReaction();
+    case UNCERTAIN_PROCESS:
+      return new UnknownTransitionReaction();
+    default:
+      throw new InvalidArgumentException();
+
+    }
+  }
+
+  /**
+   * Method used for parsing processes into reactions.
+   * 
+   * @param p
+   *          process to be parsed
+   * @param model
+   *          model to be updated with the parsed reaction
+   * @throws Exception
+   *           thrown when the process was invalid
+   */
+  private void parseProcess(Process p, Model model) throws Exception {
+    if (p.getProductArcs().isEmpty()) {
+      throw new Exception(p.getCentralPoint().getId() + ": The process must have at least one outgoing arc.");
+    }
+    p.setProductsPort((Port) p.getProductArcs().get(0).getSource());
+    for (Arc productArc : p.getProductArcs()) {
+      if (!((Port) productArc.getSource()).equals(p.getProductsPort())) {
+        p.setReversible(true);
+        p.setReagentsPort((Port) productArc.getSource());
+      }
+    }
+    if (p.getReagentsPort() == null && !p.getReagentArcs().isEmpty()) {
+      p.setReagentsPort((Port) p.getReagentArcs().get(0).getTarget());
+    }
+
+    if ((p.getReagentArcs().isEmpty() && !p.isReversible()) || (p.getRevReagentArcs().isEmpty() && p.isReversible())) {
+      throw new Exception(p.getCentralPoint().getId() + ": The process must have at least one incoming arc.");
+    }
+
+    Reaction reaction;
+    if (p.getCentralPoint() == null) {
+      throw new Exception("Process has no central point.");
+    }
+    reaction = getReactionFromProcessGlyphClazz(p.getCentralPoint().getClazz());
+    reaction.setIdReaction(p.getCentralPoint().getId());
+    reaction.setModel(model);
+
+    reaction.setReversible(p.isReversible());
+
+    // If there are multiple inputs, add "AND" operator
+    AndOperator andOperator = null;
+    if (p.getReagentArcs().size() > 1 || p.getRevReagentArcs().size() > 1) {
+      andOperator = getReactionPortAndOperator(p);
+      andOperator.setReaction(reaction);
+      reaction.addNode(andOperator);
+    }
+
+    // If there are multiple outputs, add Split operator
+    SplitOperator splitOperator = null;
+    if ((p.getProductArcs().size() > 1 && !p.isReversible())
+        || (p.isReversible() && p.getRevProductArcs().size() > 1)) {
+      splitOperator = getReactionPortSplitOperator(p);
+      splitOperator.setReaction(reaction);
+      reaction.addNode(splitOperator);
+    }
+
+    for (Arc a : p.getReagentArcs()) {
+      Reactant reactant = new Reactant();
+      reactant.setReaction(reaction);
+      Glyph source = (Glyph) a.getSource();
+      reactant.setElement(model.getElementByElementId(source.getId()));
+      List<Point2D> pointList = getLinePoints(a);
+      if (p.getReagentArcs().size() == 1) {
+        pointList.add(getCenterPointFromProcess(p));
+      } else {
+        pointList.add(pointList.get(pointList.size() - 1));
+      }
+      PolylineData line = parseLine(a, pointList);
+      reactant.setLine(line);
+      if (andOperator != null) {
+        andOperator.addInput(reactant);
+      }
+
+      reaction.addReactant(reactant);
+    }
+
+    for (Arc a : p.getProductArcs()) {
+      if (((Port) a.getSource()).equals(p.getProductsPort())) {
+        Product product = new Product();
+        product.setReaction(reaction);
+        Glyph target = (Glyph) a.getTarget();
+        product.setElement(model.getElementByElementId(target.getId()));
+        List<Point2D> pointList = getLinePoints(a);
+        if (p.getRevProductArcs().size() >= 1) {
+          pointList.add(0, getCenterPointFromProcess(p));
+        } else {
+          pointList.add(0, pointList.get(0));
+        }
+        PolylineData line = parseLine(a, pointList);
+        product.setLine(line);
+        if (splitOperator != null) {
+          splitOperator.addOutput(product);
+        }
+
+        reaction.addProduct(product);
+      } else {
+        Reactant reactant = new Reactant();
+        reactant.setReaction(reaction);
+        Glyph source = (Glyph) a.getTarget();
+        reactant.setElement(model.getElementByElementId(source.getId()));
+        List<Point2D> pointList = getLinePoints(a);
+        if (p.getRevReagentArcs().size() <= 1) {
+          pointList.add(0, getCenterPointFromProcess(p));
+        } else {
+          pointList.add(0, pointList.get(0));
+        }
+        PolylineData line = parseLine(a, pointList);
+        line = line.reverse();
+        reactant.setLine(line);
+        if (andOperator != null) {
+          andOperator.addInput(reactant);
+        }
+
+        reaction.addReactant(reactant);
+      }
+    }
+    for (Arc a : p.getModifierArcs()) {
+      Modifier modifier = null;
+      try {
+        modifier = getModifierFromArcClazz(ArcClazz.fromClazz(a.getClazz()));
+      } catch (Exception ex) {
+        logger.warn("Unable to add modifier");
+        continue;
+      }
+      if (a.getSource() instanceof Glyph) {
+        Glyph sourceGlyph = (Glyph) a.getSource();
+        Species modifierAlias = (Species) model.getElementByElementId(sourceGlyph.getId());
+        modifier.setElement(modifierAlias);
+        List<Point2D> pointList = getLinePoints(a);
+        pointList.remove(pointList.size() - 1);
+        pointList.add(getModifierEndPoint(a, reaction));
+        PolylineData line = parseLine(a, pointList);
+        modifier.setLine(line);
+
+        reaction.addModifier(modifier);
+      } else if (a.getSource() instanceof Port) {
+        // Logic operator
+        try {
+          parseLogicOperator(a, reaction, ArcClazz.fromClazz(a.getClazz()), null, model);
+        } catch (Exception ex) {
+          logger.warn(ex.getMessage());
+        }
+      }
+
+    }
+
+    model.addReaction(reaction);
+  }
+
+  /**
+   * Returns {@link ArrowTypeData} based on given {@link ArcClazz}.
+   * 
+   * @param ac
+   *          input arc class
+   * @return ArrowTypeData based on input arrow class
+   * @throws Exception
+   *           thrown when invalid arc class was given on input
+   */
+  private ArrowTypeData getAtdFromArcClazz(ArcClazz ac) throws Exception {
+    ArrowTypeData atd = new ArrowTypeData();
+    switch (ac) {
+    case CATALYSIS:
+      atd = ModifierType.CATALYSIS.getAtd();
+      break;
+    case CONSUMPTION:
+      atd.setArrowType(ArrowType.NONE);
+      break;
+    case INHIBITION:
+      atd = ModifierType.INHIBITION.getAtd();
+      break;
+    case MODULATION:
+      atd = ModifierType.MODULATION_STRING.getAtd();
+      break;
+    case NECESSARY_STIMULATION:
+      atd = ModifierType.TRIGGER_STRING.getAtd();
+      break;
+    case PRODUCTION:
+      atd.setArrowType(ArrowType.FULL);
+      break;
+    case STIMULATION:
+      atd = ModifierType.PHYSICAL_STIMULATION.getAtd();
+      break;
+    case LOGIC_ARC:
+      atd.setArrowType(ArrowType.NONE);
+      break;
+    default:
+      throw new Exception("Wrong arc class.");
+    }
+    return atd.copy();
+  }
+
+  /**
+   * Method used for parsing logic operators.
+   * 
+   * @param arc
+   *          arc with a starting point in the logic operator
+   * @param reaction
+   *          reaction that the logic operator is a part of
+   * @param modifierClass
+   *          determines type of source species
+   * @param targetOperator
+   *          target logic operator
+   * @param model
+   *          model of the map
+   * @throws Exception
+   *           thrown when parsed logic operator is invalid
+   */
+  private void parseLogicOperator(Arc arc, Reaction reaction, ArcClazz modifierClass, NodeOperator targetOperator,
+      Model model) throws Exception {
+    Port operatorPort = (Port) arc.getSource();
+    Glyph logicOperator = null;
+    for (Glyph lo : logicOperators) {
+      if (lo.getPort().contains(operatorPort)) {
+        logicOperator = lo;
+      }
+    }
+    if (logicOperator == null) {
+      throw new Exception("Missing logic operator for logic arc: " + arc.getId());
+    }
+
+    // LogicOperator is valid for CellDesigner only if it has exactly 2
+    // inputs of Species
+    final Glyph tempLogicOperator = logicOperator;
+    boolean isCellDesignerValidLogicOperator = logicArcs.stream()
+        .filter(a -> tempLogicOperator.getPort().contains(a.getTarget()) && !(a.getSource() instanceof Port))
+        .count() == 2;
+    if (!isCellDesignerValidLogicOperator) {
+      throw new Exception("Parsed operator is not valid for CellDesigner: " + logicOperator.getId());
+    }
+
+    NodeOperator operator;
+    switch (GlyphClazz.fromClazz(logicOperator.getClazz())) {
+    case AND:
+      operator = new AndOperator();
+      break;
+    case OR:
+      operator = new OrOperator();
+      break;
+    case NOT:
+      logger.warn(
+          "NOT gates are not implemented in the platform. Glyph: " + logicOperator.getId() + " has not been parsed.");
+      return;
+    default:
+      throw new Exception("Wrong logic operator class.");
+    }
+
+    // Parse line from arc and operator glyph
+    Point2D operatorCenterPoint = new Point2D.Double(
+        logicOperator.getBbox().getX() + logicOperator.getBbox().getW() / 2,
+        logicOperator.getBbox().getY() + logicOperator.getBbox().getH() / 2);
+
+    List<Point2D> linePoints = getLinePoints(arc);
+    new ArrayList<Point2D>();
+
+    if (targetOperator == null) {
+      linePoints.remove(linePoints.size() - 1);
+      linePoints.add(getModifierEndPoint(arc, reaction));
+    }
+
+    // Check if operator port is in the line from center point of the
+    // operator. If so, remove that redundant point.
+    double dx, dy;
+    dx = linePoints.get(0).getX() - operatorCenterPoint.getX();
+    dy = linePoints.get(0).getY() - operatorCenterPoint.getY();
+    double dx2, dy2;
+    if (arc.getNext().isEmpty()) {
+      dx2 = linePoints.get(linePoints.size() - 1).getX() - linePoints.get(0).getX();
+      dy2 = linePoints.get(linePoints.size() - 1).getY() - linePoints.get(0).getY();
+    } else {
+      dx2 = arc.getNext().get(0).getX() - linePoints.get(0).getX();
+      dy2 = arc.getNext().get(0).getY() - linePoints.get(0).getY();
+    }
+    DoubleComparator doubleComparator = new DoubleComparator();
+    if (doubleComparator.compare(dy / dx, dy2 / dx2) == 0) {
+      linePoints.remove(0);
+    }
+    linePoints.add(0, operatorCenterPoint);
+
+    PolylineData line = new PolylineData(linePoints);
+    ArrowTypeData atd = getAtdFromArcClazz(ArcClazz.fromClazz(arc.getClazz()));
+
+    atd.setArrowLineType(LineType.SOLID);
+    line.setEndAtd(atd);
+
+    operator.setLine(line);
+    operator.setReaction(reaction);
+
+    if (targetOperator != null) {
+      operator.addOutput(targetOperator);
+      targetOperator.addInput(operator);
+    }
+
+    for (Arc logicArc : logicArcs) {
+      if (logicOperator.getPort().contains(logicArc.getTarget())) {
+        if (logicArc.getSource() instanceof Port) {
+          // The arc has source in logic operator
+          logger.warn("Logic operators trees are not compatible with CellDesigner. Therefore they are not supported.");
+          continue;
+          // parseLogicOperator(logicArc, reaction, modifierClass,
+          // operator, model);
+        } else {
+          Modifier modifier;
+
+          switch (modifierClass) {
+          case CATALYSIS:
+            modifier = new Catalysis();
+            break;
+          case INHIBITION:
+            modifier = new Inhibition();
+            break;
+          case MODULATION:
+            modifier = new Modulation();
+            break;
+          case NECESSARY_STIMULATION:
+            modifier = new Trigger();
+            break;
+          case STIMULATION:
+            modifier = new PhysicalStimulation();
+            break;
+          default:
+            throw new Exception("Wrong arc class.");
+          }
+
+          Glyph sourceGlyph = (Glyph) logicArc.getSource();
+          Species modifierAlias = (Species) model.getElementByElementId(sourceGlyph.getId());
+          modifier.setElement(modifierAlias);
+          List<Point2D> pointList = getLinePoints(logicArc);
+          pointList.add(operatorCenterPoint);
+          PolylineData newLine = parseLine(logicArc, pointList);
+          modifier.setLine(newLine);
+
+          operator.addInput(modifier);
+
+          reaction.addModifier(modifier);
+        }
+      }
+    }
+    reaction.addNode(operator);
+  }
+
+  /**
+   * Method used for parsing compartments.
+   * 
+   * @param glyph
+   *          compartment glyph from sbgn-ml file
+   * @param model
+   *          model to be updated with the parsed compartment
+   */
+  private void parseCompartment(Glyph glyph, Model model) {
+
+    Compartment compartment = new SquareCompartment(glyph.getId());
+    if (glyph.getLabel() != null) {
+      compartment.setName(glyph.getLabel().getText());
+    }
+    compartment.setModel(model);
+    compartment.setHeight(new Double(glyph.getBbox().getH()));
+    compartment.setWidth(new Double(glyph.getBbox().getW()));
+    compartment.setX(new Double(glyph.getBbox().getX()));
+    compartment.setY(new Double(glyph.getBbox().getY()));
+    compartment.setThickness(1.0);
+    compartment.setColor(COMPARTMENT_COLOR);
+
+    if (glyph.getLabel() != null && glyph.getLabel().getBbox() != null) {
+      compartment.setNamePoint(glyph.getLabel().getBbox().getX(), glyph.getLabel().getBbox().getY());
+    } else {
+      compartment.setNamePoint(compartment.getX() + compartment.getThickness() + CONTAINER_NAME_MARGIN,
+          compartment.getY() + compartment.getThickness() + CONTAINER_NAME_MARGIN);
+    }
+    Compartment parent = findParentCompartment(compartment, model);
+    if (parent != null) {
+      compartment.setCompartment(parent);
+      parent.addElement(compartment);
+    }
+
+    model.addElement(compartment);
+  }
+}
diff --git a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/AllSbgnmlTests.java b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/AllSbgnmlTests.java
index 021f39c68f5fcf039fdcf0193f6d22a711e6dd64..255c1446232c9d447b90e23d74b373f387b9f613 100644
--- a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/AllSbgnmlTests.java
+++ b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/AllSbgnmlTests.java
@@ -9,7 +9,8 @@ import org.junit.runners.Suite.SuiteClasses;
 		CellDesignerToSbgnTest.class, //
 		DbSerializationTest.class, //
 		SbgnmlXmlExporterTest.class, //
-		SbgnmlXmlParserTest.class, //
+        SbgnmlXmlParserTest.class, //
+        SbgnmlXmlParserTest2.class, //
 })
 public class AllSbgnmlTests {
 
diff --git a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/DbSerializationTest.java b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/DbSerializationTest.java
index c98a7c7b0094e0509ea67d57e6b168a4ac2b8c87..f6f2695890c17c904ca3d40bc12e4c3c5e27b112 100644
--- a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/DbSerializationTest.java
+++ b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/DbSerializationTest.java
@@ -1,110 +1,111 @@
-package lcsb.mapviewer.converter.model.sbgnml;
-
-import static org.junit.Assert.assertEquals;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-import org.springframework.transaction.annotation.Transactional;
-
-import lcsb.mapviewer.converter.ConverterParams;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelComparator;
-import lcsb.mapviewer.model.map.model.ModelFullIndexed;
-import lcsb.mapviewer.persist.DbUtils;
-import lcsb.mapviewer.persist.dao.map.ModelDao;
-
-@Transactional(value = "txManager")
-@ContextConfiguration(locations = { "/applicationContext-persist.xml", //
-		"/test-applicationContext.xml",//
-		"/dataSource.xml", //
-		
-})
-@RunWith(SpringJUnit4ClassRunner.class)
-public class DbSerializationTest {
-	@Autowired
-	ModelDao modelDao;
-	@Autowired
-	DbUtils	 dbUtils;
-
-	Logger	 logger	= Logger.getLogger(DbSerializationTest.class.getName());
-
-	private void makeDbSerializationTest(String filePath) throws Exception {
-		SbgnmlXmlParser parser = new SbgnmlXmlParser();
-
-		Model model = parser.createModel(new ConverterParams().filename("testFiles/sbgnmlParserTestFiles/sbgnmlFiles/".concat(filePath)));
-
-		modelDao.add(model);
-		modelDao.flush();
-		modelDao.commit();
-		modelDao.evict(model);
-		Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
-
-		ModelComparator comparator = new ModelComparator();
-		assertEquals(0, comparator.compare(model, model2));
-		modelDao.delete(model2);
-	}
-
-	@Before
-	public void setUp() throws Exception {
-		// we use custom threads because in layoutservice there is commit method
-		// called, and because of that hibernate session injected by spring
-		// cannot
-		// commit at the end of the test case
-
-		dbUtils.createSessionForCurrentThread();
-
-	}
-
-	@After
-	public void tearDown() throws Exception {
-		// close session
-		dbUtils.closeSessionForCurrentThread();
-	}
-
-	@Test
-	public void VANTEDdiagramTest() throws Exception {
-		makeDbSerializationTest("VANTEDdiagram.sbgn");
-	}
-
-	@Test
-	public void activatedStat1AlphaTest() throws Exception {
-		makeDbSerializationTest("activated_stat1alpha_induction_of_the_irf1_gene.sbgn");
-	}
-
-	@Test
-	public void adhTest() throws Exception {
-		makeDbSerializationTest("adh.sbgn");
-	}
-
-	@Test
-	public void cloneMarkerTest() throws Exception {
-		makeDbSerializationTest("clone-marker.sbgn");
-	}
-
-	@Test
-	public void glycolysisTest() throws Exception {
-		makeDbSerializationTest("glycolysis.sbgn");
-	}
-
-	@Test
-	public void insulinLikeGrowthFactorSignalingTest() throws Exception {
-		makeDbSerializationTest("insulin-like_growth_factor_signaling.sbgn");
-	}
-
-	@Test
-	public void neuronalMuscleSignallingTest() throws Exception {
-		makeDbSerializationTest("neuronal_muscle_signalling.sbgn");
-	}
-
-	@Test
-	public void phenotypeTest() throws Exception {
-		makeDbSerializationTest("phenotypeTest.sbgn");
-	}
-
-}
+package lcsb.mapviewer.converter.model.sbgnml;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import lcsb.mapviewer.converter.ConverterParams;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelComparator;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.persist.DbUtils;
+import lcsb.mapviewer.persist.dao.map.ModelDao;
+
+@Transactional(value = "txManager")
+@ContextConfiguration(locations = { "/applicationContext-persist.xml", //
+    "/test-applicationContext.xml", //
+    "/dataSource.xml", //
+
+})
+@RunWith(SpringJUnit4ClassRunner.class)
+public class DbSerializationTest {
+  @Autowired
+  ModelDao modelDao;
+  @Autowired
+  DbUtils dbUtils;
+
+  Logger logger = Logger.getLogger(DbSerializationTest.class.getName());
+
+  private void makeDbSerializationTest(String filePath) throws Exception {
+    SbgnmlXmlParser parser = new SbgnmlXmlParser();
+
+    Model model = parser
+        .createModel(new ConverterParams().filename("testFiles/sbgnmlParserTestFiles/sbgnmlFiles/".concat(filePath)));
+
+    modelDao.add(model);
+    modelDao.flush();
+    modelDao.commit();
+    modelDao.evict(model);
+    Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
+
+    ModelComparator comparator = new ModelComparator();
+    assertEquals(0, comparator.compare(model, model2));
+    modelDao.delete(model2);
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    // we use custom threads because in layoutservice there is commit method
+    // called, and because of that hibernate session injected by spring
+    // cannot
+    // commit at the end of the test case
+
+    dbUtils.createSessionForCurrentThread();
+
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    // close session
+    dbUtils.closeSessionForCurrentThread();
+  }
+
+  @Test
+  public void VANTEDdiagramTest() throws Exception {
+    makeDbSerializationTest("VANTEDdiagram.sbgn");
+  }
+
+  @Test
+  public void activatedStat1AlphaTest() throws Exception {
+    makeDbSerializationTest("activated_stat1alpha_induction_of_the_irf1_gene.sbgn");
+  }
+
+  @Test
+  public void adhTest() throws Exception {
+    makeDbSerializationTest("adh.sbgn");
+  }
+
+  @Test
+  public void cloneMarkerTest() throws Exception {
+    makeDbSerializationTest("clone-marker.sbgn");
+  }
+
+  @Test
+  public void glycolysisTest() throws Exception {
+    makeDbSerializationTest("glycolysis.sbgn");
+  }
+
+  @Test
+  public void insulinLikeGrowthFactorSignalingTest() throws Exception {
+    makeDbSerializationTest("insulin-like_growth_factor_signaling.sbgn");
+  }
+
+  @Test
+  public void neuronalMuscleSignallingTest() throws Exception {
+    makeDbSerializationTest("neuronal_muscle_signalling.sbgn");
+  }
+
+  @Test
+  public void phenotypeTest() throws Exception {
+    makeDbSerializationTest("phenotypeTest.sbgn");
+  }
+
+}
diff --git a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParserTest.java b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParserTest.java
index 97da4b1aa9df9806b0d60f0c66fac046cd8c8d20..a6940ca9003e4793bd116d85ac473edd9d27907f 100644
--- a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParserTest.java
+++ b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParserTest.java
@@ -1,125 +1,131 @@
-package lcsb.mapviewer.converter.model.sbgnml;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.Collection;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.log4j.Logger;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import lcsb.mapviewer.converter.ConverterParams;
-import lcsb.mapviewer.converter.IConverter;
-import lcsb.mapviewer.converter.graphics.AbstractImageGenerator;
-import lcsb.mapviewer.converter.graphics.NormalImageGenerator;
-import lcsb.mapviewer.converter.graphics.PngImageGenerator;
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelComparator;
-
-@RunWith(Parameterized.class)
-public class SbgnmlXmlParserTest {
-
-	Logger			 logger	= Logger.getLogger(SbgnmlXmlParserTest.class.getName());
-
-	private Path filePath;
-
-	public SbgnmlXmlParserTest(Path filePath) {
-		this.filePath = filePath;
-	}
-
-	@Parameters(name = "{index} : {0}")
-	public static Collection<Object[]> data() throws IOException {
-		Collection<Object[]> data = new ArrayList<Object[]>();
-		Files.walk(Paths.get("testFiles/sbgnmlParserTestFiles/sbgnmlFiles")).forEach(fPath -> {
-			if (Files.isRegularFile(fPath) && fPath.toString().endsWith(".sbgn") && !fPath.getFileName().toString().startsWith("ASTHMA")) {
-				data.add(new Object[] { fPath });
-			}
-		});
-		return data;
-	}
-
-	@Test
-	public void createModelTest() throws Exception {
-		try {
-			String dir = Files.createTempDirectory("sbgn-temp-images-dir").toFile().getAbsolutePath();
-
-			IConverter converter = new SbgnmlXmlConverter();
-
-			Model model = converter.createModel(new ConverterParams().filename(filePath.toString()));
-
-			// Create and display image of parsed map
-			AbstractImageGenerator.Params params = new AbstractImageGenerator.Params()
-					.height(model.getHeight()).width(model.getWidth()).nested(true).scale(1).level(20).x(0).y(0).model(model);
-			NormalImageGenerator nig = new PngImageGenerator(params);
-			String pngFilePath = dir + "/".concat(filePath.getFileName().toString().substring(0, filePath.getFileName().toString().indexOf(".sbgn"))).concat(".png");
-			nig.saveToFile(pngFilePath);
-
-			CellDesignerXmlParser cellDesignerXmlParser = new CellDesignerXmlParser();
-			String xmlString = cellDesignerXmlParser.toXml(model);
-
-			String cellDesignerFilePath = dir
-					+ "/".concat(filePath.getFileName().toString().substring(0, filePath.getFileName().toString().indexOf(".sbgn"))).concat(".xml");
-			PrintWriter out = new PrintWriter(cellDesignerFilePath);
-			out.print(xmlString);
-			out.close();
-
-			InputStream is = new ByteArrayInputStream(xmlString.getBytes("UTF-8"));
-
-			Model model2 = cellDesignerXmlParser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			AbstractImageGenerator.Params params2 = new AbstractImageGenerator.Params()
-					.height(model2.getHeight()).width(model2.getWidth()).nested(true).scale(1).level(20).x(0).y(0).model(model2);
-			NormalImageGenerator nig2 = new PngImageGenerator(params2);
-			String pngFilePath2 = dir
-					+ "/".concat(filePath.getFileName().toString().substring(0, filePath.getFileName().toString().indexOf(".sbgn"))).concat("_2.png");
-			nig2.saveToFile(pngFilePath2);
-
-			assertNotNull(model2);
-			// for (Reaction r : model.getReactions()) {
-			// logger.debug("Reaction: " + r.getIdReaction());
-			// for (AbstractNode node: r.getNodes()){
-			// logger.debug(node);
-			// for (Point2D point: node.getLine().getPoints())
-			// logger.debug(point);
-			// }
-			// logger.debug("--");
-			// }
-			// for (Reaction r : model2.getReactions()) {
-			// logger.debug("Reaction: " + r.getIdReaction());
-			// for (AbstractNode node: r.getNodes()){
-			// logger.debug(node);
-			// for (Point2D point: node.getLine().getPoints())
-			// logger.debug(point);
-			// }
-			// logger.debug("--");
-			// }
-
-			// logger.debug(pngFilePath);
-			// logger.debug(pngFilePath2);
-			ModelComparator comparator = new ModelComparator(1.0);
-			assertEquals(0, comparator.compare(model, model2));
-			FileUtils.deleteDirectory(new File(dir));
-
-		} catch (Exception e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-			throw e;
-		}
-		logger.debug(filePath);
-	}
-
-}
+package lcsb.mapviewer.converter.model.sbgnml;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.log4j.Logger;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import lcsb.mapviewer.converter.ConverterParams;
+import lcsb.mapviewer.converter.IConverter;
+import lcsb.mapviewer.converter.graphics.AbstractImageGenerator;
+import lcsb.mapviewer.converter.graphics.NormalImageGenerator;
+import lcsb.mapviewer.converter.graphics.PngImageGenerator;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelComparator;
+import lcsb.mapviewer.model.map.species.Protein;
+
+@RunWith(Parameterized.class)
+public class SbgnmlXmlParserTest {
+
+  Logger logger = Logger.getLogger(SbgnmlXmlParserTest.class.getName());
+
+  private Path filePath;
+
+  public SbgnmlXmlParserTest(Path filePath) {
+    this.filePath = filePath;
+  }
+
+  @Parameters(name = "{index} : {0}")
+  public static Collection<Object[]> data() throws IOException {
+    Collection<Object[]> data = new ArrayList<Object[]>();
+    Files.walk(Paths.get("testFiles/sbgnmlParserTestFiles/sbgnmlFiles")).forEach(fPath -> {
+      if (Files.isRegularFile(fPath) && fPath.toString().endsWith(".sbgn")
+          && !fPath.getFileName().toString().startsWith("ASTHMA")) {
+        data.add(new Object[] { fPath });
+      }
+    });
+    return data;
+  }
+
+  @Test
+  public void createModelTest() throws Exception {
+    try {
+      String dir = Files.createTempDirectory("sbgn-temp-images-dir").toFile().getAbsolutePath();
+
+      IConverter converter = new SbgnmlXmlConverter();
+
+      Model model = converter.createModel(new ConverterParams().filename(filePath.toString()));
+
+      // Create and display image of parsed map
+      AbstractImageGenerator.Params params = new AbstractImageGenerator.Params().height(model.getHeight())
+          .width(model.getWidth()).nested(true).scale(1).level(20).x(0).y(0).model(model);
+      NormalImageGenerator nig = new PngImageGenerator(params);
+      String pngFilePath = dir + "/"
+          .concat(filePath.getFileName().toString().substring(0, filePath.getFileName().toString().indexOf(".sbgn")))
+          .concat(".png");
+      nig.saveToFile(pngFilePath);
+
+      CellDesignerXmlParser cellDesignerXmlParser = new CellDesignerXmlParser();
+      String xmlString = cellDesignerXmlParser.toXml(model);
+
+      String cellDesignerFilePath = dir + "/"
+          .concat(filePath.getFileName().toString().substring(0, filePath.getFileName().toString().indexOf(".sbgn")))
+          .concat(".xml");
+      PrintWriter out = new PrintWriter(cellDesignerFilePath);
+      out.print(xmlString);
+      out.close();
+
+      InputStream is = new ByteArrayInputStream(xmlString.getBytes("UTF-8"));
+
+      Model model2 = cellDesignerXmlParser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+      AbstractImageGenerator.Params params2 = new AbstractImageGenerator.Params().height(model2.getHeight())
+          .width(model2.getWidth()).nested(true).scale(1).level(20).x(0).y(0).model(model2);
+      NormalImageGenerator nig2 = new PngImageGenerator(params2);
+      String pngFilePath2 = dir + "/"
+          .concat(filePath.getFileName().toString().substring(0, filePath.getFileName().toString().indexOf(".sbgn")))
+          .concat("_2.png");
+      nig2.saveToFile(pngFilePath2);
+
+      assertNotNull(model2);
+      // for (Reaction r : model.getReactions()) {
+      // logger.debug("Reaction: " + r.getIdReaction());
+      // for (AbstractNode node: r.getNodes()){
+      // logger.debug(node);
+      // for (Point2D point: node.getLine().getPoints())
+      // logger.debug(point);
+      // }
+      // logger.debug("--");
+      // }
+      // for (Reaction r : model2.getReactions()) {
+      // logger.debug("Reaction: " + r.getIdReaction());
+      // for (AbstractNode node: r.getNodes()){
+      // logger.debug(node);
+      // for (Point2D point: node.getLine().getPoints())
+      // logger.debug(point);
+      // }
+      // logger.debug("--");
+      // }
+
+      // logger.debug(pngFilePath);
+      // logger.debug(pngFilePath2);
+      ModelComparator comparator = new ModelComparator(1.0);
+      assertEquals(0, comparator.compare(model, model2));
+      FileUtils.deleteDirectory(new File(dir));
+
+    } catch (Exception e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+      throw e;
+    }
+//    logger.debug(filePath);
+  }
+
+}
diff --git a/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParserTest2.java b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParserTest2.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4c7f7f03847f2a90a8d43b825cbc6c0cd5958c1
--- /dev/null
+++ b/converter-SBGNML/src/test/java/lcsb/mapviewer/converter/model/sbgnml/SbgnmlXmlParserTest2.java
@@ -0,0 +1,36 @@
+package lcsb.mapviewer.converter.model.sbgnml;
+
+import static org.junit.Assert.assertTrue;
+
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+import org.junit.Test;
+
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.field.Residue;
+
+public class SbgnmlXmlParserTest2 {
+
+  Logger logger = Logger.getLogger(SbgnmlXmlParserTest2.class.getName());
+
+  @Test
+  public void testAdjustModificationCoordinates() throws Exception {
+    SbgnmlXmlParser parser = new SbgnmlXmlParser();
+    GenericProtein protein = new GenericProtein("id");
+    protein.setWidth(50);
+    protein.setHeight(30);
+    protein.setX(200);
+    protein.setX(300);
+    Residue mr = new Residue();
+    Point2D position = new Point2D.Double(100, 20);
+    mr.setPosition(position);
+    protein.addModificationResidue(mr);
+    parser.adjustModificationCoordinates(protein);
+
+    assertTrue(mr.getPosition().distance(position) > Configuration.EPSILON);
+
+  }
+
+}
diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/BioEntityConverterImpl.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/BioEntityConverterImpl.java
index ee41d7e57230d4bf9f2d6cd51d5cce7839774117..48c0d1f37e3a45761188f4c398f79ab06bad4561 100644
--- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/BioEntityConverterImpl.java
+++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/BioEntityConverterImpl.java
@@ -77,7 +77,7 @@ public class BioEntityConverterImpl extends BioEntityConverter<BioEntity> {
 	 * exception is thrown.
 	 * 
 	 * @param element
-	 *          {@link Element} for which we are loooking for a converter
+	 *          {@link Element} for which we are looking for a converter
 	 * @param colorExtractor
 	 *          object that helps to convert overlay values into colors
 	 * @return converter that can be applied for the given element
diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/AntisenseRnaConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/AntisenseRnaConverter.java
index f8b7777cdc7a41ecf1397b49f59c5ff9c86d61e8..136e148f57d3389cf509eaa179a851f0c694a219 100644
--- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/AntisenseRnaConverter.java
+++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/AntisenseRnaConverter.java
@@ -1,151 +1,89 @@
-package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.Stroke;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Path2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.converter.graphics.ConverterParams;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.species.AntisenseRna;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-/**
- * This class defines methods used for drawing {@link AntisenseRna} on the
- * {@link Graphics2D} object.
- * 
- * @author Piotr Gawron
- * 
- */
-
-public class AntisenseRnaConverter extends SpeciesConverter<AntisenseRna> {
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger logger = Logger.getLogger(AntisenseRnaConverter.class.getName());
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param colorExtractor
-	 *          Object that helps to convert {@link ColorSchema} values into
-	 *          colors when drawing {@link Species}
-	 */
-	public AntisenseRnaConverter(ColorExtractor colorExtractor) {
-		super(colorExtractor);
-	}
-
-	@Override
-	public void draw(final AntisenseRna antisenseRna, final Graphics2D graphics, final ConverterParams params) {
-		GeneralPath path = getAntisenseRnaPath(antisenseRna);
-		Color c = graphics.getColor();
-		graphics.setColor(antisenseRna.getColor());
-		graphics.fill(path);
-		graphics.setColor(c);
-		Stroke stroke = graphics.getStroke();
-		graphics.setStroke(getBorderLine(antisenseRna));
-		graphics.draw(path);
-		graphics.setStroke(stroke);
-
-		for (AntisenseRnaRegion mr : antisenseRna.getRegions()) {
-			drawRegion(antisenseRna, mr, graphics, false, false);
-		}
-
-		drawText(antisenseRna, graphics, params);
-	}
-
-	/**
-	 * Returns {@link AntisenseRna} border as a {@link GeneralPath} object.
-	 * 
-	 * @param antisenseRna
-	 *          {@link AntisenseRna} for which we want to get border
-	 * @return border of the {@link AntisenseRna}
-	 */
-	private GeneralPath getAntisenseRnaPath(final AntisenseRna antisenseRna) {
-		// CHECKSTYLE:OFF
-		GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD, 4);
-		path.moveTo(antisenseRna.getX(), antisenseRna.getY());
-		path.lineTo(antisenseRna.getX() + antisenseRna.getWidth() * 3 / 4, antisenseRna.getY());
-		path.lineTo(antisenseRna.getX() + antisenseRna.getWidth(), antisenseRna.getY() + antisenseRna.getHeight());
-		path.lineTo(antisenseRna.getX() + antisenseRna.getWidth() / 4, antisenseRna.getY() + antisenseRna.getHeight());
-		// CHECKSTYLE:ON
-		path.closePath();
-		return path;
-	}
-
-	@Override
-	public PathIterator getBoundPathIterator(final AntisenseRna alias) {
-		return getAntisenseRnaPath(alias).getPathIterator(new AffineTransform());
-	}
-
-	/**
-	 * This method draws antisense rna region for given alias.
-	 * 
-	 * @param antisenseRna
-	 *          {@link AntisenseRna} on which region should be drawn
-	 * @param region
-	 *          {@link AntisenseRnaRegion} to be drawn
-	 * @param graphics
-	 *          {@link Graphics2D} where we draw region
-	 * @param drawEmptyRegion
-	 *          flag determining if we shoudl draw empty regions
-	 * @param drawDescription
-	 *          flag determining if we want to draw description as well
-	 */
-	private void drawRegion(final AntisenseRna antisenseRna, final AntisenseRnaRegion region, final Graphics2D graphics, final boolean drawEmptyRegion,
-			final boolean drawDescription) {
-		if ((!drawEmptyRegion) && (region.getState() == null)) {
-			return;
-		}
-		double diameter = DEFAULT_MODIFICATION_DIAMETER;
-
-		double x = antisenseRna.getX();
-		double y = antisenseRna.getY();
-
-		double width = antisenseRna.getWidth();
-
-		// CHECKSTYLE:OFF
-		// we draw modifier on the upper border of antisense rna (which is only in
-		// 3/4 of the width of alias)
-		Point2D p = new Point2D.Double(x + width * 3.0 / 4.0 * region.getPos(), y - diameter);
-		// CHECKSTYLE:ON
-
-		Ellipse2D ellipse = new Ellipse2D.Double(p.getX() - diameter / 2, p.getY() - diameter / 2, diameter, diameter);
-		Color c = graphics.getColor();
-		graphics.setColor(Color.WHITE);
-		graphics.fill(ellipse);
-		graphics.setColor(c);
-		graphics.draw(ellipse);
-		graphics.drawLine((int) p.getX(), (int) (p.getY() + diameter / 2), (int) p.getX(), (int) y);
-
-		String text = region.getName();
-		if (!text.equals("") && drawDescription) {
-			double textWidth = graphics.getFontMetrics().stringWidth(text);
-			Point2D p2 = new Point2D.Double(p.getX() - textWidth / 2, p.getY() - DEFAULT_SPECIES_MODIFIER_FONT_SIZE);
-			graphics.drawString(text, (int) p2.getX(), (int) p2.getY());
-		}
-		ModificationState state = region.getState();
-		if (state != null) {
-			String str = state.getAbbreviation();
-			Font tmpFont = graphics.getFont();
-			graphics.setFont(getStructuralFont());
-			double textX = p.getX() - graphics.getFontMetrics().stringWidth(str) / 2;
-			double textY = p.getY() + graphics.getFontMetrics().getAscent() / 2;
-			graphics.drawString(str, (int) textX, (int) textY);
-			graphics.setFont(tmpFont);
-		}
-
-	}
-}
+package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.converter.graphics.ConverterParams;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * This class defines methods used for drawing {@link AntisenseRna} on the
+ * {@link Graphics2D} object.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+
+public class AntisenseRnaConverter extends SpeciesConverter<AntisenseRna> {
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(AntisenseRnaConverter.class.getName());
+
+  /**
+   * Default constructor.
+   * 
+   * @param colorExtractor
+   *          Object that helps to convert {@link ColorSchema} values into colors
+   *          when drawing {@link Species}
+   */
+  public AntisenseRnaConverter(ColorExtractor colorExtractor) {
+    super(colorExtractor);
+  }
+
+  @Override
+  public void draw(final AntisenseRna antisenseRna, final Graphics2D graphics, final ConverterParams params) {
+    GeneralPath path = getAntisenseRnaPath(antisenseRna);
+    Color c = graphics.getColor();
+    graphics.setColor(antisenseRna.getColor());
+    graphics.fill(path);
+    graphics.setColor(c);
+    Stroke stroke = graphics.getStroke();
+    graphics.setStroke(getBorderLine(antisenseRna));
+    graphics.draw(path);
+    graphics.setStroke(stroke);
+
+    for (ModificationResidue mr : antisenseRna.getRegions()) {
+      drawModification(mr, graphics, false);
+    }
+
+    drawText(antisenseRna, graphics, params);
+  }
+
+  /**
+   * Returns {@link AntisenseRna} border as a {@link GeneralPath} object.
+   * 
+   * @param antisenseRna
+   *          {@link AntisenseRna} for which we want to get border
+   * @return border of the {@link AntisenseRna}
+   */
+  private GeneralPath getAntisenseRnaPath(final AntisenseRna antisenseRna) {
+    // CHECKSTYLE:OFF
+    GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD, 4);
+    path.moveTo(antisenseRna.getX(), antisenseRna.getY());
+    path.lineTo(antisenseRna.getX() + antisenseRna.getWidth() * 3 / 4, antisenseRna.getY());
+    path.lineTo(antisenseRna.getX() + antisenseRna.getWidth(), antisenseRna.getY() + antisenseRna.getHeight());
+    path.lineTo(antisenseRna.getX() + antisenseRna.getWidth() / 4, antisenseRna.getY() + antisenseRna.getHeight());
+    // CHECKSTYLE:ON
+    path.closePath();
+    return path;
+  }
+
+  @Override
+  public PathIterator getBoundPathIterator(final AntisenseRna alias) {
+    return getAntisenseRnaPath(alias).getPathIterator(new AffineTransform());
+  }
+
+}
diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/GeneConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/GeneConverter.java
index 8528b749fca21bab36324abe8e66c7d5f29cb16e..2877c47e251f6c0072e261749c6352846053c23e 100644
--- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/GeneConverter.java
+++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/GeneConverter.java
@@ -1,145 +1,83 @@
-package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.converter.graphics.ConverterParams;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.species.Gene;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-/**
- * This class defines methods used for drawing Gene SpeciesAlias on the
- * graphics2d object.
- * 
- * @author Piotr Gawron
- * 
- */
-public class GeneConverter extends SpeciesConverter<Gene> {
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger logger = Logger.getLogger(GeneConverter.class.getName());
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param colorExtractor
-	 *          Object that helps to convert {@link ColorSchema} values into
-	 *          colors when drawing {@link Species}
-	 */
-	public GeneConverter(ColorExtractor colorExtractor) {
-		super(colorExtractor);
-	}
-
-	@Override
-	public void draw(final Gene gene, final Graphics2D graphics, final ConverterParams params) {
-		Shape shape = getGeneShape(gene);
-		Color c = graphics.getColor();
-		graphics.setColor(gene.getColor());
-		graphics.fill(shape);
-		graphics.setColor(c);
-		Stroke stroke = graphics.getStroke();
-		graphics.setStroke(getBorderLine(gene));
-		graphics.draw(shape);
-		graphics.setStroke(stroke);
-
-		for (ModificationResidue mr : gene.getModificationResidues()) {
-			drawModification(gene, mr, graphics, false, false);
-		}
-
-		drawText(gene, graphics, params);
-	}
-
-	/**
-	 * This method draws modification of the alias. If drawEmptyModification is
-	 * set to false then modification is not drawn if empty. If drawDescription is
-	 * set then also description (position) of the modification is drawn on the
-	 * canvas.
-	 * 
-	 * @param gene
-	 *          object that is 'parent' of the residue
-	 * @param mr
-	 *          modification to be drawn
-	 * @param graphics
-	 *          - where the modification should be drawn
-	 * @param drawEmptyModification
-	 *          flag that indicates if we should draw empty modification
-	 * @param drawDescription
-	 *          flag that indicates if we should draw description of the
-	 *          modification
-	 */
-	private void drawModification(final Gene gene, final ModificationResidue mr, final Graphics2D graphics, final boolean drawEmptyModification,
-			final boolean drawDescription) {
-		if ((!drawEmptyModification) && (mr.getState() == null)) {
-			return;
-		}
-		double diameter = DEFAULT_MODIFICATION_DIAMETER;
-
-		double x = gene.getX();
-		double y = gene.getY();
-
-		double width = gene.getWidth();
-
-		Point2D p = new Point2D.Double(x + width * mr.getAngle(), y - DEFAULT_MODIFICATION_DIAMETER);
-
-		Ellipse2D ellipse = new Ellipse2D.Double(p.getX() - diameter / 2, p.getY() - diameter / 2, diameter, diameter);
-		Color c = graphics.getColor();
-		graphics.setColor(Color.WHITE);
-		graphics.fill(ellipse);
-		graphics.setColor(c);
-		graphics.draw(ellipse);
-		graphics.drawLine((int) p.getX(), (int) (p.getY() + diameter / 2), (int) p.getX(), (int) y);
-
-		String text = mr.getName();
-		if (!text.equals("") && drawDescription) {
-			double textWidth = graphics.getFontMetrics().stringWidth(text);
-			Point2D p2 = new Point2D.Double(p.getX() - textWidth / 2, p.getY() - DEFAULT_SPECIES_MODIFIER_FONT_SIZE);
-			graphics.drawString(text, (int) p2.getX(), (int) p2.getY());
-		}
-		ModificationState state = mr.getState();
-		if (state != null) {
-			String str = state.getAbbreviation();
-			Font tmpFont = graphics.getFont();
-			graphics.setFont(getStructuralFont());
-			double textX = p.getX() - graphics.getFontMetrics().stringWidth(str) / 2;
-			double textY = p.getY() + graphics.getFontMetrics().getAscent() / 2;
-			graphics.drawString(str, (int) textX, (int) textY);
-			graphics.setFont(tmpFont);
-		}
-
-	}
-
-	/**
-	 * Shape representation of the {@link Gene}.
-	 * 
-	 * @param gene
-	 *          {@link Gene} for which we are looking for a {@link Shape}
-	 * @return {@link Shape} that represents {@link Gene}
-	 */
-	private Shape getGeneShape(final Gene gene) {
-		Shape shape;
-		shape = new Rectangle(gene.getX().intValue(), gene.getY().intValue(), gene.getWidth().intValue(), gene.getHeight().intValue());
-		return shape;
-	}
-
-	@Override
-	public PathIterator getBoundPathIterator(final Gene gene) {
-		return getGeneShape(gene).getPathIterator(new AffineTransform());
-	}
-
-}
+package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.converter.graphics.ConverterParams;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * This class defines methods used for drawing Gene SpeciesAlias on the
+ * graphics2d object.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class GeneConverter extends SpeciesConverter<Gene> {
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(GeneConverter.class.getName());
+
+  /**
+   * Default constructor.
+   * 
+   * @param colorExtractor
+   *          Object that helps to convert {@link ColorSchema} values into colors
+   *          when drawing {@link Species}
+   */
+  public GeneConverter(ColorExtractor colorExtractor) {
+    super(colorExtractor);
+  }
+
+  @Override
+  public void draw(final Gene gene, final Graphics2D graphics, final ConverterParams params) {
+    Shape shape = getGeneShape(gene);
+    Color c = graphics.getColor();
+    graphics.setColor(gene.getColor());
+    graphics.fill(shape);
+    graphics.setColor(c);
+    Stroke stroke = graphics.getStroke();
+    graphics.setStroke(getBorderLine(gene));
+    graphics.draw(shape);
+    graphics.setStroke(stroke);
+
+    for (ModificationResidue mr : gene.getModificationResidues()) {
+      drawModification(mr, graphics, false);
+    }
+
+    drawText(gene, graphics, params);
+  }
+
+  /**
+   * Shape representation of the {@link Gene}.
+   * 
+   * @param gene
+   *          {@link Gene} for which we are looking for a {@link Shape}
+   * @return {@link Shape} that represents {@link Gene}
+   */
+  private Shape getGeneShape(final Gene gene) {
+    Shape shape;
+    shape = new Rectangle(gene.getX().intValue(), gene.getY().intValue(), gene.getWidth().intValue(),
+        gene.getHeight().intValue());
+    return shape;
+  }
+
+  @Override
+  public PathIterator getBoundPathIterator(final Gene gene) {
+    return getGeneShape(gene).getPathIterator(new AffineTransform());
+  }
+
+}
diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/IonConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/IonConverter.java
index 6b0237b7498984c0ee2b5f301a2b725a9fcb8c18..b8d1220e402c2eb9fe1d91dbf622a9e95ba363d5 100644
--- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/IonConverter.java
+++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/IonConverter.java
@@ -26,99 +26,85 @@ import lcsb.mapviewer.model.map.species.Species;
  */
 public class IonConverter extends SpeciesConverter<Ion> {
 
-	/**
-	 * Default class logger.
-	 */
-	private static Logger logger = Logger.getLogger(IonConverter.class.getName());
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(IonConverter.class.getName());
 
-	/**
-	 * Default constructor.
-	 * 
-	 * @param colorExtractor
-	 *          Object that helps to convert {@link ColorSchema} values into
-	 *          colors when drawing {@link Species}
-	 */
-	public IonConverter(ColorExtractor colorExtractor) {
-		super(colorExtractor);
-	}
+  /**
+   * Default constructor.
+   * 
+   * @param colorExtractor
+   *          Object that helps to convert {@link ColorSchema} values into colors
+   *          when drawing {@link Species}
+   */
+  public IonConverter(ColorExtractor colorExtractor) {
+    super(colorExtractor);
+  }
 
-	@Override
-	public void draw(Ion ion, final Graphics2D graphics, final ConverterParams params) {
-		double diameter = getDiameter(ion);
-		double x = getXCoord(ion, diameter);
-		double y = getYCoord(ion);
-		Shape shape = new Ellipse2D.Double(x, y, diameter, diameter);
-		Color c = graphics.getColor();
-		graphics.setColor(ion.getColor());
-		graphics.fill(shape);
-		graphics.setColor(c);
-		Stroke stroke = graphics.getStroke();
-		graphics.setStroke(getBorderLine(ion));
-		graphics.draw(shape);
-		graphics.setStroke(stroke);
-		drawText(ion, graphics, params);
-	}
+  @Override
+  public void draw(Ion ion, final Graphics2D graphics, final ConverterParams params) {
+    double diameter = getDiameter(ion);
+    double x = getXCoord(ion, diameter);
+    double y = getYCoord(ion);
+    Shape shape = new Ellipse2D.Double(x, y, diameter, diameter);
+    Color c = graphics.getColor();
+    graphics.setColor(ion.getColor());
+    graphics.fill(shape);
+    graphics.setColor(c);
+    Stroke stroke = graphics.getStroke();
+    graphics.setStroke(getBorderLine(ion));
+    graphics.draw(shape);
+    graphics.setStroke(stroke);
+    drawText(ion, graphics, params);
+  }
 
-	/**
-	 * Returns transformed y coordinate for the {@link Ion}.
-	 * 
-	 * @param ion
-	 *          {@link Ion} to to which we are looking for y coordinate
-	 * @return y coordinate of the {@link Ion}
-	 */
-	private double getYCoord(final Ion ion) {
-		double y = ion.getY();
-		return y;
-	}
+  /**
+   * Returns transformed y coordinate for the {@link Ion}.
+   * 
+   * @param ion
+   *          {@link Ion} to to which we are looking for y coordinate
+   * @return y coordinate of the {@link Ion}
+   */
+  private double getYCoord(final Ion ion) {
+    double y = ion.getY();
+    return y;
+  }
 
-	/**
-	 * Returns transformed x coordinate for the {@link Ion}.
-	 * 
-	 * @param ion
-	 *          {@link Ion} to which we are looking for x coordinate
-	 * @param diameter
-	 *          diameter of circle representation of ion
-	 * @return x coordinate of the {@link Ion}
-	 */
-	private double getXCoord(final Ion ion, final double diameter) {
-		double x = ion.getX() + (ion.getWidth() - diameter) / 2;
-		return x;
-	}
+  /**
+   * Returns transformed x coordinate for the {@link Ion}.
+   * 
+   * @param ion
+   *          {@link Ion} to which we are looking for x coordinate
+   * @param diameter
+   *          diameter of circle representation of ion
+   * @return x coordinate of the {@link Ion}
+   */
+  private double getXCoord(final Ion ion, final double diameter) {
+    double x = ion.getX() + (ion.getWidth() - diameter) / 2;
+    return x;
+  }
 
-	/**
-	 * Returns diameter of circle representation of an {@link Ion}.
-	 * 
-	 * @param ion
-	 *          {@link Ion} to to which we are looking for diameter.
-	 * @return diameter of {@link Ion} circle representation
-	 */
-	private double getDiameter(final Ion ion) {
-		double diameter = Math.min(ion.getWidth(), ion.getHeight());
-		if (diameter < 0) {
-			logger.warn("Something is wrong. Size cannot be negative");
-			diameter = 0;
-		}
+  /**
+   * Returns diameter of circle representation of an {@link Ion}.
+   * 
+   * @param ion
+   *          {@link Ion} to to which we are looking for diameter.
+   * @return diameter of {@link Ion} circle representation
+   */
+  private double getDiameter(final Ion ion) {
+    double diameter = Math.min(ion.getWidth(), ion.getHeight());
+    if (diameter < 0) {
+      logger.warn("Something is wrong. Size cannot be negative");
+      diameter = 0;
+    }
 
-		return diameter;
-	}
+    return diameter;
+  }
 
-	@Override
-	public PathIterator getBoundPathIterator(Ion ion) {
-		throw new InvalidStateException("This class doesn't have bound");
-	}
-
-	@Override
-	public Point2D getPointCoordinatesOnBorder(Ion ion, final double angle) {
-		if (ion.getWidth() == 0 && ion.getHeight() == 0) {
-			logger.warn("Looking for coordinates for the alias with 0 size");
-			return ion.getCenter();
-		}
-		double diameter = getDiameter(ion);
-		double x = getXCoord(ion, diameter);
-		double y = getYCoord(ion);
-		Point2D result = getEllipseTransformation().getPointOnEllipseByRadian(x, y, diameter, diameter, angle);
-		return result;
-
-	}
+  @Override
+  public PathIterator getBoundPathIterator(Ion ion) {
+    throw new InvalidStateException("This class doesn't have bound");
+  }
 
 }
diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ProteinConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ProteinConverter.java
index 0f97b3998052c234e8602675ece715111de38352..b160c0f10e4208e0a26b362457e43eb62407cb53 100644
--- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ProteinConverter.java
+++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/ProteinConverter.java
@@ -1,462 +1,383 @@
-package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Area;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Path2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.awt.geom.RoundRectangle2D;
-import java.util.ArrayList;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.InvalidStateException;
-import lcsb.mapviewer.converter.graphics.ConverterParams;
-import lcsb.mapviewer.model.graphics.LineType;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.species.GenericProtein;
-import lcsb.mapviewer.model.map.species.IonChannelProtein;
-import lcsb.mapviewer.model.map.species.Protein;
-import lcsb.mapviewer.model.map.species.ReceptorProtein;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.TruncatedProtein;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-import lcsb.mapviewer.modelutils.map.ElementUtils;
-
-/**
- * This class defines methods used for drawing {@link Protein} on the
- * {@link Graphics2D} object.
- * 
- * @author Piotr Gawron
- * 
- */
-public class ProteinConverter extends SpeciesConverter<Protein> {
-
-	/**
-	 * Width of the ion part in the open channel representation.
-	 */
-	private static final int ION_CHANNEL_WIDTH				 = 20;
-
-	/**
-	 * Width of the gap in the open channel representation.
-	 */
-	private static final int OPEN_ION_CHANNEL_WIDTH		 = 20;
-
-	/**
-	 * How big should be the arc in rectangle for protein representation.
-	 */
-	private static final int RECTANGLE_CORNER_ARC_SIZE = 10;
-
-	/**
-	 * Default class logger.
-	 */
-	private static Logger		 logger										 = Logger.getLogger(ProteinConverter.class.getName());
-
-	/**
-	 * Helps in providing human readable identifiers of elements for logging.
-	 */
-	private ElementUtils		 eu												 = new ElementUtils();
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param colorExtractor
-	 *          Object that helps to convert {@link ColorSchema} values into
-	 *          colors when drawing {@link Species}
-	 */
-	public ProteinConverter(ColorExtractor colorExtractor) {
-		super(colorExtractor);
-	}
-
-	/**
-	 * Returns shape of {@link Protein}.
-	 * 
-	 * @param protein
-	 *          {@link Protein} for which we are looking for a border
-	 * @return Shape object defining given alias
-	 */
-	private Shape getGenericShape(final Protein protein) {
-		return new RoundRectangle2D.Double(
-				protein.getX(), protein.getY(), protein.getWidth(), protein.getHeight(), RECTANGLE_CORNER_ARC_SIZE, RECTANGLE_CORNER_ARC_SIZE);
-	}
-
-	@Override
-	public void draw(final Protein protein, final Graphics2D graphics, final ConverterParams params) {
-		// Local variable setting the SBGN visualization
-		boolean sbgnFormat = params.isSbgnFormat();
-
-		// Unit of information text (multimer cardinality and/or ion channel's
-		// state)
-		String unitOfInformationText = "";
-		if (protein.getStatePrefix() != null && protein.getStateLabel() != null) {
-			if (protein.getStatePrefix().equals("free input")) {
-				unitOfInformationText = protein.getStateLabel();
-			} else {
-				unitOfInformationText = protein.getStatePrefix() + ":" + protein.getStateLabel();
-			}
-		}
-
-		int homodir;
-		if (sbgnFormat) {
-			// If the SBGN display mode is set, multimer is shown as two stacked
-			// glyphs
-			if (protein.getHomodimer() > 1) {
-				homodir = 2;
-			} else {
-				homodir = 1;
-			}
-		} else {
-			homodir = protein.getHomodimer();
-		}
-
-		protein.setWidth(protein.getWidth() - SpeciesConverter.HOMODIMER_OFFSET * (protein.getHomodimer() - 1));
-		protein.setHeight(protein.getHeight() - SpeciesConverter.HOMODIMER_OFFSET * (protein.getHomodimer() - 1));
-
-		protein.setX(protein.getX() + SpeciesConverter.HOMODIMER_OFFSET * (homodir));
-		protein.setY(protein.getY() + SpeciesConverter.HOMODIMER_OFFSET * (homodir));
-
-		for (int homodimerId = 0; homodimerId < homodir; homodimerId++) {
-			protein.setX(protein.getX() - SpeciesConverter.HOMODIMER_OFFSET);
-			protein.setY(protein.getY() - SpeciesConverter.HOMODIMER_OFFSET);
-
-			Shape shape = null;
-			if (protein instanceof GenericProtein || sbgnFormat) {
-				shape = getGenericShape(protein);
-				if (protein.getActivity() && !sbgnFormat) {
-					drawActivityGenericProtein(protein, graphics);
-				}
-			} else if (protein instanceof IonChannelProtein) {
-				Area a1;
-				if (!protein.getActivity()) {
-					a1 = new Area(
-							new RoundRectangle2D.Double(
-									protein.getX(), protein.getY(), protein.getWidth() - ION_CHANNEL_WIDTH - 1, protein.getHeight(), RECTANGLE_CORNER_ARC_SIZE,
-									RECTANGLE_CORNER_ARC_SIZE));
-				} else {
-					a1 = new Area(
-							new RoundRectangle2D.Double(
-									protein.getX(), protein.getY(), protein.getWidth() - ION_CHANNEL_WIDTH - OPEN_ION_CHANNEL_WIDTH - 1, protein.getHeight(),
-									RECTANGLE_CORNER_ARC_SIZE, RECTANGLE_CORNER_ARC_SIZE));
-				}
-				Area a2 = new Area(
-						new RoundRectangle2D.Double(
-								protein.getX() + protein.getWidth() - ION_CHANNEL_WIDTH, protein.getY(), ION_CHANNEL_WIDTH, protein.getHeight(), RECTANGLE_CORNER_ARC_SIZE,
-								RECTANGLE_CORNER_ARC_SIZE));
-				a1.add(a2);
-				shape = a1;
-			} else if (protein instanceof TruncatedProtein) {
-				shape = getTruncatedShape(protein);
-				if (protein.getActivity()) {
-					drawActivityTruncatedShape(protein, graphics);
-				}
-			} else if (protein instanceof ReceptorProtein) {
-				shape = getReceptorShape(protein);
-				if (protein.getActivity()) {
-					drawActivityReceptorProtein(protein, graphics);
-				}
-			} else {
-				logger.warn(eu.getElementTag(protein) + "Unknown shape for protein");
-				shape = getDefaultAliasShape(protein);
-			}
-			Color c = graphics.getColor();
-			graphics.setColor(protein.getColor());
-			graphics.fill(shape);
-			graphics.setColor(c);
-			Stroke stroke = graphics.getStroke();
-			graphics.setStroke(getBorderLine(protein));
-			graphics.draw(shape);
-			graphics.setStroke(stroke);
-
-			// SBGN display mode - units of information and state variables are
-			// printed on the top element only
-			if (!sbgnFormat || (homodimerId == homodir - 1)) {
-				for (ModificationResidue mr : protein.getModificationResidues()) {
-					// SBGN display mode - print empty state variables
-					drawModification(protein, mr, graphics, sbgnFormat, false);
-				}
-				if (sbgnFormat) {
-					// SBGN display mode - ion channel's state is marked as a unit of
-					// information
-					if (protein instanceof IonChannelProtein) {
-						if (!unitOfInformationText.equals("")) {
-							unitOfInformationText = unitOfInformationText.concat("; ");
-						}
-						if (protein.getActivity()) {
-							unitOfInformationText = unitOfInformationText.concat("open");
-						} else {
-							unitOfInformationText = unitOfInformationText.concat("closed");
-						}
-					}
-
-					// SBGN display mode - multimers have their cardinality printed as a
-					// unit of information
-					if (homodir > 1 && (unitOfInformationText == null || !unitOfInformationText.contains("N:"))) {
-						if (!unitOfInformationText.equals("")) {
-							unitOfInformationText = unitOfInformationText.concat("; ");
-						}
-						unitOfInformationText = unitOfInformationText.concat("N:").concat(Integer.toString(protein.getHomodimer()));
-					}
-				}
-			}
-		}
-
-		if (unitOfInformationText.equals("")) {
-			unitOfInformationText = null;
-		}
-
-		String text = protein.getStructuralState();
-		drawStructuralState(text, protein, graphics);
-		drawUnitOfInformation(unitOfInformationText, protein, graphics);
-		drawText(protein, graphics, params);
-		protein.setWidth(protein.getWidth() + SpeciesConverter.HOMODIMER_OFFSET * (protein.getHomodimer() - 1));
-		protein.setHeight(protein.getHeight() + SpeciesConverter.HOMODIMER_OFFSET * (protein.getHomodimer() - 1));
-	}
-
-	/**
-	 * Draws activity border of {@link GenericProtein}.
-	 * 
-	 * @param protein
-	 *          {@link Protein} that will be drawn
-	 * @param graphics
-	 *          where we are drawing
-	 */
-	private void drawActivityGenericProtein(final Protein protein, final Graphics2D graphics) {
-		int border = ACTIVITY_BORDER_DISTANCE;
-		protein.increaseBorder(border);
-		Shape shape2 = getGenericShape(protein);
-		Stroke stroke = graphics.getStroke();
-		graphics.setStroke(LineType.DOTTED.getStroke());
-		graphics.draw(shape2);
-		graphics.setStroke(stroke);
-		protein.increaseBorder(-border);
-	}
-
-	/**
-	 * Draws activity border of {@link ReceptorProtein}.
-	 * 
-	 * @param protein
-	 *          {@link Protein} that will be drawn
-	 * @param graphics
-	 *          where we are drawing
-	 */
-	public void drawActivityReceptorProtein(final Protein protein, final Graphics2D graphics) {
-		int border = ACTIVITY_BORDER_DISTANCE;
-		protein.setX(protein.getX() - border);
-		protein.setY(protein.getY() - border);
-		protein.setWidth(protein.getWidth() + border * 2);
-		protein.setHeight(protein.getHeight() + border * 2);
-		Shape shape2 = getReceptorShape(protein);
-		Stroke stroke = graphics.getStroke();
-		graphics.setStroke(LineType.DOTTED.getStroke());
-		graphics.draw(shape2);
-		graphics.setStroke(stroke);
-		protein.setX(protein.getX() + border);
-		protein.setY(protein.getY() + border);
-		protein.setWidth(protein.getWidth() - border * 2);
-		protein.setHeight(protein.getHeight() - border * 2);
-	}
-
-	/**
-	 * Draws activity border of {@link TruncatedProtein}.
-	 * 
-	 * @param protein
-	 *          {@link Protein} that will be drawn
-	 * @param graphics
-	 *          where we are drawing
-	 */
-	public void drawActivityTruncatedShape(final Protein protein, final Graphics2D graphics) {
-		int border = ACTIVITY_BORDER_DISTANCE;
-		protein.setX(protein.getX() - border);
-		protein.setY(protein.getY() - border);
-		protein.setWidth(protein.getWidth() + border * 2);
-		protein.setHeight(protein.getHeight() + border * 2);
-		Shape shape2 = getTruncatedShape(protein);
-		Stroke stroke = graphics.getStroke();
-		graphics.setStroke(LineType.DOTTED.getStroke());
-		graphics.draw(shape2);
-		graphics.setStroke(stroke);
-		protein.setX(protein.getX() + border);
-		protein.setY(protein.getY() + border);
-		protein.setWidth(protein.getWidth() - border * 2);
-		protein.setHeight(protein.getHeight() - border * 2);
-	}
-
-	/**
-	 * This method draws modification of the alias. If drawEmptyModification is
-	 * set to false then modification is not drawn if empty. If drawDescription is
-	 * set then also description (position) of the modification is drawn on the
-	 * canvas.
-	 * 
-	 * @param protein
-	 *          object that is 'parent' of the residue
-	 * @param mr
-	 *          modification to be drawn
-	 * @param graphics
-	 *          - where the modification should be drawn
-	 * @param drawEmptyModification
-	 *          flag that indicates if we should draw empty modification
-	 * @param drawDescription
-	 *          flag that indicates if we should draw description of the
-	 *          modification
-	 */
-	private void drawModification(final Protein protein, final ModificationResidue mr, final Graphics2D graphics, final boolean drawEmptyModification,
-			final boolean drawDescription) {
-		if ((!drawEmptyModification) && (mr.getState() == null)) {
-			return;
-		}
-		double diameter = DEFAULT_MODIFICATION_DIAMETER;
-		double angle = mr.getAngle();
-		if (angle < 0) {
-			angle += Math.PI * 2;
-		}
-		if (angle > Math.PI * 2) {
-			angle -= Math.PI * 2;
-		}
-
-		Point2D p = getResidueCoordinates(protein, mr.getAngle());
-		Ellipse2D ellipse = new Ellipse2D.Double(p.getX() - diameter / 2, p.getY() - diameter / 2, diameter, diameter);
-		Color c = graphics.getColor();
-		graphics.setColor(Color.WHITE);
-		graphics.fill(ellipse);
-		graphics.setColor(c);
-		graphics.draw(ellipse);
-
-		String text = mr.getName();
-		if (!text.equals("") && drawDescription) {
-
-			protein.increaseBorder(-diameter / 2);
-			Point2D p2 = getResidueCoordinates(protein, mr.getAngle());
-			protein.increaseBorder(diameter / 2);
-
-			double width = graphics.getFontMetrics().stringWidth(text);
-			double height = graphics.getFontMetrics().getHeight();
-			if (angle <= RIGHT_TOP_RESIDUE_MAX_ANGLE || angle > BOTTOM_RESIDUE_MAX_ANGLE) {
-				p2.setLocation(p2.getX() - width, p2.getY());
-			} else if (angle > RIGHT_TOP_RESIDUE_MAX_ANGLE && angle <= TOP_RESIDUE_MAX_ANGLE) {
-				p2.setLocation(p2.getX() - width / 2, p2.getY() + height - 2);
-			} else if (angle > TOP_RESIDUE_MAX_ANGLE && angle <= LEFT_RESIDUE_MAX_ANGLE) {
-				p2.setLocation(p2.getX(), p2.getY());
-			} else if (angle > LEFT_RESIDUE_MAX_ANGLE && angle <= BOTTOM_RESIDUE_MAX_ANGLE) {
-				p2.setLocation(p2.getX() - width / 2, p2.getY() - 2);
-			} else {
-				throw new InvalidStateException();
-			}
-
-			graphics.drawString(text, (int) p2.getX(), (int) p2.getY());
-		}
-		ModificationState state = mr.getState();
-		if (state != null) {
-			String str = state.getAbbreviation();
-			Font tmpFont = graphics.getFont();
-			graphics.setFont(getStructuralFont());
-			double x = p.getX() - graphics.getFontMetrics().stringWidth(str) / 2;
-			double y = p.getY() + graphics.getFontMetrics().getAscent() / 2;
-			graphics.drawString(str, (int) x, (int) y);
-			graphics.setFont(tmpFont);
-		}
-
-	}
-
-	/**
-	 * Returns shape of receptor protein.
-	 * 
-	 * @param protein
-	 *          alias for which we are looking for a border
-	 * @return Shape object defining given alias
-	 */
-	protected Shape getReceptorShape(final Protein protein) {
-		Shape shape;
-		GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD);
-		ArrayList<Point2D> points = getReceptorPoints(protein);
-		path.moveTo(points.get(0).getX(), points.get(0).getY());
-		for (int i = 1; i < points.size(); i++) {
-			path.lineTo(points.get(i).getX(), points.get(i).getY());
-		}
-		path.closePath();
-		shape = path;
-		return shape;
-	}
-
-	/**
-	 * Returns shape of truncated protein.
-	 * 
-	 * @param protein
-	 *          alias for which we are looking for a border
-	 * @return Shape object defining given alias
-	 */
-	protected Shape getTruncatedShape(final Protein protein) {
-		Shape shape;
-		GeneralPath path = new GeneralPath();
-		// CHECKSTYLE:OFF
-		path.moveTo(protein.getX() + 10, protein.getY());
-		path.lineTo(protein.getX() + protein.getWidth(), protein.getY());
-		path.lineTo(protein.getX() + protein.getWidth(), protein.getY() + protein.getHeight() * 3 / 5);
-		path.lineTo(protein.getX() + protein.getWidth() * 4 / 5, protein.getY() + protein.getHeight() * 2 / 5);
-		path.lineTo(protein.getX() + protein.getWidth() * 4 / 5, protein.getY() + protein.getHeight());
-		path.lineTo(protein.getX() + 10, protein.getY() + protein.getHeight());
-		path.curveTo(
-				protein.getX() + 5, protein.getY() + protein.getHeight() - 2, protein.getX() + 2, protein.getY() + protein.getHeight() - 5, protein.getX(),
-				protein.getY() + protein.getHeight() - 10);
-		path.lineTo(protein.getX(), protein.getY() + 10);
-		path.curveTo(protein.getX() + 2, protein.getY() + 5, protein.getX() + 5, protein.getY() + 2, protein.getX() + 10, protein.getY());
-		// CHECKSTYLE:ON
-
-		path.closePath();
-		shape = path;
-		return shape;
-	}
-
-	/**
-	 * Returns shape of receptor protein as a list of points.
-	 * 
-	 * @param protein
-	 *          alias for which we are looking for a border
-	 * @return list of points defining border of the given alias
-	 */
-	private ArrayList<Point2D> getReceptorPoints(final Protein protein) {
-		double x = protein.getX();
-		double y = protein.getY();
-		double width = protein.getWidth();
-		double height = protein.getHeight();
-		ArrayList<Point2D> points = new ArrayList<Point2D>();
-
-		// CHECKSTYLE:OFF
-		points.add(new Point2D.Double(x, y + height * 2 / 5));
-		points.add(new Point2D.Double(x, y));
-		points.add(new Point2D.Double(x + width / 2, y + height / 5));
-		points.add(new Point2D.Double(x + width, y));
-		points.add(new Point2D.Double(x + width, y + height * 2 / 5));
-		points.add(new Point2D.Double(x + width, y + height * 4 / 5));
-		points.add(new Point2D.Double(x + width / 2, y + height));
-		points.add(new Point2D.Double(x, y + height * 4 / 5));
-		// CHECKSTYLE:ON
-
-		return points;
-	}
-
-	@Override
-	public PathIterator getBoundPathIterator(final Protein protein) {
-		if (protein instanceof GenericProtein) {
-			return getGenericShape(protein).getPathIterator(new AffineTransform());
-		} else if (protein instanceof ReceptorProtein) {
-			return getReceptorShape(protein).getPathIterator(new AffineTransform());
-		} else if (protein instanceof IonChannelProtein) {
-			return getGenericShape(protein).getPathIterator(new AffineTransform());
-		} else if (protein instanceof TruncatedProtein) {
-			return getTruncatedShape(protein).getPathIterator(new AffineTransform());
-		} else {
-			throw new InvalidArgumentException("Not implemented protein converter for type: " + protein.getClass());
-		}
-	}
-
-}
+package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.RoundRectangle2D;
+import java.util.ArrayList;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.converter.graphics.ConverterParams;
+import lcsb.mapviewer.model.graphics.LineType;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.IonChannelProtein;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.ReceptorProtein;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.TruncatedProtein;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+import lcsb.mapviewer.model.map.species.field.Residue;
+import lcsb.mapviewer.modelutils.map.ElementUtils;
+
+/**
+ * This class defines methods used for drawing {@link Protein} on the
+ * {@link Graphics2D} object.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class ProteinConverter extends SpeciesConverter<Protein> {
+
+  /**
+   * Width of the ion part in the open channel representation.
+   */
+  private static final int ION_CHANNEL_WIDTH = 20;
+
+  /**
+   * Width of the gap in the open channel representation.
+   */
+  private static final int OPEN_ION_CHANNEL_WIDTH = 20;
+
+  /**
+   * How big should be the arc in rectangle for protein representation.
+   */
+  private static final int RECTANGLE_CORNER_ARC_SIZE = 10;
+
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(ProteinConverter.class.getName());
+
+  /**
+   * Helps in providing human readable identifiers of elements for logging.
+   */
+  private ElementUtils eu = new ElementUtils();
+
+  /**
+   * Default constructor.
+   * 
+   * @param colorExtractor
+   *          Object that helps to convert {@link ColorSchema} values into colors
+   *          when drawing {@link Species}
+   */
+  public ProteinConverter(ColorExtractor colorExtractor) {
+    super(colorExtractor);
+  }
+
+  /**
+   * Returns shape of {@link Protein}.
+   * 
+   * @param protein
+   *          {@link Protein} for which we are looking for a border
+   * @return Shape object defining given alias
+   */
+  private Shape getGenericShape(final Protein protein) {
+    return new RoundRectangle2D.Double(protein.getX(), protein.getY(), protein.getWidth(), protein.getHeight(),
+        RECTANGLE_CORNER_ARC_SIZE, RECTANGLE_CORNER_ARC_SIZE);
+  }
+
+  @Override
+  public void draw(final Protein protein, final Graphics2D graphics, final ConverterParams params) {
+    // Local variable setting the SBGN visualization
+    boolean sbgnFormat = params.isSbgnFormat();
+
+    // Unit of information text (multimer cardinality and/or ion channel's
+    // state)
+    String unitOfInformationText = "";
+    if (protein.getStatePrefix() != null && protein.getStateLabel() != null) {
+      if (protein.getStatePrefix().equals("free input")) {
+        unitOfInformationText = protein.getStateLabel();
+      } else {
+        unitOfInformationText = protein.getStatePrefix() + ":" + protein.getStateLabel();
+      }
+    }
+
+    int homodir;
+    if (sbgnFormat) {
+      // If the SBGN display mode is set, multimer is shown as two stacked
+      // glyphs
+      if (protein.getHomodimer() > 1) {
+        homodir = 2;
+      } else {
+        homodir = 1;
+      }
+    } else {
+      homodir = protein.getHomodimer();
+    }
+
+    protein.setWidth(protein.getWidth() - SpeciesConverter.HOMODIMER_OFFSET * (protein.getHomodimer() - 1));
+    protein.setHeight(protein.getHeight() - SpeciesConverter.HOMODIMER_OFFSET * (protein.getHomodimer() - 1));
+
+    protein.setX(protein.getX() + SpeciesConverter.HOMODIMER_OFFSET * (homodir));
+    protein.setY(protein.getY() + SpeciesConverter.HOMODIMER_OFFSET * (homodir));
+
+    for (int homodimerId = 0; homodimerId < homodir; homodimerId++) {
+      protein.setX(protein.getX() - SpeciesConverter.HOMODIMER_OFFSET);
+      protein.setY(protein.getY() - SpeciesConverter.HOMODIMER_OFFSET);
+
+      Shape shape = null;
+      if (protein instanceof GenericProtein || sbgnFormat) {
+        shape = getGenericShape(protein);
+        if (protein.getActivity() && !sbgnFormat) {
+          drawActivityGenericProtein(protein, graphics);
+        }
+      } else if (protein instanceof IonChannelProtein) {
+        Area a1;
+        if (!protein.getActivity()) {
+          a1 = new Area(
+              new RoundRectangle2D.Double(protein.getX(), protein.getY(), protein.getWidth() - ION_CHANNEL_WIDTH - 1,
+                  protein.getHeight(), RECTANGLE_CORNER_ARC_SIZE, RECTANGLE_CORNER_ARC_SIZE));
+        } else {
+          a1 = new Area(new RoundRectangle2D.Double(protein.getX(), protein.getY(),
+              protein.getWidth() - ION_CHANNEL_WIDTH - OPEN_ION_CHANNEL_WIDTH - 1, protein.getHeight(),
+              RECTANGLE_CORNER_ARC_SIZE, RECTANGLE_CORNER_ARC_SIZE));
+        }
+        Area a2 = new Area(
+            new RoundRectangle2D.Double(protein.getX() + protein.getWidth() - ION_CHANNEL_WIDTH, protein.getY(),
+                ION_CHANNEL_WIDTH, protein.getHeight(), RECTANGLE_CORNER_ARC_SIZE, RECTANGLE_CORNER_ARC_SIZE));
+        a1.add(a2);
+        shape = a1;
+      } else if (protein instanceof TruncatedProtein) {
+        shape = getTruncatedShape(protein);
+        if (protein.getActivity()) {
+          drawActivityTruncatedShape(protein, graphics);
+        }
+      } else if (protein instanceof ReceptorProtein) {
+        shape = getReceptorShape(protein);
+        if (protein.getActivity()) {
+          drawActivityReceptorProtein(protein, graphics);
+        }
+      } else {
+        logger.warn(eu.getElementTag(protein) + "Unknown shape for protein");
+        shape = getDefaultAliasShape(protein);
+      }
+      Color c = graphics.getColor();
+      graphics.setColor(protein.getColor());
+      graphics.fill(shape);
+      graphics.setColor(c);
+      Stroke stroke = graphics.getStroke();
+      graphics.setStroke(getBorderLine(protein));
+      graphics.draw(shape);
+      graphics.setStroke(stroke);
+
+      // SBGN display mode - units of information and state variables are
+      // printed on the top element only
+      if (!sbgnFormat || (homodimerId == homodir - 1)) {
+        for (ModificationResidue mr : protein.getModificationResidues()) {
+          // SBGN display mode - print empty state variables
+          drawModification(mr, graphics, sbgnFormat);
+        }
+        if (sbgnFormat) {
+          // SBGN display mode - ion channel's state is marked as a unit of
+          // information
+          if (protein instanceof IonChannelProtein) {
+            if (!unitOfInformationText.equals("")) {
+              unitOfInformationText = unitOfInformationText.concat("; ");
+            }
+            if (protein.getActivity()) {
+              unitOfInformationText = unitOfInformationText.concat("open");
+            } else {
+              unitOfInformationText = unitOfInformationText.concat("closed");
+            }
+          }
+
+          // SBGN display mode - multimers have their cardinality printed as a
+          // unit of information
+          if (homodir > 1 && (unitOfInformationText == null || !unitOfInformationText.contains("N:"))) {
+            if (!unitOfInformationText.equals("")) {
+              unitOfInformationText = unitOfInformationText.concat("; ");
+            }
+            unitOfInformationText = unitOfInformationText.concat("N:").concat(Integer.toString(protein.getHomodimer()));
+          }
+        }
+      }
+    }
+
+    if (unitOfInformationText.equals("")) {
+      unitOfInformationText = null;
+    }
+
+    String text = protein.getStructuralState();
+    drawStructuralState(text, protein, graphics);
+    drawUnitOfInformation(unitOfInformationText, protein, graphics);
+    drawText(protein, graphics, params);
+    protein.setWidth(protein.getWidth() + SpeciesConverter.HOMODIMER_OFFSET * (protein.getHomodimer() - 1));
+    protein.setHeight(protein.getHeight() + SpeciesConverter.HOMODIMER_OFFSET * (protein.getHomodimer() - 1));
+  }
+
+  /**
+   * Draws activity border of {@link GenericProtein}.
+   * 
+   * @param protein
+   *          {@link Protein} that will be drawn
+   * @param graphics
+   *          where we are drawing
+   */
+  private void drawActivityGenericProtein(final Protein protein, final Graphics2D graphics) {
+    int border = ACTIVITY_BORDER_DISTANCE;
+    protein.increaseBorder(border);
+    Shape shape2 = getGenericShape(protein);
+    Stroke stroke = graphics.getStroke();
+    graphics.setStroke(LineType.DOTTED.getStroke());
+    graphics.draw(shape2);
+    graphics.setStroke(stroke);
+    protein.increaseBorder(-border);
+  }
+
+  /**
+   * Draws activity border of {@link ReceptorProtein}.
+   * 
+   * @param protein
+   *          {@link Protein} that will be drawn
+   * @param graphics
+   *          where we are drawing
+   */
+  public void drawActivityReceptorProtein(final Protein protein, final Graphics2D graphics) {
+    int border = ACTIVITY_BORDER_DISTANCE;
+    protein.setX(protein.getX() - border);
+    protein.setY(protein.getY() - border);
+    protein.setWidth(protein.getWidth() + border * 2);
+    protein.setHeight(protein.getHeight() + border * 2);
+    Shape shape2 = getReceptorShape(protein);
+    Stroke stroke = graphics.getStroke();
+    graphics.setStroke(LineType.DOTTED.getStroke());
+    graphics.draw(shape2);
+    graphics.setStroke(stroke);
+    protein.setX(protein.getX() + border);
+    protein.setY(protein.getY() + border);
+    protein.setWidth(protein.getWidth() - border * 2);
+    protein.setHeight(protein.getHeight() - border * 2);
+  }
+
+  /**
+   * Draws activity border of {@link TruncatedProtein}.
+   * 
+   * @param protein
+   *          {@link Protein} that will be drawn
+   * @param graphics
+   *          where we are drawing
+   */
+  public void drawActivityTruncatedShape(final Protein protein, final Graphics2D graphics) {
+    int border = ACTIVITY_BORDER_DISTANCE;
+    protein.setX(protein.getX() - border);
+    protein.setY(protein.getY() - border);
+    protein.setWidth(protein.getWidth() + border * 2);
+    protein.setHeight(protein.getHeight() + border * 2);
+    Shape shape2 = getTruncatedShape(protein);
+    Stroke stroke = graphics.getStroke();
+    graphics.setStroke(LineType.DOTTED.getStroke());
+    graphics.draw(shape2);
+    graphics.setStroke(stroke);
+    protein.setX(protein.getX() + border);
+    protein.setY(protein.getY() + border);
+    protein.setWidth(protein.getWidth() - border * 2);
+    protein.setHeight(protein.getHeight() - border * 2);
+  }
+
+  /**
+   * Returns shape of receptor protein.
+   * 
+   * @param protein
+   *          alias for which we are looking for a border
+   * @return Shape object defining given alias
+   */
+  protected Shape getReceptorShape(final Protein protein) {
+    Shape shape;
+    GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD);
+    ArrayList<Point2D> points = getReceptorPoints(protein);
+    path.moveTo(points.get(0).getX(), points.get(0).getY());
+    for (int i = 1; i < points.size(); i++) {
+      path.lineTo(points.get(i).getX(), points.get(i).getY());
+    }
+    path.closePath();
+    shape = path;
+    return shape;
+  }
+
+  /**
+   * Returns shape of truncated protein.
+   * 
+   * @param protein
+   *          alias for which we are looking for a border
+   * @return Shape object defining given alias
+   */
+  protected Shape getTruncatedShape(final Protein protein) {
+    Shape shape;
+    GeneralPath path = new GeneralPath();
+    // CHECKSTYLE:OFF
+    path.moveTo(protein.getX() + 10, protein.getY());
+    path.lineTo(protein.getX() + protein.getWidth(), protein.getY());
+    path.lineTo(protein.getX() + protein.getWidth(), protein.getY() + protein.getHeight() * 3 / 5);
+    path.lineTo(protein.getX() + protein.getWidth() * 4 / 5, protein.getY() + protein.getHeight() * 2 / 5);
+    path.lineTo(protein.getX() + protein.getWidth() * 4 / 5, protein.getY() + protein.getHeight());
+    path.lineTo(protein.getX() + 10, protein.getY() + protein.getHeight());
+    path.curveTo(protein.getX() + 5, protein.getY() + protein.getHeight() - 2, protein.getX() + 2,
+        protein.getY() + protein.getHeight() - 5, protein.getX(), protein.getY() + protein.getHeight() - 10);
+    path.lineTo(protein.getX(), protein.getY() + 10);
+    path.curveTo(protein.getX() + 2, protein.getY() + 5, protein.getX() + 5, protein.getY() + 2, protein.getX() + 10,
+        protein.getY());
+    // CHECKSTYLE:ON
+
+    path.closePath();
+    shape = path;
+    return shape;
+  }
+
+  /**
+   * Returns shape of receptor protein as a list of points.
+   * 
+   * @param protein
+   *          alias for which we are looking for a border
+   * @return list of points defining border of the given alias
+   */
+  private ArrayList<Point2D> getReceptorPoints(final Protein protein) {
+    double x = protein.getX();
+    double y = protein.getY();
+    double width = protein.getWidth();
+    double height = protein.getHeight();
+    ArrayList<Point2D> points = new ArrayList<Point2D>();
+
+    // CHECKSTYLE:OFF
+    points.add(new Point2D.Double(x, y + height * 2 / 5));
+    points.add(new Point2D.Double(x, y));
+    points.add(new Point2D.Double(x + width / 2, y + height / 5));
+    points.add(new Point2D.Double(x + width, y));
+    points.add(new Point2D.Double(x + width, y + height * 2 / 5));
+    points.add(new Point2D.Double(x + width, y + height * 4 / 5));
+    points.add(new Point2D.Double(x + width / 2, y + height));
+    points.add(new Point2D.Double(x, y + height * 4 / 5));
+    // CHECKSTYLE:ON
+
+    return points;
+  }
+
+  @Override
+  public PathIterator getBoundPathIterator(final Protein protein) {
+    if (protein instanceof GenericProtein) {
+      return getGenericShape(protein).getPathIterator(new AffineTransform());
+    } else if (protein instanceof ReceptorProtein) {
+      return getReceptorShape(protein).getPathIterator(new AffineTransform());
+    } else if (protein instanceof IonChannelProtein) {
+      return getGenericShape(protein).getPathIterator(new AffineTransform());
+    } else if (protein instanceof TruncatedProtein) {
+      return getTruncatedShape(protein).getPathIterator(new AffineTransform());
+    } else {
+      throw new InvalidArgumentException("Not implemented protein converter for type: " + protein.getClass());
+    }
+  }
+
+}
diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/RnaConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/RnaConverter.java
index bf0b0533f521cf4572b7b00fdcca619f978c9263..c66fada0f4568f32e76f2634a9a3c49c9973b01d 100644
--- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/RnaConverter.java
+++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/RnaConverter.java
@@ -1,162 +1,95 @@
-/**
- * Default constructor.
- * 
- * @param colorExtractor
- *          Object that helps to convert {@link ColorSchema} values into colors
- *          when drawing {@link Species}
- */
-package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.Stroke;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Path2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.converter.graphics.ConverterParams;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.species.Rna;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
-
-/**
- * This class defines methods used for drawing {@link Rna} on the
- * {@link Graphics2D} object.
- * 
- * @author Piotr Gawron
- * 
- */
-public class RnaConverter extends SpeciesConverter<Rna> {
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger logger = Logger.getLogger(RnaConverter.class.getName());
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param colorExtractor
-	 *          Object that helps to convert {@link ColorSchema} values into
-	 *          colors when drawing {@link Species}
-	 */
-	public RnaConverter(ColorExtractor colorExtractor) {
-		super(colorExtractor);
-	}
-
-	@Override
-	public void draw(final Rna rna, final Graphics2D graphics, final ConverterParams params) {
-		GeneralPath path = getRnaPath(rna);
-		Color c = graphics.getColor();
-		graphics.setColor(rna.getColor());
-		graphics.fill(path);
-		graphics.setColor(c);
-		Stroke stroke = graphics.getStroke();
-		graphics.setStroke(getBorderLine(rna));
-		graphics.draw(path);
-		graphics.setStroke(stroke);
-
-		for (RnaRegion mr : rna.getRegions()) {
-			drawModification(rna, mr, graphics, false, false);
-		}
-
-		drawText(rna, graphics, params);
-	}
-
-	/**
-	 * Returns shape of the {@link Rna} as a {@link GeneralPath} object.
-	 * 
-	 * @param rna
-	 *          {@link Rna} for which we are looking for a border
-	 * @return {@link GeneralPath} object defining border of the given {@link Rna}
-	 */
-	private GeneralPath getRnaPath(final Rna rna) {
-		// CHECKSTYLE:OFF
-		GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD, 4);
-		path.moveTo(rna.getX() + rna.getWidth() / 4, rna.getY());
-		path.lineTo(rna.getX() + rna.getWidth(), rna.getY());
-		path.lineTo(rna.getX() + rna.getWidth() * 3 / 4, rna.getY() + rna.getHeight());
-		path.lineTo(rna.getX(), rna.getY() + rna.getHeight());
-		// CHECKSTYLE:ON
-		path.closePath();
-		return path;
-	}
-
-	@Override
-	public PathIterator getBoundPathIterator(final Rna rna) {
-		return getRnaPath(rna).getPathIterator(new AffineTransform());
-	}
-
-	/**
-	 * This method draws modification of the alias. If drawEmptyModification is
-	 * set to false then modification is not drawn if empty. If drawDescription is
-	 * set then also description (position) of the modification is drawn on the
-	 * canvas.
-	 * 
-	 * @param rna
-	 *          object that is 'parent' of the residue
-	 * @param region
-	 *          {@link RnaRegion modification} to be drawn
-	 * @param graphics
-	 *          - where the modification should be drawn
-	 * @param drawEmptyModification
-	 *          flag that indicates if we should draw empty modification
-	 * @param drawDescription
-	 *          flag that indicates if we should draw description of the
-	 *          modification
-	 */
-	private void drawModification(final Rna rna, final RnaRegion region, final Graphics2D graphics, final boolean drawEmptyModification,
-			final boolean drawDescription) {
-		if ((!drawEmptyModification) && (region.getState() == null)) {
-			return;
-		}
-		double diameter = DEFAULT_MODIFICATION_DIAMETER;
-
-		double x = rna.getX();
-		double y = rna.getY();
-
-		double width = rna.getWidth();
-
-		// CHECKSTYLE:OFF
-		// we draw modifier on the upper border of rna (which is only in
-		// 3/4 of the width of alias, but starts in 1/4 of the width)
-		Point2D p = new Point2D.Double(x + width / 4.0 + width * 3.0 / 4.0 * region.getPos(), y - DEFAULT_MODIFICATION_DIAMETER);
-		// CHECKSTYLE:ON
-
-		Ellipse2D ellipse = new Ellipse2D.Double(p.getX() - diameter / 2, p.getY() - diameter / 2, diameter, diameter);
-		Color c = graphics.getColor();
-		graphics.setColor(Color.WHITE);
-		graphics.fill(ellipse);
-		graphics.setColor(c);
-		graphics.draw(ellipse);
-		graphics.drawLine((int) p.getX(), (int) (p.getY() + diameter / 2), (int) p.getX(), (int) y);
-
-		String text = region.getName();
-		if (!text.equals("") && drawDescription) {
-			double textWidth = graphics.getFontMetrics().stringWidth(text);
-			Point2D p2 = new Point2D.Double(p.getX() - textWidth / 2, p.getY() - DEFAULT_SPECIES_MODIFIER_FONT_SIZE);
-			graphics.drawString(text, (int) p2.getX(), (int) p2.getY());
-		}
-		ModificationState state = region.getState();
-		if (state != null) {
-			String str = state.getAbbreviation();
-			Font tmpFont = graphics.getFont();
-			graphics.setFont(getStructuralFont());
-			double textX = p.getX() - graphics.getFontMetrics().stringWidth(str) / 2;
-			double textY = p.getY() + graphics.getFontMetrics().getAscent() / 2;
-			graphics.drawString(str, (int) textX, (int) textY);
-			graphics.setFont(tmpFont);
-		}
-
-	}
-
-}
+/**
+ * Default constructor.
+ * 
+ * @param colorExtractor
+ *          Object that helps to convert {@link ColorSchema} values into colors
+ *          when drawing {@link Species}
+ */
+package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.converter.graphics.ConverterParams;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * This class defines methods used for drawing {@link Rna} on the
+ * {@link Graphics2D} object.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class RnaConverter extends SpeciesConverter<Rna> {
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(RnaConverter.class.getName());
+
+  /**
+   * Default constructor.
+   * 
+   * @param colorExtractor
+   *          Object that helps to convert {@link ColorSchema} values into colors
+   *          when drawing {@link Species}
+   */
+  public RnaConverter(ColorExtractor colorExtractor) {
+    super(colorExtractor);
+  }
+
+  @Override
+  public void draw(final Rna rna, final Graphics2D graphics, final ConverterParams params) {
+    GeneralPath path = getRnaPath(rna);
+    Color c = graphics.getColor();
+    graphics.setColor(rna.getColor());
+    graphics.fill(path);
+    graphics.setColor(c);
+    Stroke stroke = graphics.getStroke();
+    graphics.setStroke(getBorderLine(rna));
+    graphics.draw(path);
+    graphics.setStroke(stroke);
+
+    for (ModificationResidue mr : rna.getRegions()) {
+      drawModification(mr, graphics, false);
+    }
+
+    drawText(rna, graphics, params);
+  }
+
+  /**
+   * Returns shape of the {@link Rna} as a {@link GeneralPath} object.
+   * 
+   * @param rna
+   *          {@link Rna} for which we are looking for a border
+   * @return {@link GeneralPath} object defining border of the given {@link Rna}
+   */
+  private GeneralPath getRnaPath(final Rna rna) {
+    // CHECKSTYLE:OFF
+    GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD, 4);
+    path.moveTo(rna.getX() + rna.getWidth() / 4, rna.getY());
+    path.lineTo(rna.getX() + rna.getWidth(), rna.getY());
+    path.lineTo(rna.getX() + rna.getWidth() * 3 / 4, rna.getY() + rna.getHeight());
+    path.lineTo(rna.getX(), rna.getY() + rna.getHeight());
+    // CHECKSTYLE:ON
+    path.closePath();
+    return path;
+  }
+
+  @Override
+  public PathIterator getBoundPathIterator(final Rna rna) {
+    return getRnaPath(rna).getPathIterator(new AffineTransform());
+  }
+
+}
diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SimpleMoleculeConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SimpleMoleculeConverter.java
index 8ce04bcc3d88e37d14e34c3f439c3cf2f9bd26c0..8a609f533ccb963ad4a8a546636cdbf909d9a5c4 100644
--- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SimpleMoleculeConverter.java
+++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SimpleMoleculeConverter.java
@@ -1,126 +1,114 @@
-package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
-
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.common.exception.InvalidStateException;
-import lcsb.mapviewer.converter.graphics.ConverterParams;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.species.SimpleMolecule;
-import lcsb.mapviewer.model.map.species.Species;
-
-/**
- * This class defines methods used for drawing {@link SimpleMolecule} on the
- * {@link Graphics2D} object.
- * 
- * @author Piotr Gawron
- * 
- */
-public class SimpleMoleculeConverter extends SpeciesConverter<SimpleMolecule> {
-	/**
-	 * Default class logger.
-	 */
-	private static Logger logger = Logger.getLogger(SimpleMoleculeConverter.class.getName());
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param colorExtractor
-	 *          Object that helps to convert {@link ColorSchema} values into
-	 *          colors when drawing {@link Species}
-	 */
-	public SimpleMoleculeConverter(ColorExtractor colorExtractor) {
-		super(colorExtractor);
-	}
-
-	@Override
-	public void draw(final SimpleMolecule simpleMolecule, final Graphics2D graphics, final ConverterParams params) {
-		int homodir;
-		if (params.isSbgnFormat()) {
-			// If the SBGN display mode is set, multimer is shown as two stacked
-			// glyphs
-			if (simpleMolecule.getHomodimer() > 1) {
-				homodir = 2;
-			} else {
-				homodir = 1;
-			}
-		} else {
-			homodir = simpleMolecule.getHomodimer();
-		}
-
-		simpleMolecule.setWidth(simpleMolecule.getWidth() - SpeciesConverter.HOMODIMER_OFFSET * (homodir - 1));
-		simpleMolecule.setHeight(simpleMolecule.getHeight() - SpeciesConverter.HOMODIMER_OFFSET * (homodir - 1));
-
-		// SBGN view - simple molecules are represented as circles
-		if (params.isSbgnFormat()) {
-			simpleMolecule.setX(simpleMolecule.getX() + (simpleMolecule.getWidth() - simpleMolecule.getHeight()) / 2);
-			simpleMolecule.setWidth(simpleMolecule.getHeight());
-		}
-
-		simpleMolecule.setX(simpleMolecule.getX() + SpeciesConverter.HOMODIMER_OFFSET * (homodir));
-		simpleMolecule.setY(simpleMolecule.getY() + SpeciesConverter.HOMODIMER_OFFSET * (homodir));
-
-		for (int i = 0; i < homodir; i++) {
-			simpleMolecule.setX(simpleMolecule.getX() - SpeciesConverter.HOMODIMER_OFFSET);
-			simpleMolecule.setY(simpleMolecule.getY() - SpeciesConverter.HOMODIMER_OFFSET);
-			Shape shape = new Ellipse2D.Double(simpleMolecule.getX(), simpleMolecule.getY(), simpleMolecule.getWidth(), simpleMolecule.getHeight());
-			Color c = graphics.getColor();
-			graphics.setColor(simpleMolecule.getColor());
-			graphics.fill(shape);
-			graphics.setColor(c);
-			Stroke stroke = graphics.getStroke();
-			graphics.setStroke(getBorderLine(simpleMolecule));
-			graphics.draw(shape);
-			graphics.setStroke(stroke);
-
-			// SBGN view - multimers are displayed with a unit of information
-			// containing cardinality
-			if (params.isSbgnFormat() && (i == homodir - 1)) {
-				String unitOfInformationText = null;
-				if (simpleMolecule.getStatePrefix() != null && simpleMolecule.getStateLabel() != null) {
-					unitOfInformationText = simpleMolecule.getStatePrefix() + ":" + simpleMolecule.getStateLabel();
-				}
-				if (homodir == 2 && (unitOfInformationText == null || !unitOfInformationText.contains("N:"))) {
-					if (unitOfInformationText != null) {
-						unitOfInformationText += "; ";
-					} else {
-						unitOfInformationText = "";
-					}
-					unitOfInformationText += "N:" + simpleMolecule.getHomodimer();
-				}
-
-				drawUnitOfInformation(unitOfInformationText, simpleMolecule, graphics);
-			}
-		}
-		simpleMolecule.setWidth(simpleMolecule.getWidth() + SpeciesConverter.HOMODIMER_OFFSET * (homodir - 1));
-		simpleMolecule.setHeight(simpleMolecule.getHeight() + SpeciesConverter.HOMODIMER_OFFSET * (homodir - 1));
-		drawText(simpleMolecule, graphics, params);
-	}
-
-	@Override
-	public PathIterator getBoundPathIterator(final SimpleMolecule simpleMolecule) {
-		throw new InvalidStateException("This class doesn't provide boundPath");
-	}
-
-	@Override
-	public Point2D getPointCoordinatesOnBorder(final SimpleMolecule simpleMolecule, final double angle) {
-		if (simpleMolecule.getWidth() == 0 && simpleMolecule.getHeight() == 0) {
-			logger.warn("Looking for coordinates on border of alias of size 0");
-			return simpleMolecule.getCenter();
-		}
-		Point2D result;
-		result = getEllipseTransformation()
-				.getPointOnEllipseByRadian(simpleMolecule.getX(), simpleMolecule.getY(), simpleMolecule.getWidth(), simpleMolecule.getHeight(), angle);
-		return result;
-
-	}
-
-}
+package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.common.exception.InvalidStateException;
+import lcsb.mapviewer.converter.graphics.ConverterParams;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.species.SimpleMolecule;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * This class defines methods used for drawing {@link SimpleMolecule} on the
+ * {@link Graphics2D} object.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class SimpleMoleculeConverter extends SpeciesConverter<SimpleMolecule> {
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(SimpleMoleculeConverter.class.getName());
+
+  /**
+   * Default constructor.
+   * 
+   * @param colorExtractor
+   *          Object that helps to convert {@link ColorSchema} values into colors
+   *          when drawing {@link Species}
+   */
+  public SimpleMoleculeConverter(ColorExtractor colorExtractor) {
+    super(colorExtractor);
+  }
+
+  @Override
+  public void draw(final SimpleMolecule simpleMolecule, final Graphics2D graphics, final ConverterParams params) {
+    int homodir;
+    if (params.isSbgnFormat()) {
+      // If the SBGN display mode is set, multimer is shown as two stacked
+      // glyphs
+      if (simpleMolecule.getHomodimer() > 1) {
+        homodir = 2;
+      } else {
+        homodir = 1;
+      }
+    } else {
+      homodir = simpleMolecule.getHomodimer();
+    }
+
+    simpleMolecule.setWidth(simpleMolecule.getWidth() - SpeciesConverter.HOMODIMER_OFFSET * (homodir - 1));
+    simpleMolecule.setHeight(simpleMolecule.getHeight() - SpeciesConverter.HOMODIMER_OFFSET * (homodir - 1));
+
+    // SBGN view - simple molecules are represented as circles
+    if (params.isSbgnFormat()) {
+      simpleMolecule.setX(simpleMolecule.getX() + (simpleMolecule.getWidth() - simpleMolecule.getHeight()) / 2);
+      simpleMolecule.setWidth(simpleMolecule.getHeight());
+    }
+
+    simpleMolecule.setX(simpleMolecule.getX() + SpeciesConverter.HOMODIMER_OFFSET * (homodir));
+    simpleMolecule.setY(simpleMolecule.getY() + SpeciesConverter.HOMODIMER_OFFSET * (homodir));
+
+    for (int i = 0; i < homodir; i++) {
+      simpleMolecule.setX(simpleMolecule.getX() - SpeciesConverter.HOMODIMER_OFFSET);
+      simpleMolecule.setY(simpleMolecule.getY() - SpeciesConverter.HOMODIMER_OFFSET);
+      Shape shape = new Ellipse2D.Double(simpleMolecule.getX(), simpleMolecule.getY(), simpleMolecule.getWidth(),
+          simpleMolecule.getHeight());
+      Color c = graphics.getColor();
+      graphics.setColor(simpleMolecule.getColor());
+      graphics.fill(shape);
+      graphics.setColor(c);
+      Stroke stroke = graphics.getStroke();
+      graphics.setStroke(getBorderLine(simpleMolecule));
+      graphics.draw(shape);
+      graphics.setStroke(stroke);
+
+      // SBGN view - multimers are displayed with a unit of information
+      // containing cardinality
+      if (params.isSbgnFormat() && (i == homodir - 1)) {
+        String unitOfInformationText = null;
+        if (simpleMolecule.getStatePrefix() != null && simpleMolecule.getStateLabel() != null) {
+          unitOfInformationText = simpleMolecule.getStatePrefix() + ":" + simpleMolecule.getStateLabel();
+        }
+        if (homodir == 2 && (unitOfInformationText == null || !unitOfInformationText.contains("N:"))) {
+          if (unitOfInformationText != null) {
+            unitOfInformationText += "; ";
+          } else {
+            unitOfInformationText = "";
+          }
+          unitOfInformationText += "N:" + simpleMolecule.getHomodimer();
+        }
+
+        drawUnitOfInformation(unitOfInformationText, simpleMolecule, graphics);
+      }
+    }
+    simpleMolecule.setWidth(simpleMolecule.getWidth() + SpeciesConverter.HOMODIMER_OFFSET * (homodir - 1));
+    simpleMolecule.setHeight(simpleMolecule.getHeight() + SpeciesConverter.HOMODIMER_OFFSET * (homodir - 1));
+    drawText(simpleMolecule, graphics, params);
+  }
+
+  @Override
+  public PathIterator getBoundPathIterator(final SimpleMolecule simpleMolecule) {
+    throw new InvalidStateException("This class doesn't provide boundPath");
+  }
+
+}
diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverter.java
index 2bf368852c188ceceb829c2009a4541d6007d2df..c707b3b147c068086f3906842bd7cfe0e68b3b04 100644
--- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverter.java
+++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverter.java
@@ -1,607 +1,694 @@
-package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.Line2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.common.exception.InvalidStateException;
-import lcsb.mapviewer.common.geometry.EllipseTransformation;
-import lcsb.mapviewer.common.geometry.LineTransformation;
-import lcsb.mapviewer.converter.graphics.ConverterParams;
-import lcsb.mapviewer.converter.graphics.DrawingException;
-import lcsb.mapviewer.converter.graphics.bioEntity.element.ElementConverter;
-import lcsb.mapviewer.model.graphics.LineType;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.Species;
-
-/**
- * This class defines basics used for drawing {@link Species} (node in the graph
- * representation) on the {@link Graphics2D} object.
- * 
- * @param <T>
- *          type of {@link Species} class that can be drawn with this converter
- * @author Piotr Gawron
- * 
- */
-public abstract class SpeciesConverter<T extends Species> extends ElementConverter<T> {
-
-	/**
-	 * PI value.
-	 */
-	private static final double		PI																			 = Math.PI;
-
-	/**
-	 * Constant determining angle of the top right corner.
-	 */
-	protected static final double	RIGHT_TOP_RESIDUE_MAX_ANGLE							 = 0.25 * PI;
-
-	/**
-	 * Constant determining angle of the top left corner.
-	 */
-	protected static final double	TOP_RESIDUE_MAX_ANGLE										 = 0.75 * PI;
-
-	/**
-	 * Constant determining angle of the bottom left corner.
-	 */
-	protected static final double	LEFT_RESIDUE_MAX_ANGLE									 = 1.25 * PI;
-
-	/**
-	 * Constant determining angle of the bottom right corner.
-	 */
-	protected static final double	BOTTOM_RESIDUE_MAX_ANGLE								 = 1.75 * PI;
-
-	/**
-	 * Default font size for the modifier description.
-	 */
-	protected static final int		DEFAULT_SPECIES_MODIFIER_FONT_SIZE			 = 10;
-
-	/**
-	 * Default diameter of the modification residues.
-	 */
-	protected static final int		DEFAULT_MODIFICATION_DIAMETER						 = 15;
-
-	/**
-	 * How far from the original shape should the activity border be drawn.
-	 */
-	protected static final int		ACTIVITY_BORDER_DISTANCE								 = 5;
-
-	/**
-	 * Default species font size.
-	 */
-	protected static final int		DEFAULT_SPECIES_FONT_SIZE								 = 12;
-
-	/**
-	 * Height of the ellipse that contain structural state description.
-	 */
-	private static final int			STRUCTURAL_STATE_HEIGHT									 = 20;
-
-	/**
-	 * Height of the rectangle that contains unit of information.
-	 */
-	private static final int			UNIT_OF_INFORMATION_HEIGHT							 = 20;
-
-	/**
-	 * Size of the margin in the structural state description.
-	 */
-	private static final int			TEXT_MARGIN_FOR_STRUCTURAL_STATE_DESC		 = 40;
-
-	/**
-	 * Size of the margin in the unit of information description.
-	 */
-	private static final int			TEXT_MARGIN_FOR_UNIT_OF_INFORMATION_DESC = 20;
-
-	/**
-	 * Minimum width of the structural state ellipse.
-	 */
-	private static final int			MIN_STRUCTURAL_STATE_WIDTH							 = 60;
-
-	/**
-	 * Minimum width of the unit of information rectangle.
-	 */
-	private static final int			MIN_UNIT_OF_INFORMATION_WIDTH						 = 40;
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger					logger																	 = Logger.getLogger(SpeciesConverter.class.getName());
-
-	/**
-	 * Graphical helper object with line transformation functions.
-	 */
-	private LineTransformation		lineTransformation											 = new LineTransformation();
-
-	/**
-	 * Graphical helper object with ellipse transformation functions.
-	 */
-	private EllipseTransformation	ellipseTransformation										 = new EllipseTransformation();
-
-	/**
-	 * Default font used to draw structural state of the species.
-	 */
-	private Font									structuralFont													 = null;
-
-	/**
-	 * Default font used to draw unit of information of the species.
-	 */
-	private Font									unitOfInformationFont										 = null;
-
-	/**
-	 * What is the distance between homodimer aliases when homodimer>1.
-	 */
-	public static final int				HOMODIMER_OFFSET												 = 6;
-
-	/**
-	 * Object that helps to convert {@link ColorSchema} values into colors.
-	 */
-	private ColorExtractor				colorExtractor;
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param colorExtractor
-	 *          Object that helps to convert {@link ColorSchema} values into
-	 *          colors when drawing {@link Species}
-	 */
-	protected SpeciesConverter(ColorExtractor colorExtractor) {
-		structuralFont = new Font(Font.SANS_SERIF, 0, DEFAULT_SPECIES_MODIFIER_FONT_SIZE);
-		this.colorExtractor = colorExtractor;
-	};
-
-	/**
-	 * Returns coordinates on the {@link Species} border for given angle.
-	 * 
-	 * @param species
-	 *          {@link Species} on border which the point is looked for
-	 * @param angle
-	 *          angle between X axis center point of {@link Species} and point
-	 *          that we are looking for
-	 * @return coordinates on the {@link Species} border that correspond to the
-	 *         angle
-	 */
-	protected Point2D getPointCoordinatesOnBorder(final T species, final double angle) {
-		Point2D result = null;
-		if (species.getWidth() == 0 && species.getHeight() == 0) {
-			result = species.getCenter();
-		} else {
-			double dist = Math.max(species.getWidth(), species.getHeight()) * 2;
-			Point2D startPoint = species.getCenter();
-			double x = startPoint.getX() + Math.cos(angle) * dist;
-			double y = startPoint.getY() - Math.sin(angle) * dist;
-			Point2D endPoint = new Point2D.Double(x, y);
-			Line2D line = new Line2D.Double(startPoint, endPoint);
-			result = lineTransformation.getIntersectionWithPathIterator(line, getBoundPathIterator(species));
-		}
-		return result;
-
-	}
-
-	/**
-	 * Returns coordinates on the {@link Species} border for given angle for
-	 * residues.
-	 * 
-	 * @param species
-	 *          object on border which the point is looked for
-	 * @param angle
-	 *          CellDEsigner specific angle defining coordinates (;/)
-	 * @return coordinates on the alias border that correspond to the angle
-	 */
-	protected Point2D getResidueCoordinates(final T species, double angle) {
-		Point2D result = null;
-		if (species.getWidth() == 0 && species.getHeight() == 0) {
-			result = species.getCenter();
-		} else {
-			double x = 0;
-			double y = 0;
-			while (angle > 2 * PI) {
-				angle -= 2 * PI;
-			}
-			while (angle < 0) {
-				angle += 2 * PI;
-			}
-			if (angle < RIGHT_TOP_RESIDUE_MAX_ANGLE) {
-				// CHECKSTYLE:OFF 0.5 is much readable than any other suggestion
-				double ratio = 0.5 + angle / (PI / 2);
-				// CHECKSTYLE:ON
-				x = species.getX() + species.getWidth();
-				y = species.getY() + species.getHeight() * (1 - ratio);
-			} else if (angle < TOP_RESIDUE_MAX_ANGLE) {
-				double ratio = (angle - RIGHT_TOP_RESIDUE_MAX_ANGLE) / (PI / 2);
-				y = species.getY();
-				x = species.getX() + species.getWidth() * (1 - ratio);
-			} else if (angle < LEFT_RESIDUE_MAX_ANGLE) {
-				double ratio = (angle - TOP_RESIDUE_MAX_ANGLE) / (PI / 2);
-				y = species.getY() + species.getHeight() * (ratio);
-				x = species.getX();
-			} else if (angle < BOTTOM_RESIDUE_MAX_ANGLE) {
-				double ratio = (angle - LEFT_RESIDUE_MAX_ANGLE) / (PI / 2);
-				y = species.getY() + species.getHeight();
-				x = species.getX() + species.getWidth() * ratio;
-			} else if (angle <= 2 * PI + Configuration.EPSILON) {
-				double ratio = (angle - BOTTOM_RESIDUE_MAX_ANGLE) / (PI / 2);
-				y = species.getY() + species.getHeight() * (1 - ratio);
-				x = species.getX() + species.getWidth();
-			} else {
-				throw new InvalidStateException();
-			}
-			Point2D center = species.getCenter();
-			double correctedAngle = -Math.atan2((y - center.getY()), (x - center.getX()));
-			result = getPointCoordinatesOnBorder(species, correctedAngle);
-		}
-		return result;
-
-	}
-
-	/**
-	 * Returns default shape of the {@link Species}.
-	 * 
-	 * @param species
-	 *          {@link Species} for which we are looking for a border
-	 * @return {@link Shape} object defining given {@link Species}
-	 */
-	protected Shape getDefaultAliasShape(final Species species) {
-		Shape shape;
-		shape = new Rectangle(species.getX().intValue(), species.getY().intValue(), species.getWidth().intValue(), species.getHeight().intValue());
-		return shape;
-	}
-
-	/**
-	 * Returns font that should be used for drawing description of the
-	 * {@link Species}.
-	 * 
-	 * @param species
-	 *          {@link Species} for which we are looking for a font
-	 * @param params
-	 *          specific drawing parameters (like scale)
-	 * @return {@link Font} that should be used for drawing {@link Species}
-	 *         description
-	 */
-	protected Font getFont(final Species species, ConverterParams params) {
-		double fontSize = DEFAULT_SPECIES_FONT_SIZE;
-		if (species.getFontSize() != null) {
-			fontSize = species.getFontSize();
-		}
-		return new Font(Font.SANS_SERIF, 0, (int) (fontSize * params.getScale()));
-	}
-
-	/**
-	 * Returns text describing {@link Species}.
-	 * 
-	 * @param species
-	 *          object under investigation
-	 * @return description of the {@link Species}
-	 */
-	protected String getText(final T species) {
-		String name = species.getName();
-		if (name.equals("")) {
-			name = " ";
-		}
-
-		return name;
-	}
-
-	@Override
-	public void drawText(final T species, final Graphics2D graphics, final ConverterParams params) {
-		String text = getText(species);
-		Font oldFont = graphics.getFont();
-		Font font = getFont(species, params);
-		graphics.setColor(Color.BLACK);
-		graphics.setFont(font);
-
-		Point2D point = species.getCenter();
-		if (species instanceof Complex) {
-			if (((Complex) species).getElements().size() > 0) {
-				if (isTransparent(species, params)) {
-					point.setLocation(point.getX(), species.getY() + species.getHeight() - graphics.getFontMetrics().getAscent());
-				}
-			}
-		}
-		drawText(point, text, graphics, true, true);
-		graphics.setFont(oldFont);
-	}
-
-	/**
-	 * Return width of the text.
-	 * 
-	 * @param text
-	 *          width of this text will be computed
-	 * @param graphics
-	 *          the width will be computed assuming using this graphics
-	 * @return width of the text
-	 */
-	protected double getTextWidth(final String text, final Graphics2D graphics) {
-		if (text == null) {
-			return 0;
-		}
-		if (text.equals("")) {
-			return 0;
-		}
-
-		double result = 0;
-		String[] lines = text.split("\n");
-		for (String string : lines) {
-			result = Math.max(result, graphics.getFontMetrics().stringWidth(string));
-		}
-
-		return result;
-	}
-
-	/**
-	 * Returns text height.
-	 * 
-	 * @param text
-	 *          height of this text will be computed
-	 * @param graphics
-	 *          the height will be computed assuming using this graphics
-	 * @return height of the text
-	 */
-	protected double getTextHeight(final String text, final Graphics2D graphics) {
-		if (text == null) {
-			return 0;
-		}
-		if (text.equals("")) {
-			return 0;
-		}
-
-		double result = 0;
-		int lines = text.split("\n").length;
-		result = graphics.getFontMetrics().getHeight() * lines;
-		return result;
-	}
-
-	/**
-	 * This method draws a string on graphics using current font. The coordinates
-	 * of the text is given as a point. Both parameters centered described if text
-	 * should be automatically centered horizontally and vertically.
-	 * 
-	 * @param point
-	 *          where the text should be drawn
-	 * @param text
-	 *          text to draw
-	 * @param graphics
-	 *          where we want to draw the object
-	 * @param horizontalCentered
-	 *          should the text be horizontally centered
-	 * @param verticalCentered
-	 *          should the text be vertically centered
-	 */
-	protected void drawText(final Point2D point, final String text, final Graphics2D graphics, final boolean horizontalCentered,
-			final boolean verticalCentered) {
-		double height = getTextHeight(text, graphics);
-		double x = point.getX();
-		double y = point.getY();
-		if (verticalCentered) {
-			y -= height / 2 - graphics.getFontMetrics().getAscent();
-		}
-		String[] lines = text.split("\n");
-
-		double lineHeight = graphics.getFontMetrics().getHeight();
-		for (String string : lines) {
-			double currX = x;
-			if (horizontalCentered) {
-				currX -= getTextWidth(string, graphics) / 2;
-			}
-			graphics.drawString(string, (int) currX, (int) y);
-			y += lineHeight;
-		}
-	}
-
-	/**
-	 * Returns line style used for drawing alias border.
-	 * 
-	 * @param species
-	 *          {@link Species} to be drawn
-	 * @return style of the line used to draw {@link Species}
-	 */
-	protected Stroke getBorderLine(final Species species) {
-		if (!species.isHypothetical()) {
-			if (species instanceof Complex) {
-				return LineType.SOLID_BOLD.getStroke();
-			} else {
-				return LineType.SOLID.getStroke();
-			}
-		} else {
-			if (species instanceof Complex) {
-				return LineType.DASHED_BOLD.getStroke();
-			} else {
-				return LineType.DASHED.getStroke();
-			}
-		}
-	}
-
-	/**
-	 * Returns border of the {@link Species} as {@link PathIterator}.
-	 * 
-	 * @param species
-	 *          {@link Species} for which we are looking for a border
-	 * @return {@link PathIterator} object defining given {@link Species}
-	 */
-	protected abstract PathIterator getBoundPathIterator(T species);
-
-	/**
-	 * @return the lineTransformation
-	 */
-	protected LineTransformation getLineTransformation() {
-		return lineTransformation;
-	}
-
-	/**
-	 * @param lineTransformation
-	 *          the lineTransformation to set
-	 */
-	protected void setLineTransformation(LineTransformation lineTransformation) {
-		this.lineTransformation = lineTransformation;
-	}
-
-	/**
-	 * @return the ellipseTransformation
-	 */
-	protected EllipseTransformation getEllipseTransformation() {
-		return ellipseTransformation;
-	}
-
-	/**
-	 * @param ellipseTransformation
-	 *          the ellipseTransformation to set
-	 */
-	protected void setEllipseTransformation(EllipseTransformation ellipseTransformation) {
-		this.ellipseTransformation = ellipseTransformation;
-	}
-
-	/**
-	 * @return the structuralFont
-	 */
-	protected Font getStructuralFont() {
-		return structuralFont;
-	}
-
-	/**
-	 * @param structuralFont
-	 *          the structuralFont to set
-	 */
-	protected void setStructuralFont(Font structuralFont) {
-		this.structuralFont = structuralFont;
-	}
-
-	/**
-	 * @return the unitOfInformationFont
-	 */
-	protected Font getUnitOfInformationFont() {
-		return unitOfInformationFont;
-	}
-
-	/**
-	 * @param unitOfInformationFont
-	 *          the unitOfInformationFont to set
-	 */
-	protected void setUnitOfInformationFont(Font unitOfInformationFont) {
-		this.unitOfInformationFont = unitOfInformationFont;
-	}
-
-	/**
-	 * Draws structural state description of the alias (ellipse in the top part of
-	 * the alias).
-	 * 
-	 * @param text
-	 *          state description text
-	 * @param species
-	 *          state description should be drawn on this {@link Species}
-	 * @param graphics
-	 *          where the drawing should be performed
-	 */
-	protected void drawStructuralState(String text, T species, final Graphics2D graphics) {
-		if (text == null) {
-			return;
-		}
-
-		Point2D p = getPointCoordinatesOnBorder(species, Math.PI / 2);
-
-		double width = MIN_STRUCTURAL_STATE_WIDTH;
-		if (!text.trim().equals("")) {
-			width = Math.max(MIN_STRUCTURAL_STATE_WIDTH, graphics.getFontMetrics().stringWidth(text) + TEXT_MARGIN_FOR_STRUCTURAL_STATE_DESC);
-		}
-		width = Math.min(width, species.getWidth());
-		double height = STRUCTURAL_STATE_HEIGHT;
-
-		Ellipse2D ellipse = new Ellipse2D.Double(p.getX() - width / 2, p.getY() - height / 2, width, height);
-		Color c = graphics.getColor();
-		graphics.setColor(Color.WHITE);
-		graphics.fill(ellipse);
-		graphics.setColor(c);
-		graphics.draw(ellipse);
-		if (!text.trim().equals("")) {
-			Font font = graphics.getFont();
-			graphics.setFont(getStructuralFont());
-
-			width = graphics.getFontMetrics().stringWidth(text);
-			height = graphics.getFontMetrics().getAscent() - graphics.getFontMetrics().getDescent();
-
-			graphics.drawString(text, (int) (p.getX() - width / 2), (int) (p.getY() + height / 2));
-			graphics.setFont(font);
-		}
-
-	}
-
-	/**
-	 * Draws unit of information for the {@link Species} (rectangle in the top
-	 * part of the alias).
-	 * 
-	 * @param text
-	 *          unit of information text
-	 * @param species
-	 *          unit of information should be drawn on this {@link Species}
-	 * @param graphics
-	 *          where the drawing should be performed
-	 */
-	protected void drawUnitOfInformation(String text, T species, final Graphics2D graphics) {
-		if (text == null) {
-			return;
-		}
-
-		Point2D p = getPointCoordinatesOnBorder(species, Math.PI / 2);
-
-		double width = MIN_UNIT_OF_INFORMATION_WIDTH;
-		if (!text.trim().equals("")) {
-			width = Math.max(MIN_UNIT_OF_INFORMATION_WIDTH, graphics.getFontMetrics().stringWidth(text) + TEXT_MARGIN_FOR_UNIT_OF_INFORMATION_DESC);
-		}
-		width = Math.min(width, species.getWidth());
-		double height = UNIT_OF_INFORMATION_HEIGHT;
-
-		Rectangle2D rectangle = new Rectangle2D.Double(p.getX() - width / 2, p.getY() - height / 2, width, height);
-		Color c = graphics.getColor();
-		graphics.setColor(Color.WHITE);
-		graphics.fill(rectangle);
-		graphics.setColor(c);
-		graphics.draw(rectangle);
-		if (!text.trim().equals("")) {
-			Font font = graphics.getFont();
-			graphics.setFont(getUnitOfInformationFont());
-
-			width = graphics.getFontMetrics().stringWidth(text);
-			height = graphics.getFontMetrics().getAscent() - graphics.getFontMetrics().getDescent();
-
-			graphics.drawString(text, (int) (p.getX() - width / 2), (int) (p.getY() + height / 2));
-			graphics.setFont(font);
-		}
-	}
-
-	@Override
-	public void draw(T species, Graphics2D graphics, ConverterParams params, List<ColorSchema> visualizedLayoutsColorSchemas) throws DrawingException {
-		draw(species, graphics, params);
-
-		Color oldColor = graphics.getColor();
-		int count = 0;
-		double width = species.getWidth() / visualizedLayoutsColorSchemas.size();
-		for (ColorSchema schema : visualizedLayoutsColorSchemas) {
-			if (schema != null) {
-				double startX = (double) count / (double) visualizedLayoutsColorSchemas.size();
-				graphics.setColor(Color.BLACK);
-
-				int x = (int) (startX * species.getWidth() + species.getX());
-				graphics.drawRect(x, species.getY().intValue(), (int) width, species.getHeight().intValue());
-
-				Color color = colorExtractor.getNormalizedColor(schema);
-				Color bgAlphaColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), LAYOUT_ALPHA);
-				graphics.setColor(bgAlphaColor);
-				graphics.fillRect(x, species.getY().intValue(), (int) width, species.getHeight().intValue());
-			}
-			count++;
-		}
-		graphics.setColor(oldColor);
-	}
-
-}
+package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.common.geometry.EllipseTransformation;
+import lcsb.mapviewer.common.geometry.LineTransformation;
+import lcsb.mapviewer.converter.graphics.ConverterParams;
+import lcsb.mapviewer.converter.graphics.DrawingException;
+import lcsb.mapviewer.converter.graphics.bioEntity.element.ElementConverter;
+import lcsb.mapviewer.converter.graphics.geometry.ArrowTransformation;
+import lcsb.mapviewer.model.graphics.ArrowType;
+import lcsb.mapviewer.model.graphics.LineType;
+import lcsb.mapviewer.model.graphics.PolylineData;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.AbstractRegionModification;
+import lcsb.mapviewer.model.map.species.field.BindingRegion;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+import lcsb.mapviewer.model.map.species.field.ProteinBindingDomain;
+import lcsb.mapviewer.model.map.species.field.RegulatoryRegion;
+import lcsb.mapviewer.model.map.species.field.Residue;
+import lcsb.mapviewer.model.map.species.field.TranscriptionSite;
+
+/**
+ * This class defines basics used for drawing {@link Species} (node in the graph
+ * representation) on the {@link Graphics2D} object.
+ * 
+ * @param <T>
+ *          type of {@link Species} class that can be drawn with this converter
+ * @author Piotr Gawron
+ * 
+ */
+public abstract class SpeciesConverter<T extends Species> extends ElementConverter<T> {
+
+  /**
+   * Default font size for the modifier description.
+   */
+  protected static final int DEFAULT_SPECIES_MODIFIER_FONT_SIZE = 10;
+
+  /**
+   * Default diameter of the modification residues.
+   */
+  protected static final int DEFAULT_MODIFICATION_DIAMETER = 15;
+
+  /**
+   * How far from the original shape should the activity border be drawn.
+   */
+  protected static final int ACTIVITY_BORDER_DISTANCE = 5;
+
+  /**
+   * Default species font size.
+   */
+  protected static final int DEFAULT_SPECIES_FONT_SIZE = 12;
+
+  /**
+   * Height of the ellipse that contain structural state description.
+   */
+  private static final int STRUCTURAL_STATE_HEIGHT = 20;
+
+  /**
+   * Height of the rectangle that contains unit of information.
+   */
+  private static final int UNIT_OF_INFORMATION_HEIGHT = 20;
+
+  /**
+   * Size of the margin in the structural state description.
+   */
+  private static final int TEXT_MARGIN_FOR_STRUCTURAL_STATE_DESC = 40;
+
+  /**
+   * Size of the margin in the unit of information description.
+   */
+  private static final int TEXT_MARGIN_FOR_UNIT_OF_INFORMATION_DESC = 20;
+
+  /**
+   * Minimum width of the structural state ellipse.
+   */
+  private static final int MIN_STRUCTURAL_STATE_WIDTH = 60;
+
+  /**
+   * Minimum width of the unit of information rectangle.
+   */
+  private static final int MIN_UNIT_OF_INFORMATION_WIDTH = 40;
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(SpeciesConverter.class.getName());
+
+  /**
+   * Graphical helper object with line transformation functions.
+   */
+  private LineTransformation lineTransformation = new LineTransformation();
+  private ArrowTransformation arrowTransformation = new ArrowTransformation();
+
+  /**
+   * Graphical helper object with ellipse transformation functions.
+   */
+  private EllipseTransformation ellipseTransformation = new EllipseTransformation();
+
+  /**
+   * Default font used to draw structural state of the species.
+   */
+  private Font structuralFont = null;
+
+  /**
+   * Default font used to draw unit of information of the species.
+   */
+  private Font unitOfInformationFont = null;
+
+  /**
+   * What is the distance between homodimer aliases when homodimer>1.
+   */
+  public static final int HOMODIMER_OFFSET = 6;
+
+  /**
+   * Object that helps to convert {@link ColorSchema} values into colors.
+   */
+  private ColorExtractor colorExtractor;
+
+  /**
+   * Default constructor.
+   * 
+   * @param colorExtractor
+   *          Object that helps to convert {@link ColorSchema} values into colors
+   *          when drawing {@link Species}
+   */
+  protected SpeciesConverter(ColorExtractor colorExtractor) {
+    structuralFont = new Font(Font.SANS_SERIF, 0, DEFAULT_SPECIES_MODIFIER_FONT_SIZE);
+    this.colorExtractor = colorExtractor;
+  };
+
+  /**
+   * Returns default shape of the {@link Species}.
+   * 
+   * @param species
+   *          {@link Species} for which we are looking for a border
+   * @return {@link Shape} object defining given {@link Species}
+   */
+  protected Shape getDefaultAliasShape(final Species species) {
+    Shape shape;
+    shape = new Rectangle(species.getX().intValue(), species.getY().intValue(), species.getWidth().intValue(),
+        species.getHeight().intValue());
+    return shape;
+  }
+
+  /**
+   * Returns font that should be used for drawing description of the
+   * {@link Species}.
+   * 
+   * @param species
+   *          {@link Species} for which we are looking for a font
+   * @param params
+   *          specific drawing parameters (like scale)
+   * @return {@link Font} that should be used for drawing {@link Species}
+   *         description
+   */
+  protected Font getFont(final Species species, ConverterParams params) {
+    double fontSize = DEFAULT_SPECIES_FONT_SIZE;
+    if (species.getFontSize() != null) {
+      fontSize = species.getFontSize();
+    }
+    return new Font(Font.SANS_SERIF, 0, (int) (fontSize * params.getScale()));
+  }
+
+  /**
+   * Returns text describing {@link Species}.
+   * 
+   * @param species
+   *          object under investigation
+   * @return description of the {@link Species}
+   */
+  protected String getText(final T species) {
+    String name = species.getName();
+    if (name.equals("")) {
+      name = " ";
+    }
+
+    return name;
+  }
+
+  @Override
+  public void drawText(final T species, final Graphics2D graphics, final ConverterParams params) {
+    String text = getText(species);
+    Font oldFont = graphics.getFont();
+    Font font = getFont(species, params);
+    graphics.setColor(Color.BLACK);
+    graphics.setFont(font);
+
+    Point2D point = species.getCenter();
+    if (species instanceof Complex) {
+      if (((Complex) species).getElements().size() > 0) {
+        if (isTransparent(species, params)) {
+          point.setLocation(point.getX(), species.getY() + species.getHeight() - graphics.getFontMetrics().getAscent());
+        }
+      }
+    }
+    drawText(point, text, graphics, true, true);
+    graphics.setFont(oldFont);
+  }
+
+  /**
+   * Return width of the text.
+   * 
+   * @param text
+   *          width of this text will be computed
+   * @param graphics
+   *          the width will be computed assuming using this graphics
+   * @return width of the text
+   */
+  protected double getTextWidth(final String text, final Graphics2D graphics) {
+    if (text == null) {
+      return 0;
+    }
+    if (text.equals("")) {
+      return 0;
+    }
+
+    double result = 0;
+    String[] lines = text.split("\n");
+    for (String string : lines) {
+      result = Math.max(result, graphics.getFontMetrics().stringWidth(string));
+    }
+
+    return result;
+  }
+
+  /**
+   * Returns text height.
+   * 
+   * @param text
+   *          height of this text will be computed
+   * @param graphics
+   *          the height will be computed assuming using this graphics
+   * @return height of the text
+   */
+  protected double getTextHeight(final String text, final Graphics2D graphics) {
+    if (text == null) {
+      return 0;
+    }
+    if (text.equals("")) {
+      return 0;
+    }
+
+    double result = 0;
+    int lines = text.split("\n").length;
+    result = graphics.getFontMetrics().getHeight() * lines;
+    return result;
+  }
+
+  /**
+   * This method draws a string on graphics using current font. The coordinates of
+   * the text is given as a point. Both parameters centered described if text
+   * should be automatically centered horizontally and vertically.
+   * 
+   * @param point
+   *          where the text should be drawn
+   * @param text
+   *          text to draw
+   * @param graphics
+   *          where we want to draw the object
+   * @param horizontalCentered
+   *          should the text be horizontally centered
+   * @param verticalCentered
+   *          should the text be vertically centered
+   */
+  protected void drawText(final Point2D point, final String text, final Graphics2D graphics,
+      final boolean horizontalCentered, final boolean verticalCentered) {
+    double height = getTextHeight(text, graphics);
+    double x = point.getX();
+    double y = point.getY();
+    if (verticalCentered) {
+      y -= height / 2 - graphics.getFontMetrics().getAscent();
+    }
+    String[] lines = text.split("\n");
+
+    double lineHeight = graphics.getFontMetrics().getHeight();
+    for (String string : lines) {
+      double currX = x;
+      if (horizontalCentered) {
+        currX -= getTextWidth(string, graphics) / 2;
+      }
+      graphics.drawString(string, (int) currX, (int) y);
+      y += lineHeight;
+    }
+  }
+
+  /**
+   * Returns line style used for drawing alias border.
+   * 
+   * @param species
+   *          {@link Species} to be drawn
+   * @return style of the line used to draw {@link Species}
+   */
+  protected Stroke getBorderLine(final Species species) {
+    if (!species.isHypothetical()) {
+      if (species instanceof Complex) {
+        return LineType.SOLID_BOLD.getStroke();
+      } else {
+        return LineType.SOLID.getStroke();
+      }
+    } else {
+      if (species instanceof Complex) {
+        return LineType.DASHED_BOLD.getStroke();
+      } else {
+        return LineType.DASHED.getStroke();
+      }
+    }
+  }
+
+  /**
+   * Returns border of the {@link Species} as {@link PathIterator}.
+   * 
+   * @param species
+   *          {@link Species} for which we are looking for a border
+   * @return {@link PathIterator} object defining given {@link Species}
+   */
+  protected abstract PathIterator getBoundPathIterator(T species);
+
+  /**
+   * @return the lineTransformation
+   */
+  protected LineTransformation getLineTransformation() {
+    return lineTransformation;
+  }
+
+  /**
+   * @param lineTransformation
+   *          the lineTransformation to set
+   */
+  protected void setLineTransformation(LineTransformation lineTransformation) {
+    this.lineTransformation = lineTransformation;
+  }
+
+  /**
+   * @return the ellipseTransformation
+   */
+  protected EllipseTransformation getEllipseTransformation() {
+    return ellipseTransformation;
+  }
+
+  /**
+   * @param ellipseTransformation
+   *          the ellipseTransformation to set
+   */
+  protected void setEllipseTransformation(EllipseTransformation ellipseTransformation) {
+    this.ellipseTransformation = ellipseTransformation;
+  }
+
+  /**
+   * @return the structuralFont
+   */
+  protected Font getStructuralFont() {
+    return structuralFont;
+  }
+
+  /**
+   * @param structuralFont
+   *          the structuralFont to set
+   */
+  protected void setStructuralFont(Font structuralFont) {
+    this.structuralFont = structuralFont;
+  }
+
+  /**
+   * @return the unitOfInformationFont
+   */
+  protected Font getUnitOfInformationFont() {
+    return unitOfInformationFont;
+  }
+
+  /**
+   * @param unitOfInformationFont
+   *          the unitOfInformationFont to set
+   */
+  protected void setUnitOfInformationFont(Font unitOfInformationFont) {
+    this.unitOfInformationFont = unitOfInformationFont;
+  }
+
+  /**
+   * Draws structural state description of the alias (ellipse in the top part of
+   * the alias).
+   * 
+   * @param text
+   *          state description text
+   * @param species
+   *          state description should be drawn on this {@link Species}
+   * @param graphics
+   *          where the drawing should be performed
+   */
+  protected void drawStructuralState(String text, T species, final Graphics2D graphics) {
+    if (text == null) {
+      return;
+    }
+
+    Point2D p = new Point2D.Double(species.getCenterX(), species.getY());
+
+    double width = MIN_STRUCTURAL_STATE_WIDTH;
+    if (!text.trim().equals("")) {
+      width = Math.max(MIN_STRUCTURAL_STATE_WIDTH,
+          graphics.getFontMetrics().stringWidth(text) + TEXT_MARGIN_FOR_STRUCTURAL_STATE_DESC);
+    }
+    width = Math.min(width, species.getWidth());
+    double height = STRUCTURAL_STATE_HEIGHT;
+
+    Ellipse2D ellipse = new Ellipse2D.Double(p.getX() - width / 2, p.getY() - height / 2, width, height);
+    Color c = graphics.getColor();
+    graphics.setColor(Color.WHITE);
+    graphics.fill(ellipse);
+    graphics.setColor(c);
+    graphics.draw(ellipse);
+    if (!text.trim().equals("")) {
+      Font font = graphics.getFont();
+      graphics.setFont(getStructuralFont());
+
+      width = graphics.getFontMetrics().stringWidth(text);
+      height = graphics.getFontMetrics().getAscent() - graphics.getFontMetrics().getDescent();
+
+      graphics.drawString(text, (int) (p.getX() - width / 2), (int) (p.getY() + height / 2));
+      graphics.setFont(font);
+    }
+
+  }
+
+  /**
+   * Draws unit of information for the {@link Species} (rectangle in the top part
+   * of the alias).
+   * 
+   * @param text
+   *          unit of information text
+   * @param species
+   *          unit of information should be drawn on this {@link Species}
+   * @param graphics
+   *          where the drawing should be performed
+   */
+  protected void drawUnitOfInformation(String text, T species, final Graphics2D graphics) {
+    if (text == null) {
+      return;
+    }
+
+    Point2D p = new Point2D.Double(species.getCenterX(), species.getY());
+
+    double width = MIN_UNIT_OF_INFORMATION_WIDTH;
+    if (!text.trim().equals("")) {
+      width = Math.max(MIN_UNIT_OF_INFORMATION_WIDTH,
+          graphics.getFontMetrics().stringWidth(text) + TEXT_MARGIN_FOR_UNIT_OF_INFORMATION_DESC);
+    }
+    width = Math.min(width, species.getWidth());
+    double height = UNIT_OF_INFORMATION_HEIGHT;
+
+    Rectangle2D rectangle = new Rectangle2D.Double(p.getX() - width / 2, p.getY() - height / 2, width, height);
+    Color c = graphics.getColor();
+    graphics.setColor(Color.WHITE);
+    graphics.fill(rectangle);
+    graphics.setColor(c);
+    graphics.draw(rectangle);
+    if (!text.trim().equals("")) {
+      Font font = graphics.getFont();
+      graphics.setFont(getUnitOfInformationFont());
+
+      width = graphics.getFontMetrics().stringWidth(text);
+      height = graphics.getFontMetrics().getAscent() - graphics.getFontMetrics().getDescent();
+
+      graphics.drawString(text, (int) (p.getX() - width / 2), (int) (p.getY() + height / 2));
+      graphics.setFont(font);
+    }
+  }
+
+  @Override
+  public void draw(T species, Graphics2D graphics, ConverterParams params,
+      List<ColorSchema> visualizedLayoutsColorSchemas) throws DrawingException {
+    draw(species, graphics, params);
+
+    Color oldColor = graphics.getColor();
+    int count = 0;
+    double width = species.getWidth() / visualizedLayoutsColorSchemas.size();
+    for (ColorSchema schema : visualizedLayoutsColorSchemas) {
+      if (schema != null) {
+        double startX = (double) count / (double) visualizedLayoutsColorSchemas.size();
+        graphics.setColor(Color.BLACK);
+
+        int x = (int) (startX * species.getWidth() + species.getX());
+        graphics.drawRect(x, species.getY().intValue(), (int) width, species.getHeight().intValue());
+
+        Color color = colorExtractor.getNormalizedColor(schema);
+        Color bgAlphaColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), LAYOUT_ALPHA);
+        graphics.setColor(bgAlphaColor);
+        graphics.fillRect(x, species.getY().intValue(), (int) width, species.getHeight().intValue());
+      }
+      count++;
+    }
+    graphics.setColor(oldColor);
+  }
+
+  /**
+   * This method draws modification of the alias. If drawEmptyModification is set
+   * to false then modification is not drawn if empty. If drawDescription is set
+   * then also description (position) of the modification is drawn on the canvas.
+   * 
+   * @param protein
+   *          object that is 'parent' of the residue
+   * @param mr
+   *          modification to be drawn
+   * @param graphics
+   *          - where the modification should be drawn
+   * @param drawEmptyModification
+   *          flag that indicates if we should draw empty modification
+   */
+  protected void drawModification(final ModificationResidue mr, final Graphics2D graphics,
+      boolean drawEmptyModification) {
+    if (mr instanceof Residue) {
+      drawResidue((Residue) mr, graphics, drawEmptyModification);
+    } else if (mr instanceof ModificationSite) {
+      drawModificationSite((ModificationSite) mr, graphics, drawEmptyModification);
+    } else if (mr instanceof BindingRegion) {
+      drawBindingRegion((BindingRegion) mr, graphics);
+    } else if (mr instanceof ProteinBindingDomain) {
+      drawProteinBindingDomain((ProteinBindingDomain) mr, graphics);
+    } else if (mr instanceof CodingRegion) {
+      drawCodingRegion((CodingRegion) mr, graphics);
+    } else if (mr instanceof RegulatoryRegion) {
+      drawRegulatoryRegion((RegulatoryRegion) mr, graphics);
+    } else if (mr instanceof TranscriptionSite) {
+      drawTranscriptionSite((TranscriptionSite) mr, graphics);
+    } else {
+      throw new InvalidArgumentException("Unknown class type: " + mr.getClass());
+    }
+  }
+
+  protected void drawResidue(final Residue residue, final Graphics2D graphics, boolean drawEmptyModification) {
+    if (!drawEmptyModification && residue.getState() == null) {
+      return;
+    }
+    double diameter = DEFAULT_MODIFICATION_DIAMETER;
+    Point2D p = residue.getPosition();
+    Ellipse2D ellipse = new Ellipse2D.Double(p.getX() - diameter / 2, p.getY() - diameter / 2, diameter, diameter);
+    Color c = graphics.getColor();
+    graphics.setColor(Color.WHITE);
+    graphics.fill(ellipse);
+    graphics.setColor(c);
+    graphics.draw(ellipse);
+
+    ModificationState state = residue.getState();
+    if (state != null) {
+      String str = state.getAbbreviation();
+      Font tmpFont = graphics.getFont();
+      graphics.setFont(getStructuralFont());
+      double x = p.getX() - graphics.getFontMetrics().stringWidth(str) / 2;
+      double y = p.getY() + graphics.getFontMetrics().getAscent() / 2;
+      graphics.drawString(str, (int) x, (int) y);
+      graphics.setFont(tmpFont);
+    }
+  }
+
+  /**
+   * This method draws {@link ModificationSite} of the {@link Species}. If
+   * drawEmptyModification is set to false then modification is not drawn if
+   * empty.
+   * 
+   * @param modificationSite
+   *          modification to be drawn
+   * @param graphics
+   *          - where the modification should be drawn
+   * @param drawEmptyModification
+   *          flag that indicates if we should draw empty modification
+   */
+  protected void drawModificationSite(final ModificationSite modificationSite, final Graphics2D graphics,
+      boolean drawEmptyModification) {
+    if (!drawEmptyModification && modificationSite.getState() == null) {
+      return;
+    }
+    double diameter = DEFAULT_MODIFICATION_DIAMETER;
+
+    double y = modificationSite.getPosition().getY();
+
+    Point2D p = new Point2D.Double(modificationSite.getPosition().getX(), y - DEFAULT_MODIFICATION_DIAMETER);
+
+    Ellipse2D ellipse = new Ellipse2D.Double(p.getX() - diameter / 2, p.getY() - diameter / 2, diameter, diameter);
+    Color c = graphics.getColor();
+    graphics.setColor(Color.WHITE);
+    graphics.fill(ellipse);
+    graphics.setColor(c);
+    graphics.draw(ellipse);
+    graphics.drawLine((int) p.getX(), (int) (p.getY() + diameter / 2), (int) p.getX(), (int) y);
+
+    ModificationState state = modificationSite.getState();
+    if (state != null) {
+      String str = state.getAbbreviation();
+      Font tmpFont = graphics.getFont();
+      graphics.setFont(getStructuralFont());
+      double textX = p.getX() - graphics.getFontMetrics().stringWidth(str) / 2;
+      double textY = p.getY() + graphics.getFontMetrics().getAscent() / 2;
+      graphics.drawString(str, (int) textX, (int) textY);
+      graphics.setFont(tmpFont);
+    }
+  }
+
+  protected void drawBindingRegion(final BindingRegion bindingRegion, final Graphics2D graphics) {
+    drawRegionModification(bindingRegion, graphics);
+  }
+
+  protected void drawProteinBindingDomain(final ProteinBindingDomain proteinBindingDomain, final Graphics2D graphics) {
+    drawRegionModification(proteinBindingDomain, graphics);
+  }
+
+  protected void drawCodingRegion(final CodingRegion codingRegion, final Graphics2D graphics) {
+    drawRegionModification(codingRegion, graphics);
+  }
+
+  private void drawRegionModification(AbstractRegionModification modification, Graphics2D graphics) {
+    Point2D rectangleCenter = modification.getPosition();
+    double width = modification.getWidth();
+    double height = modification.getHeight();
+    Rectangle2D rectangle = new Rectangle2D.Double(rectangleCenter.getX() - width / 2,
+        rectangleCenter.getY() - height / 2, width, height);
+    Color c = graphics.getColor();
+    graphics.setColor(Color.WHITE);
+    graphics.fill(rectangle);
+    graphics.setColor(c);
+    graphics.draw(rectangle);
+
+    String str = modification.getName();
+    if (str != null && !str.trim().equals("")) {
+      Font tmpFont = graphics.getFont();
+      graphics.setFont(getStructuralFont());
+      double textX = rectangleCenter.getX() - graphics.getFontMetrics().stringWidth(str) / 2;
+      double textY = rectangleCenter.getY() + graphics.getFontMetrics().getAscent() / 2;
+      graphics.drawString(str, (int) textX, (int) textY);
+      graphics.setFont(tmpFont);
+    }
+
+  }
+
+  protected void drawRegulatoryRegion(final RegulatoryRegion regulatoryRegion, final Graphics2D graphics) {
+    drawRegionModification(regulatoryRegion, graphics);
+  }
+
+  protected void drawTranscriptionSite(final TranscriptionSite transcriptionSite, final Graphics2D graphics) {
+
+    Color color = graphics.getColor();
+    if (transcriptionSite.getActive()) {
+      color = Color.RED;
+    } else {
+      color = Color.BLACK;
+    }
+    double y = transcriptionSite.getPosition().getY();
+    double x = transcriptionSite.getPosition().getX();
+    PolylineData line = new PolylineData();
+    if (transcriptionSite.getDirection().equals("RIGHT")) {
+      x += transcriptionSite.getWidth() / 2;
+      line.addPoint(new Point2D.Double(x, y));
+
+      y -= DEFAULT_MODIFICATION_DIAMETER;
+      line.addPoint(new Point2D.Double(x, y));
+
+      x -= transcriptionSite.getWidth();
+      line.addPoint(new Point2D.Double(x, y));
+    } else {
+      x -= transcriptionSite.getWidth() / 2;
+      line.addPoint(new Point2D.Double(x, y));
+
+      y -= DEFAULT_MODIFICATION_DIAMETER;
+      line.addPoint(new Point2D.Double(x, y));
+
+      x += transcriptionSite.getWidth();
+      line.addPoint(new Point2D.Double(x, y));
+    }
+    line.setColor(color);
+    line.getEndAtd().setArrowType(ArrowType.FULL);
+
+    arrowTransformation.drawLine(line, graphics);
+
+  }
+
+}
diff --git a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/UnknownConverter.java b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/UnknownConverter.java
index 8103b5141e06e83004616ac0ccd9e8941fdd2e97..a3aec15bac0cde37f378eaa13f253f5ed9fcb783 100644
--- a/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/UnknownConverter.java
+++ b/converter-graphics/src/main/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/UnknownConverter.java
@@ -1,82 +1,72 @@
-package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
-
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.common.exception.InvalidStateException;
-import lcsb.mapviewer.converter.graphics.ConverterParams;
-import lcsb.mapviewer.model.graphics.LineType;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.Unknown;
-
-/**
- * This class defines methods used for drawing {@link Unknown} on the
- * {@link Graphics2D} object.
- * 
- * @author Piotr Gawron
- * 
- */
-public class UnknownConverter extends SpeciesConverter<Unknown> {
-
-	/**
-	 * Default class logger.
-	 */
-	private static Logger logger = Logger.getLogger(UnknownConverter.class.getName());
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param colorExtractor
-	 *          Object that helps to convert {@link ColorSchema} values into
-	 *          colors when drawing {@link Species}
-	 */
-	public UnknownConverter(ColorExtractor colorExtractor) {
-		super(colorExtractor);
-	}
-
-	@Override
-	public void draw(Unknown unknown, final Graphics2D graphics, final ConverterParams params) {
-		if (unknown.getActivity()) {
-			int border = ACTIVITY_BORDER_DISTANCE;
-			unknown.increaseBorder(border);
-			Shape shape2 = new Ellipse2D.Double(unknown.getX(), unknown.getY(), unknown.getWidth(), unknown.getHeight());
-			Stroke stroke = graphics.getStroke();
-			graphics.setStroke(LineType.DOTTED.getStroke());
-			graphics.draw(shape2);
-			graphics.setStroke(stroke);
-			unknown.increaseBorder(-border);
-		}
-
-		Shape shape = new Ellipse2D.Double(unknown.getX(), unknown.getY(), unknown.getWidth(), unknown.getHeight());
-		Color c = graphics.getColor();
-		graphics.setColor(unknown.getColor());
-		graphics.fill(shape);
-		graphics.setColor(c);
-		drawText(unknown, graphics, params);
-	}
-
-	@Override
-	public PathIterator getBoundPathIterator(Unknown unknown) {
-		throw new InvalidStateException("This class doesn't provide boundPath");
-	}
-
-	@Override
-	public Point2D getPointCoordinatesOnBorder(Unknown unknown, final double angle) {
-		if (unknown.getWidth() == 0 && unknown.getHeight() == 0) {
-			logger.warn("Looking for coordinates for unknown of 0 size");
-			return unknown.getCenter();
-		}
-		Point2D result;
-		result = getEllipseTransformation().getPointOnEllipseByRadian(unknown.getX(), unknown.getY(), unknown.getWidth(), unknown.getHeight(), angle);
-		return result;
-	}
-}
+package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.common.exception.InvalidStateException;
+import lcsb.mapviewer.converter.graphics.ConverterParams;
+import lcsb.mapviewer.model.graphics.LineType;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.Unknown;
+
+/**
+ * This class defines methods used for drawing {@link Unknown} on the
+ * {@link Graphics2D} object.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public class UnknownConverter extends SpeciesConverter<Unknown> {
+
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(UnknownConverter.class.getName());
+
+  /**
+   * Default constructor.
+   * 
+   * @param colorExtractor
+   *          Object that helps to convert {@link ColorSchema} values into colors
+   *          when drawing {@link Species}
+   */
+  public UnknownConverter(ColorExtractor colorExtractor) {
+    super(colorExtractor);
+  }
+
+  @Override
+  public void draw(Unknown unknown, final Graphics2D graphics, final ConverterParams params) {
+    if (unknown.getActivity()) {
+      int border = ACTIVITY_BORDER_DISTANCE;
+      unknown.increaseBorder(border);
+      Shape shape2 = new Ellipse2D.Double(unknown.getX(), unknown.getY(), unknown.getWidth(), unknown.getHeight());
+      Stroke stroke = graphics.getStroke();
+      graphics.setStroke(LineType.DOTTED.getStroke());
+      graphics.draw(shape2);
+      graphics.setStroke(stroke);
+      unknown.increaseBorder(-border);
+    }
+
+    Shape shape = new Ellipse2D.Double(unknown.getX(), unknown.getY(), unknown.getWidth(), unknown.getHeight());
+    Color c = graphics.getColor();
+    graphics.setColor(unknown.getColor());
+    graphics.fill(shape);
+    graphics.setColor(c);
+    drawText(unknown, graphics, params);
+  }
+
+  @Override
+  public PathIterator getBoundPathIterator(Unknown unknown) {
+    throw new InvalidStateException("This class doesn't provide boundPath");
+  }
+
+}
diff --git a/converter-graphics/src/test/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverterTest.java b/converter-graphics/src/test/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverterTest.java
index 3b8f0499b32142579e6ae3bd38d58823a2b4bea4..4f67a317af0d6b5d8d8a9f5cba8062e9bd0ce1f1 100644
--- a/converter-graphics/src/test/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverterTest.java
+++ b/converter-graphics/src/test/java/lcsb/mapviewer/converter/graphics/bioEntity/element/species/SpeciesConverterTest.java
@@ -1,188 +1,333 @@
-package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.image.BufferedImage;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.converter.graphics.ConverterParams;
-import lcsb.mapviewer.converter.graphics.bioEntity.element.species.ProteinConverter;
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-import lcsb.mapviewer.model.map.layout.GenericColorSchema;
-import lcsb.mapviewer.model.map.species.GenericProtein;
-
-public class SpeciesConverterTest {
-
-	ColorExtractor colorExtractor = new ColorExtractor(Color.RED, Color.GREEN, Color.BLUE);
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testGetResidueCoords() throws Exception {
-		try {
-			GenericProtein alias = new GenericProtein("id");
-			alias.setX(135);
-			alias.setY(194.0);
-			alias.setWidth(130);
-			alias.setHeight(67);
-			ProteinConverter conv = new ProteinConverter(null);
-			assertEquals(135.0, conv.getResidueCoordinates(alias, 3.141592653589793).getX(), 2);
-			assertEquals(265., conv.getResidueCoordinates(alias, 0.0).getX(), 2);
-			assertEquals(135.0, conv.getResidueCoordinates(alias, 2.41).getX(), 2);
-			assertEquals(194.0, conv.getResidueCoordinates(alias, 1.98).getY(), 2);
-			assertEquals(194.0, conv.getResidueCoordinates(alias, 1.59).getY(), 2);
-			assertEquals(265.0, conv.getResidueCoordinates(alias, 6.28).getX(), 2);
-			assertEquals(261.0, conv.getResidueCoordinates(alias, 4.13).getY(), 2);
-			assertEquals(261.0, conv.getResidueCoordinates(alias, 4.86).getY(), 2);
-			assertEquals(265.0, conv.getResidueCoordinates(alias, 5.69).getX(), 2);
-			assertEquals(194.0, conv.getResidueCoordinates(alias, 0.99).getY(), 2);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testDrawAliasWithLayouts() throws Exception {
-		try {
-			BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
-			Graphics2D graphics = bi.createGraphics();
-			ProteinConverter rc = new ProteinConverter(colorExtractor);
-
-			GenericProtein alias = createAlias();
-			rc.draw(alias, graphics, new ConverterParams());
-
-			int val = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
-
-			GenericProtein alias2 = createAlias();
-
-			bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
-			graphics = bi.createGraphics();
-
-			ColorSchema schema = new GenericColorSchema();
-			schema.setColor(Color.RED);
-			List<ColorSchema> schemas = new ArrayList<>();
-			schemas.add(schema);
-
-			rc.draw(alias2, graphics, new ConverterParams(), schemas);
-
-			int val2 = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
-
-			assertTrue(val != val2);
-
-		} catch (Exception e) {
-			throw e;
-		}
-	}
-
-	@Test
-	public void testDrawAfterDrawingReactionWithLayouts() throws Exception {
-		try {
-			BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
-			Graphics2D graphics = bi.createGraphics();
-			ProteinConverter rc = new ProteinConverter(colorExtractor);
-
-			GenericProtein alias = createAlias();
-			rc.draw(alias, graphics, new ConverterParams());
-
-			int val = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
-
-			GenericProtein alias2 = createAlias();
-
-			bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
-			graphics = bi.createGraphics();
-
-			ColorSchema schema = new GenericColorSchema();
-			schema.setColor(Color.RED);
-			List<ColorSchema> schemas = new ArrayList<>();
-			schemas.add(schema);
-
-			rc.draw(alias2, graphics, new ConverterParams(), schemas);
-
-			int val2 = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
-
-			bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
-			graphics = bi.createGraphics();
-
-			rc.draw(alias2, graphics, new ConverterParams(), new ArrayList<>());
-
-			int val3 = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
-
-			assertTrue(val != val2);
-			assertEquals(val, val3);
-
-		} catch (Exception e) {
-			throw e;
-		}
-	}
-
-	@Test
-	public void testDrawReactionWithFewLayouts() throws Exception {
-		try {
-			BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
-			Graphics2D graphics = bi.createGraphics();
-			ProteinConverter rc = new ProteinConverter(colorExtractor);
-
-			GenericProtein alias = createAlias();
-			rc.draw(alias, graphics, new ConverterParams());
-
-			int val = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
-
-			GenericProtein alias2 = createAlias();
-
-			bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
-			graphics = bi.createGraphics();
-
-			ColorSchema schema = new GenericColorSchema();
-			schema.setColor(Color.RED);
-			List<ColorSchema> schemas = new ArrayList<>();
-			schemas.add(schema);
-			schemas.add(null);
-			schema = new GenericColorSchema();
-			schema.setColor(Color.BLUE);
-			schemas.add(schema);
-
-			rc.draw(alias2, graphics, new ConverterParams(), schemas);
-
-			int val2 = bi.getRGB((int) (alias.getX() + alias.getWidth() / 4), (int) alias.getCenterY());
-			int val3 = bi.getRGB((int) (alias.getCenterX()), (int) alias.getCenterY());
-			int val4 = bi.getRGB((int) (alias.getX() + 3 * alias.getWidth() / 4), (int) alias.getCenterY());
-
-			assertTrue(val != val2);
-			assertEquals(val, val3);
-			assertTrue(val != val4);
-
-		} catch (Exception e) {
-			throw e;
-		}
-	}
-
-	private GenericProtein createAlias() {
-		GenericProtein alias = new GenericProtein("id");
-		alias.setName("NAME_OF_THE_ELEMENT");
-		alias.setX(10);
-		alias.setY(20);
-		alias.setWidth(100);
-		alias.setHeight(80);
-		alias.setColor(Color.WHITE);
-
-		return alias;
-	}
-
-}
+package lcsb.mapviewer.converter.graphics.bioEntity.element.species;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.awt.Color;
+import java.awt.Desktop;
+import java.awt.Graphics2D;
+import java.awt.geom.Point2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.converter.graphics.ConverterParams;
+import lcsb.mapviewer.converter.graphics.MapGenerator;
+import lcsb.mapviewer.converter.graphics.PngImageGenerator;
+import lcsb.mapviewer.converter.graphics.AbstractImageGenerator.Params;
+import lcsb.mapviewer.converter.graphics.MapGenerator.MapGeneratorParams;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.layout.GenericColorSchema;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.field.BindingRegion;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.ProteinBindingDomain;
+import lcsb.mapviewer.model.map.species.field.RegulatoryRegion;
+import lcsb.mapviewer.model.map.species.field.Residue;
+import lcsb.mapviewer.model.map.species.field.TranscriptionSite;
+
+public class SpeciesConverterTest {
+  Logger logger = Logger.getLogger(SpeciesConverterTest.class);
+
+  ColorExtractor colorExtractor = new ColorExtractor(Color.RED, Color.GREEN, Color.BLUE);
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testDrawAliasWithLayouts() throws Exception {
+    try {
+      BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      Graphics2D graphics = bi.createGraphics();
+      ProteinConverter rc = new ProteinConverter(colorExtractor);
+
+      GenericProtein alias = createProtein();
+      rc.draw(alias, graphics, new ConverterParams());
+
+      int val = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
+
+      GenericProtein alias2 = createProtein();
+
+      bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      graphics = bi.createGraphics();
+
+      ColorSchema schema = new GenericColorSchema();
+      schema.setColor(Color.RED);
+      List<ColorSchema> schemas = new ArrayList<>();
+      schemas.add(schema);
+
+      rc.draw(alias2, graphics, new ConverterParams(), schemas);
+
+      int val2 = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
+
+      assertTrue(val != val2);
+
+    } catch (Exception e) {
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDrawAfterDrawingReactionWithLayouts() throws Exception {
+    try {
+      BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      Graphics2D graphics = bi.createGraphics();
+      ProteinConverter rc = new ProteinConverter(colorExtractor);
+
+      GenericProtein alias = createProtein();
+      rc.draw(alias, graphics, new ConverterParams());
+
+      int val = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
+
+      GenericProtein alias2 = createProtein();
+
+      bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      graphics = bi.createGraphics();
+
+      ColorSchema schema = new GenericColorSchema();
+      schema.setColor(Color.RED);
+      List<ColorSchema> schemas = new ArrayList<>();
+      schemas.add(schema);
+
+      rc.draw(alias2, graphics, new ConverterParams(), schemas);
+
+      int val2 = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
+
+      bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      graphics = bi.createGraphics();
+
+      rc.draw(alias2, graphics, new ConverterParams(), new ArrayList<>());
+
+      int val3 = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
+
+      assertTrue(val != val2);
+      assertEquals(val, val3);
+
+    } catch (Exception e) {
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDrawReactionWithFewLayouts() throws Exception {
+    try {
+      BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      Graphics2D graphics = bi.createGraphics();
+      ProteinConverter rc = new ProteinConverter(colorExtractor);
+
+      GenericProtein alias = createProtein();
+      rc.draw(alias, graphics, new ConverterParams());
+
+      int val = bi.getRGB((int) alias.getCenterX(), (int) alias.getCenterY());
+
+      GenericProtein alias2 = createProtein();
+
+      bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      graphics = bi.createGraphics();
+
+      ColorSchema schema = new GenericColorSchema();
+      schema.setColor(Color.RED);
+      List<ColorSchema> schemas = new ArrayList<>();
+      schemas.add(schema);
+      schemas.add(null);
+      schema = new GenericColorSchema();
+      schema.setColor(Color.BLUE);
+      schemas.add(schema);
+
+      rc.draw(alias2, graphics, new ConverterParams(), schemas);
+
+      int val2 = bi.getRGB((int) (alias.getX() + alias.getWidth() / 4), (int) alias.getCenterY());
+      int val3 = bi.getRGB((int) (alias.getCenterX()), (int) alias.getCenterY());
+      int val4 = bi.getRGB((int) (alias.getX() + 3 * alias.getWidth() / 4), (int) alias.getCenterY());
+
+      assertTrue(val != val2);
+      assertEquals(val, val3);
+      assertTrue(val != val4);
+
+    } catch (Exception e) {
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDrawResidue() throws Exception {
+    try {
+      BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      Graphics2D graphics = bi.createGraphics();
+
+      ModificationResidue residue = new Residue();
+      residue.setPosition(new Point2D.Double(10,10));
+      
+      ProteinConverter converter = Mockito.spy(new ProteinConverter(colorExtractor));
+      converter.drawModification(residue, graphics, false);
+      verify(converter, times(1)).drawResidue(any(), any(), anyBoolean());
+      
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDrawBindingRegion() throws Exception {
+    try {
+      BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      Graphics2D graphics = bi.createGraphics();
+
+      Protein protein = createProtein();
+      BindingRegion bindingRegion = new BindingRegion();
+      bindingRegion.setPosition(new Point2D.Double(10,10));
+      bindingRegion.setWidth(100.0);
+      bindingRegion.setHeight(10.0);
+      protein.addModificationResidue(bindingRegion);
+      
+      ProteinConverter converter = Mockito.spy(new ProteinConverter(colorExtractor));
+      converter.drawModification(bindingRegion, graphics, false);
+      verify(converter, times(1)).drawBindingRegion(any(), any());
+      
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDrawModificationSite() throws Exception {
+    try {
+      BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      Graphics2D graphics = bi.createGraphics();
+
+      ModificationSite modificationSite = new ModificationSite();
+      modificationSite.setPosition(new Point2D.Double(10,10));
+      
+      ProteinConverter converter = Mockito.spy(new ProteinConverter(colorExtractor));
+      converter.drawModification(modificationSite, graphics, false);
+      verify(converter, times(1)).drawModificationSite(any(), any(), anyBoolean());
+      
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDrawProteinBindingRegion() throws Exception {
+    try {
+      BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      Graphics2D graphics = bi.createGraphics();
+
+      ProteinBindingDomain proteinBindingRegion = new ProteinBindingDomain();
+      proteinBindingRegion.setPosition(new Point2D.Double(10,10));
+      proteinBindingRegion.setWidth(100);
+      proteinBindingRegion.setHeight(20);
+      
+      ProteinConverter converter = Mockito.spy(new ProteinConverter(colorExtractor));
+      converter.drawModification(proteinBindingRegion, graphics, false);
+      verify(converter, times(1)).drawProteinBindingDomain(any(), any());
+      
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDrawCodingRegion() throws Exception {
+    try {
+      BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      Graphics2D graphics = bi.createGraphics();
+
+      CodingRegion codingRegion = new CodingRegion();
+      codingRegion.setPosition(new Point2D.Double(10,10));
+      codingRegion.setWidth(100);
+      codingRegion.setHeight(20);
+      
+      ProteinConverter converter = Mockito.spy(new ProteinConverter(colorExtractor));
+      converter.drawModification(codingRegion, graphics, false);
+      verify(converter, times(1)).drawCodingRegion(any(), any());
+      
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDrawRegulatoryRegion() throws Exception {
+    try {
+      BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      Graphics2D graphics = bi.createGraphics();
+
+      RegulatoryRegion regulatoryRegion = new RegulatoryRegion();
+      regulatoryRegion.setPosition(new Point2D.Double(10,10));
+      regulatoryRegion.setWidth(100);
+      regulatoryRegion.setHeight(20);
+      
+      ProteinConverter converter = Mockito.spy(new ProteinConverter(colorExtractor));
+      converter.drawModification(regulatoryRegion, graphics, false);
+      verify(converter, times(1)).drawRegulatoryRegion(any(), any());
+      
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDrawTranscriptionSite() throws Exception {
+    try {
+      BufferedImage bi = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
+      Graphics2D graphics = bi.createGraphics();
+
+      TranscriptionSite transcriptionSite = new TranscriptionSite();
+      transcriptionSite.setPosition(new Point2D.Double(10,10));
+      transcriptionSite.setWidth(100);
+      transcriptionSite.setHeight(20);
+      transcriptionSite.setActive(true);
+      transcriptionSite.setDirection("LEFT");
+      
+      ProteinConverter converter = Mockito.spy(new ProteinConverter(colorExtractor));
+      converter.drawModification(transcriptionSite, graphics, false);
+      verify(converter, times(1)).drawTranscriptionSite(any(), any());
+      
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private GenericProtein createProtein() {
+    GenericProtein protein = new GenericProtein("id");
+    protein.setName("NAME_OF_THE_ELEMENT");
+    protein.setX(10);
+    protein.setY(20);
+    protein.setWidth(100);
+    protein.setHeight(80);
+    protein.setColor(Color.WHITE);
+
+    return protein;
+  }
+}
diff --git a/frontend-js/package-lock.json b/frontend-js/package-lock.json
index 04da0d18baf99baf8600ce5a7c047f3f3d088759..01cbb59d840e3cdcdf0b2eb1a9390d077da6aabe 100644
--- a/frontend-js/package-lock.json
+++ b/frontend-js/package-lock.json
@@ -336,9 +336,9 @@
       "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
     },
     "base62": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/base62/-/base62-1.2.0.tgz",
-      "integrity": "sha1-MeflYNyEbJ9EwaUx32UU2jVHQVc="
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/base62/-/base62-1.2.8.tgz",
+      "integrity": "sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA=="
     },
     "base64-arraybuffer": {
       "version": "0.1.5",
@@ -942,9 +942,9 @@
         "detective": "4.5.0",
         "glob": "5.0.15",
         "graceful-fs": "4.1.11",
-        "iconv-lite": "0.4.18",
+        "iconv-lite": "0.4.23",
         "mkdirp": "0.5.1",
-        "private": "0.1.7",
+        "private": "0.1.8",
         "q": "1.5.0",
         "recast": "0.11.23"
       },
@@ -1576,9 +1576,9 @@
       }
     },
     "es6-promise": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.1.tgz",
-      "integrity": "sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng=="
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz",
+      "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ=="
     },
     "escape-html": {
       "version": "1.0.3",
@@ -1742,7 +1742,7 @@
         "core-js": "1.2.7",
         "loose-envify": "1.3.1",
         "promise": "7.3.1",
-        "ua-parser-js": "0.7.14",
+        "ua-parser-js": "0.7.18",
         "whatwg-fetch": "0.9.0"
       }
     },
@@ -2308,9 +2308,12 @@
       "dev": true
     },
     "iconv-lite": {
-      "version": "0.4.18",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
-      "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA=="
+      "version": "0.4.23",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
+      "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
+      "requires": {
+        "safer-buffer": "2.1.2"
+      }
     },
     "ieee754": {
       "version": "1.1.8",
@@ -2560,7 +2563,7 @@
       "resolved": "https://registry.npmjs.org/jbinary/-/jbinary-2.1.3.tgz",
       "integrity": "sha1-JDLiOYmZPpcKE8uw7eQcp/xMkZk=",
       "requires": {
-        "es6-promise": "4.1.1",
+        "es6-promise": "4.2.4",
         "jdataview": "2.5.0",
         "request": "2.82.0"
       }
@@ -2860,7 +2863,7 @@
       "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz",
       "integrity": "sha1-CaeJk+CuTU70SH9hVakfYZDLQiM=",
       "requires": {
-        "base62": "1.2.0",
+        "base62": "1.2.8",
         "commoner": "0.10.8",
         "esprima-fb": "15001.1.0-dev-harmony-fb",
         "object-assign": "2.1.1",
@@ -3709,9 +3712,9 @@
       "dev": true
     },
     "pileup": {
-      "version": "0.6.8",
-      "resolved": "https://registry.npmjs.org/pileup/-/pileup-0.6.8.tgz",
-      "integrity": "sha1-LYhmfpRLC4I9A3tTSto1lnHBh04=",
+      "version": "0.6.9",
+      "resolved": "https://registry.npmjs.org/pileup/-/pileup-0.6.9.tgz",
+      "integrity": "sha1-y/xM24/tNzOOX0k6gJQfkE/bGko=",
       "requires": {
         "backbone": "1.1.2",
         "d3": "3.5.17",
@@ -3765,9 +3768,9 @@
       "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks="
     },
     "private": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz",
-      "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE="
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+      "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
     },
     "process": {
       "version": "0.11.10",
@@ -3970,7 +3973,7 @@
       "requires": {
         "ast-types": "0.9.6",
         "esprima": "3.1.3",
-        "private": "0.1.7",
+        "private": "0.1.8",
         "source-map": "0.5.7"
       },
       "dependencies": {
@@ -4204,6 +4207,11 @@
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
       "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
     },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
     "sax": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
@@ -4889,9 +4897,9 @@
       "dev": true
     },
     "ua-parser-js": {
-      "version": "0.7.14",
-      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.14.tgz",
-      "integrity": "sha1-EQ1T+kw/MmwSEpK76skE0uAzh8o="
+      "version": "0.7.18",
+      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz",
+      "integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA=="
     },
     "uglify-js": {
       "version": "2.8.29",
diff --git a/frontend-js/package.json b/frontend-js/package.json
index fcd4f0d0d2735dc543b139ec23b5e5d5723696a0..e7b7690cf6bef4f7510e9f923e9a56e95b9cd01d 100644
--- a/frontend-js/package.json
+++ b/frontend-js/package.json
@@ -50,7 +50,7 @@
     "log4js": "0.6.38",
     "multi-checkbox-list": "^0.2.0",
     "openlayers": "^4.6.5",
-    "pileup": "^0.6.8",
+    "pileup": "^0.6.9",
     "request": "^2.82.0",
     "spectrum-colorpicker": "^1.8.0",
     "text-encoding": "^0.6.4",
diff --git a/frontend-js/src/main/css/global.css b/frontend-js/src/main/css/global.css
index 76b792e6ce97a518f4fad838bcd6dec930e59c4a..c72de9f83c7cbc4dc258674be5bef70f29f49d7c 100644
--- a/frontend-js/src/main/css/global.css
+++ b/frontend-js/src/main/css/global.css
@@ -42,25 +42,25 @@
     clear: both;
 }
 
-.mapChartNameDiv {
+.minerva-chart-name {
     width: 150px;
     float: left;
     display: inline-block;
 }
 
-.mapChartRowEvenDiv {
+.minerva-chart-row-even, .minerva-chart-row-odd {
+    position: relative;
     white-space: nowrap;
     overflow: hidden;
     margin: 1px;
     width: 360px;
+}
+
+.minerva-chart-row-even {
     background-color: #D3D3D3;
 }
 
-.mapChartRowOddDiv {
-    white-space: nowrap;
-    overflow: hidden;
-    margin: 1px;
-    width: 360px;
+.minerva-chart-row-odd {
     background-color: #C0C0C0;
 }
 
@@ -503,14 +503,15 @@ h1 {
     font-weight: 400;
 }
 
-.minerva-projects-tab, .minerva-users-tab, .minerva-configuration-tab {
+.minerva-projects-tab, .minerva-users-tab, .minerva-configuration-tab, .minerva-genome-tab {
     margin-left: 10px;
     margin-top: 10px;
 }
 
 .minerva-projects-tab .minerva-menu-row button,
 .minerva-edit-project-dialog .minerva-menu-row button,
-.minerva-users-tab .minerva-menu-row button {
+.minerva-users-tab .minerva-menu-row button,
+.minerva-genome-tab .minerva-menu-row button {
     margin: 5px;
 }
 
@@ -748,7 +749,7 @@ a.adminLink:hover {
 }
 
 .popover {
-    max-width: 600px;
+    max-width: 800px;
     min-width: 390px;
 }
 
diff --git a/frontend-js/src/main/js/Admin.js b/frontend-js/src/main/js/Admin.js
index 8d779cee92e6d3de479481d76aee4f4d5d7ae3c7..db99eea31a4051d60d1d9642413373c01763bafd 100644
--- a/frontend-js/src/main/js/Admin.js
+++ b/frontend-js/src/main/js/Admin.js
@@ -9,6 +9,7 @@ var GuiUtils = require('./gui/leftPanel/GuiUtils');
 var ObjectWithListeners = require('./ObjectWithListeners');
 
 var ConfigurationAdminPanel = require('./gui/admin/ConfigurationAdminPanel');
+var GenomeAdminPanel = require('./gui/admin/GenomeAdminPanel');
 var MapsAdminPanel = require('./gui/admin/MapsAdminPanel');
 var UsersAdminPanel = require('./gui/admin/UsersAdminPanel');
 
@@ -19,9 +20,8 @@ var Functions = require('./Functions');
 /**
  * Default constructor.
  *
- * @param options
- *          CustomMapOptions object representing all parameters needed for map
- *          creation
+ * @param {CustomMapOptions} options
+ *           object representing all parameters needed for map creation
  */
 function Admin(options) {
   var self = this;
@@ -55,6 +55,9 @@ Admin.prototype._createGui = function () {
   }, {
     name: "CONFIGURATION",
     panelClass: ConfigurationAdminPanel
+  }, {
+    name: "GENOMES",
+    panelClass: GenomeAdminPanel
   }];
 
   var tabDiv = Functions.createElement({
diff --git a/frontend-js/src/main/js/Configuration.js b/frontend-js/src/main/js/Configuration.js
index 8254c7ae0b3d8934091205cd54967228bb26af87..beadc52c9e654e11957de7f8934dbacf0f27fa0c 100644
--- a/frontend-js/src/main/js/Configuration.js
+++ b/frontend-js/src/main/js/Configuration.js
@@ -120,9 +120,18 @@ Configuration.prototype.getOptions = function () {
   return result;
 };
 
+/**
+ *
+ * @param {string[]} overlayTypes
+ */
 Configuration.prototype.setOverlayTypes = function (overlayTypes) {
   this._overlayTypes = overlayTypes;
 };
+
+/**
+ *
+ * @returns {string[]}
+ */
 Configuration.prototype.getOverlayTypes = function () {
   return this._overlayTypes;
 };
diff --git a/frontend-js/src/main/js/Functions.js b/frontend-js/src/main/js/Functions.js
index 8463ed20aca1303186807c1b202ca9261d24b01d..b233ee58d6325cbc9a2ed659ee42cc9409f0a316 100644
--- a/frontend-js/src/main/js/Functions.js
+++ b/frontend-js/src/main/js/Functions.js
@@ -1,620 +1,675 @@
-"use strict";
-
-var Promise = require("bluebird");
-var Point = require('./map/canvas/Point');
-
-/* exported logger */
-
-var logger = require('./logger');
-
-var xss = require('xss');
-
-var Functions = {};
-
-/**
- * Bounds value between opt_min and opt_max (result will be not smaller than
- * opt_min and not bigger than opt_max).
- */
-Functions.bound = function (value, minVal, maxVal) {
-  if (minVal !== null && minVal !== undefined) {
-    value = Math.max(value, minVal);
-  }
-  if (maxVal !== null && maxVal !== undefined) {
-    value = Math.min(value, maxVal);
-  }
-  return value;
-};
-
-Functions.degreesToRadians = function (deg) {
-  return deg * (Math.PI / 180);
-};
-
-Functions.radiansToDegrees = function (rad) {
-  return rad / (Math.PI / 180);
-};
-
-Functions.intToColorString = function (value) {
-  /* jslint bitwise: true */
-  var trimmedValue = (value & 0xFFFFFF);
-  var colorStr = trimmedValue.toString(16);
-  while (colorStr.length < 6) {
-    colorStr = "0" + colorStr;
-  }
-  return '#' + colorStr;
-};
-
-
-/**
- *
- * @param {string} color
- * @param {number} opacity
- * @returns {string}
- */
-Functions.colorToRgbaString = function (color, opacity) {
-  if (color[0] !== '#' || color.length !== 7) {
-    throw new Error("Expected color in #RRGGBB format");
-  }
-  var red = parseInt(color.substr(1, 2), 16);
-  var green = parseInt(color.substr(3, 2), 16);
-  var blue = parseInt(color.substr(5, 2), 16);
-  var alpha = opacity !== undefined ? opacity : 1.0;
-  return "rgba(" + red + "," + green + "," + blue + "," + alpha + ")";
-};
-
-/**
- * Returns stack trace.
- *
- * @returns {string} stack trace
- */
-Functions.stackTrace = function () {
-  var err = new Error();
-  return err.stack;
-};
-
-/**
- * Returns the position of the element on html page.
- *
- * @param element
- *          element for which we want to get the position (top left corner)
- *
- * @return {Point} coordinates of the element
- *
- */
-Functions.getPosition = function (element) {
-  var xPosition = 0;
-  var yPosition = 0;
-
-  while (element) {
-    xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
-    yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
-    element = element.offsetParent;
-  }
-  return new Point(xPosition, yPosition);
-};
-
-/**
- * Checks if the point given as a first argument belongs to a polygon defined as
- * a second parameter. Both: point and polygon should use google.map.point
- * class.
- *
- * @param {Point} point
- *          point which we want to check
- *
- * @param {Point[]} polygon
- *          polygon where we check the point
- */
-
-Functions.pointInsidePolygon = function (point, polygon) {
-  var x = point.x;
-  var y = point.y;
-
-  var inside = false;
-  for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
-    var xi = polygon[i].x, yi = polygon[i].y;
-    var xj = polygon[j].x, yj = polygon[j].y;
-    var intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
-    if (intersect) {
-      inside = !inside;
-    }
-  }
-  return inside;
-};
-
-/**
- * In a browser variable we store information about browser user is currently
- * using. Right now only IE is supported.
- */
-Functions.browser = {
-  init: function () {
-
-    this.name = "Unknown";
-    this.version = "Unknown";
-
-    if (typeof navigator !== 'undefined') {
-      // Get the user agent string
-      var ua = navigator.userAgent;
-      this.compatibilityMode = false;
-      var re;
-      if (navigator.appName === 'Microsoft Internet Explorer') {
-        this.name = "IE";
-        re = new RegExp("MSIE ([0-9]+[\.0-9]*)");
-        if (re.exec(ua) !== undefined && re.exec(ua) !== null) {
-          this.version = parseFloat(RegExp.$1);
-        }
-        if (ua.indexOf("MSIE 7.0") > -1) {
-          this.compatibilityMode = true;
-        }
-      } else if (navigator.appName === 'Netscape') {
-        this.name = "Other";
-        ua = navigator.userAgent;
-        re = new RegExp("Trident/.*rv[ :]*([0-9]{1,}[\.0-9]{0,})");
-        if (re.exec(ua) !== undefined && re.exec(ua) !== null) {
-          this.version = parseFloat(RegExp.$1);
-        }
-      }
-    }
-  }
-};
-
-Functions.browser.init();
-
-/**
- * Returns true if parameter is integer, false otherwise.
- *
- * @param n
- *          object to check
- */
-Functions.isInt = function (n) {
-  return Number(n) === n && n % 1 === 0;
-};
-
-/**
- * Returns true if parameter is a DOM element, false otherwise.
- *
- * @param o
- *          object to check
- */
-Functions.isDomElement = function (o) {
-  if (!o) {
-    return false;
-  }
-  return (typeof HTMLElement === "object" ? o instanceof HTMLElement : // DOM2
-    o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string");
-};
-
-/**
- *
- * @returns {Promise<string>}
- */
-Functions.overlayToColor = function (elementOverlay) {
-  var self = this;
-  /* jslint bitwise: true */
-  if (elementOverlay === null || elementOverlay === undefined) {
-    return Promise.reject("elementOverlay cannot be null!");
-  } else if (elementOverlay.color !== undefined && elementOverlay.color !== null) {
-    return Promise.resolve(self.intToColorString(elementOverlay.color.rgb));
-  } else {
-    var ratio = 0;
-    var promiseColors;
-    if (elementOverlay.value !== undefined && elementOverlay.value !== null) {
-      if (elementOverlay.value < 0) {
-        ratio = -elementOverlay.value;
-        promiseColors = [ServerConnector.getMinOverlayColorInt(), ServerConnector.getNeutralOverlayColorInt()];
-      } else {
-        ratio = elementOverlay.value;
-        promiseColors = [ServerConnector.getMaxOverlayColorInt(), ServerConnector.getNeutralOverlayColorInt()];
-      }
-    } else {
-      ratio = 1;
-      promiseColors = [ServerConnector.getSimpleOverlayColorInt(), ServerConnector.getNeutralOverlayColorInt()];
-    }
-
-    return Promise.all(promiseColors).then(function (colors) {
-      var maxColor = colors[0];
-      var neutralColor = colors[1];
-
-      ratio = 1 - ratio;
-      var MAX_RED = 0xFF0000;
-      var MAX_GREEN = 0x00FF00;
-      var MAX_BLUE = 0x0000FF;
-
-      var red = maxColor & MAX_RED;
-      var neutralRed = neutralColor & MAX_RED;
-
-      red = red + (neutralRed - red) * ratio;
-      red = parseInt(red);
-      red = red & MAX_RED;
-
-      var green = maxColor & MAX_GREEN;
-      var neutralGreen = neutralColor & MAX_GREEN;
-      green = green + (neutralGreen - green) * ratio;
-      green = parseInt(green);
-      green = green & MAX_GREEN;
-
-      var blue = maxColor & MAX_BLUE;
-      var neutralBlue = neutralColor & MAX_BLUE;
-      blue = blue + (neutralBlue - blue) * ratio;
-      blue = parseInt(blue);
-      blue = blue & MAX_BLUE;
-
-      var color = red | green | blue;
-      return self.intToColorString(color);
-    });
-  }
-};
-
-Functions.getElementByName = function (element, name) {
-  if (element !== undefined) {
-    if (element.getAttribute("name") === name) {
-      return element;
-    }
-    var children = element.children;
-    for (var i = 0; i < children.length; i++) {
-      var child = children[i];
-      var res = this.getElementByName(child, name);
-      if (res !== undefined) {
-        return res;
-      }
-    }
-  }
-  return undefined;
-};
-
-
-/**
- *
- * @param {HTMLElement}element
- * @param {string} name class name
- * @returns {HTMLElement|undefined}
- */
-Functions.getElementByClassName = function (element, name) {
-  if (name.indexOf(".") !== 0) {
-    name = "." + name;
-  }
-  return $(name, element)[0];
-};
-
-/**
- *
- * @param {Object} params
- * @param {string} params.type type of the {HTMLElement} to be created
- * @param {string} [params.inputType] type of the input to be created
- * @param {string} [params.className] css class of the element
- * @param {string} [params.style] css styling
- * @param {string} [params.value]
- * @param {string|HTMLElement} [params.content]
- *
- * @returns {HTMLElement}
- */
-Functions.createElement = function (params) {
-  var result = document.createElement(params.type);
-  if (params.id !== null && params.id !== undefined) {
-    result.id = params.id;
-  }
-  if (params.name !== null && params.name !== undefined) {
-    result.setAttribute("name", params.name);
-  }
-  if (params.className !== null && params.className !== undefined) {
-    result.className = params.className;
-  }
-  if (params.inputType !== null && params.inputType !== undefined) {
-    result.type = params.inputType;
-  }
-  if (params.content !== null && params.content !== undefined) {
-    if (Functions.isDomElement(params.content)) {
-      result.appendChild(params.content);
-    } else if (params.xss !== false) {
-      var content = xss(params.content);
-      if (content !== params.content) {
-        logger.warn("XSS changed content: " + params.content);
-      }
-      result.innerHTML = content;
-    } else {
-      result.innerHTML = params.content;
-    }
-  }
-  if (params.style !== null && params.style !== undefined) {
-    result.style.cssText = params.style;
-  }
-  if (params.onclick !== null && params.onclick !== undefined) {
-    result.onclick = params.onclick;
-  }
-  if (params.onchange !== null && params.onchange !== undefined) {
-    result.onchange = params.onchange;
-  }
-  if (params.href !== null && params.href !== undefined) {
-    result.href = params.href;
-  }
-  if (params.src !== null && params.src !== undefined) {
-    result.src = params.src;
-  }
-  if (params.value !== null && params.value !== undefined) {
-    result.value = params.value;
-  }
-  if (params.title !== null && params.title !== undefined) {
-    result.title = params.title;
-  }
-  if (params.index !== null && params.index !== undefined) {
-    result.index = params.index;
-  }
-  if (params.data !== null && params.data !== undefined) {
-    $(result).attr("data", params.data);
-  }
-  return result;
-};
-
-function sqr(x) {
-  return x * x;
-}
-
-function dist2(v, w) {
-  return sqr(v.x - w.x) + sqr(v.y - w.y);
-}
-
-function distToSegmentSquared(p, v, w) {
-  var l2 = dist2(v, w);
-
-  if (l2 === 0) {
-    return dist2(p, v);
-  }
-
-  var t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
-
-  if (t < 0) {
-    return dist2(p, v);
-  }
-  if (t > 1) {
-    return dist2(p, w);
-  }
-
-  return dist2(p, new Point(v.x + t * (w.x - v.x), v.y + t * (w.y - v.y)));
-}
-
-Functions.distance = function (p1, el2) {
-  if (el2 instanceof Point) {
-    var p2 = el2;
-    return Math.sqrt((Math.pow(p1.x - p2.x, 2)) + (Math.pow(p1.y - p2.y, 2)));
-  } else {
-    return Math.sqrt(distToSegmentSquared(p1, el2.start, el2.end));
-  }
-};
-
-Functions.removeChildren = function (element) {
-  while (element.firstChild) {
-    element.removeChild(element.firstChild);
-  }
-};
-
-/**
- *
- * @returns {Promise} resolved after javascript is loaded
- */
-Functions.loadScript = function (url) {
-  return new Promise(function (resolve) {
-    var scriptExists = false;
-    var scripts = document.getElementsByTagName('script');
-    for (var i = scripts.length; i--;) {
-      if (scripts[i].src === url)
-        scriptExists = true;
-    }
-    if (!scriptExists) {
-      var head = document.getElementsByTagName('head')[0];
-      var script = document.createElement('script');
-      script.type = 'text/javascript';
-      script.src = url;
-      script.onload = function () {
-        resolve();
-      };
-      head.appendChild(script);
-    } else {
-      resolve();
-    }
-  });
-};
-
-Functions.computeMD5 = function (s) {
-  function L(k, d) {
-    return (k << d) | (k >>> (32 - d))
-  }
-
-  function K(G, k) {
-    var I, d, F, H, x;
-    F = (G & 2147483648);
-    H = (k & 2147483648);
-    I = (G & 1073741824);
-    d = (k & 1073741824);
-    x = (G & 1073741823) + (k & 1073741823);
-    if (I & d) {
-      return (x ^ 2147483648 ^ F ^ H)
-    }
-    if (I | d) {
-      if (x & 1073741824) {
-        return (x ^ 3221225472 ^ F ^ H)
-      } else {
-        return (x ^ 1073741824 ^ F ^ H)
-      }
-    } else {
-      return (x ^ F ^ H)
-    }
-  }
-
-  function r(d, F, k) {
-    return (d & F) | ((~d) & k)
-  }
-
-  function q(d, F, k) {
-    return (d & k) | (F & (~k))
-  }
-
-  function p(d, F, k) {
-    return (d ^ F ^ k)
-  }
-
-  function n(d, F, k) {
-    return (F ^ (d | (~k)))
-  }
-
-  function u(G, F, aa, Z, k, H, I) {
-    G = K(G, K(K(r(F, aa, Z), k), I));
-    return K(L(G, H), F)
-  }
-
-  function f(G, F, aa, Z, k, H, I) {
-    G = K(G, K(K(q(F, aa, Z), k), I));
-    return K(L(G, H), F)
-  }
-
-  function D(G, F, aa, Z, k, H, I) {
-    G = K(G, K(K(p(F, aa, Z), k), I));
-    return K(L(G, H), F)
-  }
-
-  function t(G, F, aa, Z, k, H, I) {
-    G = K(G, K(K(n(F, aa, Z), k), I));
-    return K(L(G, H), F)
-  }
-
-  function e(G) {
-    var Z;
-    var F = G.length;
-    var x = F + 8;
-    var k = (x - (x % 64)) / 64;
-    var I = (k + 1) * 16;
-    var aa = Array(I - 1);
-    var d = 0;
-    var H = 0;
-    while (H < F) {
-      Z = (H - (H % 4)) / 4;
-      d = (H % 4) * 8;
-      aa[Z] = (aa[Z] | (G.charCodeAt(H) << d));
-      H++
-    }
-    Z = (H - (H % 4)) / 4;
-    d = (H % 4) * 8;
-    aa[Z] = aa[Z] | (128 << d);
-    aa[I - 2] = F << 3;
-    aa[I - 1] = F >>> 29;
-    return aa
-  }
-
-  function B(x) {
-    var k = "", F = "", G, d;
-    for (d = 0; d <= 3; d++) {
-      G = (x >>> (d * 8)) & 255;
-      F = "0" + G.toString(16);
-      k = k + F.substr(F.length - 2, 2)
-    }
-    return k
-  }
-
-  function J(k) {
-    k = k.replace(/rn/g, "n");
-    var d = "";
-    for (var F = 0; F < k.length; F++) {
-      var x = k.charCodeAt(F);
-      if (x < 128) {
-        d += String.fromCharCode(x)
-      } else {
-        if ((x > 127) && (x < 2048)) {
-          d += String.fromCharCode((x >> 6) | 192);
-          d += String.fromCharCode((x & 63) | 128)
-        } else {
-          d += String.fromCharCode((x >> 12) | 224);
-          d += String.fromCharCode(((x >> 6) & 63) | 128);
-          d += String.fromCharCode((x & 63) | 128)
-        }
-      }
-    }
-    return d
-  }
-
-  var C = Array();
-  var P, h, E, v, g, Y, X, W, V;
-  var S = 7, Q = 12, N = 17, M = 22;
-  var A = 5, z = 9, y = 14, w = 20;
-  var o = 4, m = 11, l = 16, j = 23;
-  var U = 6, T = 10, R = 15, O = 21;
-  s = J(s);
-  C = e(s);
-  Y = 1732584193;
-  X = 4023233417;
-  W = 2562383102;
-  V = 271733878;
-  for (P = 0; P < C.length; P += 16) {
-    h = Y;
-    E = X;
-    v = W;
-    g = V;
-    Y = u(Y, X, W, V, C[P + 0], S, 3614090360);
-    V = u(V, Y, X, W, C[P + 1], Q, 3905402710);
-    W = u(W, V, Y, X, C[P + 2], N, 606105819);
-    X = u(X, W, V, Y, C[P + 3], M, 3250441966);
-    Y = u(Y, X, W, V, C[P + 4], S, 4118548399);
-    V = u(V, Y, X, W, C[P + 5], Q, 1200080426);
-    W = u(W, V, Y, X, C[P + 6], N, 2821735955);
-    X = u(X, W, V, Y, C[P + 7], M, 4249261313);
-    Y = u(Y, X, W, V, C[P + 8], S, 1770035416);
-    V = u(V, Y, X, W, C[P + 9], Q, 2336552879);
-    W = u(W, V, Y, X, C[P + 10], N, 4294925233);
-    X = u(X, W, V, Y, C[P + 11], M, 2304563134);
-    Y = u(Y, X, W, V, C[P + 12], S, 1804603682);
-    V = u(V, Y, X, W, C[P + 13], Q, 4254626195);
-    W = u(W, V, Y, X, C[P + 14], N, 2792965006);
-    X = u(X, W, V, Y, C[P + 15], M, 1236535329);
-    Y = f(Y, X, W, V, C[P + 1], A, 4129170786);
-    V = f(V, Y, X, W, C[P + 6], z, 3225465664);
-    W = f(W, V, Y, X, C[P + 11], y, 643717713);
-    X = f(X, W, V, Y, C[P + 0], w, 3921069994);
-    Y = f(Y, X, W, V, C[P + 5], A, 3593408605);
-    V = f(V, Y, X, W, C[P + 10], z, 38016083);
-    W = f(W, V, Y, X, C[P + 15], y, 3634488961);
-    X = f(X, W, V, Y, C[P + 4], w, 3889429448);
-    Y = f(Y, X, W, V, C[P + 9], A, 568446438);
-    V = f(V, Y, X, W, C[P + 14], z, 3275163606);
-    W = f(W, V, Y, X, C[P + 3], y, 4107603335);
-    X = f(X, W, V, Y, C[P + 8], w, 1163531501);
-    Y = f(Y, X, W, V, C[P + 13], A, 2850285829);
-    V = f(V, Y, X, W, C[P + 2], z, 4243563512);
-    W = f(W, V, Y, X, C[P + 7], y, 1735328473);
-    X = f(X, W, V, Y, C[P + 12], w, 2368359562);
-    Y = D(Y, X, W, V, C[P + 5], o, 4294588738);
-    V = D(V, Y, X, W, C[P + 8], m, 2272392833);
-    W = D(W, V, Y, X, C[P + 11], l, 1839030562);
-    X = D(X, W, V, Y, C[P + 14], j, 4259657740);
-    Y = D(Y, X, W, V, C[P + 1], o, 2763975236);
-    V = D(V, Y, X, W, C[P + 4], m, 1272893353);
-    W = D(W, V, Y, X, C[P + 7], l, 4139469664);
-    X = D(X, W, V, Y, C[P + 10], j, 3200236656);
-    Y = D(Y, X, W, V, C[P + 13], o, 681279174);
-    V = D(V, Y, X, W, C[P + 0], m, 3936430074);
-    W = D(W, V, Y, X, C[P + 3], l, 3572445317);
-    X = D(X, W, V, Y, C[P + 6], j, 76029189);
-    Y = D(Y, X, W, V, C[P + 9], o, 3654602809);
-    V = D(V, Y, X, W, C[P + 12], m, 3873151461);
-    W = D(W, V, Y, X, C[P + 15], l, 530742520);
-    X = D(X, W, V, Y, C[P + 2], j, 3299628645);
-    Y = t(Y, X, W, V, C[P + 0], U, 4096336452);
-    V = t(V, Y, X, W, C[P + 7], T, 1126891415);
-    W = t(W, V, Y, X, C[P + 14], R, 2878612391);
-    X = t(X, W, V, Y, C[P + 5], O, 4237533241);
-    Y = t(Y, X, W, V, C[P + 12], U, 1700485571);
-    V = t(V, Y, X, W, C[P + 3], T, 2399980690);
-    W = t(W, V, Y, X, C[P + 10], R, 4293915773);
-    X = t(X, W, V, Y, C[P + 1], O, 2240044497);
-    Y = t(Y, X, W, V, C[P + 8], U, 1873313359);
-    V = t(V, Y, X, W, C[P + 15], T, 4264355552);
-    W = t(W, V, Y, X, C[P + 6], R, 2734768916);
-    X = t(X, W, V, Y, C[P + 13], O, 1309151649);
-    Y = t(Y, X, W, V, C[P + 4], U, 4149444226);
-    V = t(V, Y, X, W, C[P + 11], T, 3174756917);
-    W = t(W, V, Y, X, C[P + 2], R, 718787259);
-    X = t(X, W, V, Y, C[P + 9], O, 3951481745);
-    Y = K(Y, h);
-    X = K(X, E);
-    W = K(W, v);
-    V = K(V, g)
-  }
-  var i = B(Y) + B(X) + B(W) + B(V);
-  return i.toLowerCase()
-};
-module.exports = Functions;
+"use strict";
+
+var Promise = require("bluebird");
+var Point = require('./map/canvas/Point');
+
+var logger = require('./logger');
+
+var xss = require('xss');
+
+function Functions() {
+  /**
+   * In a browser variable we store information about browser user is currently
+   * using. Right now only IE is supported.
+   */
+  this.browser = {
+    init: function () {
+
+      this.name = "Unknown";
+      this.version = "Unknown";
+
+      if (typeof navigator !== 'undefined') {
+        // Get the user agent string
+        var ua = navigator.userAgent;
+        this.compatibilityMode = false;
+        var re;
+        if (navigator.appName === 'Microsoft Internet Explorer') {
+          this.name = "IE";
+          re = new RegExp("MSIE ([0-9]+[\.0-9]*)");
+          if (re.exec(ua) !== undefined && re.exec(ua) !== null) {
+            this.version = parseFloat(RegExp.$1);
+          }
+          if (ua.indexOf("MSIE 7.0") > -1) {
+            this.compatibilityMode = true;
+          }
+        } else if (navigator.appName === 'Netscape') {
+          this.name = "Other";
+          ua = navigator.userAgent;
+          re = new RegExp("Trident/.*rv[ :]*([0-9]{1,}[\.0-9]{0,})");
+          if (re.exec(ua) !== undefined && re.exec(ua) !== null) {
+            this.version = parseFloat(RegExp.$1);
+          }
+        }
+      }
+    }
+  };
+
+  this.browser.init();
+}
+
+/**
+ * Bounds value between opt_min and opt_max (result will be not smaller than
+ * opt_min and not bigger than opt_max).
+ */
+Functions.prototype.bound = function (value, minVal, maxVal) {
+  if (minVal !== null && minVal !== undefined) {
+    value = Math.max(value, minVal);
+  }
+  if (maxVal !== null && maxVal !== undefined) {
+    value = Math.min(value, maxVal);
+  }
+  return value;
+};
+
+Functions.prototype.degreesToRadians = function (deg) {
+  return deg * (Math.PI / 180);
+};
+
+Functions.prototype.radiansToDegrees = function (rad) {
+  return rad / (Math.PI / 180);
+};
+
+Functions.prototype.intToColorString = function (value) {
+  /* jslint bitwise: true */
+  var trimmedValue = (value & 0xFFFFFF);
+  var colorStr = trimmedValue.toString(16);
+  while (colorStr.length < 6) {
+    colorStr = "0" + colorStr;
+  }
+  return '#' + colorStr;
+};
+
+/**
+ *
+ * @param value
+ * @returns {number|undefined}
+ */
+Functions.prototype.getIntOrUndefined = function (value) {
+  if (this.isInt(value)) {
+    return value;
+  } else if (value === undefined || value === null) {
+    return undefined;
+  } else {
+    logger.warn("Invalid argument type: " + value);
+    return undefined;
+  }
+};
+
+
+/**
+ *
+ * @param {string} color
+ * @param {number} opacity
+ * @returns {string}
+ */
+Functions.prototype.colorToRgbaString = function (color, opacity) {
+  if (color[0] !== '#' || color.length !== 7) {
+    throw new Error("Expected color in #RRGGBB format, but found: " + color);
+  }
+  var red = parseInt(color.substr(1, 2), 16);
+  var green = parseInt(color.substr(3, 2), 16);
+  var blue = parseInt(color.substr(5, 2), 16);
+  var alpha = opacity !== undefined ? opacity : 1.0;
+  return "rgba(" + red + "," + green + "," + blue + "," + alpha + ")";
+};
+
+
+/**
+ *
+ * @param {LayoutAlias[]|LayoutReaction[]} overlayData
+ * @returns {Promise<Array>}
+ */
+Functions.prototype.overlaysToColorDataStructure = function (overlayData) {
+  var promises = [];
+  for (var i = 0; i < overlayData.length; i++) {
+    promises.push(this.overlayToColor(overlayData[i]));
+  }
+  return Promise.all(promises).then(function (colors) {
+    var countByColor = [], color;
+    for (var i = 0; i < colors.length; i++) {
+      color = colors[i];
+      if (countByColor[color] !== undefined) {
+        countByColor[color]++;
+      } else {
+        countByColor[color] = 1;
+      }
+    }
+    var result = [];
+    for (color in countByColor) {
+      if (countByColor.hasOwnProperty(color)) {
+        result.push({color: color, amount: countByColor[color]});
+      }
+    }
+    var compare = function (a, b) {
+      return a.color.localeCompare(b.color);
+    };
+    result.sort(compare);
+    return result;
+  });
+
+};
+
+/**
+ * Returns stack trace.
+ *
+ * @returns {string} stack trace
+ */
+Functions.prototype.stackTrace = function () {
+  var err = new Error();
+  return err.stack;
+};
+
+/**
+ * Returns the position of the element on html page.
+ *
+ * @param element
+ *          element for which we want to get the position (top left corner)
+ *
+ * @return {Point} coordinates of the element
+ *
+ */
+Functions.prototype.getPosition = function (element) {
+  var xPosition = 0;
+  var yPosition = 0;
+
+  while (element) {
+    xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
+    yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
+    element = element.offsetParent;
+  }
+  return new Point(xPosition, yPosition);
+};
+
+/**
+ * Checks if the point given as a first argument belongs to a polygon defined as
+ * a second parameter. Both: point and polygon should use google.map.point
+ * class.
+ *
+ * @param {Point} point
+ *          point which we want to check
+ *
+ * @param {Point[]} polygon
+ *          polygon where we check the point
+ */
+
+Functions.prototype.pointInsidePolygon = function (point, polygon) {
+  var x = point.x;
+  var y = point.y;
+
+  var inside = false;
+  for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
+    var xi = polygon[i].x, yi = polygon[i].y;
+    var xj = polygon[j].x, yj = polygon[j].y;
+    var intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
+    if (intersect) {
+      inside = !inside;
+    }
+  }
+  return inside;
+};
+
+/**
+ * Returns true if parameter is integer, false otherwise.
+ *
+ * @param n
+ *          object to check
+ */
+Functions.prototype.isInt = function (n) {
+  return Number(n) === n && n % 1 === 0;
+};
+
+/**
+ * Returns true if parameter is a DOM element, false otherwise.
+ *
+ * @param o
+ *          object to check
+ */
+Functions.prototype.isDomElement = function (o) {
+  if (!o) {
+    return false;
+  }
+  return (typeof HTMLElement === "object" ? o instanceof HTMLElement : // DOM2
+    o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string");
+};
+
+/**
+ *
+ * @param {LayoutAlias|LayoutReaction} elementOverlay
+ *
+ * @returns {Promise<string>}
+ */
+
+Functions.prototype.overlayToColor = function (elementOverlay) {
+  var self = this;
+  if (elementOverlay === null || elementOverlay === undefined) {
+    return Promise.reject("elementOverlay cannot be null!");
+  } else if (elementOverlay.color !== undefined && elementOverlay.color !== null) {
+    return Promise.resolve(self.intToColorString(elementOverlay.color.rgb));
+  } else {
+    var ratio = 0;
+    var promiseColors;
+    if (elementOverlay.value !== undefined && elementOverlay.value !== null) {
+      if (elementOverlay.value < 0) {
+        ratio = -elementOverlay.value;
+        promiseColors = [ServerConnector.getMinOverlayColorInt(), ServerConnector.getNeutralOverlayColorInt()];
+      } else {
+        ratio = elementOverlay.value;
+        promiseColors = [ServerConnector.getMaxOverlayColorInt(), ServerConnector.getNeutralOverlayColorInt()];
+      }
+    } else {
+      ratio = 1;
+      promiseColors = [ServerConnector.getSimpleOverlayColorInt(), ServerConnector.getNeutralOverlayColorInt()];
+    }
+
+    return Promise.all(promiseColors).then(function (colors) {
+      var maxColor = colors[0];
+      var neutralColor = colors[1];
+
+      ratio = 1 - ratio;
+      var MAX_RED = 0xFF0000;
+      var MAX_GREEN = 0x00FF00;
+      var MAX_BLUE = 0x0000FF;
+
+      var red = maxColor & MAX_RED;
+      var neutralRed = neutralColor & MAX_RED;
+
+      red = red + (neutralRed - red) * ratio;
+      red = parseInt(red);
+      red = red & MAX_RED;
+
+      var green = maxColor & MAX_GREEN;
+      var neutralGreen = neutralColor & MAX_GREEN;
+      green = green + (neutralGreen - green) * ratio;
+      green = parseInt(green);
+      green = green & MAX_GREEN;
+
+      var blue = maxColor & MAX_BLUE;
+      var neutralBlue = neutralColor & MAX_BLUE;
+      blue = blue + (neutralBlue - blue) * ratio;
+      blue = parseInt(blue);
+      blue = blue & MAX_BLUE;
+
+      var color = red | green | blue;
+      return self.intToColorString(color);
+    });
+  }
+};
+
+Functions.prototype.getElementByName = function (element, name) {
+  if (element !== undefined) {
+    if (element.getAttribute("name") === name) {
+      return element;
+    }
+    var children = element.children;
+    for (var i = 0; i < children.length; i++) {
+      var child = children[i];
+      var res = this.getElementByName(child, name);
+      if (res !== undefined) {
+        return res;
+      }
+    }
+  }
+  return undefined;
+};
+
+
+/**
+ *
+ * @param {HTMLElement}element
+ * @param {string} name class name
+ * @returns {HTMLElement|undefined}
+ */
+Functions.prototype.getElementByClassName = function (element, name) {
+  if (name.indexOf(".") !== 0) {
+    name = "." + name;
+  }
+  return $(name, element)[0];
+};
+
+/**
+ *
+ * @param {Object} params
+ * @param {string} params.type type of the {HTMLElement} to be created
+ * @param {string} [params.inputType] type of the input to be created
+ * @param {string} [params.className] css class of the element
+ * @param {string} [params.style] css styling
+ * @param {string} [params.value]
+ * @param {string|HTMLElement} [params.content]
+ *
+ * @returns {HTMLElement}
+ */
+Functions.prototype.createElement = function (params) {
+  var result = document.createElement(params.type);
+  if (params.id !== null && params.id !== undefined) {
+    result.id = params.id;
+  }
+  if (params.name !== null && params.name !== undefined) {
+    result.setAttribute("name", params.name);
+  }
+  if (params.className !== null && params.className !== undefined) {
+    result.className = params.className;
+  }
+  if (params.inputType !== null && params.inputType !== undefined) {
+    result.type = params.inputType;
+  }
+  if (params.content !== null && params.content !== undefined) {
+    if (this.isDomElement(params.content)) {
+      result.appendChild(params.content);
+    } else if (params.xss !== false) {
+      var content = xss(params.content);
+      if (content !== params.content) {
+        logger.warn("XSS changed content: " + params.content);
+      }
+      result.innerHTML = content;
+    } else {
+      result.innerHTML = params.content;
+    }
+  }
+  if (params.style !== null && params.style !== undefined) {
+    result.style.cssText = params.style;
+  }
+  if (params.onclick !== null && params.onclick !== undefined) {
+    result.onclick = params.onclick;
+  }
+  if (params.onchange !== null && params.onchange !== undefined) {
+    result.onchange = params.onchange;
+  }
+  if (params.href !== null && params.href !== undefined) {
+    result.href = params.href;
+  }
+  if (params.src !== null && params.src !== undefined) {
+    result.src = params.src;
+  }
+  if (params.value !== null && params.value !== undefined) {
+    result.value = params.value;
+  }
+  if (params.title !== null && params.title !== undefined) {
+    result.title = params.title;
+  }
+  if (params.index !== null && params.index !== undefined) {
+    result.index = params.index;
+  }
+  if (params.data !== null && params.data !== undefined) {
+    $(result).attr("data", params.data);
+  }
+  return result;
+};
+
+function sqr(x) {
+  return x * x;
+}
+
+function dist2(v, w) {
+  return sqr(v.x - w.x) + sqr(v.y - w.y);
+}
+
+function distToSegmentSquared(p, v, w) {
+  var l2 = dist2(v, w);
+
+  if (l2 === 0) {
+    return dist2(p, v);
+  }
+
+  var t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
+
+  if (t < 0) {
+    return dist2(p, v);
+  }
+  if (t > 1) {
+    return dist2(p, w);
+  }
+
+  return dist2(p, new Point(v.x + t * (w.x - v.x), v.y + t * (w.y - v.y)));
+}
+
+Functions.prototype.distance = function (p1, el2) {
+  if (el2 instanceof Point) {
+    var p2 = el2;
+    return Math.sqrt((Math.pow(p1.x - p2.x, 2)) + (Math.pow(p1.y - p2.y, 2)));
+  } else {
+    return Math.sqrt(distToSegmentSquared(p1, el2.start, el2.end));
+  }
+};
+
+Functions.prototype.removeChildren = function (element) {
+  while (element.firstChild) {
+    element.removeChild(element.firstChild);
+  }
+};
+
+/**
+ *
+ * @returns {Promise} resolved after javascript is loaded
+ */
+Functions.prototype.loadScript = function (url) {
+  return new Promise(function (resolve) {
+    var scriptExists = false;
+    var scripts = document.getElementsByTagName('script');
+    for (var i = scripts.length; i--;) {
+      if (scripts[i].src === url)
+        scriptExists = true;
+    }
+    if (!scriptExists) {
+      var head = document.getElementsByTagName('head')[0];
+      var script = document.createElement('script');
+      script.type = 'text/javascript';
+      script.src = url;
+      script.onload = function () {
+        resolve();
+      };
+      head.appendChild(script);
+    } else {
+      resolve();
+    }
+  });
+};
+
+Functions.prototype.computeMD5 = function (s) {
+  function L(k, d) {
+    return (k << d) | (k >>> (32 - d))
+  }
+
+  function K(G, k) {
+    var I, d, F, H, x;
+    F = (G & 2147483648);
+    H = (k & 2147483648);
+    I = (G & 1073741824);
+    d = (k & 1073741824);
+    x = (G & 1073741823) + (k & 1073741823);
+    if (I & d) {
+      return (x ^ 2147483648 ^ F ^ H)
+    }
+    if (I | d) {
+      if (x & 1073741824) {
+        return (x ^ 3221225472 ^ F ^ H)
+      } else {
+        return (x ^ 1073741824 ^ F ^ H)
+      }
+    } else {
+      return (x ^ F ^ H)
+    }
+  }
+
+  function r(d, F, k) {
+    return (d & F) | ((~d) & k)
+  }
+
+  function q(d, F, k) {
+    return (d & k) | (F & (~k))
+  }
+
+  function p(d, F, k) {
+    return (d ^ F ^ k)
+  }
+
+  function n(d, F, k) {
+    return (F ^ (d | (~k)))
+  }
+
+  function u(G, F, aa, Z, k, H, I) {
+    G = K(G, K(K(r(F, aa, Z), k), I));
+    return K(L(G, H), F)
+  }
+
+  function f(G, F, aa, Z, k, H, I) {
+    G = K(G, K(K(q(F, aa, Z), k), I));
+    return K(L(G, H), F)
+  }
+
+  function D(G, F, aa, Z, k, H, I) {
+    G = K(G, K(K(p(F, aa, Z), k), I));
+    return K(L(G, H), F)
+  }
+
+  function t(G, F, aa, Z, k, H, I) {
+    G = K(G, K(K(n(F, aa, Z), k), I));
+    return K(L(G, H), F)
+  }
+
+  function e(G) {
+    var Z;
+    var F = G.length;
+    var x = F + 8;
+    var k = (x - (x % 64)) / 64;
+    var I = (k + 1) * 16;
+    var aa = Array(I - 1);
+    var d = 0;
+    var H = 0;
+    while (H < F) {
+      Z = (H - (H % 4)) / 4;
+      d = (H % 4) * 8;
+      aa[Z] = (aa[Z] | (G.charCodeAt(H) << d));
+      H++
+    }
+    Z = (H - (H % 4)) / 4;
+    d = (H % 4) * 8;
+    aa[Z] = aa[Z] | (128 << d);
+    aa[I - 2] = F << 3;
+    aa[I - 1] = F >>> 29;
+    return aa
+  }
+
+  function B(x) {
+    var k = "", F = "", G, d;
+    for (d = 0; d <= 3; d++) {
+      G = (x >>> (d * 8)) & 255;
+      F = "0" + G.toString(16);
+      k = k + F.substr(F.length - 2, 2)
+    }
+    return k
+  }
+
+  function J(k) {
+    k = k.replace(/rn/g, "n");
+    var d = "";
+    for (var F = 0; F < k.length; F++) {
+      var x = k.charCodeAt(F);
+      if (x < 128) {
+        d += String.fromCharCode(x)
+      } else {
+        if ((x > 127) && (x < 2048)) {
+          d += String.fromCharCode((x >> 6) | 192);
+          d += String.fromCharCode((x & 63) | 128)
+        } else {
+          d += String.fromCharCode((x >> 12) | 224);
+          d += String.fromCharCode(((x >> 6) & 63) | 128);
+          d += String.fromCharCode((x & 63) | 128)
+        }
+      }
+    }
+    return d
+  }
+
+  var C = Array();
+  var P, h, E, v, g, Y, X, W, V;
+  var S = 7, Q = 12, N = 17, M = 22;
+  var A = 5, z = 9, y = 14, w = 20;
+  var o = 4, m = 11, l = 16, j = 23;
+  var U = 6, T = 10, R = 15, O = 21;
+  s = J(s);
+  C = e(s);
+  Y = 1732584193;
+  X = 4023233417;
+  W = 2562383102;
+  V = 271733878;
+  for (P = 0; P < C.length; P += 16) {
+    h = Y;
+    E = X;
+    v = W;
+    g = V;
+    Y = u(Y, X, W, V, C[P + 0], S, 3614090360);
+    V = u(V, Y, X, W, C[P + 1], Q, 3905402710);
+    W = u(W, V, Y, X, C[P + 2], N, 606105819);
+    X = u(X, W, V, Y, C[P + 3], M, 3250441966);
+    Y = u(Y, X, W, V, C[P + 4], S, 4118548399);
+    V = u(V, Y, X, W, C[P + 5], Q, 1200080426);
+    W = u(W, V, Y, X, C[P + 6], N, 2821735955);
+    X = u(X, W, V, Y, C[P + 7], M, 4249261313);
+    Y = u(Y, X, W, V, C[P + 8], S, 1770035416);
+    V = u(V, Y, X, W, C[P + 9], Q, 2336552879);
+    W = u(W, V, Y, X, C[P + 10], N, 4294925233);
+    X = u(X, W, V, Y, C[P + 11], M, 2304563134);
+    Y = u(Y, X, W, V, C[P + 12], S, 1804603682);
+    V = u(V, Y, X, W, C[P + 13], Q, 4254626195);
+    W = u(W, V, Y, X, C[P + 14], N, 2792965006);
+    X = u(X, W, V, Y, C[P + 15], M, 1236535329);
+    Y = f(Y, X, W, V, C[P + 1], A, 4129170786);
+    V = f(V, Y, X, W, C[P + 6], z, 3225465664);
+    W = f(W, V, Y, X, C[P + 11], y, 643717713);
+    X = f(X, W, V, Y, C[P + 0], w, 3921069994);
+    Y = f(Y, X, W, V, C[P + 5], A, 3593408605);
+    V = f(V, Y, X, W, C[P + 10], z, 38016083);
+    W = f(W, V, Y, X, C[P + 15], y, 3634488961);
+    X = f(X, W, V, Y, C[P + 4], w, 3889429448);
+    Y = f(Y, X, W, V, C[P + 9], A, 568446438);
+    V = f(V, Y, X, W, C[P + 14], z, 3275163606);
+    W = f(W, V, Y, X, C[P + 3], y, 4107603335);
+    X = f(X, W, V, Y, C[P + 8], w, 1163531501);
+    Y = f(Y, X, W, V, C[P + 13], A, 2850285829);
+    V = f(V, Y, X, W, C[P + 2], z, 4243563512);
+    W = f(W, V, Y, X, C[P + 7], y, 1735328473);
+    X = f(X, W, V, Y, C[P + 12], w, 2368359562);
+    Y = D(Y, X, W, V, C[P + 5], o, 4294588738);
+    V = D(V, Y, X, W, C[P + 8], m, 2272392833);
+    W = D(W, V, Y, X, C[P + 11], l, 1839030562);
+    X = D(X, W, V, Y, C[P + 14], j, 4259657740);
+    Y = D(Y, X, W, V, C[P + 1], o, 2763975236);
+    V = D(V, Y, X, W, C[P + 4], m, 1272893353);
+    W = D(W, V, Y, X, C[P + 7], l, 4139469664);
+    X = D(X, W, V, Y, C[P + 10], j, 3200236656);
+    Y = D(Y, X, W, V, C[P + 13], o, 681279174);
+    V = D(V, Y, X, W, C[P + 0], m, 3936430074);
+    W = D(W, V, Y, X, C[P + 3], l, 3572445317);
+    X = D(X, W, V, Y, C[P + 6], j, 76029189);
+    Y = D(Y, X, W, V, C[P + 9], o, 3654602809);
+    V = D(V, Y, X, W, C[P + 12], m, 3873151461);
+    W = D(W, V, Y, X, C[P + 15], l, 530742520);
+    X = D(X, W, V, Y, C[P + 2], j, 3299628645);
+    Y = t(Y, X, W, V, C[P + 0], U, 4096336452);
+    V = t(V, Y, X, W, C[P + 7], T, 1126891415);
+    W = t(W, V, Y, X, C[P + 14], R, 2878612391);
+    X = t(X, W, V, Y, C[P + 5], O, 4237533241);
+    Y = t(Y, X, W, V, C[P + 12], U, 1700485571);
+    V = t(V, Y, X, W, C[P + 3], T, 2399980690);
+    W = t(W, V, Y, X, C[P + 10], R, 4293915773);
+    X = t(X, W, V, Y, C[P + 1], O, 2240044497);
+    Y = t(Y, X, W, V, C[P + 8], U, 1873313359);
+    V = t(V, Y, X, W, C[P + 15], T, 4264355552);
+    W = t(W, V, Y, X, C[P + 6], R, 2734768916);
+    X = t(X, W, V, Y, C[P + 13], O, 1309151649);
+    Y = t(Y, X, W, V, C[P + 4], U, 4149444226);
+    V = t(V, Y, X, W, C[P + 11], T, 3174756917);
+    W = t(W, V, Y, X, C[P + 2], R, 718787259);
+    X = t(X, W, V, Y, C[P + 9], O, 3951481745);
+    Y = K(Y, h);
+    X = K(X, E);
+    W = K(W, v);
+    V = K(V, g)
+  }
+  var i = B(Y) + B(X) + B(W) + B(V);
+  return i.toLowerCase()
+};
+
+var singleton = new Functions();
+
+module.exports = singleton;
diff --git a/frontend-js/src/main/js/ServerConnector.js b/frontend-js/src/main/js/ServerConnector.js
index 8801a35ab120a35a26c219803fb6108e45debece..a4d4f5bb0fcce4131ef7fe74359107037b8247e7 100644
--- a/frontend-js/src/main/js/ServerConnector.js
+++ b/frontend-js/src/main/js/ServerConnector.js
@@ -124,6 +124,12 @@ ServerConnector.getNeutralOverlayColorInt = function () {
   });
 };
 
+/**
+ *
+ * @param url
+ * @param description
+ * @returns {Promise}
+ */
 ServerConnector.sendGetRequest = function (url, description) {
   return this.sendRequest({
     url: url,
@@ -153,7 +159,7 @@ function isSessionExpiredError(error) {
 /**
  *
  * @param params
- * @returns {PromiseLike}
+ * @returns {PromiseLike|Promise}
  */
 ServerConnector.sendRequest = function (params) {
   var self = this;
@@ -225,6 +231,12 @@ ServerConnector._sendRequest = function (params) {
   });
 };
 
+/**
+ *
+ * @param {string} url
+ * @param {Object} params
+ * @returns {Promise}
+ */
 ServerConnector.sendPostRequest = function (url, params) {
   return this.sendRequest({
     method: "POST",
@@ -243,9 +255,9 @@ ServerConnector.sendDeleteRequest = function (url, json) {
 
 /**
  *
- * @param url
- * @param json
- * @returns {PromiseLike}
+ * @param {string} url
+ * @param {Object} json
+ * @returns {Promise}
  */
 ServerConnector.sendPatchRequest = function (url, json) {
   return this.sendRequest({
@@ -255,6 +267,10 @@ ServerConnector.sendPatchRequest = function (url, json) {
   });
 };
 
+/**
+ *
+ * @returns {string}
+ */
 ServerConnector.getApiBaseUrl = function () {
   return this.getServerBaseUrl() + "/api/";
 };
@@ -307,6 +323,15 @@ ServerConnector.createGetParams = function (params, prefix) {
   return result;
 };
 
+/**
+ *
+ * @param {Object} paramObj
+ * @param {string} [paramObj.type]
+ * @param {string} paramObj.url
+ * @param {Object} [paramObj.params]
+ *
+ * @returns {string}
+ */
 ServerConnector.getApiUrl = function (paramObj) {
   var type = paramObj.type;
   var params = this.createGetParams(paramObj.params);
@@ -411,12 +436,124 @@ ServerConnector.getSbmlParameterUrl = function (queryParams, filterParams) {
   });
 };
 
+/**
+ *
+ * @param {Object} queryParams
+ * @param {string} [queryParams.version]
+ * @param {string} [queryParams.organism]
+ * @param {string} [queryParams.type]
+ * @param {string} [queryParams.genomeId]
+ * @param {Object} filterParams
+ *
+ * @returns {string}
+ */
 ServerConnector.getReferenceGenomeUrl = function (queryParams, filterParams) {
-  var version = this.getIdOrAsterisk(queryParams.version);
+  if (queryParams.genomeId !== undefined) {
+    return this.getApiUrl({
+      type: "genomics/" + queryParams.genomeId + "/",
+      params: filterParams
+    });
+  } else {
+    var version = this.getIdOrAsterisk(queryParams.version);
+
+    return this.getApiUrl({
+      type: "genomics/taxonomies/" + queryParams.organism + "/genomeTypes/" + queryParams.type + "/versions/" + version
+      + "/",
+      params: filterParams
+    });
+  }
+};
+
+/**
+ *
+ * @param {Object} queryParams
+ * @param {string} queryParams.genomeId
+ * @param {string} queryParams.mappingId
+ * @param {Object} [filterParams]
+ *
+ * @returns {string}
+ */
+ServerConnector.getReferenceGenomeGeneMappingUrl = function (queryParams, filterParams) {
+  return this.getApiUrl({
+    type: "genomics/" + queryParams.genomeId + "/geneMapping/" + queryParams.mappingId + "/",
+    params: filterParams
+  });
+};
 
+/**
+ *
+ * @param {Object} queryParams
+ * @param {string} queryParams.genomeId
+ * @param {Object} [filterParams]
+ *
+ * @returns {string}
+ */
+ServerConnector.getReferenceGenomeGeneMappingsUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
-    type: "genomics/taxonomies/" + queryParams.organism + "/genomeTypes/" + queryParams.type + "/versions/" + version
-    + "/",
+    type: "genomics/" + queryParams.genomeId + "/geneMapping/",
+    params: filterParams
+  });
+};
+
+/**
+ *
+ * @param {Object} queryParams
+ * @param {string} queryParams.version
+ * @param {Annotation} queryParams.organism
+ * @param {string} queryParams.type
+ * @param {Object} filterParams
+ *
+ * @returns {string}
+ */
+ServerConnector.getAvailableGenomeUrlsUrl = function (queryParams, filterParams) {
+  return this.getApiUrl({
+    type: "genomics/taxonomies/" + queryParams.organism.getResource() + "/genomeTypes/" + queryParams.type + "/versions/" + queryParams.version
+    + ":getAvailableRemoteUrls",
+    params: filterParams
+  });
+};
+
+/**
+ *
+ * @param {Object} queryParams
+ * @param {Annotation} queryParams.organism
+ * @param {Object} [filterParams]
+ *
+ * @returns {string}
+ */
+ServerConnector.getReferenceGenomeTypesUrl = function (queryParams, filterParams) {
+  return this.getApiUrl({
+    type: "genomics/taxonomies/" + queryParams.organism.getResource() + "/genomeTypes/",
+    params: filterParams
+  });
+};
+
+/**
+ *
+ * @param {Object} queryParams
+ * @param {Annotation} queryParams.organism
+ * @param {string} queryParams.type
+ * @param {Object} [filterParams]
+ *
+ * @returns {string}
+ */
+ServerConnector.getReferenceGenomeVersionsUrl = function (queryParams, filterParams) {
+  return this.getApiUrl({
+    type: "genomics/taxonomies/" + queryParams.organism.getResource() + "/genomeTypes/" + queryParams.type + "/versions/",
+    params: filterParams
+  });
+};
+
+/**
+ *
+ * @param {Object} [queryParams]
+ * @param {Object} [filterParams]
+ *
+ * @returns {string}
+ */
+ServerConnector.getReferenceGenomeOrganismsUrl = function (queryParams, filterParams) {
+  return this.getApiUrl({
+    type: "genomics/taxonomies/",
     params: filterParams
   });
 };
@@ -718,6 +855,21 @@ ServerConnector.getUsersUrl = function (queryParams, filterParams) {
   });
 };
 
+/**
+ *
+ * @param {Object} [queryParams]
+ * @param {Object} [filterParams]
+ *
+ * @returns {string}
+ */
+ServerConnector.getReferenceGenomesUrl = function (queryParams, filterParams) {
+  return this.getApiUrl({
+    type: "genomics/",
+    params: filterParams
+  });
+};
+
+
 ServerConnector.getUserUrl = function (queryParams, filterParams) {
   return this.getApiUrl({
     url: this.getUsersUrl() + queryParams.login,
@@ -1001,6 +1153,11 @@ ServerConnector.getLoggedUser = function () {
   }
 };
 
+/**
+ *
+ * @param {string} login
+ * @returns {Promise}
+ */
 ServerConnector.getUser = function (login) {
   var self = this;
   var queryParams = {
@@ -1027,7 +1184,7 @@ ServerConnector.getUser = function (login) {
 /**
  *
  * @param {User} user
- * @returns {PromiseLike<any>}
+ * @returns {Promise}
  */
 ServerConnector.updateUser = function (user) {
   var self = this;
@@ -1040,7 +1197,8 @@ ServerConnector.updateUser = function (user) {
       surname: user.getSurname(),
       password: user.getPassword(),
       email: user.getEmail(),
-      termsOfUseConsent: user.isTermsOfUseConsent()
+      termsOfUseConsent: user.isTermsOfUseConsent(),
+      connectedToLdap: user.isConnectedToLdap()
     }
   };
   return self.sendPatchRequest(self.getUserUrl(queryParams), filterParams).then(function () {
@@ -1048,8 +1206,13 @@ ServerConnector.updateUser = function (user) {
   }).then(function (configuration) {
     return self.updateUserPrivileges({user: user, privileges: user.privilegesToExport(configuration)});
   });
-
 };
+
+/**
+ *
+ * @param {User} user
+ * @returns {Promise}
+ */
 ServerConnector.addUser = function (user) {
   var self = this;
   var queryParams = {
@@ -1067,18 +1230,29 @@ ServerConnector.addUser = function (user) {
   }).then(function (configuration) {
     return self.updateUserPrivileges({user: user, privileges: user.privilegesToExport(configuration)});
   });
-
 };
 
+/**
+ *
+ * @param {string} login
+ * @returns {Promise}
+ */
 ServerConnector.removeUser = function (login) {
   var self = this;
   var queryParams = {
     login: login
   };
   return self.sendDeleteRequest(self.getUserUrl(queryParams));
-
 };
 
+/**
+ *
+ * @param {Object} params
+ * @param {User} params.user
+ * @param {Object} params.privileges
+ *
+ * @returns {Promise}
+ */
 ServerConnector.updateUserPrivileges = function (params) {
   var self = this;
   var queryParams = {
@@ -1101,6 +1275,11 @@ ServerConnector.updateUserPrivileges = function (params) {
   });
 };
 
+/**
+ *
+ * @param {Error} error
+ * @returns {Promise}
+ */
 ServerConnector.processNetworkError = function (error) {
   if ((error instanceof NetworkError)) {
     switch (error.statusCode) {
@@ -1116,7 +1295,14 @@ ServerConnector.processNetworkError = function (error) {
   }
 };
 
-
+/**
+ *
+ * @param {Object} params
+ * @param {User} params.user
+ * @param {UserPreferences} params.preferences
+ *
+ * @returns {Promise}
+ */
 ServerConnector.updateUserPreferences = function (params) {
   var self = this;
   var queryParams = {
@@ -1137,6 +1323,12 @@ ServerConnector.updateUserPreferences = function (params) {
   });
 };
 
+/**
+ *
+ * @param {boolean} forceRefresh
+ *
+ * @returns {Promise}
+ */
 ServerConnector.getUsers = function (forceRefresh) {
   var self = this;
 
@@ -1160,9 +1352,35 @@ ServerConnector.getUsers = function (forceRefresh) {
       return self.processNetworkError(error);
     });
   }
+};
 
+/**
+ *
+ * @returns {Promise<Array>}
+ */
+ServerConnector.getReferenceGenomes = function () {
+  var self = this;
+
+  return self.sendGetRequest(self.getReferenceGenomesUrl()).then(function (content) {
+    var result = [];
+    var parsedData = JSON.parse(content);
+    for (var i = 0; i < parsedData.length; i++) {
+      var genome = new ReferenceGenome(parsedData[i]);
+      result.push(genome)
+    }
+    return result;
+  });
 };
 
+/**
+ *
+ * @param {Object} [params]
+ * @param {string} [params.creator] user login
+ * @param {boolean} [params.publicOverlay]
+ * @param {string} [params.projectId]
+ *
+ * @returns {Promise<Array>}
+ */
 ServerConnector.getOverlays = function (params) {
   var self = this;
   if (params === undefined) {
@@ -1187,6 +1405,13 @@ ServerConnector.getOverlays = function (params) {
   });
 };
 
+/**
+ *
+ * @param {number} overlayId
+ * @param {string} [projectId]
+ *
+ * @returns {Promise}
+ */
 ServerConnector.getOverlayElements = function (overlayId, projectId) {
   var self = this;
   if (overlayId === undefined) {
@@ -1244,6 +1469,11 @@ ServerConnector.getFullOverlayElement = function (params) {
   });
 };
 
+/**
+ *
+ * @param {string} [projectId]
+ * @returns {Promise}
+ */
 ServerConnector.getProjectId = function (projectId) {
   var self = this;
   if (projectId !== undefined && projectId !== null && projectId !== "") {
@@ -1733,7 +1963,6 @@ ServerConnector.addComment = function (params) {
   delete filterParams.modelId;
   return self.getProjectId(params.projectId).then(function (result) {
     queryParams.projectId = result;
-    console.log(self.addCommentUrl(queryParams));
     return self.sendPostRequest(self.addCommentUrl(queryParams), filterParams);
   }).then(function (content) {
     var response = JSON.parse(content);
@@ -1761,6 +1990,7 @@ ServerConnector.addOverlay = function (params) {
     content: overlay.getContent(),
     filename: overlay.getFilename(),
     googleLicenseConsent: overlay.isGoogleLicenseConsent(),
+    type: overlay.getType(),
     fileId: params.fileId
   };
   return self.getProjectId(params.projectId).then(function (result) {
@@ -1771,6 +2001,12 @@ ServerConnector.addOverlay = function (params) {
   });
 };
 
+/**
+ *
+ * @param {string} name
+ * @param {string} content
+ * @returns {Promise}
+ */
 ServerConnector.addOverlayFromString = function (name, content) {
   var fileName = name + ".txt";
   var overlay = new DataOverlay({
@@ -1945,14 +2181,163 @@ ServerConnector.getPublications = function (params) {
   });
 };
 
+/**
+ *
+ * @param {Object} params
+ * @param {string} [params.version]
+ * @param {string} [params.organism]
+ * @param {string} [params.type]
+ * @param {string|number} [params.genomeId]
+ *
+ * @returns {Promise}
+ */
 ServerConnector.getReferenceGenome = function (params) {
   var self = this;
   var filterParams = {};
-  return self.sendGetRequest(self.getReferenceGenomeUrl(params, filterParams)).then(function (content) {
-    return new ReferenceGenome(JSON.parse(content));
+  if (params.genomeId !== undefined) {
+    return self.getReferenceGenomes().then(function (referenceGenomes) {
+      for (var i = 0; i < referenceGenomes.length; i++) {
+        var genome = referenceGenomes[i];
+        if (genome.getId() === params.genomeId) {
+          return genome;
+        }
+      }
+      return null;
+    });
+  } else {
+    return self.sendGetRequest(self.getReferenceGenomeUrl(params, filterParams)).then(function (content) {
+      return new ReferenceGenome(JSON.parse(content));
+    });
+  }
+};
+
+
+/**
+ *
+ * @param {Object} params
+ * @param {string|number} params.genomeId
+ * @param {string} params.mappingName
+ * @param {string} params.mappingUrl
+ *
+ * @returns {Promise}
+ */
+ServerConnector.addGeneMapping = function (params) {
+  var self = this;
+  var data = {
+    name: params.mappingName,
+    url: params.mappingUrl
+  };
+  return self.sendPostRequest(self.getReferenceGenomeGeneMappingsUrl(params), data);
+};
+/**
+ *
+ * @param {Object} params
+ * @param {string} params.version
+ * @param {Annotation} params.organism
+ * @param {string} params.type
+ *
+ * @returns {Promise<string[]>}
+ */
+ServerConnector.getAvailableGenomeUrls = function (params) {
+  var self = this;
+  var filterParams = {};
+  return self.sendGetRequest(self.getAvailableGenomeUrlsUrl(params, filterParams)).then(function (content) {
+    var result = [];
+    var raw = JSON.parse(content);
+    for (var i = 0; i < raw.length; i++) {
+      result.push(raw[i].url);
+    }
+    return result;
+  });
+};
+
+/**
+ *
+ * @param {ReferenceGenome} genome
+ * @returns {Promise<ReferenceGenome>}
+ */
+ServerConnector.addReferenceGenome = function (genome) {
+  var self = this;
+  var data = {
+    organismId: genome.getOrganism().getResource(),
+    type: genome.getType(),
+    version: genome.getVersion(),
+    sourceUrl: genome.getSourceUrl()
+  };
+  return self.sendPostRequest(self.getReferenceGenomesUrl(), data);
+};
+
+/**
+ *
+ * @param {Object} params
+ * @param {string} params.genomeId
+ * @param {string} params.mappingId
+ *
+ * @returns {Promise}
+ */
+ServerConnector.removeReferenceGenomeGeneMapping = function (params) {
+  var self = this;
+  return self.sendDeleteRequest(self.getReferenceGenomeGeneMappingUrl(params));
+};
+
+
+/**
+ *
+ * @param {Object} params
+ * @param {Annotation} params.organism
+ * @returns {Promise}
+ */
+ServerConnector.getReferenceGenomeTypes = function (params) {
+  var self = this;
+  var filterParams = {};
+  return self.sendGetRequest(self.getReferenceGenomeTypesUrl(params, filterParams)).then(function (content) {
+    return JSON.parse(content);
   });
 };
 
+/**
+ *
+ * @param {Object} params
+ * @param {Annotation} params.organism
+ * @param {string} params.type
+ * @returns {Promise}
+ */
+ServerConnector.getReferenceGenomeVersions = function (params) {
+  var self = this;
+  var filterParams = {};
+  return self.sendGetRequest(self.getReferenceGenomeVersionsUrl(params, filterParams)).then(function (content) {
+    return JSON.parse(content);
+  });
+};
+
+/**
+ *
+ * @returns {Promise}
+ */
+ServerConnector.getReferenceGenomeOrganisms = function () {
+  var self = this;
+  return self.sendGetRequest(self.getReferenceGenomeOrganismsUrl()).then(function (content) {
+    var array = JSON.parse(content);
+    var result = [];
+    for (var i = 0; i < array.length; i++) {
+      result.push(new Annotation(array[i]));
+    }
+    return result;
+  });
+};
+
+/**
+ *
+ * @param {Object} params
+ * @param {string} params.genomeId
+ * @returns {Promise}
+ */
+ServerConnector.removeReferenceGenome = function (params) {
+  var self = this;
+  var filterParams = {};
+  return self.sendDeleteRequest(self.getReferenceGenomeUrl(params, filterParams));
+};
+
 ServerConnector.uploadFile = function (params) {
   var CHUNK_SIZE = 65535 * 8;
   var self = this;
@@ -2093,6 +2478,10 @@ ServerConnector.setPluginUserParam = function (params) {
   });
 };
 
+/**
+ *
+ * @returns {Promise}
+ */
 ServerConnector.getSubmapConnections = function () {
   var self = this;
   var queryParams = {};
diff --git a/frontend-js/src/main/js/gui/AbstractGuiElement.js b/frontend-js/src/main/js/gui/AbstractGuiElement.js
index 3ba1e7fdc6fd227ac9871e8fd87e19a625c9c160..95a72bfd8f964fe589c8d764a06b0d91fbbf89b8 100644
--- a/frontend-js/src/main/js/gui/AbstractGuiElement.js
+++ b/frontend-js/src/main/js/gui/AbstractGuiElement.js
@@ -10,7 +10,13 @@ var logger = require('../logger');
 
 /**
  *
- * @param params
+ * @param {Object} params
+ * @param {HTMLElement} params.element
+ * @param {CustomMap} params.customMap
+ * @param {Configuration} params.configuration
+ * @param {Project} [params.project]
+ * @param {ServerConnector} [params.serverConnector]
+ *
  * @constructor
  *
  * @extends ObjectWithListeners
@@ -21,9 +27,10 @@ function AbstractGuiElement(params) {
   var self = this;
 
   self.setElement(params.element);
+  self.setConfiguration(params.configuration);
   self.setProject(params.project);
   self.setMap(params.customMap);
-  self.setConfiguration(params.configuration);
+  self.setServerConnector(params.serverConnector);
 
   self._controlElements = [];
 
@@ -91,6 +98,11 @@ AbstractGuiElement.prototype.getProject = function () {
 };
 
 
+/**
+ *
+ * @param {string} type
+ * @param {HTMLElement} element
+ */
 AbstractGuiElement.prototype.setControlElement = function (type, element) {
   if (type === null || type === undefined) {
     throw new Error("Unknown control element type");
@@ -102,6 +114,11 @@ AbstractGuiElement.prototype.setControlElement = function (type, element) {
   this._controlElements[type] = element;
 };
 
+/**
+ *
+ * @param {string} type
+ * @returns {HTMLElement}
+ */
 AbstractGuiElement.prototype.getControlElement = function (type) {
   if (type === null || type === undefined) {
     throw new Error("Unknown control element type");
@@ -113,11 +130,19 @@ AbstractGuiElement.prototype.getControlElement = function (type) {
   return this._controlElements[type];
 };
 
+/**
+ *
+ * @param {string} url
+ */
 AbstractGuiElement.prototype.downloadFile = function (url) {
   this._downloadFile = url;
   window.open(url, '_blank');
 };
 
+/**
+ *
+ * @returns {string}
+ */
 AbstractGuiElement.prototype.getLastDownloadUrl = function () {
   return this._downloadFile;
 };
@@ -138,6 +163,26 @@ AbstractGuiElement.prototype.getConfiguration = function () {
   return this._configuration;
 };
 
+/**
+ *
+ * @param {ServerConnector} serverConnector
+ */
+AbstractGuiElement.prototype.setServerConnector = function (serverConnector) {
+  this._serverConnector = serverConnector;
+};
+
+/**
+ *
+ * @returns {ServerConnector}
+ */
+AbstractGuiElement.prototype.getServerConnector = function () {
+  if (this._serverConnector !== undefined) {
+    return this._serverConnector;
+  } else {
+    return this.getMap().getServerConnector();
+  }
+};
+
 /**
  *
  * @param {string} [params.content]
diff --git a/frontend-js/src/main/js/gui/AddOverlayDialog.js b/frontend-js/src/main/js/gui/AddOverlayDialog.js
index d49c6a153db8f9436d021c8a4126d5cb3cbc9436..497045042e7987b2dfe9674b8806d69ad4897ec8 100644
--- a/frontend-js/src/main/js/gui/AddOverlayDialog.js
+++ b/frontend-js/src/main/js/gui/AddOverlayDialog.js
@@ -18,6 +18,19 @@ var HttpStatus = require('http-status-codes');
 var Promise = require("bluebird");
 var TextEncoder = require('text-encoding').TextEncoder;
 
+/**
+ *
+ * @param {Object} params
+ * @param {HTMLElement} params.element
+ * @param {CustomMap} params.customMap
+ * @param {Configuration} params.configuration
+ * @param {Project} params.project
+ * @param {ServerConnector} [params.serverConnector]
+ *
+ * @constructor
+ *
+ * @extends AbstractGuiElement
+ */
 function AddOverlayDialog(params) {
   AbstractGuiElement.call(this, params);
   var self = this;
@@ -28,9 +41,12 @@ function AddOverlayDialog(params) {
 AddOverlayDialog.prototype = Object.create(AbstractGuiElement.prototype);
 AddOverlayDialog.prototype.constructor = AddOverlayDialog;
 
+/**
+ *
+ */
 AddOverlayDialog.prototype.createGui = function () {
   var self = this;
-  var guiUtils = new GuiUtils();
+  var guiUtils = new GuiUtils(self.getConfiguration());
   var content = document.createElement("div");
   content.style.width = "100%";
   content.style.height = "100%";
@@ -52,6 +68,24 @@ AddOverlayDialog.prototype.createGui = function () {
   content.appendChild(descriptionInput);
   content.appendChild(guiUtils.createNewLine());
 
+  content.appendChild(guiUtils.createLabel("Type: "));
+  content.appendChild(guiUtils.createNewLine());
+  var types = self.getConfiguration().getOverlayTypes();
+  var typeSelect = Functions.createElement({
+    type: "select",
+    name: "overlay-type",
+    value: types[0]
+  });
+  for (var i = 0; i < types.length; i++) {
+    $(typeSelect).append($('<option>', {
+      value: types[i],
+      text: types[i]
+    }));
+  }
+
+  content.appendChild(typeSelect);
+  content.appendChild(guiUtils.createNewLine());
+
   content.appendChild(guiUtils.createLabel("Upload file: "));
   var fileInput = Functions.createElement({
     type: "input",
@@ -100,6 +134,7 @@ AddOverlayDialog.prototype.processFile = function (file) {
           var overlay = overlayParser.parse(evt.target.result);
           var nameInput = $("[name='overlay-name']", self.getElement())[0];
           var descriptionInput = $("[name='overlay-description']", self.getElement())[0];
+          var typeSelect = $("[name='overlay-type']", self.getElement());
           if (overlay.getName() !== undefined) {
             nameInput.value = overlay.getName();
           } else {
@@ -116,6 +151,9 @@ AddOverlayDialog.prototype.processFile = function (file) {
           if (overlay.getDescription() !== undefined) {
             descriptionInput.value = overlay.getDescription();
           }
+          if (overlay.getType() !== undefined) {
+            typeSelect.val(overlay.getType());
+          }
           resolve(self.getFileContent());
         } catch (error) {
           reject(error);
@@ -155,32 +193,39 @@ AddOverlayDialog.prototype.getFileContent = function () {
   }
 };
 
+/**
+ *
+ * @returns {Promise}
+ */
 AddOverlayDialog.prototype.init = function () {
   return Promise.resolve();
 };
 
+
 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 type = $("[name='overlay-type']", self.getElement()).val();
   var consent = $("[name='overlay-google-consent']", self.getElement()).is(":checked");
   var overlay = new DataOverlay({
     name: nameInput.value,
     description: descriptionInput.value,
     filename: filename,
-    googleLicenseConsent: consent
+    googleLicenseConsent: consent,
+    type: type
   });
 
   if (filename === undefined || filename === "") {
     filename = "unknown.txt";
   }
   GuiConnector.showProcessing();
-  return ServerConnector.uploadFile({
+  return self.getServerConnector().uploadFile({
     filename: filename,
     content: self.getFileContent()
   }).then(function (file) {
-    return ServerConnector.addOverlay({
+    return self.getServerConnector().addOverlay({
       fileId: file.id,
       overlay: overlay,
       projectId: self.getProject().getProjectId()
diff --git a/frontend-js/src/main/js/gui/Panel.js b/frontend-js/src/main/js/gui/Panel.js
index 3a931f2420d31d7cef93b8da19600cb8ba6ddd31..75ebb3459b1ea5d8f6aa595dc1caf6b2f584d5bd 100644
--- a/frontend-js/src/main/js/gui/Panel.js
+++ b/frontend-js/src/main/js/gui/Panel.js
@@ -20,7 +20,6 @@ var xss = require('xss');
  * @param {string} params.panelName
  * @param {boolean} params.scrollable
  * @param {string} [params.helpTip]
- * @param {ServerConnector} [params.serverConnector]
  * @param params.parent
  *
  * @constructor
@@ -33,7 +32,6 @@ function Panel(params) {
   var self = this;
 
   self.setParent(params.parent);
-  self.setServerConnector(params.serverConnector);
   var configuration = params.configuration;
   if (params.configuration === undefined) {
     configuration = self.getMap().getConfiguration();
@@ -239,10 +237,18 @@ Panel.prototype.getParent = function () {
   return this._parent;
 };
 
+/**
+ *
+ * @param {GuiUtils} guiUtils
+ */
 Panel.prototype.setGuiUtils = function (guiUtils) {
   this._guiUtils = guiUtils;
 };
 
+/**
+ *
+ * @returns {GuiUtils}
+ */
 Panel.prototype.getGuiUtils = function () {
   return this._guiUtils;
 };
@@ -300,24 +306,4 @@ Panel.prototype.destroy = function () {
   }
 };
 
-/**
- *
- * @returns {ServerConnector}
- */
-Panel.prototype.getServerConnector = function () {
-  if (this._serverConnector !== undefined) {
-    return this._serverConnector;
-  }
-  return this.getMap().getServerConnector();
-};
-
-/**
- *
- * @param {ServerConnector} serverConnector
- */
-Panel.prototype.setServerConnector = function (serverConnector) {
-  this._serverConnector = serverConnector;
-};
-
-
 module.exports = Panel;
diff --git a/frontend-js/src/main/js/gui/admin/AbstractAdminPanel.js b/frontend-js/src/main/js/gui/admin/AbstractAdminPanel.js
index 58a37304c30c853f99405ebfb5f7d765595dc469..3780b8749497a11a6018655e42f606d4e09443ab 100644
--- a/frontend-js/src/main/js/gui/admin/AbstractAdminPanel.js
+++ b/frontend-js/src/main/js/gui/admin/AbstractAdminPanel.js
@@ -9,15 +9,30 @@ var GuiConnector = require('../../GuiConnector');
 
 // noinspection JSUnusedLocalSymbols
 var logger = require('../../logger');
+// noinspection JSUnusedLocalSymbols
 var Functions = require('../../Functions');
 var Promise = require("bluebird");
 
+/**
+ *
+ * @param {Configuration} [params.configuration]
+ * @param {HTMLElement} params.element
+ * @param {Project} params.project
+ * @param {CustomMap} params.customMap
+ * @param {string} params.panelName
+ * @param {string} [params.helpTip]
+ * @param params.parent
+ *
+ * @constructor
+ * @extends Panel
+ */
 function AbstractAdminPanel(params) {
-  params.scrollable = true;
+  params["scrollable"] = true;
   Panel.call(this, params);
   this._createHeader(params.name);
 
   this._initPromises = [];
+  this._eventBinds = [];
 }
 
 AbstractAdminPanel.prototype = Object.create(Panel.prototype);
@@ -30,12 +45,25 @@ AbstractAdminPanel.prototype._createHeader = function (name) {
   // }));
 };
 
+/**
+ *
+ * @returns {Promise}
+ */
 AbstractAdminPanel.prototype.init = function () {
   return Promise.all(this._initPromises);
 };
 
+/**
+ *
+ * @param {Object} params
+ * @param {string} params.event
+ * @param {jQuery} params.jQueryObject
+ * @param {string} params.preferenceName
+ * @param {Object} params.defaultValue
+ * @param {function} params.getter
+ * @param {function} params.setter
+ */
 AbstractAdminPanel.prototype.bindUserGuiPreference = function (params) {
-
   params.jQueryObject.on(params.event, function () {
     return ServerConnector.getLoggedUser().then(function (user) {
       var oldValue = user.getPreferences().getGuiPreference(params.preferenceName, params.defaultValue);
@@ -53,6 +81,18 @@ AbstractAdminPanel.prototype.bindUserGuiPreference = function (params) {
     var value = user.getPreferences().getGuiPreference(params.preferenceName, params.defaultValue);
     return params.setter(value);
   }));
+
+  this._eventBinds.push(params);
+};
+
+/**
+ *
+ * @returns {Promise}
+ */
+AbstractAdminPanel.prototype.destroy = function () {
+  return Promise.each(this._eventBinds, function (params) {
+    params.jQueryObject.off(params.event);
+  });
 };
 
 
diff --git a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
index 0ab83e41a584db1d9547d034a2ff23d553578a4d..a436197c2afc643d766b5fcb0159975209c58744 100644
--- a/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
+++ b/frontend-js/src/main/js/gui/admin/AddProjectDialog.js
@@ -160,11 +160,11 @@ AddProjectDialog.prototype.showValidatorsDialog = function () {
 AddProjectDialog.prototype.createGeneralTabContent = function () {
   var self = this;
 
-  var result = new Functions.createElement({
+  var result = Functions.createElement({
     type: "div"
   });
 
-  var table = new Functions.createElement({
+  var table = Functions.createElement({
     type: "div",
     style: "display:table; width:100%"
   });
@@ -352,12 +352,12 @@ AddProjectDialog.prototype.createInputRow = function (params) {
   if (params.defaultValue === undefined) {
     params.defaultValue = "";
   }
-  var label = new Functions.createElement({
+  var label = Functions.createElement({
     type: "div",
     style: "display:table-cell; width:200px",
     content: xss(params.labelName)
   });
-  var input = new Functions.createElement({
+  var input = Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "<input name='" + xss(params.inputName) + "' value='" + xss(params.defaultValue) + "' style='width:100%'/>",
@@ -409,7 +409,7 @@ AddProjectDialog.prototype.createCheckboxRow = function (params) {
 };
 
 AddProjectDialog.prototype.createRow = function (elements) {
-  var result = new Functions.createElement({
+  var result = Functions.createElement({
     type: "div",
     style: "display:table-row"
   });
@@ -420,7 +420,7 @@ AddProjectDialog.prototype.createRow = function (elements) {
       if (columnNumber === 0) {
         style += "width:200px;";
       }
-      var labelContainer = new Functions.createElement({
+      var labelContainer = Functions.createElement({
         type: "div",
         style: style
       });
diff --git a/frontend-js/src/main/js/gui/admin/EditGenomeDialog.js b/frontend-js/src/main/js/gui/admin/EditGenomeDialog.js
new file mode 100644
index 0000000000000000000000000000000000000000..db63e854dc8534215b76cd1b12bf8fada93cf2ce
--- /dev/null
+++ b/frontend-js/src/main/js/gui/admin/EditGenomeDialog.js
@@ -0,0 +1,703 @@
+"use strict";
+
+var Promise = require("bluebird");
+
+var AbstractGuiElement = require('../AbstractGuiElement');
+var Annotation = require('../../map/data/Annotation');
+var GuiConnector = require('../../GuiConnector');
+
+var Functions = require('../../Functions');
+// noinspection JSUnusedLocalSymbols
+var logger = require('../../logger');
+
+var guiUtils = new (require('../leftPanel/GuiUtils'))();
+
+/**
+ *
+ * @param {Object} params
+ * @param {HTMLElement} params.element
+ * @param {CustomMap} params.customMap
+ * @param {Configuration} params.configuration
+ * @param {ReferenceGenome} params.referenceGenome
+ * @param {ServerConnector} [params.serverConnector]
+
+ * @constructor
+ *
+ * @extends AbstractGuiElement
+ */
+function EditGenomeDialog(params) {
+  AbstractGuiElement.call(this, params);
+  var self = this;
+  self.setReferenceGenome(params.referenceGenome);
+
+  $(self.getElement()).css({overflow: "hidden"});
+
+  self.createGui();
+  self.registerListenerType("onSave");
+}
+
+EditGenomeDialog.prototype = Object.create(AbstractGuiElement.prototype);
+EditGenomeDialog.prototype.constructor = EditGenomeDialog;
+
+/**
+ *
+ * @param {ReferenceGenome} referenceGenome
+ */
+EditGenomeDialog.prototype.setReferenceGenome = function (referenceGenome) {
+  this._referenceGenome = referenceGenome;
+};
+
+/**
+ *
+ * @returns {ReferenceGenome}
+ */
+EditGenomeDialog.prototype.getReferenceGenome = function () {
+  return this._referenceGenome;
+};
+
+/**
+ *
+ * @returns {boolean}
+ */
+EditGenomeDialog.prototype.isNew = function () {
+  return this.getReferenceGenome().getId() === undefined;
+};
+
+/**
+ *
+ */
+EditGenomeDialog.prototype.createGui = function () {
+  var self = this;
+  var element = self.getElement();
+
+  var tabDiv = Functions.createElement({
+    type: "div",
+    name: "tabView",
+    className: "tabbable boxed parentTabs",
+    style: "position:absolute;top:10px;bottom:40px;left:10px;right:10px"
+  });
+  element.appendChild(tabDiv);
+
+  var tabMenuDiv = Functions.createElement({
+    type: "ul",
+    className: "nav nav-tabs"
+  });
+  tabDiv.appendChild(tabMenuDiv);
+
+  var tabContentDiv = Functions.createElement({
+    type: "div",
+    className: "tab-content",
+    style: "height:100%"
+  });
+  tabDiv.appendChild(tabContentDiv);
+
+  self.createGeneralTab(tabMenuDiv, tabContentDiv);
+  self.createGeneMappingTab(tabMenuDiv, tabContentDiv);
+  $("a", tabMenuDiv).bind("click", function () {
+    //workaround for some css issues...
+    tabDiv.style.top = "40px";
+    tabDiv.style.bottom = "10px";
+  });
+
+};
+
+/**
+ *
+ * @param {HTMLElement} tabMenuDiv
+ * @param {HTMLElement} tabContentDiv
+ */
+EditGenomeDialog.prototype.createGeneralTab = function (tabMenuDiv, tabContentDiv) {
+  var self = this;
+  self.addTab({
+    tabMenuDiv: tabMenuDiv,
+    tabContentDiv: tabContentDiv,
+    name: "DETAILS",
+    content: self.createGeneralTabContent()
+  });
+
+};
+
+/**
+ *
+ * @param {HTMLElement} tabMenuDiv
+ * @param {HTMLElement} tabContentDiv
+ */
+EditGenomeDialog.prototype.createGeneMappingTab = function (tabMenuDiv, tabContentDiv) {
+  var self = this;
+  self.addTab({
+    tabMenuDiv: tabMenuDiv,
+    tabContentDiv: tabContentDiv,
+    name: "GENE MAPPING",
+    content: self.createGeneMappingTabContent()
+  });
+
+};
+
+var id_counter = 0;
+
+/**
+ *
+ * @param {string} tab_name
+ * @returns {string}
+ */
+EditGenomeDialog.prototype.generateTabId = function (tab_name) {
+  var self = this;
+  var id = self.getReferenceGenome().getId();
+  if (id === undefined) {
+    id = "new_genome_" + (id_counter++);
+  }
+  return id + tab_name.replace(" ", "_") + "_TAB";
+};
+
+EditGenomeDialog.prototype.addTab = function (params) {
+  var id = this.generateTabId(params.name);
+
+  var navLi = guiUtils.createTabMenuObject({
+    id: id,
+    name: params.name,
+    navigationBar: params.tabMenuDiv
+  });
+  params.tabMenuDiv.appendChild(navLi);
+
+  var contentDiv = guiUtils.createTabContentObject({
+    id: id,
+    navigationObject: navLi,
+    navigationBar: params.tabMenuDiv
+  });
+
+  $(contentDiv).css("overflow", "auto");
+  if (params.content !== undefined) {
+    contentDiv.appendChild(params.content);
+  }
+
+  params.tabContentDiv.appendChild(contentDiv);
+};
+
+/**
+ *
+ * @returns {HTMLElement}
+ */
+EditGenomeDialog.prototype.createGeneralTabContent = function () {
+
+  var self = this;
+
+  var result = Functions.createElement({
+    type: "div",
+    style: "margin-top:10px;"
+  });
+
+  var table = Functions.createElement({
+    type: "table",
+    name: "detailsTable",
+    className: "display",
+    style: "width:100%"
+  });
+  result.appendChild(table);
+
+  $(table).on("change", "[name='genomeOrganismSelect']", function () {
+    return self._fillTypeSelect(self.getReferenceGenome(), self.getSelectedOrganism());
+  });
+
+  $(table).on("change", "[name='genomeTypeSelect']", function () {
+    return self._fillVersionSelect(self.getReferenceGenome(), self.getSelectedOrganism(), self.getSelectedType());
+  });
+
+  $(table).on("change", "[name='genomeVersionSelect']", function () {
+    return self._fillUrl(self.getReferenceGenome(), self.getSelectedOrganism(), self.getSelectedType(), self.getSelectedVersion());
+  });
+
+
+  var menuRow = Functions.createElement({
+    type: "div",
+    className: "minerva-menu-row",
+    style: "display:table-row; margin:10px"
+  });
+  result.appendChild(menuRow);
+
+  var saveUserButton = Functions.createElement({
+    type: "button",
+    name: "saveGenome",
+    content: '<span class="ui-icon ui-icon-disk"></span>&nbsp;SAVE',
+    onclick: function () {
+      return self.onSaveClicked().then(function () {
+        return self.close();
+      }).catch(GuiConnector.alert);
+    },
+    xss: false
+  });
+  var cancelButton = Functions.createElement({
+    type: "button",
+    name: "cancelGenome",
+    content: '<span class="ui-icon ui-icon-cancel"></span>&nbsp;CANCEL',
+    onclick: function () {
+      return self.close();
+    },
+    xss: false
+  });
+  menuRow.appendChild(saveUserButton);
+  menuRow.appendChild(cancelButton);
+
+  return result;
+};
+
+/**
+ *
+ * @returns {HTMLElement}
+ */
+EditGenomeDialog.prototype.createGeneMappingTabContent = function () {
+
+  var self = this;
+
+  var result = Functions.createElement({
+    type: "div",
+    style: "margin-top:10px;"
+  });
+
+  var geneMappingTable = Functions.createElement({
+    type: "table",
+    name: "geneMappingTable",
+    className: "display",
+    style: "width:100%"
+  });
+  result.appendChild(geneMappingTable);
+
+  // noinspection JSUnusedGlobalSymbols
+  $(geneMappingTable).DataTable({
+    columns: [{
+      title: 'Name'
+    }, {
+      title: 'Source'
+    }, {
+      title: 'Progress'
+    }, {
+      title: 'Remove',
+      orderable: false
+    }],
+    order: [[1, "asc"]]
+  });
+
+  $(geneMappingTable).on("click", "[name='removeMapping']", function () {
+    var button = this;
+    return self.askConfirmRemoval({
+      title: "INFO",
+      content: "Do you really want to remove this gene mapping?",
+      input: false
+    }).then(function (param) {
+      if (param.status) {
+        return self.getServerConnector().removeReferenceGenomeGeneMapping({
+          mappingId: $(button).attr("data").toString(),
+          genomeId: self.getReferenceGenome().getId().toString()
+        }).then(function () {
+          return self.getServerConnector().getReferenceGenome({genomeId: self.getReferenceGenome().getId()});
+        }).then(function (referenceGenome) {
+          self.setReferenceGenome(referenceGenome);
+          return self.refresh();
+        });
+      }
+    }).catch(GuiConnector.alert);
+  });
+
+  var menuRow = Functions.createElement({
+    type: "div",
+    className: "minerva-menu-row",
+    style: "display:table-row; margin:10px"
+  });
+  result.appendChild(menuRow);
+
+  var addGeneMappingButton = Functions.createElement({
+    type: "button",
+    name: "saveGenome",
+    content: '<span class="ui-icon ui-icon-disk"></span>&nbsp;ADD GENE MAPPING',
+    onclick: function () {
+      return self.openAddGeneMapping();
+    },
+    xss: false
+  });
+
+  menuRow.appendChild(addGeneMappingButton);
+
+  return result;
+};
+
+/**
+ *
+ * @returns {Promise|PromiseLike}
+ */
+EditGenomeDialog.prototype.onSaveClicked = function () {
+  var self = this;
+  if (!self.isNew()) {
+    return self.callListeners("onSave");
+  } else {
+    var genome = self.getReferenceGenome();
+    genome.setSourceUrl(self.getSourceUrl());
+    genome.setOrganism(self.getSelectedOrganism());
+    genome.setType(self.getSelectedType());
+    genome.setVersion(self.getSelectedVersion());
+    return self.getServerConnector().addReferenceGenome(genome).then(function () {
+      return self.callListeners("onSave");
+    });
+  }
+};
+/**
+ *
+ * @param {ReferenceGenome} genome
+ * @returns {Promise}
+ * @private
+ */
+EditGenomeDialog.prototype._fillOrganismSelect = function (genome) {
+  var self = this;
+  return self.getServerConnector().getReferenceGenomeOrganisms().then(function (organisms) {
+    var genomeOrganismSelect = $("[name=genomeOrganismSelect]", self.getElement());
+    genomeOrganismSelect.empty();
+    var selectedOrganism;
+    if (self.isNew()) {
+      selectedOrganism = organisms[0];
+      for (var i = 0; i < organisms.length; i++) {
+        if (organisms[i].getResource() === "9606") {
+          selectedOrganism = organisms[i];
+        }
+      }
+    } else {
+      selectedOrganism = genome.getOrganism();
+    }
+    $.each(organisms, function (i, organism) {
+      var disable = false;
+      if (organism.getResource() !== selectedOrganism.getResource() && !self.isNew()) {
+        disable = true;
+      }
+      genomeOrganismSelect.append($('<option>', {
+        value: organism.getResource(),
+        text: organism.getResource(),
+        disabled: disable
+      }));
+    });
+    genomeOrganismSelect.val(selectedOrganism.getResource());
+    return self._fillTypeSelect(genome, selectedOrganism);
+  });
+};
+
+/**
+ *
+ * @param {ReferenceGenome} genome
+ * @param {Annotation} selectedOrganism
+ * @returns {Promise}
+ * @private
+ */
+EditGenomeDialog.prototype._fillTypeSelect = function (genome, selectedOrganism) {
+  var self = this;
+  return self.getServerConnector().getReferenceGenomeTypes({organism: selectedOrganism}).then(function (types) {
+
+    var genomeTypeSelect = $("[name=genomeTypeSelect]", self.getElement());
+    genomeTypeSelect.empty();
+
+    var selectedType;
+    if (self.isNew()) {
+      selectedType = types[0].type;
+    } else {
+      selectedType = genome.getType();
+    }
+    $.each(types, function (i, type) {
+      var disable = false;
+      if (type.type !== selectedType && !self.isNew()) {
+        disable = true;
+      }
+      genomeTypeSelect.append($('<option>', {
+        value: type.type,
+        text: type.type,
+        disabled: disable
+      }));
+    });
+    genomeTypeSelect.val(selectedType);
+    return self._fillVersionSelect(genome, selectedOrganism, selectedType);
+  })
+};
+
+/**
+ *
+ * @param {ReferenceGenome} genome
+ * @param {Annotation} selectedOrganism
+ * @param {string} selectedType
+ * @returns {Promise}
+ * @private
+ */
+EditGenomeDialog.prototype._fillVersionSelect = function (genome, selectedOrganism, selectedType) {
+  var self = this;
+  return self.getServerConnector().getReferenceGenomeVersions({
+    organism: selectedOrganism,
+    type: selectedType
+  }).then(function (versions) {
+    var genomeVersionSelect = $("[name=genomeVersionSelect]", self.getElement());
+    genomeVersionSelect.empty();
+
+    var selectedVersion;
+    if (self.isNew()) {
+      selectedVersion = versions[0].version;
+    } else {
+      selectedVersion = genome.getVersion();
+    }
+    $.each(versions, function (i, version) {
+      var disable = false;
+      if (version.version !== selectedVersion && !self.isNew()) {
+        disable = true;
+      }
+      genomeVersionSelect.append($('<option>', {
+        value: version.version,
+        text: version.version,
+        disabled: disable
+      }));
+    });
+    genomeVersionSelect.val(selectedVersion);
+    return self._fillUrl(genome, selectedOrganism, selectedType, selectedVersion);
+  })
+};
+
+/**
+ *
+ * @param {ReferenceGenome} genome
+ * @param {Annotation} organism
+ * @param {string} type
+ * @param {string} version
+ * @returns {Promise}
+ * @private
+ */
+EditGenomeDialog.prototype._fillUrl = function (genome, organism, type, version) {
+  var self = this;
+  var genomeSourceUrlInput = $("[name=genomeSourceUrl]", self.getElement());
+  var genomeLocalUrlInput = $("[name=genomeLocalUrl]", self.getElement());
+  var genomeProgressInput = $("[name=genomeProgress]", self.getElement());
+  genomeLocalUrlInput.prop("disabled", true);
+  genomeProgressInput.val(genome.getDownloadProgressStatus());
+  genomeProgressInput.prop("disabled", true);
+  if (!self.isNew()) {
+    genomeSourceUrlInput.val(genome.getSourceUrl());
+    genomeSourceUrlInput.prop("disabled", true);
+
+    genomeLocalUrlInput.val(genome.getLocalUrl());
+  } else {
+    genomeSourceUrlInput.prop("disabled", false);
+
+    genomeLocalUrlInput.val("");
+    return self.getServerConnector().getAvailableGenomeUrls({
+      organism: organism,
+      type: type,
+      version: version
+    }).then(function (urls) {
+      if (urls.length > 0) {
+        genomeSourceUrlInput.val(urls[0]);
+      } else {
+        genomeSourceUrlInput.val("");
+      }
+    })
+  }
+  return Promise.resolve();
+}
+;
+
+
+/**
+ *
+ * @param {ReferenceGenomeGeneMapping} geneMapping
+ * @returns {Array}
+ */
+EditGenomeDialog.prototype.geneMappingToTableRow = function (geneMapping) {
+  var row = [];
+  row[0] = geneMapping.getName();
+  row[1] = geneMapping.getSourceUrl();
+  row[2] = geneMapping.getProgress();
+  row[3] = "<button name='removeMapping' data='" + geneMapping.getId() + "'><i class='fa fa-trash-o' style='font-size:17px'></button>";
+  return row;
+};
+/**
+ *
+ * @returns {Promise}
+ */
+EditGenomeDialog.prototype.init = function () {
+  var self = this;
+
+  var detailsTable = $("[name=detailsTable]", self.getElement())[0];
+
+  // noinspection JSCheckFunctionSignatures
+  $(detailsTable).DataTable({
+    columns: [{
+      title: "Name"
+    }, {
+      title: "Value"
+    }],
+    paging: false,
+    ordering: false,
+    searching: false,
+    bInfo: false
+  });
+
+  return self.refresh();
+};
+
+/**
+ *
+ * @returns {Promise}
+ */
+EditGenomeDialog.prototype.refresh = function () {
+  var self = this;
+
+  var genome = self.getReferenceGenome();
+
+  var dataTable = $("[name=detailsTable]", self.getElement()).DataTable();
+  var data = [];
+
+  data.push(['Organism', Functions.createElement({type: "select", name: "genomeOrganismSelect"}).outerHTML]);
+  data.push(['Type', Functions.createElement({type: "select", name: "genomeTypeSelect"}).outerHTML]);
+  data.push(['Version', Functions.createElement({type: "select", name: "genomeVersionSelect"}).outerHTML]);
+  data.push(['Source url', Functions.createElement({type: "input", name: "genomeSourceUrl"}).outerHTML]);
+  data.push(['Local url', Functions.createElement({type: "input", name: "genomeLocalUrl"}).outerHTML]);
+  data.push(['Progress', Functions.createElement({type: "input", name: "genomeProgress"}).outerHTML]);
+
+  dataTable.clear().rows.add(data).draw();
+
+  dataTable = $("[name=geneMappingTable]", self.getElement()).DataTable();
+  data = [];
+  var page = dataTable.page();
+
+  for (var i = 0; i < genome.getGeneMappings().length; i++) {
+    var geneMapping = genome.getGeneMappings()[i];
+    var rowData = self.geneMappingToTableRow(geneMapping);
+    data.push(rowData);
+  }
+  //it should be simplified, but I couldn't make it work
+  dataTable.clear().rows.add(data).page(page).draw(false).page(page).draw(false);
+
+  return self._fillOrganismSelect(genome);
+};
+
+/**
+ *
+ */
+EditGenomeDialog.prototype.destroy = function () {
+  var self = this;
+  var div = self.getElement();
+
+  var detailsTable = $("[name=detailsTable]", div)[0];
+  if ($.fn.DataTable.isDataTable(detailsTable)) {
+    $(detailsTable).DataTable().destroy();
+  }
+
+  var geneMappingTable = $("[name=geneMappingTable]", div)[0];
+  if ($.fn.DataTable.isDataTable(geneMappingTable)) {
+    $(geneMappingTable).DataTable().destroy();
+  }
+
+  if ($(div).hasClass("ui-dialog-content")) {
+    $(div).dialog("destroy");
+  }
+};
+
+/**
+ *
+ */
+EditGenomeDialog.prototype.open = function () {
+  var self = this;
+  var div = self.getElement();
+  var title;
+  if (self.isNew()) {
+    title = "Download genome";
+  } else {
+    var genome = self.getReferenceGenome();
+    title = genome.getType() + " " + genome.getOrganism().getResource() + " " + genome.getVersion();
+  }
+  if (!$(div).hasClass("ui-dialog-content")) {
+    $(div).dialog({
+      title: title,
+      width: window.innerWidth / 2,
+      height: window.innerHeight / 2
+    });
+  }
+  $(div).dialog("open");
+};
+
+/**
+ *
+ */
+EditGenomeDialog.prototype.close = function () {
+  var self = this;
+  $(self.getElement()).dialog("close");
+};
+
+/**
+ *
+ * @returns {Annotation}
+ */
+EditGenomeDialog.prototype.getSelectedOrganism = function () {
+  var self = this;
+  return new Annotation({
+    resource: ($("[name='genomeOrganismSelect']", self.getElement()).val()).toString(),
+    link: '',
+    id: 0,
+    type: ''
+  })
+};
+
+/**
+ *
+ * @returns {string}
+ */
+EditGenomeDialog.prototype.getSelectedType = function () {
+  var self = this;
+  return ($("[name='genomeTypeSelect']", self.getElement()).val()).toString();
+};
+
+/**
+ *
+ * @returns {string}
+ */
+EditGenomeDialog.prototype.getSelectedVersion = function () {
+  var self = this;
+  return ($("[name='genomeVersionSelect']", self.getElement()).val()).toString();
+};
+
+/**
+ *
+ * @returns {string}
+ */
+EditGenomeDialog.prototype.getSourceUrl = function () {
+  var self = this;
+  return ($("[name='genomeSourceUrl']", self.getElement()).val()).toString();
+};
+
+/**
+ *
+ */
+EditGenomeDialog.prototype.openAddGeneMapping = function () {
+  var self = this;
+  var html = '<form style="z-index:10000"><span>Name: </span><input type="text" name="gene-mapping-name"><br>' +
+    '<span>Url: </span><input type="text" name="gene-mapping-url"><br></form>';
+  $(html).dialog({
+    modal: true,
+    title: "Add gene mapping",
+    close: function () {
+      $(this).dialog('destroy').remove();
+    },
+    buttons: {
+      'ADD': function () {
+        var dialog = this;
+        var name = $('input[name="gene-mapping-name"]').val().toString();
+        var url = $('input[name="gene-mapping-url"]').val().toString();
+        return self.getServerConnector().addGeneMapping({
+          genomeId: self.getReferenceGenome().getId(),
+          mappingName: name,
+          mappingUrl: url
+        }).then(function () {
+          return self.getServerConnector().getReferenceGenome({genomeId: self.getReferenceGenome().getId()});
+        }).then(function (referenceGenome) {
+          self.setReferenceGenome(referenceGenome);
+          return self.refresh();
+        }).then(function () {
+          $(dialog).dialog('destroy').remove();
+        });
+      },
+      'Cancel': function () {
+        $(this).dialog('destroy').remove();
+      }
+    }
+  });
+};
+
+module.exports = EditGenomeDialog;
diff --git a/frontend-js/src/main/js/gui/admin/EditProjectDialog.js b/frontend-js/src/main/js/gui/admin/EditProjectDialog.js
index dc3e4c6681148590e707f5f9075ed2aab1ce43b1..4e1127816fd5763d179ea7f7d3d66bce21ae5b04 100644
--- a/frontend-js/src/main/js/gui/admin/EditProjectDialog.js
+++ b/frontend-js/src/main/js/gui/admin/EditProjectDialog.js
@@ -138,22 +138,22 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
   var self = this;
   var project = self.getProject();
 
-  var result = new Functions.createElement({
+  var result = Functions.createElement({
     type: "div"
   });
 
-  var table = new Functions.createElement({
+  var table = Functions.createElement({
     type: "div",
     style: "display:table"
   });
   result.appendChild(table);
 
-  var projectIdRow = new Functions.createElement({
+  var projectIdRow = Functions.createElement({
     type: "div",
     style: "display:table-row"
   });
   table.appendChild(projectIdRow);
-  projectIdRow.appendChild(new Functions.createElement({
+  projectIdRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "ProjectId"
@@ -204,46 +204,46 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
     })
   }));
 
-  var nameRow = new Functions.createElement({
+  var nameRow = Functions.createElement({
     type: "div",
     style: "display:table-row"
   });
   table.appendChild(nameRow);
-  nameRow.appendChild(new Functions.createElement({
+  nameRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "Name"
   }));
-  nameRow.appendChild(new Functions.createElement({
+  nameRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "<input name='projectName' value='" + xss(project.getName()) + "'/>",
     xss: false
   }));
 
-  var versionRow = new Functions.createElement({
+  var versionRow = Functions.createElement({
     type: "div",
     style: "display:table-row"
   });
   table.appendChild(versionRow);
-  versionRow.appendChild(new Functions.createElement({
+  versionRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "Version"
   }));
-  versionRow.appendChild(new Functions.createElement({
+  versionRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "<input name='projectVersion' value='" + xss(project.getVersion()) + "'/>",
     xss: false
   }));
 
-  var diseaseRow = new Functions.createElement({
+  var diseaseRow = Functions.createElement({
     type: "div",
     style: "display:table-row"
   });
   table.appendChild(diseaseRow);
-  diseaseRow.appendChild(new Functions.createElement({
+  diseaseRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "Disease"
@@ -252,19 +252,19 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
   if (project.getDisease() !== undefined) {
     disease = xss(project.getDisease().getResource());
   }
-  diseaseRow.appendChild(new Functions.createElement({
+  diseaseRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "<input name='projectDisease' value='" + disease + "'/>",
     xss: false
   }));
 
-  var organismRow = new Functions.createElement({
+  var organismRow = Functions.createElement({
     type: "div",
     style: "display:table-row"
   });
   table.appendChild(organismRow);
-  organismRow.appendChild(new Functions.createElement({
+  organismRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "Organism"
@@ -273,19 +273,19 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
   if (project.getOrganism() !== undefined) {
     organism = xss(project.getOrganism().getResource());
   }
-  organismRow.appendChild(new Functions.createElement({
+  organismRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "<input name='projectOrganism' value='" + organism + "'/>",
     xss: false
   }));
 
-  var emailRow = new Functions.createElement({
+  var emailRow = Functions.createElement({
     type: "div",
     style: "display:table-row"
   });
   table.appendChild(emailRow);
-  emailRow.appendChild(new Functions.createElement({
+  emailRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "Notify email"
@@ -294,7 +294,7 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
   if (project.getNotifyEmail() !== undefined) {
     email = xss(project.getNotifyEmail());
   }
-  emailRow.appendChild(new Functions.createElement({
+  emailRow.appendChild(Functions.createElement({
     type: "div",
     style: "display:table-cell",
     content: "<input name='projectNotifyEmail' value='" + email + "'/>",
@@ -962,7 +962,8 @@ EditProjectDialog.prototype.openAddOverlayDialog = function () {
   self._addOverlayDialog = new AddOverlayDialog({
     project: self.getProject(),
     customMap: null,
-    element: document.createElement("div")
+    element: document.createElement("div"),
+    configuration: self.getConfiguration()
   });
   self._addOverlayDialog.addListener("onAddOverlay", function () {
     return self.refreshOverlays();
diff --git a/frontend-js/src/main/js/gui/admin/EditUserDialog.js b/frontend-js/src/main/js/gui/admin/EditUserDialog.js
index 6b631121bd8f81047778829264d5299aaed40cd0..3030c8cab407a8ce2f5c38275cba2f4acd858435 100644
--- a/frontend-js/src/main/js/gui/admin/EditUserDialog.js
+++ b/frontend-js/src/main/js/gui/admin/EditUserDialog.js
@@ -145,12 +145,12 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
 
   var self = this;
 
-  var result = new Functions.createElement({
+  var result = Functions.createElement({
     type: "div",
     style: "margin-top:10px;"
   });
 
-  var table = new Functions.createElement({
+  var table = Functions.createElement({
     type: "table",
     name: "detailsTable",
     className: "display",
diff --git a/frontend-js/src/main/js/gui/admin/GenomeAdminPanel.js b/frontend-js/src/main/js/gui/admin/GenomeAdminPanel.js
new file mode 100644
index 0000000000000000000000000000000000000000..7abf854ec353de6035bb7ca3caf24739982c2efd
--- /dev/null
+++ b/frontend-js/src/main/js/gui/admin/GenomeAdminPanel.js
@@ -0,0 +1,326 @@
+"use strict";
+
+var AbstractAdminPanel = require('./AbstractAdminPanel');
+var EditGenomeDialog = require('./EditGenomeDialog');
+
+var Functions = require('../../Functions');
+var GuiConnector = require('../../GuiConnector');
+var PrivilegeType = require('../../map/data/PrivilegeType');
+var ReferenceGenome = require('../../map/data/ReferenceGenome');
+
+// noinspection JSUnusedLocalSymbols
+var logger = require('../../logger');
+
+var Promise = require('bluebird');
+
+/**
+ *
+ * @param {Configuration} params.configuration
+ * @param {HTMLElement} params.element
+ *
+ * @constructor
+ */
+function GenomeAdminPanel(params) {
+  params["panelName"] = "genomes";
+  AbstractAdminPanel.call(this, params);
+
+  var self = this;
+  $(self.getElement()).addClass("minerva-genome-tab");
+
+  self._createGui();
+}
+
+GenomeAdminPanel.prototype = Object.create(AbstractAdminPanel.prototype);
+GenomeAdminPanel.prototype.constructor = GenomeAdminPanel;
+
+/**
+ *
+ * @private
+ */
+GenomeAdminPanel.prototype._createGui = function () {
+  var self = this;
+  var genomeDiv = Functions.createElement({
+    type: "div"
+  });
+  self.getElement().appendChild(genomeDiv);
+
+  genomeDiv.appendChild(self._createMenuRow());
+
+  var genomesTable = Functions.createElement({
+    type: "table",
+    name: "genomeTable",
+    className: "display",
+    style: "width:100%"
+  });
+  genomeDiv.appendChild(genomesTable);
+
+  // noinspection JSUnusedGlobalSymbols
+  $(genomesTable).DataTable({
+    columns: [{
+      title: 'Type'
+    }, {
+      title: 'Organism'
+    }, {
+      title: 'Version'
+    }, {
+      title: 'Progress'
+    }, {
+      title: 'Source'
+    }, {
+      title: 'Edit',
+      orderable: false
+    }, {
+      title: 'Remove',
+      orderable: false
+    }],
+    order: [[1, "asc"]]
+  });
+  self.bindUserGuiPreference({
+    jQueryObject: $(genomesTable),
+    event: 'length.dt',
+    preferenceName: 'admin-genome-datatable-length',
+    defaultValue: '10',
+    getter: function () {
+      return $(genomesTable).DataTable().page.len() + '';
+    },
+    setter: function (value) {
+      return $(genomesTable).DataTable().page.len(value).draw();
+    }
+  });
+
+  $(genomesTable).on("click", "[name='removeGenome']", function () {
+    var button = this;
+    return self.askConfirmRemoval({
+      title: "INFO",
+      content: "Do you really want to remove this genome?",
+      input: false
+    }).then(function (param) {
+      if (param.status) {
+        return self.getServerConnector().removeReferenceGenome({genomeId: $(button).attr("data")});
+      }
+    }).catch(GuiConnector.alert);
+  });
+
+  $(genomesTable).on("click", "[name='editGenome']", function () {
+    var button = this;
+    return self.showEditDialog(parseInt($(button).attr("data"))).catch(GuiConnector.alert);
+  });
+
+  genomeDiv.appendChild(self._createMenuRow());
+
+};
+
+/**
+ *
+ * @returns {HTMLElement}
+ * @private
+ */
+GenomeAdminPanel.prototype._createMenuRow = function () {
+  var self = this;
+  var menuRow = Functions.createElement({
+    type: "div",
+    className: "minerva-menu-row",
+    style: "display:table-row; margin:10px"
+  });
+
+  var addProjectButton = Functions.createElement({
+    type: "button",
+    name: "addGenome",
+    content: '<span class="ui-icon ui-icon-circle-plus"></span>&nbsp;ADD GENOME',
+    onclick: function () {
+      return self.onAddClicked().catch(GuiConnector.alert);
+    },
+    xss: false
+  });
+  var refreshButton = Functions.createElement({
+    type: "button",
+    name: "refreshGenomes",
+    content: '<span class="ui-icon ui-icon-refresh"></span>&nbsp;REFRESH',
+    onclick: function () {
+      return self.onRefreshClicked().catch(GuiConnector.alert);
+    },
+    xss: false
+  });
+  menuRow.appendChild(addProjectButton);
+  menuRow.appendChild(refreshButton);
+  return menuRow;
+};
+
+/**
+ *
+ * @returns {Promise}
+ */
+GenomeAdminPanel.prototype.init = function () {
+  var self = this;
+  return AbstractAdminPanel.prototype.init.call(this).then(function () {
+    return self.getServerConnector().getLoggedUser();
+  }).then(function (user) {
+    if (user.hasPrivilege(self.getConfiguration().getPrivilegeType(PrivilegeType.MANAGE_GENOMES))) {
+      return self.onRefreshClicked();
+    } else {
+      self.disablePanel("You have no privilege to manage genomes");
+    }
+  });
+};
+
+/**
+ *
+ * @returns {Promise}
+ */
+GenomeAdminPanel.prototype.onRefreshClicked = function () {
+  var self = this;
+  return self.getServerConnector().getReferenceGenomes().then(function (referenceGenomes) {
+    return self.setReferenceGenomes(referenceGenomes);
+  });
+};
+
+/**
+ *
+ * @param {ReferenceGenome[]} referenceGenomes
+ *
+ * @returns {Promise}
+ *
+ */
+GenomeAdminPanel.prototype.setReferenceGenomes = function (referenceGenomes) {
+  var self = this;
+
+  return self.getServerConnector().getLoggedUser().then(function (user) {
+
+    var dataTable = $("[name='genomeTable']", self.getElement()).DataTable();
+    var data = [];
+    var page = dataTable.page();
+
+    for (var i = 0; i < referenceGenomes.length; i++) {
+      var genome = referenceGenomes[i];
+      var rowData = self.genomeToTableRow(genome, user);
+      data.push(rowData);
+    }
+    //it should be simplified, but I couldn't make it work
+    dataTable.clear().rows.add(data).page(page).draw(false).page(page).draw(false);
+  })
+};
+
+/**
+ *
+ * @param {ReferenceGenome} genome
+ * @param {User} user
+ * @returns {Array}
+ */
+GenomeAdminPanel.prototype.genomeToTableRow = function (genome, user) {
+  var self = this;
+  var row = [];
+
+  row[0] = genome.getType();
+  row[1] = self.getGuiUtils().createAnnotationLink(genome.getOrganism()).outerHTML;
+  row[2] = genome.getVersion();
+  row[3] = genome.getDownloadProgressStatus();
+  row[4] = genome.getSourceUrl();
+
+  var disabled = " disabled ";
+  if (user.hasPrivilege(self.getConfiguration().getPrivilegeType(PrivilegeType.MANAGE_GENOMES))) {
+    disabled = "";
+  }
+  row[5] = "<button name='editGenome' data='" + genome.getId() + "'" + disabled + "><i class='fa fa-edit' style='font-size:17px'></i></button>";
+  row[6] = "<button name='removeGenome' data='" + genome.getId() + "'" + disabled + "><i class='fa fa-trash-o' style='font-size:17px'></button>";
+  return row;
+};
+
+
+/**
+ *
+ * @returns {Promise}
+ */
+GenomeAdminPanel.prototype.destroy = function () {
+  var self = this;
+  var table = $("[name='genomeTable']", self.getElement())[0];
+  if ($.fn.DataTable.isDataTable(table)) {
+    $(table).DataTable().destroy();
+  }
+  var promises = [];
+  for (var key in self._dialogs) {
+    if (self._dialogs.hasOwnProperty(key)) {
+      promises.push(self._dialogs[key].destroy());
+    }
+  }
+  promises.push(AbstractAdminPanel.prototype.destroy.call(self));
+
+  return Promise.all(promises);
+};
+
+/**
+ *
+ * @param {ReferenceGenome} [genome]
+ * @returns {Promise}
+ */
+GenomeAdminPanel.prototype.getDialog = function (genome) {
+  var self = this;
+  if (self._dialogs === undefined) {
+    self._dialogs = [];
+  }
+  var id = genome.getId();
+  var dialog = self._dialogs[id];
+  if (dialog === undefined) {
+    dialog = new EditGenomeDialog({
+      element: Functions.createElement({
+        type: "div"
+      }),
+      configuration: self.getConfiguration(),
+      referenceGenome: genome,
+      customMap: null,
+      serverConnector: self.getServerConnector()
+    });
+    self._dialogs[id] = dialog;
+    if (id === undefined) {
+      dialog.addListener("onSave", function () {
+        return self.onRefreshClicked();
+      });
+    }
+    return dialog.init().then(function () {
+      return dialog;
+    });
+  } else {
+    return Promise.resolve(dialog);
+  }
+};
+
+/**
+ *
+ * @param {number} id
+ * @returns {Promise}
+ */
+GenomeAdminPanel.prototype.showEditDialog = function (id) {
+  var self = this;
+  GuiConnector.showProcessing();
+  return self.getServerConnector().getReferenceGenome({genomeId: id}).then(function (referenceGenome) {
+    if (referenceGenome === null) {
+      referenceGenome = new ReferenceGenome();
+    }
+    return self.getDialog(referenceGenome);
+  }).then(function (dialog) {
+    dialog.open();
+    GuiConnector.hideProcessing();
+  }).catch(function (error) {
+    GuiConnector.hideProcessing();
+    return Promise.reject(error);
+  });
+};
+
+/**
+ *
+ * @returns {Promise}
+ */
+GenomeAdminPanel.prototype.onAddClicked = function () {
+  var self = this;
+  GuiConnector.showProcessing();
+  var referenceGenome = new ReferenceGenome();
+  return self.getDialog(referenceGenome).then(function (dialog) {
+    dialog.open();
+    GuiConnector.hideProcessing();
+  }).catch(function (error) {
+    GuiConnector.hideProcessing();
+    return Promise.reject(error);
+  });
+};
+
+
+module.exports = GenomeAdminPanel;
diff --git a/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js b/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js
index 3bef291f7e7061ae3c636eeaf0018d63937e08bf..1bbc720da8c241f3792adc69edae5d5705e3f409 100644
--- a/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js
+++ b/frontend-js/src/main/js/gui/admin/UsersAdminPanel.js
@@ -6,7 +6,6 @@ var PrivilegeType = require('../../map/data/PrivilegeType');
 
 var AbstractAdminPanel = require('./AbstractAdminPanel');
 var EditUserDialog = require('./EditUserDialog');
-var SecurityError = require('../../SecurityError');
 
 var User = require("../../map/data/User");
 
@@ -15,6 +14,13 @@ var GuiConnector = require('../../GuiConnector');
 // noinspection JSUnusedLocalSymbols
 var logger = require('../../logger');
 
+/**
+ *
+ * @param {Object} params
+ *
+ * @constructor
+ * @extends AbstractAdminPanel
+ */
 function UsersAdminPanel(params) {
   var self = this;
   AbstractAdminPanel.call(self, params);
@@ -25,6 +31,10 @@ function UsersAdminPanel(params) {
 UsersAdminPanel.prototype = Object.create(AbstractAdminPanel.prototype);
 UsersAdminPanel.prototype.constructor = UsersAdminPanel;
 
+/**
+ *
+ * @private
+ */
 UsersAdminPanel.prototype._createGui = function () {
   var self = this;
   var usersDiv = Functions.createElement({
@@ -44,6 +54,11 @@ UsersAdminPanel.prototype._createGui = function () {
 
 };
 
+/**
+ *
+ * @returns {HTMLElement}
+ * @private
+ */
 UsersAdminPanel.prototype._createMenuRow = function () {
   var self = this;
   var menuRow = Functions.createElement({
@@ -75,6 +90,11 @@ UsersAdminPanel.prototype._createMenuRow = function () {
   return menuRow;
 };
 
+/**
+ *
+ * @returns {HTMLElement}
+ * @private
+ */
 UsersAdminPanel.prototype._createUsersTableRow = function () {
   var self = this;
   var projectsRow = Functions.createElement({
@@ -90,7 +110,7 @@ UsersAdminPanel.prototype._createUsersTableRow = function () {
   });
   projectsRow.appendChild(usersTable);
 
-  // noinspection JSUnusedGlobalSymbols
+  // noinspection JSCheckFunctionSignatures
   $(usersTable).DataTable({
     fnRowCallback: function (nRow, aData) {
       nRow.setAttribute('id', aData[0]);
@@ -103,6 +123,8 @@ UsersAdminPanel.prototype._createUsersTableRow = function () {
       title: 'Surname'
     }, {
       title: 'Email'
+    }, {
+      title: 'Authentication'
     }, {
       title: 'Edit'
     }, {
@@ -136,6 +158,24 @@ UsersAdminPanel.prototype._createUsersTableRow = function () {
     }).catch(GuiConnector.alert);
   });
 
+  $(usersTable).on("click", "[name='ldap-auth']", function () {
+    var field = this;
+    var login = $(this).attr('data');
+    GuiConnector.showProcessing();
+    return self.getServerConnector().getUser(login).then(function (user) {
+      var newIsConnected = $('input:checked', field).val() === "LDAP";
+      var isConnected = user.isConnectedToLdap();
+      if (isConnected !== newIsConnected) {
+        user.setConnectedToLdap(newIsConnected);
+        return self.getServerConnector().updateUser(user);
+      }
+    }).catch(function (error) {
+      GuiConnector.alert(error);
+    }).finally(function(){
+      GuiConnector.hideProcessing();
+    });
+  });
+
   $(usersTable).on("click", "[name='showEditDialog']", function () {
     var button = this;
     return self.showEditDialog($(button).attr("data")).then(null, GuiConnector.alert);
@@ -144,10 +184,15 @@ UsersAdminPanel.prototype._createUsersTableRow = function () {
   return projectsRow;
 };
 
+/**
+ *
+ * @param {String} login
+ * @returns {Promise}
+ */
 UsersAdminPanel.prototype.showEditDialog = function (login) {
   var self = this;
   GuiConnector.showProcessing();
-  return ServerConnector.getUser(login).then(function (user) {
+  return self.getServerConnector().getUser(login).then(function (user) {
     return self.getDialog(user);
   }).then(function (dialog) {
     dialog.open();
@@ -158,6 +203,11 @@ UsersAdminPanel.prototype.showEditDialog = function (login) {
   });
 };
 
+/**
+ *
+ * @param {User} user
+ * @returns {Promise}
+ */
 UsersAdminPanel.prototype.getDialog = function (user) {
   var self = this;
   if (self._dialogs === undefined) {
@@ -186,14 +236,18 @@ UsersAdminPanel.prototype.getDialog = function (user) {
   }
 };
 
+/**
+ *
+ * @returns {Promise}
+ */
 UsersAdminPanel.prototype.init = function () {
   var self = this;
   return AbstractAdminPanel.prototype.init.call(this).then(function () {
-    return ServerConnector.getLoggedUser();
+    return self.getServerConnector().getLoggedUser();
   }).then(function (user) {
     var privilege = self.getConfiguration().getPrivilegeType(PrivilegeType.USER_MANAGEMENT);
     if (user.hasPrivilege(privilege)) {
-      return ServerConnector.getUsers().then(function (users) {
+      return self.getServerConnector().getUsers().then(function (users) {
         return self.setUsers(users);
       });
     } else {
@@ -202,6 +256,10 @@ UsersAdminPanel.prototype.init = function () {
   });
 };
 
+/**
+ *
+ * @param {User[]} users
+ */
 UsersAdminPanel.prototype.setUsers = function (users) {
   var self = this;
   var dataTable = $($("[name='usersTable']", self.getElement())[0]).DataTable();
@@ -218,6 +276,11 @@ UsersAdminPanel.prototype.setUsers = function (users) {
 };
 
 
+/**
+ *
+ * @param {User} user
+ * @param {Array} dataTableRow
+ */
 UsersAdminPanel.prototype.addUpdateListener = function (user, dataTableRow) {
   var self = this;
 
@@ -241,7 +304,12 @@ UsersAdminPanel.prototype.addUpdateListener = function (user, dataTableRow) {
   user.addListener("onreload", listener);
 };
 
-
+/**
+ *
+ * @param {User} user
+ * @param {Array} [row]
+ * @returns {Array}
+ */
 UsersAdminPanel.prototype.userToTableRow = function (user, row) {
   if (row === undefined) {
     row = [];
@@ -251,20 +319,39 @@ UsersAdminPanel.prototype.userToTableRow = function (user, row) {
   row[1] = user.getName();
   row[2] = user.getSurname();
   row[3] = user.getEmail();
-  row[4] = "<button name='showEditDialog' data='" + user.getLogin() + "'><i class='fa fa-edit' style='font-size:17px'></i></button>";
-  row[5] = "<button name='removeUser' data='" + user.getLogin() + "'><i class='fa fa-trash-o' style='font-size:17px'></i></button>";
+  var ldapFieldId = 'ldap-auth-' + user.getLogin();
+  if (user.isConnectedToLdap()) {
+    row[4] = "<fieldset name='ldap-auth' id='" + ldapFieldId + "' data='" + user.getLogin() + "'> <input type='radio' name='" + ldapFieldId + "' value='LOCAL'> LOCAL <input type='radio' name='" + ldapFieldId + "' checked value='LDAP'> LDAP </fieldset>";
+  } else {
+    if (user.isLdapAccountAvailable()) {
+      row[4] = "<fieldset name='ldap-auth' id='" + ldapFieldId + "' data='" + user.getLogin() + "'> <input type='radio' name='" + ldapFieldId + "' value='LOCAL' checked> LOCAL <input type='radio' name='" + ldapFieldId + "' value='LDAP'> LDAP </fieldset>";
+      // row[4] = "LOCAL <button name='connectLdap' data='" + user.getLogin() + "'>CONNECT LDAP</button>"
+    } else {
+      row[4] = "<fieldset name='ldap-auth' id='" + ldapFieldId + "' data='" + user.getLogin() + "'> <input type='radio' name='" + ldapFieldId + "' value='LOCAL' checked> LOCAL</fieldset>";
+    }
+  }
+
+  row[5] = "<button name='showEditDialog' data='" + user.getLogin() + "'><i class='fa fa-edit' style='font-size:17px'></i></button>";
+  row[6] = "<button name='removeUser' data='" + user.getLogin() + "'><i class='fa fa-trash-o' style='font-size:17px'></i></button>";
 
   return row;
 };
 
+/**
+ *
+ * @returns {Promise}
+ */
 UsersAdminPanel.prototype.onRefreshClicked = function () {
   var self = this;
-  return ServerConnector.getUsers(true).then(function (users) {
+  return self.getServerConnector().getUsers(true).then(function (users) {
     return self.setUsers(users);
   });
 };
 
 
+/**
+ *
+ */
 UsersAdminPanel.prototype.destroy = function () {
   var self = this;
   var table = $("[name='usersTable']", self.getElement())[0];
@@ -277,9 +364,12 @@ UsersAdminPanel.prototype.destroy = function () {
       self._dialogs[key].destroy();
     }
   }
-
 };
 
+/**
+ *
+ * @returns {Promise}
+ */
 UsersAdminPanel.prototype.onAddClicked = function () {
   var self = this;
   var user = new User({});
@@ -293,10 +383,15 @@ UsersAdminPanel.prototype.onAddClicked = function () {
   });
 };
 
+/**
+ *
+ * @param {string} login
+ * @returns {Promise}
+ */
 UsersAdminPanel.prototype.removeUser = function (login) {
   var self = this;
   GuiConnector.showProcessing();
-  return ServerConnector.removeUser(login).then(function () {
+  return self.getServerConnector().removeUser(login).then(function () {
     return self.onRefreshClicked();
   }).then(function () {
     GuiConnector.hideProcessing();
diff --git a/frontend-js/src/main/js/gui/leftPanel/AbstractDbPanel.js b/frontend-js/src/main/js/gui/leftPanel/AbstractDbPanel.js
index 73fa48f126b94db5707701045588809b343fc77f..8d5c6d84f7e3159aeea25af7454d251187e11601 100644
--- a/frontend-js/src/main/js/gui/leftPanel/AbstractDbPanel.js
+++ b/frontend-js/src/main/js/gui/leftPanel/AbstractDbPanel.js
@@ -208,12 +208,12 @@ AbstractPanel.prototype.refreshSearchResults = function () {
     promises.push(searchDb.getElementsByQuery(queries[i]));
   }
   return Promise.all(promises).then(function (results) {
-    for (var i = 0; i < queries.length; i++) {
-      self.addResultTab(queries[i], results[i]);
-    }
+    return Promise.each(queries, function(query, index){
+      return self.addResultTab(query, results[index]);
+    });
+  }).then(function(){
     self.onresize();
   });
-
 };
 
 AbstractPanel.prototype.getAutocomplete = function () {
@@ -225,6 +225,7 @@ AbstractPanel.prototype.searchByQuery = function () {
 };
 
 AbstractPanel.prototype.addResultTab = function (query, elements) {
+  var self = this;
   var name = JSON.parse(query).query;
 
   var tabId = this.getPanelName() + "Tab_" + this._tabIdCount;
@@ -277,13 +278,29 @@ AbstractPanel.prototype.addResultTab = function (query, elements) {
   var tableBody = document.createElement("tbody");
   tableDiv.appendChild(tableBody);
 
-  for (var i = 0; i < elements.length; i++) {
-    var element = elements[i].element;
-    var icon = elements[i].icon;
-    tableBody.appendChild(this.createTableElement(element, icon));
-  }
+  return Promise.each(elements, function (entry) {
+    var element = entry.element;
+    var icon = entry.icon;
+    return self.createTableElement(element, icon).then(function (div) {
+      return tableBody.appendChild(div);
+    });
+  });
+};
+
+/**
+ *
+ * @returns {Promise<HTMLTableRowElement>}
+ */
+AbstractPanel.prototype.createTableElement = function () {
+  throw new Error("Not implemented");
 };
 
+/**
+ *
+ * @param {Target} target
+ * @param {string} icon
+ * @returns {Promise<HTMLTableRowElement>}
+ */
 AbstractPanel.prototype.createTargetRow = function (target, icon) {
   var self = this;
   var guiUtils = self.getGuiUtils();
@@ -349,7 +366,7 @@ AbstractPanel.prototype.createTargetRow = function (target, icon) {
       descColumn.appendChild(button);
     }
   }
-  return result;
+  return Promise.resolve(result);
 };
 
 AbstractPanel.prototype.computeAutocompleteDictionary = function (queries) {
diff --git a/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js b/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js
index 931d88743cb4d3bbbc23cc1ed577d39d26de896d..e1b3d6fa419a879bf18c388d3bebeafea431b6ae 100644
--- a/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js
+++ b/frontend-js/src/main/js/gui/leftPanel/GenericSearchPanel.js
@@ -48,6 +48,12 @@ GenericSearchPanel.prototype.createSearchGui = function () {
   searchDiv.appendChild(perfectMatchLabel);
 };
 
+/**
+ *
+ * @param {SearchBioEntityGroup|BioEntity} element
+ * @param {string} icon
+ * @returns {Promise<HTMLTableRowElement>}
+ */
 GenericSearchPanel.prototype.createTableElement = function (element, icon) {
   if (element instanceof Alias) {
     return this.createAliasElement(element, icon);
@@ -64,6 +70,11 @@ GenericSearchPanel.prototype.createPreamble = function () {
   return document.createElement("div");
 };
 
+/**
+ *
+ * @param {Reaction} reaction
+ * @returns {Promise<HTMLTableRowElement>}
+ */
 GenericSearchPanel.prototype.createReactionElement = function (reaction) {
   var self = this;
   var guiUtils = self.getGuiUtils();
@@ -71,15 +82,19 @@ GenericSearchPanel.prototype.createReactionElement = function (reaction) {
   var td = document.createElement("td");
   result.appendChild(td);
 
-  var div = guiUtils.createReactionElement({
-    reaction: reaction
-  });
-
-  div.appendChild(guiUtils.createSeparator());
-  td.appendChild(div);
-  return result;
+  return guiUtils.createReactionElement({reaction: reaction}).then((function (div) {
+    div.appendChild(guiUtils.createSeparator());
+    td.appendChild(div);
+    return result;
+  }));
 };
 
+/**
+ *
+ * @param {Alias} alias
+ * @param {string} icon
+ * @returns {Promise<HTMLTableRowElement>}
+ */
 GenericSearchPanel.prototype.createAliasElement = function (alias, icon) {
   var self = this;
   var guiUtils = self.getGuiUtils();
@@ -87,30 +102,37 @@ GenericSearchPanel.prototype.createAliasElement = function (alias, icon) {
   var result = document.createElement("tr");
   var td = document.createElement("td");
   result.appendChild(td);
-  var div = guiUtils.createAliasElement({
+  return guiUtils.createAliasElement({
     alias: alias,
     icon: icon
-  });
+  }).then(function (div) {
+    div.appendChild(guiUtils.createSeparator());
+    td.appendChild(div);
 
-  div.appendChild(guiUtils.createSeparator());
-  td.appendChild(div);
+    return result;
+  });
 
-  return result;
 };
 
-GenericSearchPanel.prototype.createSearchBioEntityGroupElement = function (group, icon) {
+/**
+ *
+ * @param {SearchBioEntityGroup} group
+ * @returns {Promise<HTMLTableRowElement>}
+ */
+GenericSearchPanel.prototype.createSearchBioEntityGroupElement = function (group) {
   var self = this;
   var guiUtils = self.getGuiUtils();
 
   var result = document.createElement("tr");
   var td = document.createElement("td");
   result.appendChild(td);
-  var div = guiUtils.createSearchBioEntityGroupElement(group);
+  return guiUtils.createSearchBioEntityGroupElement(group).then(function (div) {
+    div.appendChild(guiUtils.createSeparator());
+    td.appendChild(div);
 
-  div.appendChild(guiUtils.createSeparator());
-  td.appendChild(div);
+    return result;
+  });
 
-  return result;
 };
 
 GenericSearchPanel.prototype.searchByQuery = function () {
diff --git a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js
index 69fdb3189da3886e905e2d97aa212d47a9481715..37c7cb0f4c0e25753841dfdb4462072ee0cd6b74 100644
--- a/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js
+++ b/frontend-js/src/main/js/gui/leftPanel/GuiUtils.js
@@ -4,6 +4,9 @@
 
 var Alias = require('../../map/data/Alias');
 var ConfigurationType = require('../../ConfigurationType');
+var IdentifiedElement = require('../../map/data/IdentifiedElement');
+var SearchBioEntityGroup = require('../../map/data/SearchBioEntityGroup');
+
 
 var GuiConnector = require('../../GuiConnector');
 var AbstractGuiElement = require('../AbstractGuiElement');
@@ -12,8 +15,15 @@ var Functions = require('../../Functions');
 var logger = require('../../logger');
 var xss = require('xss');
 
+var Promise = require('bluebird');
+
 var tabIdCounter = 0;
 
+/**
+ *
+ * @param {Configuration} configuration
+ * @constructor
+ */
 function GuiUtils(configuration) {
   var self = this;
   self.setConfiguration(configuration);
@@ -22,14 +32,27 @@ function GuiUtils(configuration) {
 GuiUtils.prototype = Object.create(AbstractGuiElement.prototype);
 GuiUtils.prototype.constructor = GuiUtils;
 
+/**
+ *
+ * @param {Configuration} configuration
+ */
 GuiUtils.prototype.setConfiguration = function (configuration) {
   this._configuration = configuration;
 };
 
+/**
+ *
+ * @returns {Configuration}
+ */
 GuiUtils.prototype.getConfiguration = function () {
   return this._configuration;
 };
 
+/**
+ *
+ * @param {string} value
+ * @returns {HTMLSpanElement}
+ */
 GuiUtils.prototype.createLabel = function (value) {
   var result = document.createElement("span");
   result.innerHTML = value;
@@ -37,56 +60,117 @@ GuiUtils.prototype.createLabel = function (value) {
   return result;
 };
 
+/**
+ *
+ * @param {Object} modification
+ * @param {string} [modification.name]
+ * @param {string} modification.type
+ * @param {string} [modification.state]
+ *
+ * @returns {HTMLElement| null}
+ */
+GuiUtils.prototype.createModificationRow = function (modification) {
+  var self = this;
+  var row = null;
+  var name = modification.name;
+  var desc = undefined;
+  if (modification.state !== undefined && modification.state !== null) {
+    var modificationStateType = self.getConfiguration().getModificationStateTypeByName(modification.state);
+    var state = modificationStateType.getCommonName();
+
+    if (name !== null && name !== undefined && name !== "") {
+      desc = state + " at position " + name + ", ";
+    } else {
+      desc = state + ",";
+    }
+  } else if (name !== null && name !== undefined && name !== "" &&
+    (modification.type === "BINDING_REGION" ||
+      modification.type === "CODING_REGION" ||
+      modification.type === "PROTEIN_BINDING_DOMAIN" ||
+      modification.type === "TRANSCRIPTION_SITE_LEFT" ||
+      modification.type === "TRANSCRIPTION_SITE_RIGHT" ||
+      modification.type === "REGULATORY_REGION"
+    )) {
+    desc = name + ",";
+  }
+
+  if (desc !== undefined) {
+    row = Functions.createElement({
+      type: "li"
+    });
+    row.appendChild(self.createLabelText(desc));
+  }
+  return row;
+};
+
+/**
+ *
+ * @param {string} label
+ * @param {Object[]} value
+ * @returns {HTMLDivElement}
+ */
 GuiUtils.prototype.createPostTranslationalModifications = function (label, value) {
   var result = document.createElement("div");
+  var count = 0;
   if (value !== undefined && value.length > 0) {
     var self = this;
-    result.appendChild(self.createLabel(label));
+    var userFriendlyLabel = label + ": ";
+    if (label === "RESIDUE") {
+      userFriendlyLabel = "Posttranslational modifications: "
+    } else if (label === "BINDING_REGION") {
+      userFriendlyLabel = "Binding regions: "
+    } else if (label === "CODING_REGION") {
+      userFriendlyLabel = "Coding regions: "
+    } else if (label === "PROTEIN_BINDING_DOMAIN") {
+      userFriendlyLabel = "Protein binding domains: "
+    } else if (label === "TRANSCRIPTION_SITE_LEFT") {
+      userFriendlyLabel = "Transcription sites (left): "
+    } else if (label === "TRANSCRIPTION_SITE_RIGHT") {
+      userFriendlyLabel = "Transcription sites (right): "
+    } else if (label === "TRANSCRIPTION_SITE") {
+      userFriendlyLabel = "Transcription sites: "
+    } else if (label === "MODIFICATION_SITE") {
+      userFriendlyLabel = "Modification sites: "
+    }
+    result.appendChild(self.createLabel(userFriendlyLabel));
     result.appendChild(self.createNewLine());
     var list = Functions.createElement({
       type: "ul"
     });
     for (var i = 0; i < value.length; i++) {
-      var name = value[i].name;
-      var modificationStateType = self.getConfiguration().getModificationStateTypeByName(value[i].state);
-      var state = modificationStateType.getCommonName();
-      var desc;
-      if (name !== null && name !== undefined && name !== "") {
-        desc = state + " at position " + name + ", ";
-      } else {
-        desc = state + ",";
+      var modification = value[i];
+      var row = self.createModificationRow(modification, self);
+      if (row !== null) {
+        list.appendChild(row);
+        count++;
       }
-      var row = Functions.createElement({
-        type: "li"
-      });
-      row.appendChild(self.createLabelText(desc));
-      list.appendChild(row);
     }
     result.appendChild(list);
   }
-  return result;
-};
-
-GuiUtils.prototype.createCandidates = function (label, value) {
-  var result = document.createElement("div");
-  if (value !== undefined) {
-    throw new Error("Not implemented");
+  if (count > 0) {
+    return result;
+  } else {
+    return document.createElement("div");
   }
-  return result;
 };
 
-GuiUtils.prototype.createChebiTree = function (label, value) {
-  var result = document.createElement("div");
-  if (value !== undefined) {
-    throw new Error("Not implemented");
-  }
-  return result;
-};
+/**
+ *
+ * @returns {HTMLHRElement}
+ */
 GuiUtils.prototype.createSeparator = function () {
   return document.createElement("hr");
 };
 
+/**
+ *
+ * @param {number} [count]
+ * @returns {HTMLParagraphElement}
+ */
 GuiUtils.prototype.createNewLine = function (count) {
+  if (count === undefined) {
+    count = 0;
+  }
   var result = document.createElement("p");
   if (count > 0) {
     result.style.height = ((count - 1) * 10) + "px";
@@ -94,14 +178,16 @@ GuiUtils.prototype.createNewLine = function (count) {
   return result;
 };
 
+/**
+ *
+ * @param {string} [url]
+ * @param {string} name
+ * @returns {HTMLElement}
+ */
 GuiUtils.prototype.createLink = function (url, name) {
   if (url === null || url === undefined) {
     logger.warn("URL not defined for: \"" + name + "\" link");
-    return Functions.createElement(
-      {
-        type: "span",
-        content: name
-      });
+    return Functions.createElement({type: "span", content: name});
   }
   var link = document.createElement("a");
   link.href = url;
@@ -111,6 +197,12 @@ GuiUtils.prototype.createLink = function (url, name) {
   return link;
 };
 
+/**
+ *
+ * @param {Annotation} annotation
+ * @param {boolean} [showType=false]
+ * @returns {HTMLElement}
+ */
 GuiUtils.prototype.createAnnotationLink = function (annotation, showType) {
   var self = this;
   var name, type, hint;
@@ -148,6 +240,15 @@ GuiUtils.prototype.createAnnotationLink = function (annotation, showType) {
   }
 };
 
+/**
+ *
+ * @param {string} label
+ * @param {Annotation[]} [value]
+ * @param {Object} [options]
+ * @param {boolean} [options.inline]
+ *
+ * @returns {HTMLDivElement}
+ */
 GuiUtils.prototype.createAnnotations = function (label, value, options) {
   var self = this;
 
@@ -170,9 +271,16 @@ GuiUtils.prototype.createAnnotations = function (label, value, options) {
   return result;
 };
 
+/**
+ *
+ * @param {boolean} inline
+ * @param {string} annotatorClass
+ * @param {Object.<string, Annotator>} annotatorsClassMapping
+ * @param {boolean} groupAnnotations
+ * @returns {HTMLElement}
+ */
 function createGroupContainer(inline, annotatorClass, annotatorsClassMapping, groupAnnotations) {
   var automaticallyAnnotated = !(annotatorClass === undefined || annotatorClass === "undefined" || annotatorClass === null || annotatorClass === "");
-// var desc = grouppedAnnotations.keys()[i];
   var groupContainer = (inline ? document.createElement("span") : document.createElement("div"));
   var descContainer = (inline ? document.createElement("span") : document.createElement("div"));
 
@@ -332,6 +440,11 @@ GuiUtils.prototype.createAnnotationList = function (annotations, options) {
   return result;
 };
 
+/**
+ *
+ * @param {string} [value]
+ * @returns {HTMLSpanElement}
+ */
 GuiUtils.prototype.createLabelText = function (value) {
   var result = document.createElement("span");
   if (value !== undefined) {
@@ -340,6 +453,11 @@ GuiUtils.prototype.createLabelText = function (value) {
   return result;
 };
 
+/**
+ *
+ * @param {string} [value]
+ * @returns {HTMLInputElement}
+ */
 GuiUtils.prototype.createInputText = function (value) {
   var result = document.createElement("input");
   result.setAttribute('type', 'text');
@@ -350,6 +468,11 @@ GuiUtils.prototype.createInputText = function (value) {
   return result;
 };
 
+/**
+ *
+ * @param {string} [value]
+ * @returns {HTMLTextAreaElement}
+ */
 GuiUtils.prototype.createTextArea = function (value) {
   var result = document.createElement("textarea");
 
@@ -360,16 +483,12 @@ GuiUtils.prototype.createTextArea = function (value) {
   return result;
 };
 
-GuiUtils.prototype.createCheckbox = function (value) {
-  var result = document.createElement("input");
-  result.type = "checkbox";
-
-  if (value) {
-    result.checked = true;
-  }
-  return result;
-};
-
+/**
+ *
+ * @param {string} label
+ * @param {string|number} [value]
+ * @returns {HTMLDivElement}
+ */
 GuiUtils.prototype.createParamLine = function (label, value) {
   var result = document.createElement("div");
   if (value !== undefined && value !== null && value !== "") {
@@ -380,6 +499,12 @@ GuiUtils.prototype.createParamLine = function (label, value) {
   return result;
 };
 
+/**
+ *
+ * @param {string} [icon]
+ * @param {function} [onclickFunction]
+ * @returns {HTMLDivElement}
+ */
 GuiUtils.prototype.createIcon = function (icon, onclickFunction) {
   var result = document.createElement("div");
   if (icon !== undefined && icon !== null) {
@@ -395,6 +520,13 @@ GuiUtils.prototype.createIcon = function (icon, onclickFunction) {
   return result;
 };
 
+/**
+ *
+ * @param {string} label
+ * @param {string[]} [value]
+ *
+ * @returns {HTMLDivElement}
+ */
 GuiUtils.prototype.createArrayParamLine = function (label, value) {
   var result = document.createElement("div");
   if (value !== undefined && value.length > 0) {
@@ -405,6 +537,12 @@ GuiUtils.prototype.createArrayParamLine = function (label, value) {
   return result;
 };
 
+/**
+ *
+ * @param {string} label
+ * @param {number} [modelId]
+ * @returns {HTMLDivElement}
+ */
 GuiUtils.prototype.createSubMapLink = function (label, modelId) {
   var self = this;
   var result = document.createElement("div");
@@ -422,6 +560,11 @@ GuiUtils.prototype.createSubMapLink = function (label, modelId) {
   return result;
 };
 
+/**
+ *
+ * @param {Array<string|HTMLElement>} elements
+ * @returns {HTMLElement}
+ */
 GuiUtils.prototype.createTableRow = function (elements) {
   var row = Functions.createElement({
     type: "div",
@@ -443,6 +586,14 @@ GuiUtils.prototype.createTableRow = function (elements) {
   return row;
 };
 
+/**
+ *
+ * @param {Reaction|SearchBioEntityGroup} params.reaction
+ * @param {string} [params.icon]
+ * @param {boolean} [params.showTitle]
+ *
+ * @returns {Promise<HTMLDivElement>}
+ */
 GuiUtils.prototype.createReactionElement = function (params) {
   var reaction = params.reaction;
   var showTitle = ((params.showTitle === undefined) || params.showTitle);
@@ -477,9 +628,44 @@ GuiUtils.prototype.createReactionElement = function (params) {
   div.appendChild(self.createArrayParamLine("Synonyms: ", reaction.getSynonyms()));
   div.appendChild(self.createParamLine("Description: ", reaction.getDescription()));
   div.appendChild(self.createAnnotations("Annotations: ", reaction.getReferences()));
-  return div;
+  return Promise.resolve(div);
 };
 
+/**
+ *
+ * @param {Object[]} modifications
+ *
+ * @returns {HTMLDivElement}
+ */
+GuiUtils.prototype.createModifications = function (modifications) {
+  var self = this;
+  var result = document.createElement("div");
+  var modificationsByType = [];
+  if (modifications !== undefined) {
+    for (var i = 0; i < modifications.length; i++) {
+      var modification = modifications[i];
+      if (modificationsByType[modification.type] === undefined) {
+        modificationsByType[modification.type] = [];
+      }
+      modificationsByType[modification.type].push(modification);
+    }
+    for (var key in modificationsByType) {
+      if (modificationsByType.hasOwnProperty(key)) {
+        result.appendChild(self.createPostTranslationalModifications(key, modificationsByType[key]));
+      }
+    }
+  }
+  return result;
+};
+
+/**
+ *
+ * @param {Alias|SearchBioEntityGroup} params.alias
+ * @param {string} [params.icon]
+ * @param {boolean} [params.showTitle]
+ *
+ * @returns {Promise<HTMLDivElement>}
+ */
 GuiUtils.prototype.createAliasElement = function (params) {
   var alias = params.alias;
   var icon = params.icon;
@@ -505,27 +691,49 @@ GuiUtils.prototype.createAliasElement = function (params) {
       div.appendChild(self.createSubMapLink("In submap: ", alias.getModelId()));
     }
   }
-  if (alias.getLinkedSubmodelId() !== null && alias.getLinkedSubmodelId() !== undefined) {
+  if (alias.getLinkedSubmodelId() !== undefined) {
     div.appendChild(self.createSubMapLink("Associated submap: ", alias.getLinkedSubmodelId()));
   }
+  if (alias instanceof SearchBioEntityGroup && alias.getBioEntities().length > 1) {
+    div.appendChild(self.createLabelText("Group of " + alias.getBioEntities().length + " elements."));
+  }
   if (showTitle) {
     div.appendChild(self.createNewLine(3));
   }
 
-  div.appendChild(self.createParamLine("Full name: ", alias.getFullName()));
-  div.appendChild(self.createParamLine("Symbol: ", alias.getSymbol()));
-  div.appendChild(self.createParamLine("Abbreviation: ", alias.getAbbreviation()));
-  div.appendChild(self.createParamLine("Formula: ", alias.getFormula()));
-  div.appendChild(self.createArrayParamLine("Former symbols: ", alias.getFormerSymbols()));
-  div.appendChild(self.createPostTranslationalModifications("PostTranslational modifications: ", alias
-    .getOther('modifications')));
-  div.appendChild(self.createParamLine("Charge: ", alias.getCharge()));
-  div.appendChild(self.createArrayParamLine("Synonyms: ", alias.getSynonyms()));
-  div.appendChild(self.createLabelText(alias.getDescription()));
-  // div.appendChild(self.createChebiTree("Chebi ontology: ", alias.getOther('chebiTree')));
-  div.appendChild(self.createAnnotations("Annotations: ", alias.getReferences()));
-  return div;
+  var promise = Promise.resolve();
+  if (alias.getCompartmentId() !== undefined) {
+    promise = self.getMap().getModel().getByIdentifiedElement(new IdentifiedElement({
+      type: "ALIAS",
+      id: alias.getCompartmentId(),
+      modelId: alias.getModelId()
+    }), true).then(function (compartment) {
+      div.appendChild(self.createParamLine("Compartment: ", compartment.getName()));
+    })
+  }
+
+  return promise.then(function () {
+
+    div.appendChild(self.createParamLine("Full name: ", alias.getFullName()));
+    div.appendChild(self.createParamLine("Symbol: ", alias.getSymbol()));
+    div.appendChild(self.createParamLine("Abbreviation: ", alias.getAbbreviation()));
+    div.appendChild(self.createParamLine("Formula: ", alias.getFormula()));
+    div.appendChild(self.createArrayParamLine("Former symbols: ", alias.getFormerSymbols()));
+    div.appendChild(self.createModifications(alias.getOther('modifications')));
+    div.appendChild(self.createParamLine("Charge: ", alias.getCharge()));
+    div.appendChild(self.createArrayParamLine("Synonyms: ", alias.getSynonyms()));
+    div.appendChild(self.createLabelText(alias.getDescription()));
+    div.appendChild(self.createAnnotations("Annotations: ", alias.getReferences()));
+
+    return div;
+  })
 };
+
+/**
+ *
+ * @param {SearchBioEntityGroup} group
+ * @returns {Promise<HTMLDivElement>}
+ */
 GuiUtils.prototype.createSearchBioEntityGroupElement = function (group) {
   if (group.getBioEntities()[0] instanceof Alias) {
     return this.createAliasElement({alias: group, icon: group.getIcon()});
@@ -534,6 +742,10 @@ GuiUtils.prototype.createSearchBioEntityGroupElement = function (group) {
   }
 };
 
+/**
+ *
+ * @returns {HTMLAnchorElement}
+ */
 GuiUtils.prototype.createLogoutLink = function () {
   var logoutLink = document.createElement("a");
   logoutLink.href = "#";
@@ -545,6 +757,14 @@ GuiUtils.prototype.createLogoutLink = function () {
   return logoutLink;
 };
 
+/**
+ *
+ * @param {string} params.name
+ * @param {string} params.id
+ * @param {HTMLElement} params.navigationBar
+ *
+ * @returns {HTMLLIElement}
+ */
 GuiUtils.prototype.createTabMenuObject = function (params) {
   var name = params.name;
   var id = params.id;
@@ -573,6 +793,13 @@ GuiUtils.prototype.createTabMenuObject = function (params) {
   return navLi;
 };
 
+/**
+ *
+ * @param {string} params.id
+ * @param {HTMLElement} params.navigationObject
+ *
+ * @returns {HTMLDivElement}
+ */
 GuiUtils.prototype.createTabContentObject = function (params) {
   var navigationObject = params.navigationObject;
   var tabId = params.id;
@@ -589,6 +816,13 @@ GuiUtils.prototype.createTabContentObject = function (params) {
   return result;
 };
 
+/**
+ *
+ * @param {HTMLElement} [params.element]
+ * @param {string} params.id
+ *
+ * @returns {{element: HTMLElement, menu: HTMLElement, content: HTMLElement, tabId: *}}
+ */
 GuiUtils.prototype.createTabDiv = function (params) {
   var tabDiv = Functions.createElement({
     type: "div",
@@ -608,7 +842,7 @@ GuiUtils.prototype.createTabDiv = function (params) {
   });
   tabDiv.appendChild(tabContentDiv);
 
-  if (params !== undefined && params.element !== undefined) {
+  if (params.element !== undefined) {
     params.element.appendChild(tabDiv);
   }
 
@@ -621,7 +855,6 @@ GuiUtils.prototype.createTabDiv = function (params) {
 };
 
 GuiUtils.prototype.createTab = function (params) {
-  var self = this;
   var tabData = params.tabData;
 
   var tabId = tabData.tabId + "_tab_" + tabIdCounter;
@@ -669,6 +902,12 @@ GuiUtils.prototype.createTab = function (params) {
   }
 };
 
+/**
+ *
+ * @param {string} toolTip
+ * @param {boolean} [useXss=false]
+ * @returns {HTMLElement}
+ */
 GuiUtils.prototype.createHelpButton = function (toolTip, useXss) {
   var helpContent;
   if (useXss) {
diff --git a/frontend-js/src/main/js/gui/leftPanel/LeftPanel.js b/frontend-js/src/main/js/gui/leftPanel/LeftPanel.js
index 2b19d922e08d63f12ab54a814bee478ed133f4f7..7a6942a1f5717649a9d6315bc0cac209373ca2bc 100644
--- a/frontend-js/src/main/js/gui/leftPanel/LeftPanel.js
+++ b/frontend-js/src/main/js/gui/leftPanel/LeftPanel.js
@@ -20,6 +20,19 @@ var SubmapPanel = require('./SubmapPanel');
 var Functions = require('../../Functions');
 var logger = require('../../logger');
 
+/**
+ *
+ * @param {Object} params
+ * @param {HTMLElement} params.element
+ * @param {CustomMap} params.customMap
+ * @param {Configuration} params.configuration
+ * @param {Project} [params.project]
+ * @param {ServerConnector} [params.serverConnector]
+ *
+ * @constructor
+ *
+ * @extends AbstractGuiElement
+ */
 function LeftPanel(params) {
   AbstractGuiElement.call(this, params);
   var self = this;
@@ -174,9 +187,13 @@ LeftPanel.prototype.showElementDetails = function (element) {
 
   if (element !== undefined && openTabName !== undefined && (openTabName.indexOf("SEARCH") === -1 || searchTabName !== "GENERIC")) {
     var model = self.getMap().getSubmapById(element.getModelId()).getModel();
-    return model.getByIdentifiedElement(element, true).then(function (bioEntity) {
+    var bioEntity;
+    return model.getByIdentifiedElement(element, true).then(function (result) {
+      bioEntity=result;
+      return self.prepareElementDetailsContent(bioEntity);
+    }).then(function(elementDetailsDiv){
       div.innerHTML = "";
-      div.appendChild(self.prepareElementDetailsContent(bioEntity));
+      div.appendChild(elementDetailsDiv);
       $(div).dialog("open");
       $(div).dialog("option", "title", self.getElementTitle(bioEntity));
       $(div).scrollTop(0);
@@ -187,6 +204,12 @@ LeftPanel.prototype.showElementDetails = function (element) {
   }
 };
 
+/**
+ *
+ * @param {BioEntity} bioEntity
+ *
+ * @returns {Promise<HTMLDivElement>}
+ */
 LeftPanel.prototype.prepareElementDetailsContent = function (bioEntity) {
   var guiUtils = this.getGuiUtils();
   if (bioEntity instanceof Reaction) {
@@ -200,14 +223,18 @@ LeftPanel.prototype.prepareElementDetailsContent = function (bioEntity) {
       showTitle: false
     });
   } else if (bioEntity instanceof PointData) {
-    return Functions.createElement({
+    return Promise.resolve(Functions.createElement({
       type: "div"
-    });
+    }));
   } else {
     throw new Error("Unknown element type:" + bioEntity);
   }
 };
 
+/**
+ *
+ * @returns {GuiUtils}
+ */
 LeftPanel.prototype.getGuiUtils = function () {
   var self = this;
   if (self._guiUtils === undefined) {
@@ -217,6 +244,11 @@ LeftPanel.prototype.getGuiUtils = function () {
   return self._guiUtils;
 };
 
+/**
+ *
+ * @param {BioEntity} bioEntity
+ * @returns {string}
+ */
 LeftPanel.prototype.getElementTitle = function (bioEntity) {
   if (bioEntity instanceof Reaction) {
     return bioEntity.getType() + ": " + bioEntity.getReactionId();
@@ -255,6 +287,7 @@ LeftPanel.prototype.addTab = function (params, tabData) {
   this._panels.push(new params.panelClass({
     element: data.content,
     customMap: self.getMap(),
+    configuration: self.getConfiguration(),
     parent: self
   }));
 
diff --git a/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js b/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
index 4c9637d4d214f24ed873af3045610f3a38840892..862b8f9f46349a84796d866ffea8f3016e8cca71 100644
--- a/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
+++ b/frontend-js/src/main/js/gui/leftPanel/OverlayPanel.js
@@ -16,11 +16,12 @@ var Promise = require('bluebird');
 /**
  *
  * @param {Object} params
- * @param {Configuration} [params.configuration]
  * @param {HTMLElement} params.element
- * @param {Project} params.project
  * @param {CustomMap} params.customMap
+ * @param {Configuration} [params.configuration]
+ * @param {Project} [params.project]
  * @param params.parent
+ *
  * @constructor
  * @extends Panel
  */
@@ -30,6 +31,9 @@ function OverlayPanel(params) {
   params["helpTip"] = "<p>Overlays tab allows to display or generate custom coloring of elements and interactions in the map.</p>"
     + "<p>General overlays are overlays accessible for every user viewing the content.</p>"
     + "<p>Custom overlays are user-provided overlays, this menu becomes available upon login (see below).</p>";
+  if (params.project === undefined) {
+    params.project = params.customMap.getProject();
+  }
   Panel.call(this, params);
 
   //overflow is defined in minerva-overlay-panel, so remove the one that is already there
@@ -211,8 +215,8 @@ OverlayPanel.prototype.createTableHeader = function (edit) {
 /**
  *
  * @param {DataOverlay} overlay
- * @param {boolean} checked
- * @param {boolean} disabled
+ * @param {boolean} [checked=false]
+ * @param {boolean} [disabled=false]
  * @returns {HTMLElement}
  */
 OverlayPanel.prototype.createOverlayRow = function (overlay, checked, disabled) {
@@ -549,7 +553,8 @@ OverlayPanel.prototype.openAddOverlayDialog = function () {
   self._addOverlayDialog = new AddOverlayDialog({
     project: self.getProject(),
     customMap: self.getMap(),
-    element: document.createElement("div")
+    element: document.createElement("div"),
+    configuration: self.getConfiguration()
   });
   self._addOverlayDialog.addListener("onAddOverlay", function (e) {
     self.getProject().addDataOverlay(e.arg);
diff --git a/frontend-js/src/main/js/map/AbstractCustomMap.js b/frontend-js/src/main/js/map/AbstractCustomMap.js
index 967fff2cb0a0ce4e92bdb9664a8decb529c778e7..03f7119a22234b8e84ddcd4af47f08c9e4ce3627 100644
--- a/frontend-js/src/main/js/map/AbstractCustomMap.js
+++ b/frontend-js/src/main/js/map/AbstractCustomMap.js
@@ -9,6 +9,7 @@ var AliasInfoWindow = require('./window/AliasInfoWindow');
 var AliasSurface = require('./surface/AliasSurface');
 var GuiConnector = require('../GuiConnector');
 var IdentifiedElement = require('./data/IdentifiedElement');
+var LayoutAlias = require('./data/LayoutAlias');
 var ObjectWithListeners = require('../ObjectWithListeners');
 var MapModel = require('./data/MapModel');
 var Point = require('./canvas/Point');
@@ -362,65 +363,127 @@ AbstractCustomMap.prototype._showSelectedDataOverlay = function (overlayId, inde
   // end ratio
   var endX = (index + 1) * (1.0 / length);
 
-  var overlayAliases;
-  var overlayReactions;
-
   return self.getProject().getDataOverlayById(overlayId).then(function (overlay) {
-    overlayAliases = overlay.getAliases();
-    overlayReactions = overlay.getReactions();
+    return Promise.all([self._showDataOverlayAliases(overlay, startX, endX),
+      self._showDataOverlayReactions(overlay, length === 1)
+    ]);
+  });
+};
 
-    var i, identifiedElements = [];
-    for (i = 0; i < overlayAliases.length; i++) {
-      if (overlayAliases[i].getModelId() === self.getId()) {
-        identifiedElements.push(new IdentifiedElement(overlayAliases[i]));
-      }
+/**
+ *
+ * @param {DataOverlay} overlay
+ * @param {number} startX
+ * @param {number} endX
+ *
+ * @returns {Promise|PromiseLike}
+ * @private
+ */
+AbstractCustomMap.prototype._showDataOverlayAliases = function (overlay, startX, endX) {
+  var self = this;
+  var overlayAliases = overlay.getAliases();
+  var overlayAliasesOnMap = [];
+
+  var i, identifiedElements = [];
+  var usedAliasIds = [];
+  var overlayMapIds = [];
+  for (i = 0; i < overlayAliases.length; i++) {
+    if (overlayMapIds[overlayAliases[i].getModelId()] === undefined) {
+      overlayMapIds[overlayAliases[i].getModelId()] = [];
     }
-    for (i = 0; i < overlayReactions.length; i++) {
-      if (overlayReactions[i].getModelId() === self.getId()) {
-        identifiedElements.push(new IdentifiedElement(overlayReactions[i]));
+    overlayMapIds[overlayAliases[i].getModelId()].push(overlayAliases[i]);
+
+    if (overlayAliases[i].getModelId() === self.getId()) {
+      identifiedElements.push(new IdentifiedElement(overlayAliases[i]));
+      overlayAliasesOnMap.push(overlayAliases[i]);
+      usedAliasIds[overlayAliases[i].getId()] = true;
+    }
+  }
+  var elementsPointingToSubmapPromises = [];
+  for (var mapId in overlayMapIds) {
+    elementsPointingToSubmapPromises.push(self.getProject().getElementsPointingToSubmap(parseInt(mapId)));
+  }
+  return Promise.all(elementsPointingToSubmapPromises).then(function (elementsPointingToSubmap) {
+    for (var i = 0; i < elementsPointingToSubmap.length; i++) {
+      var row = elementsPointingToSubmap[i];
+      for (var j = 0; j < row.length; j++) {
+        var identifiedElement = row[j];
+        if (identifiedElement.getModelId() === self.getId() && !usedAliasIds[identifiedElement.getId()]) {
+          usedAliasIds[identifiedElement.getId()] = true;
+          overlayAliasesOnMap.push(new LayoutAlias({
+            idObject: identifiedElement.getId(),
+            modelId: identifiedElement.getModelId(),
+            value: 0
+          }));
+        }
       }
     }
-    return self.getModel().getByIdentifiedElements(identifiedElements, false);
+    return self.getModel().getByIdentifiedElements(identifiedElements, false)
   }).then(function () {
-    return Promise.each(overlayAliases, function (overlayAlias) {
-      if (overlayAlias.getModelId() === self.getId()) {
-        return self.getModel().getAliasById(overlayAlias.getId()).then(function (aliasData) {
-          var surface = new AliasSurface({
-            overlayAlias: overlayAlias,
-            alias: aliasData,
-            map: self,
-            startX: startX,
-            endX: endX,
-            onClick: [function () {
-              return self.getTopMap().getOverlayByName("search").searchByTarget(new IdentifiedElement(aliasData));
-            }, function () {
-              return self.getTopMap().callListeners("onBioEntityClick", new IdentifiedElement(aliasData));
-            }]
-          });
-          self.selectedLayoutOverlays[overlayId].push(surface);
-          return surface.show();
+    return Promise.each(overlayAliasesOnMap, function (overlayAlias) {
+      return self.getModel().getAliasById(overlayAlias.getId()).then(function (aliasData) {
+        var overlayData;
+        if (aliasData.getLinkedSubmodelId() !== undefined && overlayMapIds[aliasData.getLinkedSubmodelId()] !== undefined) {
+          overlayData = overlayMapIds[aliasData.getLinkedSubmodelId()];
+        } else {
+          overlayData = [overlayAlias];
+        }
+        var surface = new AliasSurface({
+          overlayData: overlayData,
+          alias: aliasData,
+          map: self,
+          startX: startX,
+          endX: endX,
+          onClick: [function () {
+            return self.getTopMap().getOverlayByName("search").searchByTarget(new IdentifiedElement(aliasData));
+          }, function () {
+            return self.getTopMap().callListeners("onBioEntityClick", new IdentifiedElement(aliasData));
+          }]
         });
-      }
+        self.selectedLayoutOverlays[overlay.getId()].push(surface);
+        return surface.show();
+      });
     });
-  }).then(function () {
-    return Promise.each(overlayReactions, function (overlayReaction) {
-      if (overlayReaction.getModelId() === self.getId()) {
-        return self.getModel().getReactionById(overlayReaction.getId()).then(function (reactionData) {
-          var surface = new ReactionSurface({
-            layoutReaction: overlayReaction,
-            reaction: reactionData,
-            map: self,
-            onClick: [function () {
-              return self.getTopMap().getOverlayByName("search").searchByTarget(new IdentifiedElement(reactionData));
-            }, function () {
-              return self.getTopMap().callListeners("onBioEntityClick", new IdentifiedElement(reactionData));
-            }],
-            customized: (length === 1)
-          });
-          self.selectedLayoutOverlays[overlayId].push(surface);
-          return surface.show();
+  });
+};
+
+/**
+ *
+ * @param {DataOverlay} overlay
+ * @param {boolean} customized
+ *
+ * @returns {Promise}
+ * @private
+ */
+AbstractCustomMap.prototype._showDataOverlayReactions = function (overlay, customized) {
+  var self = this;
+  var overlayReactions = overlay.getReactions();
+  var overlayReactionsOnMap = [];
+
+  var i, identifiedElements = [];
+  for (i = 0; i < overlayReactions.length; i++) {
+    if (overlayReactions[i].getModelId() === self.getId()) {
+      identifiedElements.push(new IdentifiedElement(overlayReactions[i]));
+      overlayReactionsOnMap.push(overlayReactions[i]);
+    }
+  }
+  return self.getModel().getByIdentifiedElements(identifiedElements, false).then(function () {
+    return Promise.each(overlayReactionsOnMap, function (overlayReaction) {
+      return self.getModel().getReactionById(overlayReaction.getId()).then(function (reactionData) {
+        var surface = new ReactionSurface({
+          layoutReaction: overlayReaction,
+          reaction: reactionData,
+          map: self,
+          onClick: [function () {
+            return self.getTopMap().getOverlayByName("search").searchByTarget(new IdentifiedElement(reactionData));
+          }, function () {
+            return self.getTopMap().callListeners("onBioEntityClick", new IdentifiedElement(reactionData));
+          }],
+          customized: customized
         });
-      }
+        self.selectedLayoutOverlays[overlay.getId()].push(surface);
+        return surface.show();
+      });
     });
   });
 };
@@ -440,7 +503,7 @@ AbstractCustomMap.prototype._hideSelectedLayout = function (overlayId) {
     return Promise.resolve();
   }
 
-  var promises =[];
+  var promises = [];
   for (var i = 0; i < this.selectedLayoutOverlays[overlayId].length; i++) {
     promises.push(this.selectedLayoutOverlays[overlayId][i].hide());
   }
@@ -508,27 +571,6 @@ AbstractCustomMap.prototype._openInfoWindowForAlias = function (alias, marker) {
   }
 };
 
-/**
- * Returns promise of a list of {@link LayoutAlias} information for a given
- * {@link Alias} in all currently visualized overlays.
- *
- * @param {number} aliasId
- *          identifier of the {@link Alias}
- * @returns {PromiseLike<LayoutAlias[]>| Promise<LayoutAlias[]>} promise of an {Array} with list of {@link LayoutAlias} information
- *          for a given {@link Alias} in all currently visualized overlays
- */
-AbstractCustomMap.prototype.getAliasVisibleLayoutsData = function (aliasId) {
-  var self = this;
-  return self.getTopMap().getVisibleDataOverlays().then(function (visibleDataOverlays) {
-    var result = [];
-    for (var i = 0; i < visibleDataOverlays.length; i++) {
-      var overlay = visibleDataOverlays[i];
-      result.push(overlay.getFullAliasById(aliasId));
-    }
-    return Promise.all(result);
-  });
-};
-
 /**
  * Opens {@link ReactionInfoWindow} for given reaction identifier.
  *
diff --git a/frontend-js/src/main/js/map/OverlayParser.js b/frontend-js/src/main/js/map/OverlayParser.js
index 72fc466358ac3bc06fb988402834959eca341687..320c0b936c4e09eedceea040c4c5f88e58eb7541 100644
--- a/frontend-js/src/main/js/map/OverlayParser.js
+++ b/frontend-js/src/main/js/map/OverlayParser.js
@@ -7,6 +7,11 @@ var TextDecoder = require('text-encoding').TextDecoder;
 function OverlayParser() {
 }
 
+/**
+ *
+ * @param {string| Uint8Array|ArrayBuffer} content
+ * @returns {DataOverlay}
+ */
 OverlayParser.prototype.parse = function (content) {
   if (content instanceof Uint8Array || content instanceof ArrayBuffer) {
     content = new TextDecoder("UTF8").decode(content);
diff --git a/frontend-js/src/main/js/map/canvas/Bounds.js b/frontend-js/src/main/js/map/canvas/Bounds.js
index 210e7484774d27156809bd26498fa32e75cb9352..0cbc6b1f2c88c2616b0248973d5c194bae2bee46 100644
--- a/frontend-js/src/main/js/map/canvas/Bounds.js
+++ b/frontend-js/src/main/js/map/canvas/Bounds.js
@@ -73,4 +73,16 @@ Bounds.prototype.contains = function (point) {
 
 };
 
+/**
+ *
+ * @returns {string}
+ */
+Bounds.prototype.toString = function () {
+  if (this._topLeft === undefined) {
+    return "[NaN]";
+  } else {
+    return "[" + this._topLeft.x + "," + this._topLeft.y + "]-[" + this._rightBottom.x + "," + this._rightBottom.y + "]";
+  }
+};
+
 module.exports = Bounds;
diff --git a/frontend-js/src/main/js/map/canvas/GoogleMaps/GoogleMapsApiCanvas.js b/frontend-js/src/main/js/map/canvas/GoogleMaps/GoogleMapsApiCanvas.js
index 60fb32554f4e23ad3d96ca0f92effd87d5ff3821..2e465b34a8d719c99c9ab9127745803fb3f875e3 100644
--- a/frontend-js/src/main/js/map/canvas/GoogleMaps/GoogleMapsApiCanvas.js
+++ b/frontend-js/src/main/js/map/canvas/GoogleMaps/GoogleMapsApiCanvas.js
@@ -232,9 +232,9 @@ GoogleMapsApiCanvas.prototype.createMarker = function (options) {
 /**
  *
  * @param {Bounds} options.bounds
- * @param {string} options.id
- * @param {number} options.fillOpacity
  * @param {string} options.fillColor
+ * @param {number} options.fillOpacity
+ * @param {string} options.id
  * @param {string} options.strokeColor
  * @param {number} options.strokeOpacity
  * @param {number} options.strokeWeight
diff --git a/frontend-js/src/main/js/map/canvas/GoogleMaps/GoogleMapsApiRectangle.js b/frontend-js/src/main/js/map/canvas/GoogleMaps/GoogleMapsApiRectangle.js
index 97ac9369942a054c256d233fc99e2d10c6ee237a..4490ef861d517ddaf4ce19f58270f3e6fa497c62 100644
--- a/frontend-js/src/main/js/map/canvas/GoogleMaps/GoogleMapsApiRectangle.js
+++ b/frontend-js/src/main/js/map/canvas/GoogleMaps/GoogleMapsApiRectangle.js
@@ -1,21 +1,23 @@
 "use strict";
 
-var Rectangle = require('../Rectangle');
 var Bounds = require('../Bounds');
+var Point = require('../Point');
+var Rectangle = require('../Rectangle');
 
 // noinspection JSUnusedLocalSymbols
 var logger = require('../../../logger');
 
 /**
  *
- * @param {MapCanvas} options.map
+ * @param {GoogleMapsApiCanvas} options.map
  * @param {Bounds} options.bounds
- * @param {MapCanvas} options.fillOpacity
- * @param {number} options.id
- * @param {number} options.strokeWeight
- * @param {string} options.fillColor
+ * @param {string} [options.fillColor]
+ * @param {{color: string, amount: number}[]} [options.fillGradient]
+ * @param {number} options.fillOpacity
+ * @param {string} options.id
  * @param {string} options.strokeColor
  * @param {number} options.strokeOpacity
+ * @param {number} options.strokeWeight
  *
  * @constructor
  * @extends Rectangle
@@ -24,24 +26,67 @@ function GoogleMapsApiRectangle(options) {
   Rectangle.call(this, options);
 
   var self = this;
+  self._rectangles = [];
+
+
+  var i;
+  var bounds;
+  if (options.fillGradient !== undefined) {
+    var totalAmount = 0;
+    for (i = 0; i < options.fillGradient.length; i++) {
+      totalAmount += options.fillGradient[i].amount;
+    }
+    var y = options.bounds.getTopLeft().y;
+    for (i = 0; i < options.fillGradient.length; i++) {
+      var x1 = options.bounds.getTopLeft().x;
+      var x2 = options.bounds.getRightBottom().x;
+      var y1 = y;
+      var ratio = options.fillGradient[i].amount / totalAmount;
+
+      var y2 = y1 + ratio * (options.bounds.getRightBottom().y - options.bounds.getTopLeft().y);
+      y = y2;
+      bounds = new google.maps.LatLngBounds();
+      bounds.extend(self.getMap().fromPointToLatLng(new Point(x1, y1)));
+      bounds.extend(self.getMap().fromPointToLatLng(new Point(x2, y2)));
+      self.addGoogleRectangle(new google.maps.Rectangle({
+        bounds: bounds,
+        fillOpacity: options.fillOpacity,
+        strokeWeight: 0.0,
+        fillColor: options.fillGradient[i].color
+      }));
+    }
+    bounds = new google.maps.LatLngBounds();
+    bounds.extend(self.getMap().fromPointToLatLng(options.bounds.getTopLeft()));
+    bounds.extend(self.getMap().fromPointToLatLng(options.bounds.getRightBottom()));
+    self.addGoogleRectangle(new google.maps.Rectangle({
+      bounds: bounds,
+      fillOpacity: 0.0,
+      id: options.id,
+      strokeWeight: options.strokeWeight,
+      strokeColor: options.strokeColor,
+      strokeOpacity: options.strokeOpacity
+    }));
+  } else {
+    bounds = new google.maps.LatLngBounds();
+    bounds.extend(self.getMap().fromPointToLatLng(options.bounds.getTopLeft()));
+    bounds.extend(self.getMap().fromPointToLatLng(options.bounds.getRightBottom()));
+    self.addGoogleRectangle(new google.maps.Rectangle({
+      bounds: bounds,
+      fillOpacity: options.fillOpacity,
+      id: options.id,
+      strokeWeight: options.strokeWeight,
+      fillColor: options.fillColor,
+      strokeColor: options.strokeColor,
+      strokeOpacity: options.strokeOpacity
+    }));
+  }
 
-  var bounds = new google.maps.LatLngBounds();
-  bounds.extend(this.getMap().fromPointToLatLng(options.bounds.getTopLeft()));
-  bounds.extend(this.getMap().fromPointToLatLng(options.bounds.getRightBottom()));
-
-  this.setGoogleRectangle(new google.maps.Rectangle({
-    bounds: bounds,
-    fillOpacity: options.fillOpacity,
-    id: options.id,
-    strokeWeight: options.strokeWeight,
-    fillColor: options.fillColor,
-    strokeColor: options.strokeColor,
-    strokeOpacity: options.strokeOpacity
-  }));
-
-  google.maps.event.addListener(this.getGoogleRectangle(), "click", function(){
-    return self.callListeners("click");
-  });
+  var rectangles = self.getGoogleRectangles();
+  for (i = 0; i < rectangles.length; i++) {
+    google.maps.event.addListener(rectangles[i], "click", function () {
+      return self.callListeners("click");
+    });
+  }
 }
 
 GoogleMapsApiRectangle.prototype = Object.create(Rectangle.prototype);
@@ -51,33 +96,31 @@ GoogleMapsApiRectangle.prototype.constructor = GoogleMapsApiRectangle;
  *
  * @param {google.maps.Rectangle} rectangle
  */
-GoogleMapsApiRectangle.prototype.setGoogleRectangle = function (rectangle) {
-  this._rectangle = rectangle;
+GoogleMapsApiRectangle.prototype.addGoogleRectangle = function (rectangle) {
+  this._rectangles.push(rectangle);
 };
 
 /**
  *
- * @returns {google.maps.Rectangle}
+ * @returns {google.maps.Rectangle[]}
  */
-GoogleMapsApiRectangle.prototype.getGoogleRectangle = function () {
-  return this._rectangle;
+GoogleMapsApiRectangle.prototype.getGoogleRectangles = function () {
+  return this._rectangles;
 };
 
 GoogleMapsApiRectangle.prototype.show = function () {
-  var googleRectangle = this.getGoogleRectangle();
-  if (googleRectangle.getMap() !== undefined && googleRectangle.getMap() !== null) {
-    logger.warn("Rectangle is already shown");
-  }
-  else {
-    googleRectangle.setMap(this.getMap().getGoogleMap());
+  var rectangles = this.getGoogleRectangles();
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    rectangle.setMap(this.getMap().getGoogleMap());
   }
 };
 
 GoogleMapsApiRectangle.prototype.hide = function () {
-  if (!this.isShown()) {
-    logger.warn("Rectangle is already invisible");
-  } else {
-    this.getGoogleRectangle().setMap(null);
+  var rectangles = this.getGoogleRectangles();
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    rectangle.setMap(null);
   }
 };
 
@@ -86,19 +129,40 @@ GoogleMapsApiRectangle.prototype.hide = function () {
  * @returns {boolean}
  */
 GoogleMapsApiRectangle.prototype.isShown = function () {
-  var googleRectangle = this.getGoogleRectangle();
-  return googleRectangle.getMap() !== null && googleRectangle.getMap() !== undefined;
+  var rectangles = this.getGoogleRectangles();
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    if (rectangle.getMap() !== null && rectangle.getMap() !== undefined) {
+      return true;
+    }
+  }
+  return false;
 };
 
 /**
  *
- * @param bounds {Bounds}
+ * @param newBounds {Bounds}
  */
-GoogleMapsApiRectangle.prototype.setBounds = function (bounds) {
-  var latLngBounds = new google.maps.LatLngBounds();
-  latLngBounds.extend(this.getMap().fromPointToLatLng(bounds.getTopLeft()));
-  latLngBounds.extend(this.getMap().fromPointToLatLng(bounds.getRightBottom()));
-  this.getGoogleRectangle().setBounds(latLngBounds);
+GoogleMapsApiRectangle.prototype.setBounds = function (newBounds) {
+  var oldBounds = this.getBounds();
+
+  var rectangles = this.getGoogleRectangles();
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    var rectangleLatLngBounds = rectangle.getBounds();
+    var currentBounds = new Bounds();
+    currentBounds.extend(this.getMap().fromLatLngToPoint(rectangleLatLngBounds.getSouthWest()));
+    currentBounds.extend(this.getMap().fromLatLngToPoint(rectangleLatLngBounds.getNorthEast()));
+
+    var latLngBounds = new google.maps.LatLngBounds();
+
+    var topLeft = this._transformCoordinates(currentBounds.getTopLeft(), oldBounds, newBounds);
+    var rightBottom = this._transformCoordinates(currentBounds.getRightBottom(), oldBounds, newBounds);
+
+    latLngBounds.extend(this.getMap().fromPointToLatLng(topLeft));
+    latLngBounds.extend(this.getMap().fromPointToLatLng(rightBottom));
+    rectangle.setBounds(latLngBounds);
+  }
 };
 
 /**
@@ -106,10 +170,15 @@ GoogleMapsApiRectangle.prototype.setBounds = function (bounds) {
  * @returns {Bounds}
  */
 GoogleMapsApiRectangle.prototype.getBounds = function () {
-  var latLngBounds = this.getGoogleRectangle().getBounds();
   var result = new Bounds();
-  result.extend(this.getMap().fromLatLngToPoint(latLngBounds.getSouthWest()));
-  result.extend(this.getMap().fromLatLngToPoint(latLngBounds.getNorthEast()));
+
+  var rectangles = this.getGoogleRectangles();
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    var latLngBounds = rectangle.getBounds();
+    result.extend(this.getMap().fromLatLngToPoint(latLngBounds.getSouthWest()));
+    result.extend(this.getMap().fromLatLngToPoint(latLngBounds.getNorthEast()));
+  }
   return result;
 };
 
@@ -118,7 +187,11 @@ GoogleMapsApiRectangle.prototype.getBounds = function () {
  * @param {Object} options
  */
 GoogleMapsApiRectangle.prototype.setOptions = function (options) {
-  this.getGoogleRectangle().setOptions(options);
+  var rectangles = this.getGoogleRectangles();
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    rectangle.setOptions(options);
+  }
 };
 
 
diff --git a/frontend-js/src/main/js/map/canvas/OpenLayers/OpenLayerRectangle.js b/frontend-js/src/main/js/map/canvas/OpenLayers/OpenLayerRectangle.js
index eb0b859ee61e9a8156d3eea4eb6e9f2028ae3841..b9037203fc91b3ca670297309d81ca687f3a8839 100644
--- a/frontend-js/src/main/js/map/canvas/OpenLayers/OpenLayerRectangle.js
+++ b/frontend-js/src/main/js/map/canvas/OpenLayers/OpenLayerRectangle.js
@@ -27,29 +27,84 @@ function OpenLayersRectangle(options) {
     options.strokeWeight = 1;
   }
   this._options = options;
+  this._rectangles = [];
+
+  if (options.fillGradient !== undefined) {
+    var totalAmount = 0;
+    for (var i = 0; i < options.fillGradient.length; i++) {
+      totalAmount += options.fillGradient[i].amount;
+    }
+    var y = options.bounds.getTopLeft().y;
+    for (i = 0; i < options.fillGradient.length; i++) {
+      var x1 = options.bounds.getTopLeft().x;
+      var x2 = options.bounds.getRightBottom().x;
+      var y1 = y;
+      var ratio = options.fillGradient[i].amount / totalAmount;
+
+      var y2 = y1 + ratio * (options.bounds.getRightBottom().y - options.bounds.getTopLeft().y);
+      y = y2;
+
+      var bounds = new Bounds(new Point(x1, y1), new Point(x2, y2));
+
+      self.addOpenLayersRectangle(self._createFeature({
+        strokeWeight: 0.5,
+        strokeColor: options.fillGradient[i].color,
+        strokeOpacity: options.fillOpacity,
+        bounds: bounds,
+        fillOpacity: options.fillOpacity,
+        fillColor: options.fillGradient[i].color,
+        source: options.source
+      }));
+    }
+    self.addOpenLayersRectangle(self._createFeature({
+      strokeWeight: options.strokeWeight,
+      strokeColor: options.strokeColor,
+      strokeOpacity: options.strokeOpacity,
+      bounds: options.bounds,
+      fillOpacity: 0.0,
+      id: options.id,
+      fillColor: "#000000",
+      source: options.source
+    }));
+  } else {
+    self.addOpenLayersRectangle(self._createFeature(options));
+  }
 
-  var style = self.createStyle(options);
+}
+
+OpenLayersRectangle.prototype = Object.create(Rectangle.prototype);
+OpenLayersRectangle.prototype.constructor = OpenLayersRectangle;
 
-  var polygon = this.createPolygon(options.bounds);
 
+OpenLayersRectangle.prototype._createFeature = function (options) {
+  var self = this;
+  var style = self.createStyle(options);
+  var polygon;
+  polygon = self.createPolygon(options.bounds);
   var feature = new ol.Feature({
     geometry: polygon,
     id: options.id
   });
 
-  this.setOpenLayersRectangle(feature);
   feature.setStyle(new ol.style.Style({}));
   options.source.addFeature(feature);
 
   feature.__openLayerRectangle = this;
+  /**
+   *
+   * @type {style.Style}
+   * @private
+   */
+  feature.__style = style;
+  return feature;
+};
 
-  this._style = style;
-
-}
-
-OpenLayersRectangle.prototype = Object.create(Rectangle.prototype);
-OpenLayersRectangle.prototype.constructor = OpenLayersRectangle;
 
+/**
+ *
+ * @param {Bounds} bounds
+ * @returns {geom.Polygon}
+ */
 OpenLayersRectangle.prototype.createPolygon = function (bounds) {
   var self = this;
 
@@ -68,6 +123,16 @@ OpenLayersRectangle.prototype.createPolygon = function (bounds) {
   return new ol.geom.Polygon([points]);
 };
 
+/**
+ *
+ * @param {string} options.strokeColor
+ * @param {number} options.strokeOpacity
+ * @param {number} options.strokeWeight
+ * @param {string} options.fillColor
+ * @param {number} options.fillOpacity
+ *
+ * @returns {style.Style}
+ */
 OpenLayersRectangle.prototype.createStyle = function (options) {
   return new ol.style.Style({
     stroke: new ol.style.Stroke({
@@ -80,54 +145,110 @@ OpenLayersRectangle.prototype.createStyle = function (options) {
   });
 };
 
-
-OpenLayersRectangle.prototype.setOpenLayersRectangle = function (rectangle) {
-  this._rectangle = rectangle;
+OpenLayersRectangle.prototype.addOpenLayersRectangle = function (rectangle) {
+  this._rectangles.push(rectangle);
 };
 
-OpenLayersRectangle.prototype.getOpenLayersRectangle = function () {
-  return this._rectangle;
+/**
+ *
+ * @returns {Array}
+ */
+OpenLayersRectangle.prototype.getOpenLayersRectangles = function () {
+  return this._rectangles;
 };
 
+/**
+ *
+ */
 OpenLayersRectangle.prototype.show = function () {
-  return this.getOpenLayersRectangle().setStyle(this._style);
+  var rectangles = this.getOpenLayersRectangles();
+
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    rectangle.setStyle(rectangle.__style);
+  }
 };
 
 OpenLayersRectangle.prototype.hide = function () {
-  return this.getOpenLayersRectangle().setStyle(new ol.style.Style({}));
+  var rectangles = this.getOpenLayersRectangles();
+  var hiddenStyle = new ol.style.Style({});
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    rectangle.setStyle(hiddenStyle);
+  }
 };
 OpenLayersRectangle.prototype.isShown = function () {
-  return this.getOpenLayersRectangle().getStyle().getFill() !== null;
+  var rectangles = this.getOpenLayersRectangles();
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    if (rectangle.getStyle().getFill() !== null) {
+      return true;
+    }
+  }
 };
 
 /**
  *
- * @param bounds {Bounds}
+ * @param newBounds {Bounds}
  */
-OpenLayersRectangle.prototype.setBounds = function (bounds) {
-  this._options.bounds = bounds;
-  this.getOpenLayersRectangle().setGeometry(this.createPolygon(bounds));
+OpenLayersRectangle.prototype.setBounds = function (newBounds) {
+  var self = this;
+
+  self._options.bounds = newBounds;
+  var oldBounds = self.getBounds();
+
+  var rectangles = self.getOpenLayersRectangles();
+
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    var currentBounds = new Bounds();
+    var extent = rectangle.getGeometry().getExtent();
+
+    var projection1 = [extent[0], extent[1]];
+    currentBounds.extend(self.getMap().fromProjectionToPoint(projection1));
+    var projection2 = [extent[2], extent[3]];
+    currentBounds.extend(self.getMap().fromProjectionToPoint(projection2));
+
+    var topLeft = self._transformCoordinates(currentBounds.getTopLeft(), oldBounds, newBounds);
+    var rightBottom = self._transformCoordinates(currentBounds.getRightBottom(), oldBounds, newBounds);
+
+    rectangle.setGeometry(self.createPolygon(new Bounds(topLeft, rightBottom)));
+  }
+
 };
 
 OpenLayersRectangle.prototype.getBounds = function () {
   var self = this;
-  var extent = self.getOpenLayersRectangle().getGeometry().getExtent();
-
-  var projection1 = [extent[0], extent[1]];
-  var p1 = self.getMap().fromProjectionToPoint(projection1);
-  var projection2 = [extent[2], extent[3]];
-  var p2 = self.getMap().fromProjectionToPoint(projection2);
-  return new Bounds(p1, p2);
+  var bounds = new Bounds();
+  var rectangles = this.getOpenLayersRectangles();
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    var extent = rectangle.getGeometry().getExtent();
+
+    var projection1 = [extent[0], extent[1]];
+    bounds.extend(self.getMap().fromProjectionToPoint(projection1));
+    var projection2 = [extent[2], extent[3]];
+    bounds.extend(self.getMap().fromProjectionToPoint(projection2));
+  }
+  return bounds;
 };
 
 OpenLayersRectangle.prototype.setOptions = function (options) {
   var self = this;
   self._options = Object.assign(self._options, options);
-  var style = self.createStyle(self._options);
-  if (self.isShown()) {
-    self.getOpenLayersRectangle().setStyle(style);
+  var rectangles = this.getOpenLayersRectangles();
+  for (var i = 0; i < rectangles.length; i++) {
+    var rectangle = rectangles[i];
+    var style = rectangle.__style;
+    if (self._options.fillColor !== undefined) {
+      style.getFill().setColor(Functions.colorToRgbaString(self._options.fillColor, self._options.fillOpacity));
+    }
+
+    if (i === rectangles.length - 1) {
+      style.getStroke().setWidth(self._options.strokeWeight);
+      style.getStroke().setColor(Functions.colorToRgbaString(self._options.strokeColor, self._options.strokeOpacity));
+    }
   }
-  self._style = style;
 };
 
 module.exports = OpenLayersRectangle;
diff --git a/frontend-js/src/main/js/map/canvas/Point.js b/frontend-js/src/main/js/map/canvas/Point.js
index 5d382661af887724b11bc53ea262b2524c9085d0..dcec9a39f16137179e68feeb6ddfe2699aff3113 100644
--- a/frontend-js/src/main/js/map/canvas/Point.js
+++ b/frontend-js/src/main/js/map/canvas/Point.js
@@ -30,4 +30,12 @@ Point.prototype.toString = function () {
   return "[" + this.x + ", " + this.y + "]";
 };
 
+/**
+ * @param {Point} otherPoint
+ * @returns {number}
+ */
+Point.prototype.distanceTo = function (otherPoint) {
+  return Math.sqrt((otherPoint.x - this.x) * (otherPoint.x - this.x) + (otherPoint.y - this.y) * (otherPoint.y - this.y));
+};
+
 module.exports = Point;
diff --git a/frontend-js/src/main/js/map/canvas/Rectangle.js b/frontend-js/src/main/js/map/canvas/Rectangle.js
index b30ec9c9ea811cd02685665975a8009a7a960260..9da655253c42dc1842b7902122b70d50ea0f67da 100644
--- a/frontend-js/src/main/js/map/canvas/Rectangle.js
+++ b/frontend-js/src/main/js/map/canvas/Rectangle.js
@@ -1,6 +1,7 @@
 "use strict";
 
 var MapCanvas = require('./MapCanvas');
+var Point = require('./Point');
 
 // noinspection JSUnusedLocalSymbols
 var logger = require('../../logger');
@@ -74,4 +75,19 @@ Rectangle.prototype.getMap = function () {
   return this._map;
 };
 
+/**
+ *
+ * @param {Point} point
+ * @param {Bounds} oldBounds
+ * @param {Bounds} newBounds
+ *
+ * @returns {Point}
+ * @protected
+ */
+Rectangle.prototype._transformCoordinates = function (point, oldBounds, newBounds) {
+  var x = newBounds.getTopLeft().x + (point.x - oldBounds.getTopLeft().x) / (oldBounds.getRightBottom().x - oldBounds.getTopLeft().x) * (newBounds.getRightBottom().x - newBounds.getTopLeft().x);
+  var y = newBounds.getTopLeft().y + (point.y - oldBounds.getTopLeft().y) / (oldBounds.getRightBottom().y - oldBounds.getTopLeft().y) * (newBounds.getRightBottom().y - newBounds.getTopLeft().y);
+  return new Point(x, y);
+};
+
 module.exports = Rectangle;
diff --git a/frontend-js/src/main/js/map/data/Alias.js b/frontend-js/src/main/js/map/data/Alias.js
index c1207a70457ce3f9d17a5db9a55274b46667d811..1bfd76989315b1d645d6a6438a4fad8556fbe213 100644
--- a/frontend-js/src/main/js/map/data/Alias.js
+++ b/frontend-js/src/main/js/map/data/Alias.js
@@ -26,6 +26,7 @@ function Alias(javaObject) {
     this.setWidth(javaObject.bounds.width);
     this.setHeight(javaObject.bounds.height);
   }
+  this.setLinkedSubmodelId(javaObject.linkedSubmodel);
 
   if (this._modelId === undefined) {
     throw new Error("ModelId is not defined for alias" + javaObject);
@@ -341,7 +342,7 @@ Alias.prototype.setFullName = function (fullName) {
 
 /**
  *
- * @returns {number}
+ * @returns {number|undefined}
  */
 Alias.prototype.getCompartmentId = function () {
   return this._compartmentId;
diff --git a/frontend-js/src/main/js/map/data/Annotation.js b/frontend-js/src/main/js/map/data/Annotation.js
index 748eff92445c3ccd2e9bc33a806652a206279760..7b6f82bef9bf4a6518da736cb18df40c06c23303 100644
--- a/frontend-js/src/main/js/map/data/Annotation.js
+++ b/frontend-js/src/main/js/map/data/Annotation.js
@@ -11,10 +11,10 @@ var logger = require('../../logger');
  * @typedef {Object} AnnotationOptions
  * @property {string} link
  * @property {number} id
- * @property {Article|ArticleOptions} article
+ * @property {Article|ArticleOptions} [article]
  * @property {string} type
  * @property {string} resource
- * @property {string} annotatorClassName
+ * @property {string} [annotatorClassName]
  */
 
 /**
@@ -140,7 +140,7 @@ Annotation.prototype.setAnnotatorClassName = function (annotatorClassName) {
 
 /**
  *
- * @returns {string}
+ * @returns {string|undefined}
  */
 Annotation.prototype.getAnnotatorClassName = function () {
   return this._annotatorClassName;
diff --git a/frontend-js/src/main/js/map/data/BioEntity.js b/frontend-js/src/main/js/map/data/BioEntity.js
index f5e5a8370645e2cff368bca1356317948e9aafb5..f2deb9b7686a2f9fc60e57f141c172d0b665ebba 100644
--- a/frontend-js/src/main/js/map/data/BioEntity.js
+++ b/frontend-js/src/main/js/map/data/BioEntity.js
@@ -1,10 +1,11 @@
 "use strict";
 
 var Annotation = require("./Annotation");
+var Functions = require("../../Functions");
 
 /**
  * Class representing BioEntity.
- * 
+ *
  * @constructor
  */
 function BioEntity() {
@@ -12,9 +13,9 @@ function BioEntity() {
 
 /**
  *
- * @returns {number}
+ * @returns {number|undefined}
  */
-BioEntity.prototype.getLinkedSubmodelId = function() {
+BioEntity.prototype.getLinkedSubmodelId = function () {
   return this._linkedSubmodelId;
 };
 
@@ -22,16 +23,16 @@ BioEntity.prototype.getLinkedSubmodelId = function() {
  *
  * @param {number} linkedSubmodelId
  */
-BioEntity.prototype.setLinkedSubmodelId = function(linkedSubmodelId) {
-  this._linkedSubmodelId = linkedSubmodelId;
+BioEntity.prototype.setLinkedSubmodelId = function (linkedSubmodelId) {
+  this._linkedSubmodelId = Functions.getIntOrUndefined(linkedSubmodelId);
 };
 
 /**
  * Returns identifier of the BioEntity.
- * 
+ *
  * @returns {number} identifier of the BioEntity
  */
-BioEntity.prototype.getId = function() {
+BioEntity.prototype.getId = function () {
   return this.id;
 };
 
@@ -39,16 +40,16 @@ BioEntity.prototype.getId = function() {
  *
  * @param {number} id
  */
-BioEntity.prototype.setId = function(id) {
+BioEntity.prototype.setId = function (id) {
   this.id = id;
 };
 
 /**
  * Returns model identifier where {@link BioEntity} is located.
- * 
+ *
  * @returns {number} model identifier where {@link BioEntity} is located
  */
-BioEntity.prototype.getModelId = function() {
+BioEntity.prototype.getModelId = function () {
   return this._modelId;
 };
 
@@ -56,7 +57,7 @@ BioEntity.prototype.getModelId = function() {
  *
  * @param {number} modelId
  */
-BioEntity.prototype.setModelId = function(modelId) {
+BioEntity.prototype.setModelId = function (modelId) {
   this._modelId = modelId;
 };
 
@@ -64,7 +65,7 @@ BioEntity.prototype.setModelId = function(modelId) {
  *
  * @returns {boolean}
  */
-BioEntity.prototype.isComplete = function() {
+BioEntity.prototype.isComplete = function () {
   return this._complete;
 };
 
@@ -72,7 +73,7 @@ BioEntity.prototype.isComplete = function() {
  *
  * @param {boolean} complete
  */
-BioEntity.prototype.setIsComplete = function(complete) {
+BioEntity.prototype.setIsComplete = function (complete) {
   this._complete = complete;
 };
 
@@ -80,7 +81,7 @@ BioEntity.prototype.setIsComplete = function(complete) {
  *
  * @returns {string}
  */
-BioEntity.prototype.getSymbol = function() {
+BioEntity.prototype.getSymbol = function () {
   return this.symbol;
 };
 
@@ -88,7 +89,7 @@ BioEntity.prototype.getSymbol = function() {
  *
  * @param {string} symbol
  */
-BioEntity.prototype.setSymbol = function(symbol) {
+BioEntity.prototype.setSymbol = function (symbol) {
   this.symbol = symbol;
 };
 
@@ -96,7 +97,7 @@ BioEntity.prototype.setSymbol = function(symbol) {
  *
  * @returns {string}
  */
-BioEntity.prototype.getAbbreviation = function() {
+BioEntity.prototype.getAbbreviation = function () {
   return this._abbreviation;
 };
 
@@ -104,7 +105,7 @@ BioEntity.prototype.getAbbreviation = function() {
  *
  * @param {string} abbreviation
  */
-BioEntity.prototype.setAbbreviation = function(abbreviation) {
+BioEntity.prototype.setAbbreviation = function (abbreviation) {
   this._abbreviation = abbreviation;
 };
 
@@ -112,7 +113,7 @@ BioEntity.prototype.setAbbreviation = function(abbreviation) {
  *
  * @returns {string}
  */
-BioEntity.prototype.getFormula = function() {
+BioEntity.prototype.getFormula = function () {
   return this._formula;
 };
 
@@ -120,7 +121,7 @@ BioEntity.prototype.getFormula = function() {
  *
  * @param {string} formula
  */
-BioEntity.prototype.setFormula = function(formula) {
+BioEntity.prototype.setFormula = function (formula) {
   this._formula = formula;
 };
 
@@ -128,7 +129,7 @@ BioEntity.prototype.setFormula = function(formula) {
  *
  * @param {string[]} synonyms
  */
-BioEntity.prototype.setSynonyms = function(synonyms) {
+BioEntity.prototype.setSynonyms = function (synonyms) {
   this._synonyms = synonyms;
 };
 
@@ -136,7 +137,7 @@ BioEntity.prototype.setSynonyms = function(synonyms) {
  *
  * @returns {string[]}
  */
-BioEntity.prototype.getSynonyms = function() {
+BioEntity.prototype.getSynonyms = function () {
   return this._synonyms;
 };
 
@@ -144,7 +145,7 @@ BioEntity.prototype.getSynonyms = function() {
  *
  * @param {string} description
  */
-BioEntity.prototype.setDescription = function(description) {
+BioEntity.prototype.setDescription = function (description) {
   this._description = description;
 };
 
@@ -152,7 +153,7 @@ BioEntity.prototype.setDescription = function(description) {
  *
  * @returns {string}
  */
-BioEntity.prototype.getDescription = function() {
+BioEntity.prototype.getDescription = function () {
   return this._description;
 };
 
@@ -160,7 +161,7 @@ BioEntity.prototype.getDescription = function() {
  *
  * @param {string} type
  */
-BioEntity.prototype.setType = function(type) {
+BioEntity.prototype.setType = function (type) {
   if (type === undefined) {
     throw new Error("type cannot be undefined");
   }
@@ -171,7 +172,7 @@ BioEntity.prototype.setType = function(type) {
  *
  * @returns {string}
  */
-BioEntity.prototype.getType = function() {
+BioEntity.prototype.getType = function () {
   return this._type;
 };
 
@@ -180,7 +181,7 @@ BioEntity.prototype.getType = function() {
  * @param {string} type
  * @returns {Object}
  */
-BioEntity.prototype.getOther = function(type) {
+BioEntity.prototype.getOther = function (type) {
   if (this._other !== undefined) {
     return (type === undefined) ? this._other : this._other[type];
   }
@@ -190,7 +191,7 @@ BioEntity.prototype.getOther = function(type) {
  *
  * @param {Object} other
  */
-BioEntity.prototype.setOther = function(other) {
+BioEntity.prototype.setOther = function (other) {
   this._other = other;
 };
 
@@ -198,7 +199,7 @@ BioEntity.prototype.setOther = function(other) {
  *
  * @returns {number}
  */
-BioEntity.prototype.getHierarchyVisibilityLevel = function() {
+BioEntity.prototype.getHierarchyVisibilityLevel = function () {
   return this._hierarchyVisibilityLevel;
 };
 
@@ -206,7 +207,7 @@ BioEntity.prototype.getHierarchyVisibilityLevel = function() {
  *
  * @param {number} hierarchyVisibilityLevel
  */
-BioEntity.prototype.setHierarchyVisibilityLevel = function(hierarchyVisibilityLevel) {
+BioEntity.prototype.setHierarchyVisibilityLevel = function (hierarchyVisibilityLevel) {
   this._hierarchyVisibilityLevel = hierarchyVisibilityLevel;
 };
 
@@ -214,7 +215,7 @@ BioEntity.prototype.setHierarchyVisibilityLevel = function(hierarchyVisibilityLe
  *
  * @returns {Annotation[]}
  */
-BioEntity.prototype.getReferences = function() {
+BioEntity.prototype.getReferences = function () {
   return this.references;
 };
 
@@ -222,8 +223,8 @@ BioEntity.prototype.getReferences = function() {
  *
  * @param {Annotation[]} references
  */
-BioEntity.prototype.setReferences = function(references) {
-  if (references=== undefined) {
+BioEntity.prototype.setReferences = function (references) {
+  if (references === undefined) {
     throw new Error("references must be defined");
   }
   this.references = [];
@@ -235,7 +236,7 @@ BioEntity.prototype.setReferences = function(references) {
 /**
  * @returns {Point}
  */
-BioEntity.prototype.getCenter = function() {
+BioEntity.prototype.getCenter = function () {
   throw new Error("Not implemented");
 };
 
diff --git a/frontend-js/src/main/js/map/data/DataOverlay.js b/frontend-js/src/main/js/map/data/DataOverlay.js
index e508d179054d5a283b94d2db58239b0b64a87985..c957147c37c78b05fc84220366908b2f2aa5ab7f 100644
--- a/frontend-js/src/main/js/map/data/DataOverlay.js
+++ b/frontend-js/src/main/js/map/data/DataOverlay.js
@@ -210,7 +210,7 @@ DataOverlay.prototype.getFullAliasById = function (id) {
   var self = this;
   var alias = self.getAliasById(id);
   if (alias !== undefined) {
-    if (alias.getType() === LayoutAlias.LIGTH) {
+    if (alias.getType() === LayoutAlias.LIGHT) {
       return ServerConnector.getFullOverlayElement({
         element: new IdentifiedElement(alias),
         overlay: self
diff --git a/frontend-js/src/main/js/map/data/GeneVariant.js b/frontend-js/src/main/js/map/data/GeneVariant.js
index 1b4a6e0d7665ad84944c75b1468a6c6919c545c4..50fa4462f2eecc232ad702e927cdd6dfbed6928b 100644
--- a/frontend-js/src/main/js/map/data/GeneVariant.js
+++ b/frontend-js/src/main/js/map/data/GeneVariant.js
@@ -1,5 +1,19 @@
 "use strict";
 
+/**
+ *
+ * @param {Object} javaObject
+ * @param {number} javaObject.position
+ * @param {string} javaObject.originalDna
+ * @param {string} javaObject.modifiedDna
+ * @param {string} javaObject.referenceGenomeType
+ * @param {string} javaObject.referenceGenomeVersion
+ * @param {string} javaObject.contig
+ * @param {null|number} [javaObject.allelFrequency]
+ * @param {null|string} [javaObject.variantIdentifier]
+ *
+ * @constructor
+ */
 function GeneVariant(javaObject) {
   this.setPosition(javaObject.position);
   this.setOriginalDna(javaObject.originalDna);
@@ -11,68 +25,139 @@ function GeneVariant(javaObject) {
   this.setVariantIdentifier(javaObject.variantIdentifier);
 }
 
-GeneVariant.prototype.setPosition = function(position) {
+/**
+ *
+ * @param {number} position
+ */
+GeneVariant.prototype.setPosition = function (position) {
   this._position = position;
 };
 
-GeneVariant.prototype.getPosition = function() {
+/**
+ *
+ * @returns {number}
+ */
+GeneVariant.prototype.getPosition = function () {
   return this._position;
 };
 
-GeneVariant.prototype.setOriginalDna = function(originalDna) {
+/**
+ *
+ * @param {string} originalDna
+ */
+GeneVariant.prototype.setOriginalDna = function (originalDna) {
   this._original = originalDna;
 };
 
-GeneVariant.prototype.getOriginalDna = function() {
+/**
+ *
+ * @returns {string}
+ */
+GeneVariant.prototype.getOriginalDna = function () {
   return this._original;
 };
 
-GeneVariant.prototype.setModifiedDna = function(modifiedDna) {
+/**
+ *
+ * @param {string} modifiedDna
+ */
+GeneVariant.prototype.setModifiedDna = function (modifiedDna) {
   this._modifiedDna = modifiedDna;
 };
 
-GeneVariant.prototype.getModifiedDna = function() {
+/**
+ *
+ * @returns {string}
+ */
+GeneVariant.prototype.getModifiedDna = function () {
   return this._modifiedDna;
 };
 
-GeneVariant.prototype.setContig = function(contig) {
+/**
+ *
+ * @param {string} contig
+ */
+GeneVariant.prototype.setContig = function (contig) {
   this._contig = contig;
 };
 
-GeneVariant.prototype.getContig = function() {
+/**
+ *
+ * @returns {string}
+ */
+GeneVariant.prototype.getContig = function () {
   return this._contig;
 };
 
-GeneVariant.prototype.setAllelFrequency = function(allelFrequency) {
-  this._allelFrequency = allelFrequency;
+/**
+ *
+ * @param {number} allelFrequency
+ */
+GeneVariant.prototype.setAllelFrequency = function (allelFrequency) {
+  if (allelFrequency === null) {
+    this._allelFrequency = undefined;
+  } else {
+    this._allelFrequency = allelFrequency;
+  }
 };
 
-GeneVariant.prototype.getAllelFrequency = function() {
+/**
+ *
+ * @returns {number}
+ */
+GeneVariant.prototype.getAllelFrequency = function () {
   return this._allelFrequency;
 };
 
-GeneVariant.prototype.setVariantIdentifier = function(variantIdentifier) {
-  this._variantIdentifier = variantIdentifier;
+/**
+ *
+ * @param {string} variantIdentifier
+ */
+GeneVariant.prototype.setVariantIdentifier = function (variantIdentifier) {
+  if (variantIdentifier === null) {
+    this._variantIdentifier = undefined;
+  } else {
+    this._variantIdentifier = variantIdentifier;
+  }
 };
 
-GeneVariant.prototype.getVariantIdentifier = function() {
+/**
+ *
+ * @returns {string}
+ */
+GeneVariant.prototype.getVariantIdentifier = function () {
   return this._variantIdentifier;
 };
 
-GeneVariant.prototype.setReferenceGenomeType = function(referenceGenomeType) {
+/**
+ *
+ * @param {string} referenceGenomeType
+ */
+GeneVariant.prototype.setReferenceGenomeType = function (referenceGenomeType) {
   this._referenceGenomeType = referenceGenomeType;
 };
 
-GeneVariant.prototype.getReferenceGenomeType = function() {
+/**
+ *
+ * @returns {string}
+ */
+GeneVariant.prototype.getReferenceGenomeType = function () {
   return this._referenceGenomeType;
 };
 
-GeneVariant.prototype.setReferenceGenomeVersion = function(
-    referenceGenomeVersion) {
+/**
+ *
+ * @param {string} referenceGenomeVersion
+ */
+GeneVariant.prototype.setReferenceGenomeVersion = function (referenceGenomeVersion) {
   this._referenceGenomeVersion = referenceGenomeVersion;
 };
 
-GeneVariant.prototype.getReferenceGenomeVersion = function() {
+/**
+ *
+ * @returns {string}
+ */
+GeneVariant.prototype.getReferenceGenomeVersion = function () {
   return this._referenceGenomeVersion;
 };
 
diff --git a/frontend-js/src/main/js/map/data/LayoutAlias.js b/frontend-js/src/main/js/map/data/LayoutAlias.js
index d41d52b7bc5f173f05a86fd859876b6fafb04646..e82336b0ce6f72c0e25549a5a4bb2367ec430ee8 100644
--- a/frontend-js/src/main/js/map/data/LayoutAlias.js
+++ b/frontend-js/src/main/js/map/data/LayoutAlias.js
@@ -1,111 +1,116 @@
-"use strict";
-
-var GeneVariant = require('./GeneVariant');
-
-/**
- * Class representing alias visualized in a overlay.
- *
- * @param javaObject
- *          object de-serialized ajax query to the server side
- */
-function LayoutAlias(javaObject) {
-  this.setId(javaObject.idObject);
-  this.setValue(javaObject.value);
-  this.setColor(javaObject.color);
-  this.setModelId(javaObject.modelId);
-  this.setDescription(javaObject.description);
-  if (javaObject.type === undefined) {
-    this.setType(LayoutAlias.LIGTH);
-  } else if (javaObject.type === LayoutAlias.GENETIC_VARIANT) {
-    this.setType(LayoutAlias.GENETIC_VARIANT);
-  } else if (javaObject.type === LayoutAlias.GENERIC) {
-    this.setType(LayoutAlias.GENERIC);
-  } else {
-    throw new Error("Unknown type: " + javaObject.type);
-  }
-
-  this.setGeneVariants([]);
-  if (javaObject.geneVariations !== undefined) {
-    for (var i = 0; i < javaObject.geneVariations.length; i++) {
-      this.addGeneVariant(new GeneVariant(javaObject.geneVariations[i]));
-    }
-  }
-}
-
-LayoutAlias.LIGHT = "LIGHT";
-LayoutAlias.GENETIC_VARIANT = "GENETIC_VARIANT";
-LayoutAlias.GENERIC = "GENERIC";
-
-LayoutAlias.prototype.getId = function () {
-  return this.id;
-};
-
-LayoutAlias.prototype.setId = function (id) {
-  this.id = parseInt(id);
-};
-
-LayoutAlias.prototype.getModelId = function () {
-  return this._modelId;
-};
-
-LayoutAlias.prototype.setModelId = function (modelId) {
-  this._modelId = parseInt(modelId);
-};
-
-LayoutAlias.prototype.getValue = function () {
-  return this.value;
-};
-
-LayoutAlias.prototype.getColor = function () {
-  return this.color;
-};
-
-LayoutAlias.prototype.getType = function () {
-  return this._type;
-};
-
-LayoutAlias.prototype.getGeneVariants = function () {
-  return this._geneVariants;
-};
-
-LayoutAlias.prototype.setValue = function (newValue) {
-  this.value = newValue;
-};
-
-LayoutAlias.prototype.setColor = function (newColor) {
-  this.color = newColor;
-};
-
-LayoutAlias.prototype.setType = function (newType) {
-  this._type = newType;
-};
-
-LayoutAlias.prototype.setGeneVariants = function (newGeneVariants) {
-  this._geneVariants = newGeneVariants;
-};
-
-LayoutAlias.prototype.update = function (alias) {
-  if (!(alias instanceof LayoutAlias)) {
-    throw new Error("Unknown parameter type: " + alias);
-  }
-
-  this.setValue(alias.getValue());
-  this.setColor(alias.getColor());
-  this.setGeneVariants(alias.getGeneVariants());
-  this.setType(alias.getType());
-  this.setDescription(alias.getDescription());
-};
-
-LayoutAlias.prototype.addGeneVariant = function (geneVariant) {
-  this._geneVariants.push(geneVariant);
-};
-
-LayoutAlias.prototype.getDescription = function () {
-  return this._description;
-};
-
-LayoutAlias.prototype.setDescription = function (description) {
-  this._description = description;
-};
-
-module.exports = LayoutAlias;
+"use strict";
+
+var GeneVariant = require('./GeneVariant');
+
+/**
+ * Class representing alias visualized in a overlay.
+ *
+ * @param {number} javaObject.idObject
+ * @param {number} [javaObject.value]
+ * @param {string} [javaObject.color]
+ * @param {number} javaObject.modelId
+ * @param {string} [javaObject.description]
+ * @param {string} [javaObject.type=LayoutAlias.LIGHT]
+ * @param {Array} [javaObject.geneVariations]
+ */
+function LayoutAlias(javaObject) {
+  this.setId(javaObject.idObject);
+  this.setValue(javaObject.value);
+  this.setColor(javaObject.color);
+  this.setModelId(javaObject.modelId);
+  this.setDescription(javaObject.description);
+  if (javaObject.type === undefined) {
+    this.setType(LayoutAlias.LIGHT);
+  } else if (javaObject.type === LayoutAlias.GENETIC_VARIANT) {
+    this.setType(LayoutAlias.GENETIC_VARIANT);
+  } else if (javaObject.type === LayoutAlias.GENERIC) {
+    this.setType(LayoutAlias.GENERIC);
+  } else {
+    throw new Error("Unknown type: " + javaObject.type);
+  }
+
+  this.setGeneVariants([]);
+  if (javaObject.geneVariations !== undefined) {
+    for (var i = 0; i < javaObject.geneVariations.length; i++) {
+      this.addGeneVariant(new GeneVariant(javaObject.geneVariations[i]));
+    }
+  }
+}
+
+LayoutAlias.LIGHT = "LIGHT";
+LayoutAlias.GENETIC_VARIANT = "GENETIC_VARIANT";
+LayoutAlias.GENERIC = "GENERIC";
+
+LayoutAlias.prototype.getId = function () {
+  return this.id;
+};
+
+LayoutAlias.prototype.setId = function (id) {
+  this.id = parseInt(id);
+};
+
+LayoutAlias.prototype.getModelId = function () {
+  return this._modelId;
+};
+
+LayoutAlias.prototype.setModelId = function (modelId) {
+  this._modelId = parseInt(modelId);
+};
+
+LayoutAlias.prototype.getValue = function () {
+  return this.value;
+};
+
+LayoutAlias.prototype.getColor = function () {
+  return this.color;
+};
+
+LayoutAlias.prototype.getType = function () {
+  return this._type;
+};
+
+LayoutAlias.prototype.getGeneVariants = function () {
+  return this._geneVariants;
+};
+
+LayoutAlias.prototype.setValue = function (newValue) {
+  this.value = newValue;
+};
+
+LayoutAlias.prototype.setColor = function (newColor) {
+  this.color = newColor;
+};
+
+LayoutAlias.prototype.setType = function (newType) {
+  this._type = newType;
+};
+
+LayoutAlias.prototype.setGeneVariants = function (newGeneVariants) {
+  this._geneVariants = newGeneVariants;
+};
+
+LayoutAlias.prototype.update = function (alias) {
+  if (!(alias instanceof LayoutAlias)) {
+    throw new Error("Unknown parameter type: " + alias);
+  }
+
+  this.setValue(alias.getValue());
+  this.setColor(alias.getColor());
+  this.setGeneVariants(alias.getGeneVariants());
+  this.setType(alias.getType());
+  this.setDescription(alias.getDescription());
+};
+
+LayoutAlias.prototype.addGeneVariant = function (geneVariant) {
+  this._geneVariants.push(geneVariant);
+};
+
+LayoutAlias.prototype.getDescription = function () {
+  return this._description;
+};
+
+LayoutAlias.prototype.setDescription = function (description) {
+  this._description = description;
+};
+
+module.exports = LayoutAlias;
diff --git a/frontend-js/src/main/js/map/data/MapModel.js b/frontend-js/src/main/js/map/data/MapModel.js
index 81a5dae53e5580ab0fa912bd3b7df2be7257ad81..2173114711ad26566674abb7edb539d4d5d8f0c3 100644
--- a/frontend-js/src/main/js/map/data/MapModel.js
+++ b/frontend-js/src/main/js/map/data/MapModel.js
@@ -256,7 +256,7 @@ MapModel.prototype.getMissingElements = function (elements) {
     } else {
       aliasPromise = ServerConnector.getAliases({
         ids: aliasIds,
-        columns: "id,bounds,modelId"
+        columns: "id,bounds,modelId,linkedSubmodel"
       });
 
     }
diff --git a/frontend-js/src/main/js/map/data/PrivilegeType.js b/frontend-js/src/main/js/map/data/PrivilegeType.js
index 54e528f1214a998043abe0eccb4fcc2a46ad4b9f..45af426283985ab02e2165bc19cd799600a71254 100644
--- a/frontend-js/src/main/js/map/data/PrivilegeType.js
+++ b/frontend-js/src/main/js/map/data/PrivilegeType.js
@@ -17,8 +17,9 @@ PrivilegeType.prototype = Object.create(ObjectWithListeners.prototype);
 PrivilegeType.prototype.constructor = PrivilegeType;
 
 PrivilegeType.CONFIGURATION_MANAGE = 'CONFIGURATION_MANAGE';
-PrivilegeType.USER_MANAGEMENT = 'USER_MANAGEMENT';
+PrivilegeType.MANAGE_GENOMES = 'MANAGE_GENOMES';
 PrivilegeType.PROJECT_MANAGEMENT = 'PROJECT_MANAGEMENT';
+PrivilegeType.USER_MANAGEMENT = 'USER_MANAGEMENT';
 
 PrivilegeType.prototype.setObjectType = function (objectType) {
   this._objectType = objectType;
diff --git a/frontend-js/src/main/js/map/data/ReferenceGenome.js b/frontend-js/src/main/js/map/data/ReferenceGenome.js
index 38756a6bd0341c76e46c6266e6d0ce0b7c225891..8ed9b5445016bb0b1a922580129e125079e4c7be 100644
--- a/frontend-js/src/main/js/map/data/ReferenceGenome.js
+++ b/frontend-js/src/main/js/map/data/ReferenceGenome.js
@@ -1,50 +1,192 @@
 "use strict";
 
+var Annotation = require('./Annotation');
 var ReferenceGenomeGeneMapping = require('./ReferenceGenomeGeneMapping');
 
 function ReferenceGenome(javaObject) {
   if (javaObject !== undefined && javaObject !== null) {
+    this.setId(javaObject.idObject);
     this.setType(javaObject.type);
     this.setVersion(javaObject.version);
+    this.setLocalUrl(javaObject.localUrl);
+    this.setSourceUrl(javaObject.sourceUrl);
     if (javaObject.localUrl !== undefined) {
       this.setUrl(javaObject.localUrl);
     } else {
       this.setUrl(javaObject.sourceUrl);
     }
+    this.setOrganism(new Annotation(javaObject.organism));
+    this.setDownloadProgress(javaObject.downloadProgress);
     this._geneMapping = [];
     if (javaObject.geneMapping !== undefined) {
       for (var i = 0; i < javaObject.geneMapping.length; i++) {
         this._geneMapping.push(new ReferenceGenomeGeneMapping(javaObject.geneMapping[i]));
       }
     }
+  } else {
+    this._geneMapping = [];
   }
 }
 
-ReferenceGenome.prototype.setType = function(type) {
+/**
+ *
+ * @param {string} type
+ */
+ReferenceGenome.prototype.setType = function (type) {
   this._type = type;
 };
 
-ReferenceGenome.prototype.getType = function() {
+/**
+ *
+ * @returns {string}
+ */
+ReferenceGenome.prototype.getType = function () {
   return this._type;
 };
 
-ReferenceGenome.prototype.setUrl = function(url) {
+/**
+ *
+ * @param {number} id
+ */
+ReferenceGenome.prototype.setId = function (id) {
+  this._id = id;
+};
+
+/**
+ *
+ * @returns {number}
+ */
+ReferenceGenome.prototype.getId = function () {
+  return this._id;
+};
+
+/**
+ *
+ * @returns {number}
+ */
+ReferenceGenome.prototype.getDownloadProgress = function () {
+  return this._downloadProgress;
+};
+
+/**
+ *
+ * @param {number} downloadProgress
+ */
+ReferenceGenome.prototype.setDownloadProgress = function (downloadProgress) {
+  this._downloadProgress = downloadProgress;
+};
+
+
+/**
+ *
+ * @returns {string}
+ */
+ReferenceGenome.prototype.getDownloadProgressStatus = function () {
+  if (this.getDownloadProgress() === 100) {
+    if (this.getLocalUrl() !== undefined) {
+      return "READY";
+    } else {
+      return "ERROR";
+    }
+  } else {
+    if (this.getDownloadProgress() === undefined) {
+      return "N/A";
+    } else {
+      return this.getDownloadProgress().toString();
+    }
+  }
+};
+
+
+/**
+ *
+ * @param {Annotation} organism
+ */
+ReferenceGenome.prototype.setOrganism = function (organism) {
+  this._organism = organism;
+};
+
+/**
+ *
+ * @returns {Annotation}
+ */
+ReferenceGenome.prototype.getOrganism = function () {
+  return this._organism;
+};
+
+/**
+ *
+ * @param {string} url
+ */
+ReferenceGenome.prototype.setUrl = function (url) {
   this._url = url;
 };
 
-ReferenceGenome.prototype.getUrl = function() {
+/**
+ *
+ * @returns {string}
+ */
+ReferenceGenome.prototype.getUrl = function () {
   return this._url;
 };
 
-ReferenceGenome.prototype.setVersion = function(version) {
+/**
+ *
+ * @returns {string}
+ */
+ReferenceGenome.prototype.getSourceUrl = function () {
+  return this._sourceUrl;
+};
+
+/**
+ *
+ * @param {string} sourceUrl
+ */
+ReferenceGenome.prototype.setSourceUrl = function (sourceUrl) {
+  this._sourceUrl = sourceUrl;
+};
+
+/**
+ *
+ * @returns {string}
+ */
+ReferenceGenome.prototype.getLocalUrl = function () {
+  return this._localUrl;
+};
+
+/**
+ *
+ * @param {string} localUrl
+ */
+ReferenceGenome.prototype.setLocalUrl = function (localUrl) {
+  if (localUrl === null) {
+    this._localUrl = undefined;
+  } else {
+    this._localUrl = localUrl;
+  }
+};
+
+/**
+ *
+ * @param {string} version
+ */
+ReferenceGenome.prototype.setVersion = function (version) {
   this._version = version;
 };
 
-ReferenceGenome.prototype.getVersion = function() {
+/**
+ *
+ * @returns {string}
+ */
+ReferenceGenome.prototype.getVersion = function () {
   return this._version;
 };
 
-ReferenceGenome.prototype.getGeneMappings = function() {
+/**
+ *
+ * @returns {ReferenceGenomeGeneMapping[]}
+ */
+ReferenceGenome.prototype.getGeneMappings = function () {
   return this._geneMapping;
 };
 
diff --git a/frontend-js/src/main/js/map/data/ReferenceGenomeGeneMapping.js b/frontend-js/src/main/js/map/data/ReferenceGenomeGeneMapping.js
index 5b6ad8744b16c438f3150de669ea07540636dffa..b28f702bb5667b2d93d8672502bb26faa1b602a8 100644
--- a/frontend-js/src/main/js/map/data/ReferenceGenomeGeneMapping.js
+++ b/frontend-js/src/main/js/map/data/ReferenceGenomeGeneMapping.js
@@ -7,19 +7,106 @@ function ReferenceGenomeGeneMapping(javaObject) {
   } else {
     this.setUrl(javaObject.sourceUrl);
   }
+  this.setLocalUrl(javaObject.localUrl);
+  this.setSourceUrl(javaObject.sourceUrl);
+  this.setProgress(javaObject.downloadProgress);
+  this.setId(javaObject.idObject);
 }
 
-ReferenceGenomeGeneMapping.prototype.setName = function(name) {
+/**
+ *
+ * @param {string} name
+ */
+ReferenceGenomeGeneMapping.prototype.setName = function (name) {
   this._name = name;
 };
-ReferenceGenomeGeneMapping.prototype.setUrl = function(url) {
-  this._url = url;
-};
-ReferenceGenomeGeneMapping.prototype.getName = function() {
+
+/**
+ *
+ * @returns {string}
+ */
+ReferenceGenomeGeneMapping.prototype.getName = function () {
   return this._name;
 };
-ReferenceGenomeGeneMapping.prototype.getUrl = function() {
+
+/**
+ *
+ * @param {string} url
+ */
+ReferenceGenomeGeneMapping.prototype.setUrl = function (url) {
+  this._url = url;
+};
+
+/**
+ *
+ * @returns {string}
+ */
+ReferenceGenomeGeneMapping.prototype.getUrl = function () {
   return this._url;
 };
 
+/**
+ *
+ * @param {string} url
+ */
+ReferenceGenomeGeneMapping.prototype.setLocalUrl = function (url) {
+  this._localUrl = url;
+};
+
+/**
+ *
+ * @returns {string}
+ */
+ReferenceGenomeGeneMapping.prototype.getLocalUrl = function () {
+  return this._localUrl;
+};
+
+/**
+ *
+ * @returns {string}
+ */
+ReferenceGenomeGeneMapping.prototype.getSourceUrl = function () {
+  return this._sourceUrl;
+};
+
+/**
+ *
+ * @param {string} url
+ */
+ReferenceGenomeGeneMapping.prototype.setSourceUrl = function (url) {
+  this._sourceUrl = url;
+};
+
+/**
+ *
+ * @param {number} progress
+ */
+ReferenceGenomeGeneMapping.prototype.setProgress = function (progress) {
+  this._progress = progress;
+};
+
+/**
+ *
+ * @returns {number}
+ */
+ReferenceGenomeGeneMapping.prototype.getProgress = function () {
+  return this._progress;
+};
+
+/**
+ *
+ * @param {number} id
+ */
+ReferenceGenomeGeneMapping.prototype.setId = function (id) {
+  this._id = id;
+};
+
+/**
+ *
+ * @returns {number}
+ */
+ReferenceGenomeGeneMapping.prototype.getId = function () {
+  return this._id;
+};
+
 module.exports = ReferenceGenomeGeneMapping;
diff --git a/frontend-js/src/main/js/map/data/SearchBioEntityGroup.js b/frontend-js/src/main/js/map/data/SearchBioEntityGroup.js
index bee43aa1ad2488796144079fca8f2670d7253723..16e07a3fe3d759e763ed2b449944a8e7fd57e0ac 100644
--- a/frontend-js/src/main/js/map/data/SearchBioEntityGroup.js
+++ b/frontend-js/src/main/js/map/data/SearchBioEntityGroup.js
@@ -13,14 +13,14 @@ var logger = require('../../logger');
  * @param bioEntity
  *          initial bioEntity from which group is created
  */
-function SearchAliasGroup(bioEntity) {
+function SearchBioEntityGroup(bioEntity) {
   if (!(bioEntity instanceof BioEntity)) {
     throw new Error("Invalid argument");
   }
   this._bioEntites = [bioEntity];
 }
 
-SearchAliasGroup.prototype.bioEntityMatch = function (newBioEntity) {
+SearchBioEntityGroup.prototype.bioEntityMatch = function (newBioEntity) {
   var result = true;
   var self = this;
 
@@ -33,15 +33,15 @@ SearchAliasGroup.prototype.bioEntityMatch = function (newBioEntity) {
   return result;
 };
 
-SearchAliasGroup.prototype.addBioEntity = function (newBioEntity) {
+SearchBioEntityGroup.prototype.addBioEntity = function (newBioEntity) {
   this._bioEntites.push(newBioEntity);
 };
 
-SearchAliasGroup.prototype.getBioEntities = function () {
+SearchBioEntityGroup.prototype.getBioEntities = function () {
   return this._bioEntites;
 };
 
-SearchAliasGroup.prototype.bioEntityComparator = function (bioEntity1, bioEntity2) {
+SearchBioEntityGroup.prototype.bioEntityComparator = function (bioEntity1, bioEntity2) {
   if (bioEntity1 instanceof Alias && bioEntity2 instanceof Alias) {
     if (bioEntity1.getName() !== bioEntity2.getName()) {
       return -1;
@@ -92,89 +92,93 @@ SearchAliasGroup.prototype.bioEntityComparator = function (bioEntity1, bioEntity
   return -9;
 };
 
-SearchAliasGroup.prototype.setIcon = function (icon) {
+SearchBioEntityGroup.prototype.setIcon = function (icon) {
   this._icon = icon;
 };
 
-SearchAliasGroup.prototype.getIcon = function () {
+SearchBioEntityGroup.prototype.getIcon = function () {
   return this._icon;
 };
 
 //aggregated data
-SearchAliasGroup.prototype.getType = function () {
+SearchBioEntityGroup.prototype.getType = function () {
   return this._bioEntites[0].getType();
 };
 
-SearchAliasGroup.prototype.getName = function () {
+SearchBioEntityGroup.prototype.getName = function () {
   return this._bioEntites[0].getName();
 };
 
-SearchAliasGroup.prototype.getModelId = function () {
+SearchBioEntityGroup.prototype.getModelId = function () {
   return this._bioEntites[0].getModelId();
 };
 
-SearchAliasGroup.prototype.getReactants = function () {
+SearchBioEntityGroup.prototype.getCompartmentId = function () {
+  return this._bioEntites[0].getCompartmentId();
+};
+
+SearchBioEntityGroup.prototype.getReactants = function () {
   return this._bioEntites[0].getReactants();
 };
-SearchAliasGroup.prototype.getProducts = function () {
+SearchBioEntityGroup.prototype.getProducts = function () {
   return this._bioEntites[0].getProducts();
 };
-SearchAliasGroup.prototype.getModifiers = function () {
+SearchBioEntityGroup.prototype.getModifiers = function () {
   return this._bioEntites[0].getModifiers();
 };
 
-SearchAliasGroup.prototype.getFullName = function () {
+SearchBioEntityGroup.prototype.getFullName = function () {
   return this.getMergedParameterByFunction("getFullName");
 };
 
-SearchAliasGroup.prototype.getReactionId = function () {
+SearchBioEntityGroup.prototype.getReactionId = function () {
   return this.getMergedParameterByFunction("getReactionId");
 };
-SearchAliasGroup.prototype.getLinkedSubmodelId = function () {
+SearchBioEntityGroup.prototype.getLinkedSubmodelId = function () {
   return this.getMergedParameterByFunction("getLinkedSubmodelId");
 };
-SearchAliasGroup.prototype.getSymbol = function () {
+SearchBioEntityGroup.prototype.getSymbol = function () {
   return this.getMergedParameterByFunction("getSymbol");
 };
-SearchAliasGroup.prototype.getAbbreviation = function () {
+SearchBioEntityGroup.prototype.getAbbreviation = function () {
   return this.getMergedParameterByFunction("getAbbreviation");
 };
-SearchAliasGroup.prototype.getFormula = function () {
+SearchBioEntityGroup.prototype.getFormula = function () {
   return this.getMergedParameterByFunction("getFormula");
 };
-SearchAliasGroup.prototype.getMechanicalConfidenceScore = function () {
+SearchBioEntityGroup.prototype.getMechanicalConfidenceScore = function () {
   return this.getMergedParameterByFunction("getMechanicalConfidenceScore");
 };
-SearchAliasGroup.prototype.getLowerBound = function () {
+SearchBioEntityGroup.prototype.getLowerBound = function () {
   return this.getMergedParameterByFunction("getLowerBound");
 };
-SearchAliasGroup.prototype.getUpperBound = function () {
+SearchBioEntityGroup.prototype.getUpperBound = function () {
   return this.getMergedParameterByFunction("getUpperBound");
 };
-SearchAliasGroup.prototype.getGeneProteinReaction = function () {
+SearchBioEntityGroup.prototype.getGeneProteinReaction = function () {
   return this.getMergedParameterByFunction("getGeneProteinReaction");
 };
-SearchAliasGroup.prototype.getSubsystem = function () {
+SearchBioEntityGroup.prototype.getSubsystem = function () {
   return this.getMergedParameterByFunction("getSubsystem");
 };
-SearchAliasGroup.prototype.getDescription = function () {
+SearchBioEntityGroup.prototype.getDescription = function () {
   return this.getMergedParameterByFunction("getDescription");
 };
-SearchAliasGroup.prototype.getCharge = function () {
+SearchBioEntityGroup.prototype.getCharge = function () {
   return this.getMergedParameterByFunction("getCharge");
 };
-SearchAliasGroup.prototype.getSynonyms = function () {
+SearchBioEntityGroup.prototype.getSynonyms = function () {
   return this.getIntersectionListByFunction("getSynonyms");
 };
-SearchAliasGroup.prototype.getFormerSymbols = function () {
+SearchBioEntityGroup.prototype.getFormerSymbols = function () {
   return this.getIntersectionListByFunction("getFormerSymbols");
 };
 
-SearchAliasGroup.prototype.getReferences = function () {
+SearchBioEntityGroup.prototype.getReferences = function () {
   return this.getIntersectionListByFunction("getReferences");
 };
 
-SearchAliasGroup.prototype.getOther = function (param) {
+SearchBioEntityGroup.prototype.getOther = function (param) {
   if (param === "modifications") {
     return this.getIntersectionListByFunction(function (alias) {
       return alias.getOther(param)
@@ -184,7 +188,7 @@ SearchAliasGroup.prototype.getOther = function (param) {
   }
 };
 
-SearchAliasGroup.prototype.getMergedParameterByFunction = function (functionName) {
+SearchBioEntityGroup.prototype.getMergedParameterByFunction = function (functionName) {
   var bioEntities = this.getBioEntities();
   var result = bioEntities[0][functionName]();
   for (var i = 1; i < bioEntities.length; i++) {
@@ -196,7 +200,7 @@ SearchAliasGroup.prototype.getMergedParameterByFunction = function (functionName
   return result;
 };
 
-SearchAliasGroup.prototype.getIntersectionListByFunction = function (functionName) {
+SearchBioEntityGroup.prototype.getIntersectionListByFunction = function (functionName) {
   var bioEntities = this.getBioEntities();
   var result;
   if (typeof functionName === "function") {
@@ -220,4 +224,4 @@ SearchAliasGroup.prototype.getIntersectionListByFunction = function (functionNam
 };
 
 
-module.exports = SearchAliasGroup;
+module.exports = SearchBioEntityGroup;
diff --git a/frontend-js/src/main/js/map/data/User.js b/frontend-js/src/main/js/map/data/User.js
index fdccd92f982a38273718678650934804e9f0f9e6..8c129f086c3f34238fc1b46169f8458b21b4398d 100644
--- a/frontend-js/src/main/js/map/data/User.js
+++ b/frontend-js/src/main/js/map/data/User.js
@@ -2,11 +2,17 @@
 
 /* exported logger */
 
+// noinspection JSUnusedLocalSymbols
 var logger = require('../../logger');
 
 var UserPreferences = require('./UserPreferences');
 var ObjectWithListeners = require('../../ObjectWithListeners');
 
+/**
+ *
+ * @param javaObject
+ * @constructor
+ */
 function User(javaObject) {
   // call super constructor
   ObjectWithListeners.call(this);
@@ -25,6 +31,8 @@ function User(javaObject) {
   this.setNeutralColor(javaObject.neutralColor);
   this.setSimpleColor(javaObject.simpleColor);
   this.setTermsOfUseConsent(javaObject.termsOfUseConsent);
+  this.setLdapAccountAvailable(javaObject.ldapAccountAvailable);
+  this.setConnectedToLdap(javaObject.connectedToLdap);
 }
 
 // this class inherits from ObjectWithListeners class where generic methods for
@@ -32,86 +40,170 @@ function User(javaObject) {
 User.prototype = Object.create(ObjectWithListeners.prototype);
 User.prototype.constructor = User;
 
+/**
+ *
+ * @param {string} login
+ */
 User.prototype.setLogin = function (login) {
   this._login = login;
 };
 
+/**
+ *
+ * @returns {string}
+ */
 User.prototype.getLogin = function () {
   return this._login;
 };
 
+/**
+ *
+ * @param {string} name
+ */
 User.prototype.setName = function (name) {
   this._name = name;
 };
 
+/**
+ *
+ * @returns {string}
+ */
 User.prototype.getName = function () {
   return this._name;
 };
 
+/**
+ *
+ * @param {string} surname
+ */
 User.prototype.setSurname = function (surname) {
   this._surname = surname;
 };
 
+/**
+ *
+ * @returns {string}
+ */
 User.prototype.getSurname = function () {
   return this._surname;
 };
 
+/**
+ *
+ * @param {string} email
+ */
 User.prototype.setEmail = function (email) {
   this._email = email;
 };
 
+/**
+ *
+ * @returns {string}
+ */
 User.prototype.getEmail = function () {
   return this._email;
 };
 
+/**
+ *
+ * @param {boolean} removed
+ */
 User.prototype.setRemoved = function (removed) {
   this._removed = removed;
 };
 
+/**
+ *
+ * @returns {boolean}
+ */
 User.prototype.getRemoved = function () {
   return this._removed;
 };
 
+/**
+ *
+ * @param {string} minColor
+ */
 User.prototype.setMinColor = function (minColor) {
   this._minColor = minColor;
 };
 
+/**
+ *
+ * @returns {string}
+ */
 User.prototype.getMinColor = function () {
   return this._minColor;
 };
 
+/**
+ *
+ * @param {string} simpleColor
+ */
 User.prototype.setSimpleColor = function (simpleColor) {
   this._simpleColor = simpleColor;
 };
 
+/**
+ *
+ * @returns {string}
+ */
 User.prototype.getSimpleColor = function () {
   return this._simpleColor;
 };
 
+/**
+ *
+ * @param {string} neutralColor
+ */
 User.prototype.setNeutralColor = function (neutralColor) {
   this._neutralColor = neutralColor;
 };
 
+/**
+ *
+ * @returns {string}
+ */
 User.prototype.getNeutralColor = function () {
   return this._neutralColor;
 };
 
+/**
+ *
+ * @param {string} maxColor
+ */
 User.prototype.setMaxColor = function (maxColor) {
   this._maxColor = maxColor;
 };
 
+/**
+ *
+ * @returns {string}
+ */
 User.prototype.getMaxColor = function () {
   return this._maxColor;
 };
 
+/**
+ *
+ * @param {string} password
+ */
 User.prototype.setPassword = function (password) {
   this._password = password;
 };
 
+/**
+ *
+ * @returns {string}
+ */
 User.prototype.getPassword = function () {
   return this._password;
 };
 
+/**
+ *
+ * @param {Object[]} privileges
+ */
 User.prototype.setPrivileges = function (privileges) {
   this._privileges = privileges;
   if (this._privileges === undefined) {
@@ -119,10 +211,18 @@ User.prototype.setPrivileges = function (privileges) {
   }
 };
 
+/**
+ *
+ * @returns {Array}
+ */
 User.prototype.getPrivileges = function () {
   return this._privileges;
 };
 
+/**
+ *
+ * @param {UserPreferences|Object} preferences
+ */
 User.prototype.setPreferences = function (preferences) {
   if (!(preferences instanceof UserPreferences)) {
     preferences = new UserPreferences(preferences);
@@ -130,14 +230,31 @@ User.prototype.setPreferences = function (preferences) {
   this._preferences = preferences;
 };
 
+/**
+ *
+ * @returns {UserPreferences}
+ */
 User.prototype.getPreferences = function () {
   return this._preferences;
 };
 
+/**
+ *
+ * @param {PrivilegeType} type
+ * @param {number} [objectId]
+ * @returns {boolean}
+ */
 User.prototype.hasPrivilege = function (type, objectId) {
   return this.getPrivilegeValue(type, objectId) > 0;
 };
 
+/**
+ *
+ * @param {Object} params
+ * @param {number} params.objectId
+ * @param {PrivilegeType} params.type
+ * @param {number} [params.value=1]
+ */
 User.prototype.setPrivilege = function (params) {
   var objectId = params.objectId;
   var type = params.type;
@@ -165,6 +282,13 @@ User.prototype.setPrivilege = function (params) {
   });
 };
 
+/**
+ *
+ * @param {PrivilegeType} type
+ * @param {number} [objectId]
+ *
+ * @returns {number}
+ */
 User.prototype.getPrivilegeValue = function (type, objectId) {
   for (var i = 0; i < this._privileges.length; i++) {
     var privilege = this._privileges[i];
@@ -177,6 +301,12 @@ User.prototype.getPrivilegeValue = function (type, objectId) {
   return 0;
 };
 
+/**
+ *
+ * @param {Configuration} configuration
+ *
+ * @returns {Object}
+ */
 User.prototype.privilegesToExport = function (configuration) {
   var self = this;
   var result = {};
@@ -201,6 +331,11 @@ User.prototype.privilegesToExport = function (configuration) {
   return result;
 };
 
+/**
+ *
+ * @param {User} user
+ * @returns {PromiseLike}
+ */
 User.prototype.update = function (user) {
   var self = this;
   self.setLogin(user.getLogin());
@@ -217,12 +352,52 @@ User.prototype.update = function (user) {
   return self.callListeners("onreload");
 };
 
+/**
+ *
+ * @param {boolean} termsOfUseConsent
+ */
 User.prototype.setTermsOfUseConsent = function (termsOfUseConsent) {
   this._termsOfUseConsent = termsOfUseConsent;
 };
 
+/**
+ *
+ * @returns {boolean}
+ */
 User.prototype.isTermsOfUseConsent = function () {
   return this._termsOfUseConsent;
 };
 
+/**
+ *
+ * @param {boolean} ldapAccountAvailable
+ */
+User.prototype.setLdapAccountAvailable = function (ldapAccountAvailable) {
+  this._ldapAccountAvailable = ldapAccountAvailable;
+};
+
+/**
+ *
+ * @returns {boolean}
+ */
+User.prototype.isLdapAccountAvailable = function () {
+  return this._ldapAccountAvailable;
+};
+
+/**
+ *
+ * @param {boolean} connectedToLdap
+ */
+User.prototype.setConnectedToLdap = function (connectedToLdap) {
+  this._connectedToLdap = connectedToLdap;
+};
+
+/**
+ *
+ * @returns {boolean}
+ */
+User.prototype.isConnectedToLdap = function () {
+  return this._connectedToLdap;
+};
+
 module.exports = User;
diff --git a/frontend-js/src/main/js/map/surface/AliasSurface.js b/frontend-js/src/main/js/map/surface/AliasSurface.js
index f7dc2968bc2c47f7f20d80ad3847b9fc11c9ecdc..b80391ef416accf3cd996390e639767efd78f6d5 100644
--- a/frontend-js/src/main/js/map/surface/AliasSurface.js
+++ b/frontend-js/src/main/js/map/surface/AliasSurface.js
@@ -1,260 +1,291 @@
-"use strict";
-
-/* exported logger */
-
-// noinspection JSUnusedLocalSymbols
-var logger = require('../../logger');
-var functions = require('../../Functions');
-
-var AbstractSurfaceElement = require('./AbstractSurfaceElement');
-var ConfigurationType = require('../../ConfigurationType');
-var IdentifiedElement = require('../data/IdentifiedElement');
-var Bounds = require('../canvas/Bounds');
-var Point = require('../canvas/Point');
-
-/**
- * Class representing overlay of the alias on the map relevant for a specific
- * layout.
- *
- * @param {LayoutAlias} [params.overlayAlias] - {@link LayoutAlias} for which overlay is created
- * @param {number} [params.startX] - this is the ratio on OX axis that should be use as a
- *          starting point of the overlay. For instance when there are three
- *          overlays to visualize then
- *          <ul>
- *          <li>the first layout have startX=0.0; endX=0.33333</li>
- *          <li>second layout have startX=0.33333; endX=0.66666</li>
- *          <li>the last layout have startX=0.66666; endX=1.0</li>
- *          </ul>
- * @param {number} [params.endX] this is the ratio on OX axis that should be use as a
- *          starting point of the overlay
-
- * @param {IdentifiedElement} [params.element]
- * @param {Alias} params.alias
- * @param {AbstractCustomMap} params.map
- * @param {function|function[]} [params.onClick]
- * @constructor
- * @extends AbstractSurfaceElement
- */
-function AliasSurface(params) {
-  // call super constructor
-  AbstractSurfaceElement.call(this, params);
-
-  this.setOverlayData(params.overlayAlias);
-  this.setStartX(params.startX);
-  this.setEndX(params.endX);
-
-  this.setColor(params.color);
-  this.setFillOpacity(params.opacity);
-  this.setStrokeWeight(params.strokeWeight);
-  this.setStrokeColor(params.strokeColor);
-  this.setStrokeOpacity(params.strokeOpacity);
-
-  // original data
-  this.setBioEntity(params.alias);
-  this.setIdentifiedElement(new IdentifiedElement(params.alias));
-}
-
-AliasSurface.prototype = Object.create(AbstractSurfaceElement.prototype);
-AliasSurface.prototype.constructor = AliasSurface;
-
-/**
- *
- * @param {string} color
- */
-AliasSurface.prototype.setColor = function (color) {
-  if (color === undefined) {
-    color = "#FF0000";
-  }
-
-  this._color = color;
-  var mapCanvasObjects = this.getMapCanvasObjects();
-  for (var i = 0; i < mapCanvasObjects.length; i++) {
-    mapCanvasObjects[i].setOptions({
-      strokeColor: color
-    });
-  }
-};
-
-/**
- *
- * @param {number} opacity
- */
-AliasSurface.prototype.setFillOpacity = function (opacity) {
-  this._fillOpacity = opacity;
-};
-
-/**
- *
- * @returns {number|undefined}
- */
-AliasSurface.prototype.getFillOpacity = function () {
-  return this._fillOpacity;
-};
-
-/**
- *
- * @param {number} weight
- */
-AliasSurface.prototype.setStrokeWeight = function (weight) {
-  if (weight === undefined) {
-    weight = 1;
-  }
-  this._strokeWeight = weight;
-};
-
-/**
- *
- * @returns {number}
- */
-AliasSurface.prototype.getStrokeWeight = function () {
-  return this._strokeWeight;
-};
-
-/**
- *
- * @param {string} color
- */
-AliasSurface.prototype.setStrokeColor = function (color) {
-  if (color === undefined) {
-    color = "#000000";
-  }
-  this._strokeColor = color;
-};
-
-/**
- *
- * @returns {string}
- */
-AliasSurface.prototype.getStrokeColor = function () {
-  return this._strokeColor;
-};
-
-/**
- *
- * @param {number} opacity
- */
-AliasSurface.prototype.setStrokeOpacity = function (opacity) {
-  if (opacity === undefined) {
-    opacity = 1;
-  }
-  this._strokeOpacity = opacity;
-};
-
-AliasSurface.prototype.getStrokeOpacity = function () {
-  return this._strokeOpacity;
-};
-
-/**
- * Function used to recalculate boundaries of the {@link AliasSurface}.
- * Boundaries define how big part of original alias is taken by this layout
- * visualization.
- *
- * @param {number} startX
- *          value between 0..1 defining where should be the start on OX axis
- * @param {number} endX
- *          value between 0..1 defining where should be the end on OX axis
- */
-AliasSurface.prototype.setBoundsForAlias = function (startX, endX) {
-  var alias = this.getBioEntity();
-  var pointA = new Point(alias.getX() + startX * alias.getWidth(), alias.getY());
-  var pointB = new Point(alias.getX() + endX * alias.getWidth(), alias.getY() + alias.getHeight());
-
-  var bounds = new Bounds(pointA, pointB);
-  this.getMapCanvasObjects()[0].setBounds(bounds);
-};
-
-/**
- *
- * @returns {PromiseLike<any>}
- */
-AliasSurface.prototype.init = function () {
-  var self = this;
-  var overlayData = self.getOverlayData();
-  var alias = self.getBioEntity();
-  var map = self.getCustomMap();
-  var startX = self.getStartX();
-  var endX = self.getEndX();
-
-  var pointA = new Point(alias.getX() + startX * alias.getWidth(), alias.getY());
-  var pointB = new Point(alias.getX() + endX * alias.getWidth(), alias.getY() + alias.getHeight());
-
-  var bounds = new Bounds(pointA, pointB);
-  var fillOpacity;
-  return ServerConnector.getConfigurationParam(ConfigurationType.OVERLAY_OPACITY).then(function (result) {
-    fillOpacity = self.getFillOpacity();
-    if (fillOpacity === undefined) {
-      fillOpacity = result;
-    }
-    if (overlayData !== undefined) {
-      return functions.overlayToColor(overlayData);
-    } else {
-      return "#FF0000";
-    }
-  }).then(function (color) {
-    self.addMapCanvasObject(map.getMapCanvas().createRectangle({
-      fillOpacity: fillOpacity,
-      strokeColor: self.getStrokeColor(),
-      strokeOpacity: self.getStrokeOpacity(),
-      strokeWeight: self.getStrokeWeight(),
-      fillColor: color,
-      bounds: bounds
-    }));
-  });
-};
-
-/**
- *
- * @returns {LayoutAlias}
- */
-AliasSurface.prototype.getOverlayData = function () {
-  return this._overlayData;
-};
-
-/**
- *
- * @param {LayoutAlias} overlayData
- */
-AliasSurface.prototype.setOverlayData = function (overlayData) {
-  this._overlayData = overlayData;
-};
-
-/**
- *
- * @returns {number}
- */
-AliasSurface.prototype.getStartX = function () {
-  return this._startX;
-};
-
-/**
- *
- * @param {number} startX
- */
-AliasSurface.prototype.setStartX = function (startX) {
-  if (startX === undefined) {
-    startX = 0;
-  }
-  this._startX = startX;
-};
-
-/**
- *
- * @returns {number}
- */
-AliasSurface.prototype.getEndX = function () {
-  return this._endX;
-};
-
-/**
- *
- * @param {number} endX
- */
-AliasSurface.prototype.setEndX = function (endX) {
-  if (endX === undefined) {
-    endX = 1;
-  }
-  this._endX = endX;
-};
-
-
-module.exports = AliasSurface;
+"use strict";
+
+/* exported logger */
+
+// noinspection JSUnusedLocalSymbols
+var logger = require('../../logger');
+var functions = require('../../Functions');
+
+var AbstractSurfaceElement = require('./AbstractSurfaceElement');
+var ConfigurationType = require('../../ConfigurationType');
+var IdentifiedElement = require('../data/IdentifiedElement');
+var Bounds = require('../canvas/Bounds');
+var Point = require('../canvas/Point');
+
+/**
+ * Class representing overlay of the alias on the map relevant for a specific
+ * layout.
+ *
+ * @param {LayoutAlias[]} [params.overlayData] - {@link LayoutAlias} for which overlay is created
+ * @param {number} [params.startX] - this is the ratio on OX axis that should be use as a
+ *          starting point of the overlay. For instance when there are three
+ *          overlays to visualize then
+ *          <ul>
+ *          <li>the first layout have startX=0.0; endX=0.33333</li>
+ *          <li>second layout have startX=0.33333; endX=0.66666</li>
+ *          <li>the last layout have startX=0.66666; endX=1.0</li>
+ *          </ul>
+ * @param {number} [params.endX] this is the ratio on OX axis that should be use as a
+ *          starting point of the overlay
+
+ * @param {IdentifiedElement} [params.element]
+ * @param {Alias} params.alias
+ * @param {AbstractCustomMap} params.map
+ * @param {function|function[]} [params.onClick]
+ * @constructor
+ * @extends AbstractSurfaceElement
+ */
+function AliasSurface(params) {
+  // call super constructor
+  AbstractSurfaceElement.call(this, params);
+  if (params.overlayAlias !== undefined) {
+    throw new Error();
+  }
+
+  this.setOverlayData(params.overlayData);
+  this.setStartX(params.startX);
+  this.setEndX(params.endX);
+
+  this.setColor(params.color);
+  this.setFillOpacity(params.opacity);
+  this.setStrokeWeight(params.strokeWeight);
+  this.setStrokeColor(params.strokeColor);
+  this.setStrokeOpacity(params.strokeOpacity);
+
+  // original data
+  this.setBioEntity(params.alias);
+  this.setIdentifiedElement(new IdentifiedElement(params.alias));
+}
+
+AliasSurface.prototype = Object.create(AbstractSurfaceElement.prototype);
+AliasSurface.prototype.constructor = AliasSurface;
+
+/**
+ *
+ * @param {string} color
+ */
+AliasSurface.prototype.setColor = function (color) {
+  if (color === undefined) {
+    color = "#FF0000";
+  }
+
+  this._color = color;
+  var mapCanvasObjects = this.getMapCanvasObjects();
+  for (var i = 0; i < mapCanvasObjects.length; i++) {
+    mapCanvasObjects[i].setOptions({
+      strokeColor: color
+    });
+  }
+};
+
+/**
+ *
+ * @returns {string}
+ */
+AliasSurface.prototype.getColor = function () {
+  return this._color;
+};
+
+/**
+ *
+ * @param {number} opacity
+ */
+AliasSurface.prototype.setFillOpacity = function (opacity) {
+  this._fillOpacity = opacity;
+};
+
+/**
+ *
+ * @returns {number|undefined}
+ */
+AliasSurface.prototype.getFillOpacity = function () {
+  return this._fillOpacity;
+};
+
+/**
+ *
+ * @param {number} weight
+ */
+AliasSurface.prototype.setStrokeWeight = function (weight) {
+  if (weight === undefined) {
+    weight = 1;
+  }
+  this._strokeWeight = weight;
+};
+
+/**
+ *
+ * @returns {number}
+ */
+AliasSurface.prototype.getStrokeWeight = function () {
+  return this._strokeWeight;
+};
+
+/**
+ *
+ * @param {string} color
+ */
+AliasSurface.prototype.setStrokeColor = function (color) {
+  if (color === undefined) {
+    color = "#000000";
+  }
+  this._strokeColor = color;
+};
+
+/**
+ *
+ * @returns {string}
+ */
+AliasSurface.prototype.getStrokeColor = function () {
+  return this._strokeColor;
+};
+
+/**
+ *
+ * @param {number} opacity
+ */
+AliasSurface.prototype.setStrokeOpacity = function (opacity) {
+  if (opacity === undefined) {
+    opacity = 1;
+  }
+  this._strokeOpacity = opacity;
+};
+
+/**
+ *
+ * @returns {number}
+ */
+AliasSurface.prototype.getStrokeOpacity = function () {
+  return this._strokeOpacity;
+};
+
+/**
+ * Function used to recalculate boundaries of the {@link AliasSurface}.
+ * Boundaries define how big part of original alias is taken by this layout
+ * visualization.
+ *
+ * @param {number} startX
+ *          value between 0..1 defining where should be the start on OX axis
+ * @param {number} endX
+ *          value between 0..1 defining where should be the end on OX axis
+ */
+AliasSurface.prototype.setBoundsForAlias = function (startX, endX) {
+  var alias = this.getBioEntity();
+  var pointA = new Point(alias.getX() + startX * alias.getWidth(), alias.getY());
+  var pointB = new Point(alias.getX() + endX * alias.getWidth(), alias.getY() + alias.getHeight());
+
+  var bounds = new Bounds(pointA, pointB);
+  this.getMapCanvasObjects()[0].setBounds(bounds);
+};
+
+AliasSurface.prototype._computeColors = function () {
+  var self = this;
+  var overlayData = self.getOverlayData();
+  if (overlayData === undefined || overlayData.length === 0) {
+    return self.getColor();
+  } else {
+    return functions.overlaysToColorDataStructure(overlayData);
+  }
+
+};
+/**
+ *
+ * @returns {PromiseLike<any>}
+ */
+AliasSurface.prototype.init = function () {
+  var self = this;
+  var alias = self.getBioEntity();
+  var map = self.getCustomMap();
+  var startX = self.getStartX();
+  var endX = self.getEndX();
+
+  var pointA = new Point(alias.getX() + startX * alias.getWidth(), alias.getY());
+  var pointB = new Point(alias.getX() + endX * alias.getWidth(), alias.getY() + alias.getHeight());
+
+  var bounds = new Bounds(pointA, pointB);
+  var fillOpacity;
+  return map.getServerConnector().getConfigurationParam(ConfigurationType.OVERLAY_OPACITY).then(function (result) {
+    fillOpacity = self.getFillOpacity();
+    if (fillOpacity === undefined) {
+      fillOpacity = result;
+    }
+    return self._computeColors();
+  }).then(function (color) {
+    if (typeof color === 'string' || color instanceof String) {
+      self.addMapCanvasObject(map.getMapCanvas().createRectangle({
+        fillOpacity: fillOpacity,
+        strokeColor: self.getStrokeColor(),
+        strokeOpacity: self.getStrokeOpacity(),
+        strokeWeight: self.getStrokeWeight(),
+        fillColor: color,
+        bounds: bounds
+      }));
+    } else {
+      self.addMapCanvasObject(map.getMapCanvas().createRectangle({
+        fillOpacity: fillOpacity,
+        strokeColor: self.getStrokeColor(),
+        strokeOpacity: self.getStrokeOpacity(),
+        strokeWeight: self.getStrokeWeight(),
+        fillGradient: color,
+        bounds: bounds
+      }));
+    }
+  });
+};
+
+/**
+ *
+ * @returns {LayoutAlias[]}
+ */
+AliasSurface.prototype.getOverlayData = function () {
+  return this._overlayData;
+};
+
+/**
+ *
+ * @param {LayoutAlias[]} overlayData
+ */
+AliasSurface.prototype.setOverlayData = function (overlayData) {
+  this._overlayData = overlayData;
+};
+
+/**
+ *
+ * @returns {number}
+ */
+AliasSurface.prototype.getStartX = function () {
+  return this._startX;
+};
+
+/**
+ *
+ * @param {number} startX
+ */
+AliasSurface.prototype.setStartX = function (startX) {
+  if (startX === undefined) {
+    startX = 0;
+  }
+  this._startX = startX;
+};
+
+/**
+ *
+ * @returns {number}
+ */
+AliasSurface.prototype.getEndX = function () {
+  return this._endX;
+};
+
+/**
+ *
+ * @param {number} endX
+ */
+AliasSurface.prototype.setEndX = function (endX) {
+  if (endX === undefined) {
+    endX = 1;
+  }
+  this._endX = endX;
+};
+
+
+module.exports = AliasSurface;
diff --git a/frontend-js/src/main/js/map/window/AbstractInfoWindow.js b/frontend-js/src/main/js/map/window/AbstractInfoWindow.js
index c174f946a93fbf7a57590a1c94d5a0e60b53f37e..63a91ad29070633a007e64f983e726c8df451051 100644
--- a/frontend-js/src/main/js/map/window/AbstractInfoWindow.js
+++ b/frontend-js/src/main/js/map/window/AbstractInfoWindow.js
@@ -1,743 +1,743 @@
-"use strict";
-
-var Promise = require("bluebird");
-
-var logger = require('../../logger');
-var Functions = require('../../Functions');
-
-var Comment = require('../data/Comment');
-var GuiConnector = require('../../GuiConnector');
-var GuiUtils = require('../../gui/leftPanel/GuiUtils');
-var IdentifiedElement = require('../data/IdentifiedElement');
-var ObjectWithListeners = require('../../ObjectWithListeners');
-var TargettingStructure = require('../data/TargettingStructure');
-
-/**
- * Class representing any info window in our map.
- *
- * @param {IdentifiedElement} params.identifiedElement
- * @param {AbstractCustomMap} params.map
- * @param {Marker} params.marker
- *
- * @constructor
- */
-function AbstractInfoWindow(params) {
-  // call super constructor
-  ObjectWithListeners.call(this);
-
-  var self = this;
-
-  self.setIdentifiedElement(params.identifiedElement);
-
-  self.setCustomMap(params.map);
-  self.setMarker(params.marker);
-
-  self.setContent(this.createWaitingContentDiv());
-
-  self._overlayFullView = [];
-
-  self.registerPropertyType("overlayFullView");
-
-  self.registerListenerType("onShow");
-  self.registerListenerType("onUpdate");
-
-  self.setGuiUtils(new GuiUtils());
-
-  var dbOverlaySearchChanged = function () {
-    return self.update();
-  };
-  var searchDbOverlay = params.map.getTopMap().getOverlayByName("search");
-  if (searchDbOverlay !== undefined) {
-    searchDbOverlay.addListener("onSearch", dbOverlaySearchChanged);
-  }
-  var commentDbOverlay = params.map.getTopMap().getOverlayByName("comment");
-  if (commentDbOverlay !== undefined) {
-    commentDbOverlay.addListener("onSearch", dbOverlaySearchChanged);
-  }
-}
-
-AbstractInfoWindow.prototype = Object.create(ObjectWithListeners.prototype);
-AbstractInfoWindow.prototype.constructor = AbstractInfoWindow;
-
-/**
- * Returns <code>true</code> if overlay should visualize all possible values.
- *
- * @param {string} overlayName
- *          name of the overlay
- * @returns {boolean}, <code>true</code> if overlay should visualize all possible values
- */
-AbstractInfoWindow.prototype.isOverlayFullView = function (overlayName) {
-  if (this._overlayFullView[overlayName] === undefined) {
-    this._overlayFullView[overlayName] = false;
-  }
-  return this._overlayFullView[overlayName];
-};
-
-/**
- * Returns associative array with information if specific overlay should present
- * all possible results or only specified by the data searched by user.
- *
- * @returns {Object.<string,boolean>} with information if specific overlay should present all
- *          possible results or only specified by the data searched by user
- */
-AbstractInfoWindow.prototype.getOverlayFullViewArray = function () {
-  return this._overlayFullView;
-};
-
-/**
- *
- * @param {string} overlayName
- * @param {boolean} value
- * @returns {Promise}
- */
-AbstractInfoWindow.prototype.setOverlayFullView = function (overlayName, value) {
-  var oldVal = this._overlayFullView[overlayName];
-  this._overlayFullView[overlayName] = value;
-  if (oldVal !== value) {
-    return this.firePropertyChangeListener("overlayFullView", overlayName + "," + oldVal, value);
-  } else {
-    return Promise.resolve();
-  }
-};
-
-/**
- * This method checks if {@link AbstractInfoWindow} is opened.
- *
- * @returns {Boolean} <code>true</code> if window is opened,
- *          <code>false</code> otherwise
- */
-AbstractInfoWindow.prototype.isOpened = function () {
-  if (this._infoWindow === undefined) {
-    return false;
-  }
-  return this._infoWindow.isOpened();
-};
-
-/**
- * Opens Info Window.
- *
- * @param {Marker} [newMarker]
- *
- * @returns {PromiseLike<any> | Promise<any>}
- */
-AbstractInfoWindow.prototype.open = function (newMarker) {
-  var self = this;
-  var infoWindow = self._infoWindow;
-  if (infoWindow === null || infoWindow === undefined) {
-    logger.warn("Cannot open window.");
-    return Promise.resolve();
-  }
-  if (newMarker !== undefined) {
-    infoWindow.setMarker(newMarker);
-  }
-  infoWindow.open();
-
-  return self.update().then(function () {
-    return self.callListeners("onShow");
-  });
-};
-
-/**
- * Sets new content of the info window.
- *
- * @param {HTMLElement|string} content
- *          new content of the window
- */
-AbstractInfoWindow.prototype.setContent = function (content) {
-  var self = this;
-  self._content = content;
-  if (self._infoWindow !== undefined) {
-    self._infoWindow.setContent(content);
-  }
-};
-
-/**
- * Returns content visualized in the info window.
- *
- * @returns {string|HTMLElement} content visualized in the info window
- */
-AbstractInfoWindow.prototype.getContent = function () {
-  return this._content;
-};
-
-/**
- * Creates div for an overlay data.
- *
- * @param {AbstractDbOverlay} overlay
- *          corresponding overlay
- * @param {BioEntity[]|Comment[]|Drug[]|MiRna[]|Chemical[]} data
- *          data taken from overlay
- * @returns {HTMLElement} div for given overlay data
- */
-AbstractInfoWindow.prototype.createOverlayInfoDiv = function (overlay, data) {
-  var alias = this.alias;
-  if (alias !== undefined) {
-    if (alias.getType() !== undefined) {
-      if (overlay.name === "drug") {
-        if (alias.getType().toUpperCase() === "RNA" || //
-          alias.getType().toUpperCase() === "PROTEIN" || //
-          alias.getType().toUpperCase() === "GENE") {
-          return this._createDrugInfoDiv(overlay, data);
-        } else {
-          return null;
-        }
-      } else if (overlay.name === "chemical") {
-        if (this.alias.getType().toUpperCase() === "RNA" || //
-          alias.getType().toUpperCase() === "PROTEIN" || //
-          alias.getType().toUpperCase() === "GENE") {
-          return this._createChemicalInfoDiv(overlay, data);
-        } else {
-          return null;
-        }
-      } else if (overlay.name === "mirna") {
-        if (alias.getType().toUpperCase() === "RNA" || //
-          alias.getType().toUpperCase() === "PROTEIN" || //
-          alias.getType().toUpperCase() === "GENE") {
-          return this._createMiRnaInfoDiv(overlay, data);
-        } else {
-          return null;
-        }
-
-      } else if (overlay.name === "comment") {
-        return this._createCommentInfoDiv(overlay, data);
-      } else {
-        logger.warn("Unknown overlay data for AliasInfoWindow: " + overlay.name);
-        return this._createDefaultInfoDiv(overlay, data);
-      }
-    } else {
-      logger.debug(alias);
-      throw new Error("Cannot customize info window. Alias type is unknown ");
-    }
-  } else {
-    if (overlay.getName() === "comment") {
-      return this._createCommentInfoDiv(overlay, data);
-    } else {
-      logger.debug("Cannot customize info window. Alias not defined. Overlay: " + overlay.getName());
-      return null;
-    }
-  }
-};
-
-/**
- * Creates and returns div for drug overlay information.
- *
- * @param {AbstractDbOverlay} overlay
- * @param {Drug[]} data
- *          data taken from drug overlay
- * @returns {HTMLElement} div for drug overlay information
- * @private
- */
-AbstractInfoWindow.prototype._createDrugInfoDiv = function (overlay, data) {
-  return this._createTargetInfoDiv({
-    overlay: overlay,
-    data: data,
-    name: "Interacting drugs"
-  });
-};
-
-/**
- * Creates and returns div for comment overlay information.
- *
- * @param {AbstractDbOverlay} overlay
- * @param {Comment[]} data
- *          data taken from comment overlay
- * @returns {HTMLElement} div for comment overlay information
- */
-AbstractInfoWindow.prototype._createCommentInfoDiv = function (overlay, data) {
-  if (data.length === 0 || data[0] === undefined) {
-    return null;
-  }
-  var result = document.createElement("div");
-
-  var titleElement = document.createElement("h3");
-  titleElement.innerHTML = "Comments";
-  result.appendChild(titleElement);
-  for (var i = 0; i < data.length; i++) {
-    var comment = data[i];
-    if (comment instanceof Comment) {
-      if (!comment.isRemoved()) {
-        result.appendChild(document.createElement("hr"));
-        var commentId = document.createElement("div");
-        commentId.innerHTML = '#' + comment.getId();
-        result.appendChild(commentId);
-        result.appendChild(document.createElement("br"));
-        var commentContent = Functions.createElement({type: "div", content: comment.getContent(), xss: true});
-
-        result.appendChild(commentContent);
-      }
-    } else {
-      throw new Error("Invalid comment data: " + comment);
-    }
-  }
-
-  return result;
-};
-
-/**
- * Creates and returns div for unknown overlay.
- *
- * @param {AbstractDbOverlay} overlay
- * @param {Array} data
- *          data taken from overlay
- * @returns {HTMLElement} div for overlay information
- */
-
-AbstractInfoWindow.prototype._createDefaultInfoDiv = function (overlay, data) {
-  var divElement = document.createElement("div");
-  var count = 0;
-
-  var titleElement = document.createElement("h3");
-  var title = document.createTextNode(overlay.getName());
-  titleElement.appendChild(title);
-  divElement.appendChild(titleElement);
-  for (var searchId in data) {
-    if (data.hasOwnProperty(searchId) && data[searchId] !== undefined && data[searchId] !== null) {
-      count++;
-      var resultTitleElement = document.createElement("h4");
-      var resultTitle = document.createTextNode(searchId);
-      resultTitleElement.appendChild(resultTitle);
-      divElement.appendChild(resultTitleElement);
-
-      var keys = Object.keys(data[searchId]);
-      for (var i = 0; i < keys.length; i++) {
-        var resultValElement = document.createElement("p");
-        var resultVal = document.createTextNode(keys[i] + ": " + data[searchId][keys[i]]);
-        resultValElement.appendChild(resultVal);
-        divElement.appendChild(resultValElement);
-      }
-    }
-  }
-
-  if (count === 0) {
-    divElement = null;
-  }
-  return divElement;
-};
-
-/**
- * Returns Marker object where this info window is attached.
- *
- * @returns {Marker} object where this info window is attached
- */
-AbstractInfoWindow.prototype.getMarker = function () {
-  return this._marker;
-};
-
-/**
- *
- * @param {Marker} marker
- */
-AbstractInfoWindow.prototype.setMarker = function (marker) {
-  this._marker = marker;
-  if (this._infoWindow !== undefined) {
-    this._infoWindow.setMarker(marker);
-  }
-};
-
-/**
- * Returns {@link AbstractCustomMap} where this window is presented.
- *
- * @returns {AbstractCustomMap} where this window is presented
- */
-AbstractInfoWindow.prototype.getCustomMap = function () {
-  return this.customMap;
-};
-
-/**
- *
- * @param {AbstractCustomMap} map
- */
-AbstractInfoWindow.prototype.setCustomMap = function (map) {
-  if (map === undefined) {
-    throw new Error("Map must be defined");
-  }
-  this.customMap = map;
-};
-
-/**
- * Returns html DOM object with content that should presented when waiting for
- * some data from server.
- *
- * @returns {HTMLElement} html with content that should presented when waiting for
- *          some data from server
- */
-AbstractInfoWindow.prototype.createWaitingContentDiv = function () {
-  var result = document.createElement("div");
-  var img = document.createElement("img");
-  img.src = GuiConnector.getImgPrefix() + GuiConnector.getLoadingImg();
-  var message = document.createElement("h4");
-  message.innerHTML = "loading...";
-  result.appendChild(img);
-  result.appendChild(message);
-  return result;
-};
-
-/**
- * This is a generic method that updates content of the window.
- *
- * @returns {Promise|PromiseLike}
- * @private
- */
-AbstractInfoWindow.prototype._updateContent = function () {
-  var contentDiv = null;
-  var self = this;
-
-  if (!self.isOpened()) {
-    return Promise.resolve();
-  } else {
-    self.setContent(self.createWaitingContentDiv());
-
-    return self.createContentDiv().then(function (content) {
-      contentDiv = content;
-      return self.createOverlaysDiv();
-    }).then(function (overlaysDiv) {
-      if (overlaysDiv !== undefined && overlaysDiv !== null) {
-        contentDiv.appendChild(overlaysDiv);
-      }
-      self.setContent(contentDiv);
-      return self.callListeners("onUpdate");
-    }).then(function () {
-      return contentDiv;
-    });
-  }
-};
-
-/**
- * Creates and returns div with overlays content.
- *
- * @returns {Promise<HTMLElement>} with html representing data taken from
- *          {@link AbstractDbOverlay} for this window
- */
-AbstractInfoWindow.prototype.createOverlaysDiv = function () {
-  var self = this;
-  var result = document.createElement("div");
-  return this.getOverlaysData(self.getOverlayFullViewArray()).then(function (overlayData) {
-    for (var i = 0; i < overlayData.length; i++) {
-      var overlay = overlayData[i].overlay;
-      var data = overlayData[i].data;
-      var overlayInfo = self.createOverlayInfoDiv(overlay, data);
-      if (overlayInfo !== null) {
-        result.appendChild(overlayInfo);
-      }
-    }
-    return result;
-  });
-};
-
-// noinspection JSUnusedLocalSymbols
-/**
- * Returns array with data taken from all known {@link AbstractDbOverlay}.
- *
- * @param {Object.<string,boolean>} general
- *          if true then all elements will be returned, if false then only ones
- *          available right now in the overlay
- *
- * @returns {Promise} array with data from {@link AbstractDbOverlay}
- */
-AbstractInfoWindow.prototype.getOverlaysData = function (general) {
-  throw new Error("Not implemented");
-};
-
-/**
- * Abstract method (to be implemented by subclasses) for updating content.
- *
- * @returns {Promise}
- */
-AbstractInfoWindow.prototype.update = function () {
-  return this._updateContent();
-};
-
-/**
- *
- * @param {string} params.name
- * @param {AbstractDbOverlay} params.overlay
- * @param {Array} params.data
- * @returns {HTMLElement}
- * @private
- */
-AbstractInfoWindow.prototype._createTargetInfoDiv = function (params) {
-  var overlay = params.overlay;
-  var data = params.data;
-  var name = params.name;
-
-  var self = this;
-  var result = document.createElement("div");
-
-  var titleElement = document.createElement("h3");
-  titleElement.innerHTML = name;
-  result.appendChild(titleElement);
-  if (overlay.allowGeneralSearch()) {
-    var checkboxDiv = document.createElement("div");
-    checkboxDiv.style.float = "right";
-
-    var checkbox = document.createElement("input");
-    checkbox.id = "checkbox-" + name + "-" + this.getElementType() + "-" + this.getElementId();
-    checkbox.type = "checkbox";
-    checkbox.checked = self.isOverlayFullView(overlay.getName());
-    checkbox.onclick = function () {
-      return self.setOverlayFullView(overlay.getName(), this.checked).then(null, GuiConnector.alert);
-    };
-
-    checkboxDiv.appendChild(checkbox);
-
-    var description = document.createElement("div");
-    description.style.float = "right";
-    description.innerHTML = "Show all";
-    checkboxDiv.appendChild(description);
-    result.appendChild(checkboxDiv);
-  }
-  var count = 0;
-  for (var dataId in data) {
-    if (data.hasOwnProperty(dataId)) {
-      count++;
-    }
-  }
-
-  var table = self._createTableForTargetDiv(data, overlay);
-
-  if (count === 0 && !overlay.allowGeneralSearch() && !this.isOverlayFullView(overlay.getName())) {
-    result = null;
-  }
-  if (result !== null) {
-    result.appendChild(table);
-  }
-  return result;
-};
-
-/**
- *
- * @param {Array} data
- * @param {AbstractDbOverlay} overlay
- * @returns {HTMLElement}
- * @private
- */
-AbstractInfoWindow.prototype._createTableForTargetDiv = function (data, overlay) {
-  var self = this;
-  var table = document.createElement("table");
-  table.className = "minerva-window-drug-table";
-  var header = document.createElement("tr");
-  var headerCol = document.createElement("th");
-  headerCol.innerHTML = "Name";
-  header.appendChild(headerCol);
-  headerCol = document.createElement("th");
-  headerCol.innerHTML = "References";
-  header.appendChild(headerCol);
-
-  var cell;
-  table.appendChild(header);
-  var row;
-
-  var onclick = function () {
-    // ';' enforces single query (in case there are ',' characters in the name)
-    return overlay.searchByQuery(this.innerHTML + ";");
-  };
-
-  var count = 0;
-  for (var searchId in data) {
-    if (data.hasOwnProperty(searchId)) {
-
-      row = document.createElement("tr");
-      var nameContent = searchId;
-      var annotations = [];
-      if (typeof data[searchId] === "string") {
-        nameContent = data[searchId];
-      } else if (data[searchId] instanceof TargettingStructure) {
-        nameContent = data[searchId].getName();
-        var targets = data[searchId].getTargetsForIdentifiedElement(self.getIdentifiedElement());
-        for (var i = 0; i < targets.length; i++) {
-          var references = targets[i].getReferences();
-          for (var j = 0; j < references.length; j++) {
-            annotations.push(references[j]);
-          }
-        }
-      }
-      var link = Functions.createElement({
-        type: "a",
-        onclick: onclick,
-        href: "#",
-        content: nameContent
-      });
-
-      var nameTd = Functions.createElement({
-        type: "td"
-      });
-      nameTd.appendChild(link);
-      row.appendChild(nameTd);
-
-      var referencesCell = Functions.createElement({
-        type: "td"
-      });
-      referencesCell.appendChild(self.getGuiUtils().createAnnotationList(annotations, {groupAnnotations: false}));
-
-      row.appendChild(referencesCell);
-
-      table.appendChild(row);
-      count++;
-    }
-  }
-
-  if (self.isOverlayFullView(overlay.getName()) && count === 0) {
-    row = document.createElement("tr");
-    cell = document.createElement("td");
-    cell.colSpan = 2;
-    cell.innerHTML = "No results available";
-    row.appendChild(cell);
-    table.appendChild(row);
-  }
-
-  if (!self.isOverlayFullView(overlay.getName()) && count === 0 && overlay.allowGeneralSearch()) {
-    row = document.createElement("tr");
-    cell = document.createElement("td");
-    cell.colSpan = 2;
-    cell.innerHTML = "Search for available targets";
-    row.appendChild(cell);
-    table.appendChild(row);
-  }
-  return table;
-};
-
-/**
- *
- * @returns {PromiseLike<any> | Promise<any>}
- */
-AbstractInfoWindow.prototype.init = function () {
-  var self = this;
-  var promises = [
-    // default settings of visualizing full information about elements
-    this.setOverlayFullView("drug", false),
-    this.setOverlayFullView("chemical", false),
-    this.setOverlayFullView("mirna", false),
-    this.setOverlayFullView("search", false),
-    // only all comments should be visible from the beginning
-    this.setOverlayFullView("comment", true)
-  ];
-
-  return Promise.all(promises).then(function () {
-    // listener called when user want to see all data about specific data overlay
-    var onOverlayFullViewChanged = function (e) {
-      var self = e.object;
-      // first change the content of the element
-      return self.update().then(function () {
-        if (e.newVal) {
-          var element = new IdentifiedElement({
-            objectId: self.getElementId(),
-            modelId: self.getCustomMap().getId(),
-            type: self.getElementType()
-          });
-          var topMap = self.getCustomMap().getTopMap();
-          return topMap.retrieveOverlayDetailDataForElement(element, self.getOverlayFullViewArray());
-        }
-      });
-
-    };
-
-    self.addPropertyChangeListener("overlayFullView", onOverlayFullViewChanged);
-
-    self._infoWindow = self.getCustomMap().getMapCanvas().createInfoWindow({
-      content: self.content,
-      position: self.getPosition(),
-      marker: self._marker
-    });
-
-    return ServerConnector.getConfiguration();
-  }).then(function (configuration) {
-    self.getGuiUtils().setConfiguration(configuration);
-    self.getGuiUtils().setMap(self.getCustomMap());
-  });
-};
-
-/**
- *
- * @param {GuiUtils} guiUtils
- */
-AbstractInfoWindow.prototype.setGuiUtils = function (guiUtils) {
-  this._guiUtils = guiUtils;
-};
-
-/**
- *
- * @returns {GuiUtils}
- */
-AbstractInfoWindow.prototype.getGuiUtils = function () {
-  return this._guiUtils;
-};
-
-/**
- * Creates and returns DOM div for chemical overlay information.
- *
- * @param {AbstractDbOverlay} overlay
- * @param {Chemical[]} data
- *          data taken from chemical overlay
- * @returns {HTMLElement} element with a div for comment overlay information
- * @private
- */
-AbstractInfoWindow.prototype._createChemicalInfoDiv = function (overlay, data) {
-  return this._createTargetInfoDiv({
-    overlay: overlay,
-    data: data,
-    name: "Interacting chemicals"
-  });
-};
-
-/**
- * Creates and returns DOM div for mi rna overlay information.
- *
- * @param {AbstractDbOverlay} overlay
- * @param {MiRna[]} data
- *          data taken from mi rna overlay
- * @returns {HTMLElement} DOM element with a div for comment overlay information
- */
-AbstractInfoWindow.prototype._createMiRnaInfoDiv = function (overlay, data) {
-  return this._createTargetInfoDiv({
-    overlay: overlay,
-    data: data,
-    name: "Interacting Micro RNAs"
-  });
-};
-
-/**
- *
- * @param {IdentifiedElement} identifiedElement
- */
-AbstractInfoWindow.prototype.setIdentifiedElement = function (identifiedElement) {
-  if (identifiedElement === undefined) {
-    throw new Error("identifiedElement cannot be undefined");
-  }
-  this._identifiedElement = identifiedElement;
-};
-
-/**
- *
- * @returns {IdentifiedElement}
- */
-AbstractInfoWindow.prototype.getIdentifiedElement = function () {
-  return this._identifiedElement;
-};
-
-
-/**
- * Method returning identifier of the object for which this window was created.
- *
- * @returns {string|number}
- */
-AbstractInfoWindow.prototype.getElementId = function () {
-  return this.getIdentifiedElement().getId();
-};
-
-/**
- * Method returning type of the object for which this window was created.
- *
- * @returns {string}
- */
-AbstractInfoWindow.prototype.getElementType = function () {
-  return this.getIdentifiedElement().getType();
-};
-
-/**
- * @returns {Point}
- */
-AbstractInfoWindow.prototype.getPosition = function () {
-  throw new Error("Not Implemented");
-};
-
-module.exports = AbstractInfoWindow;
+"use strict";
+
+var Promise = require("bluebird");
+
+var logger = require('../../logger');
+var Functions = require('../../Functions');
+
+var Comment = require('../data/Comment');
+var GuiConnector = require('../../GuiConnector');
+var GuiUtils = require('../../gui/leftPanel/GuiUtils');
+var IdentifiedElement = require('../data/IdentifiedElement');
+var ObjectWithListeners = require('../../ObjectWithListeners');
+var TargettingStructure = require('../data/TargettingStructure');
+
+/**
+ * Class representing any info window in our map.
+ *
+ * @param {IdentifiedElement} params.identifiedElement
+ * @param {AbstractCustomMap} params.map
+ * @param {Marker} params.marker
+ *
+ * @constructor
+ */
+function AbstractInfoWindow(params) {
+  // call super constructor
+  ObjectWithListeners.call(this);
+
+  var self = this;
+
+  self.setIdentifiedElement(params.identifiedElement);
+
+  self.setCustomMap(params.map);
+  self.setMarker(params.marker);
+
+  self.setContent(this.createWaitingContentDiv());
+
+  self._overlayFullView = [];
+
+  self.registerPropertyType("overlayFullView");
+
+  self.registerListenerType("onShow");
+  self.registerListenerType("onUpdate");
+
+  self.setGuiUtils(new GuiUtils());
+
+  var dbOverlaySearchChanged = function () {
+    return self.update();
+  };
+  var searchDbOverlay = params.map.getTopMap().getOverlayByName("search");
+  if (searchDbOverlay !== undefined) {
+    searchDbOverlay.addListener("onSearch", dbOverlaySearchChanged);
+  }
+  var commentDbOverlay = params.map.getTopMap().getOverlayByName("comment");
+  if (commentDbOverlay !== undefined) {
+    commentDbOverlay.addListener("onSearch", dbOverlaySearchChanged);
+  }
+}
+
+AbstractInfoWindow.prototype = Object.create(ObjectWithListeners.prototype);
+AbstractInfoWindow.prototype.constructor = AbstractInfoWindow;
+
+/**
+ * Returns <code>true</code> if overlay should visualize all possible values.
+ *
+ * @param {string} overlayName
+ *          name of the overlay
+ * @returns {boolean}, <code>true</code> if overlay should visualize all possible values
+ */
+AbstractInfoWindow.prototype.isOverlayFullView = function (overlayName) {
+  if (this._overlayFullView[overlayName] === undefined) {
+    this._overlayFullView[overlayName] = false;
+  }
+  return this._overlayFullView[overlayName];
+};
+
+/**
+ * Returns associative array with information if specific overlay should present
+ * all possible results or only specified by the data searched by user.
+ *
+ * @returns {Object.<string,boolean>} with information if specific overlay should present all
+ *          possible results or only specified by the data searched by user
+ */
+AbstractInfoWindow.prototype.getOverlayFullViewArray = function () {
+  return this._overlayFullView;
+};
+
+/**
+ *
+ * @param {string} overlayName
+ * @param {boolean} value
+ * @returns {Promise}
+ */
+AbstractInfoWindow.prototype.setOverlayFullView = function (overlayName, value) {
+  var oldVal = this._overlayFullView[overlayName];
+  this._overlayFullView[overlayName] = value;
+  if (oldVal !== value) {
+    return this.firePropertyChangeListener("overlayFullView", overlayName + "," + oldVal, value);
+  } else {
+    return Promise.resolve();
+  }
+};
+
+/**
+ * This method checks if {@link AbstractInfoWindow} is opened.
+ *
+ * @returns {Boolean} <code>true</code> if window is opened,
+ *          <code>false</code> otherwise
+ */
+AbstractInfoWindow.prototype.isOpened = function () {
+  if (this._infoWindow === undefined) {
+    return false;
+  }
+  return this._infoWindow.isOpened();
+};
+
+/**
+ * Opens Info Window.
+ *
+ * @param {Marker} [newMarker]
+ *
+ * @returns {PromiseLike<any> | Promise<any>}
+ */
+AbstractInfoWindow.prototype.open = function (newMarker) {
+  var self = this;
+  var infoWindow = self._infoWindow;
+  if (infoWindow === null || infoWindow === undefined) {
+    logger.warn("Cannot open window.");
+    return Promise.resolve();
+  }
+  if (newMarker !== undefined) {
+    infoWindow.setMarker(newMarker);
+  }
+  infoWindow.open();
+
+  return self.update().then(function () {
+    return self.callListeners("onShow");
+  });
+};
+
+/**
+ * Sets new content of the info window.
+ *
+ * @param {HTMLElement|string} content
+ *          new content of the window
+ */
+AbstractInfoWindow.prototype.setContent = function (content) {
+  var self = this;
+  self._content = content;
+  if (self._infoWindow !== undefined) {
+    self._infoWindow.setContent(content);
+  }
+};
+
+/**
+ * Returns content visualized in the info window.
+ *
+ * @returns {string|HTMLElement} content visualized in the info window
+ */
+AbstractInfoWindow.prototype.getContent = function () {
+  return this._content;
+};
+
+/**
+ * Creates div for an overlay data.
+ *
+ * @param {AbstractDbOverlay} overlay
+ *          corresponding overlay
+ * @param {BioEntity[]|Comment[]|Drug[]|MiRna[]|Chemical[]} data
+ *          data taken from overlay
+ * @returns {HTMLElement} div for given overlay data
+ */
+AbstractInfoWindow.prototype.createOverlayInfoDiv = function (overlay, data) {
+  var alias = this.alias;
+  if (alias !== undefined) {
+    if (alias.getType() !== undefined) {
+      if (overlay.name === "drug") {
+        if (alias.getType().toUpperCase() === "RNA" || //
+          alias.getType().toUpperCase() === "PROTEIN" || //
+          alias.getType().toUpperCase() === "GENE") {
+          return this._createDrugInfoDiv(overlay, data);
+        } else {
+          return null;
+        }
+      } else if (overlay.name === "chemical") {
+        if (this.alias.getType().toUpperCase() === "RNA" || //
+          alias.getType().toUpperCase() === "PROTEIN" || //
+          alias.getType().toUpperCase() === "GENE") {
+          return this._createChemicalInfoDiv(overlay, data);
+        } else {
+          return null;
+        }
+      } else if (overlay.name === "mirna") {
+        if (alias.getType().toUpperCase() === "RNA" || //
+          alias.getType().toUpperCase() === "PROTEIN" || //
+          alias.getType().toUpperCase() === "GENE") {
+          return this._createMiRnaInfoDiv(overlay, data);
+        } else {
+          return null;
+        }
+
+      } else if (overlay.name === "comment") {
+        return this._createCommentInfoDiv(overlay, data);
+      } else {
+        logger.warn("Unknown overlay data for AliasInfoWindow: " + overlay.name);
+        return this._createDefaultInfoDiv(overlay, data);
+      }
+    } else {
+      logger.debug(alias);
+      throw new Error("Cannot customize info window. Alias type is unknown ");
+    }
+  } else {
+    if (overlay.getName() === "comment") {
+      return this._createCommentInfoDiv(overlay, data);
+    } else {
+      logger.debug("Cannot customize info window. Alias not defined. Overlay: " + overlay.getName());
+      return null;
+    }
+  }
+};
+
+/**
+ * Creates and returns div for drug overlay information.
+ *
+ * @param {AbstractDbOverlay} overlay
+ * @param {Drug[]} data
+ *          data taken from drug overlay
+ * @returns {HTMLElement} div for drug overlay information
+ * @private
+ */
+AbstractInfoWindow.prototype._createDrugInfoDiv = function (overlay, data) {
+  return this._createTargetInfoDiv({
+    overlay: overlay,
+    data: data,
+    name: "Interacting drugs"
+  });
+};
+
+/**
+ * Creates and returns div for comment overlay information.
+ *
+ * @param {AbstractDbOverlay} overlay
+ * @param {Comment[]} data
+ *          data taken from comment overlay
+ * @returns {HTMLElement} div for comment overlay information
+ */
+AbstractInfoWindow.prototype._createCommentInfoDiv = function (overlay, data) {
+  if (data.length === 0 || data[0] === undefined) {
+    return null;
+  }
+  var result = document.createElement("div");
+
+  var titleElement = document.createElement("h3");
+  titleElement.innerHTML = "Comments";
+  result.appendChild(titleElement);
+  for (var i = 0; i < data.length; i++) {
+    var comment = data[i];
+    if (comment instanceof Comment) {
+      if (!comment.isRemoved()) {
+        result.appendChild(document.createElement("hr"));
+        var commentId = document.createElement("div");
+        commentId.innerHTML = '#' + comment.getId();
+        result.appendChild(commentId);
+        result.appendChild(document.createElement("br"));
+        var commentContent = Functions.createElement({type: "div", content: comment.getContent(), xss: true});
+
+        result.appendChild(commentContent);
+      }
+    } else {
+      throw new Error("Invalid comment data: " + comment);
+    }
+  }
+
+  return result;
+};
+
+/**
+ * Creates and returns div for unknown overlay.
+ *
+ * @param {AbstractDbOverlay} overlay
+ * @param {Array} data
+ *          data taken from overlay
+ * @returns {HTMLElement} div for overlay information
+ */
+
+AbstractInfoWindow.prototype._createDefaultInfoDiv = function (overlay, data) {
+  var divElement = document.createElement("div");
+  var count = 0;
+
+  var titleElement = document.createElement("h3");
+  var title = document.createTextNode(overlay.getName());
+  titleElement.appendChild(title);
+  divElement.appendChild(titleElement);
+  for (var searchId in data) {
+    if (data.hasOwnProperty(searchId) && data[searchId] !== undefined && data[searchId] !== null) {
+      count++;
+      var resultTitleElement = document.createElement("h4");
+      var resultTitle = document.createTextNode(searchId);
+      resultTitleElement.appendChild(resultTitle);
+      divElement.appendChild(resultTitleElement);
+
+      var keys = Object.keys(data[searchId]);
+      for (var i = 0; i < keys.length; i++) {
+        var resultValElement = document.createElement("p");
+        var resultVal = document.createTextNode(keys[i] + ": " + data[searchId][keys[i]]);
+        resultValElement.appendChild(resultVal);
+        divElement.appendChild(resultValElement);
+      }
+    }
+  }
+
+  if (count === 0) {
+    divElement = null;
+  }
+  return divElement;
+};
+
+/**
+ * Returns Marker object where this info window is attached.
+ *
+ * @returns {Marker} object where this info window is attached
+ */
+AbstractInfoWindow.prototype.getMarker = function () {
+  return this._marker;
+};
+
+/**
+ *
+ * @param {Marker} marker
+ */
+AbstractInfoWindow.prototype.setMarker = function (marker) {
+  this._marker = marker;
+  if (this._infoWindow !== undefined) {
+    this._infoWindow.setMarker(marker);
+  }
+};
+
+/**
+ * Returns {@link AbstractCustomMap} where this window is presented.
+ *
+ * @returns {AbstractCustomMap} where this window is presented
+ */
+AbstractInfoWindow.prototype.getCustomMap = function () {
+  return this.customMap;
+};
+
+/**
+ *
+ * @param {AbstractCustomMap} map
+ */
+AbstractInfoWindow.prototype.setCustomMap = function (map) {
+  if (map === undefined) {
+    throw new Error("Map must be defined");
+  }
+  this.customMap = map;
+};
+
+/**
+ * Returns html DOM object with content that should presented when waiting for
+ * some data from server.
+ *
+ * @returns {HTMLElement} html with content that should presented when waiting for
+ *          some data from server
+ */
+AbstractInfoWindow.prototype.createWaitingContentDiv = function () {
+  var result = document.createElement("div");
+  var img = document.createElement("img");
+  img.src = GuiConnector.getImgPrefix() + GuiConnector.getLoadingImg();
+  var message = document.createElement("h4");
+  message.innerHTML = "loading...";
+  result.appendChild(img);
+  result.appendChild(message);
+  return result;
+};
+
+/**
+ * This is a generic method that updates content of the window.
+ *
+ * @returns {Promise|PromiseLike}
+ * @private
+ */
+AbstractInfoWindow.prototype._updateContent = function () {
+  var contentDiv = null;
+  var self = this;
+
+  if (!self.isOpened()) {
+    return Promise.resolve();
+  } else {
+    self.setContent(self.createWaitingContentDiv());
+
+    return self.createContentDiv().then(function (content) {
+      contentDiv = content;
+      return self.createDbOverlaysDiv();
+    }).then(function (overlaysDiv) {
+      if (overlaysDiv !== undefined && overlaysDiv !== null) {
+        contentDiv.appendChild(overlaysDiv);
+      }
+      self.setContent(contentDiv);
+      return self.callListeners("onUpdate");
+    }).then(function () {
+      return contentDiv;
+    });
+  }
+};
+
+/**
+ * Creates and returns div with overlays content.
+ *
+ * @returns {Promise<HTMLElement>} with html representing data taken from
+ *          {@link AbstractDbOverlay} for this window
+ */
+AbstractInfoWindow.prototype.createDbOverlaysDiv = function () {
+  var self = this;
+  var result = document.createElement("div");
+  return this.getDbOverlaysData(self.getOverlayFullViewArray()).then(function (overlayData) {
+    for (var i = 0; i < overlayData.length; i++) {
+      var overlay = overlayData[i].overlay;
+      var data = overlayData[i].data;
+      var overlayInfo = self.createOverlayInfoDiv(overlay, data);
+      if (overlayInfo !== null) {
+        result.appendChild(overlayInfo);
+      }
+    }
+    return result;
+  });
+};
+
+// noinspection JSUnusedLocalSymbols
+/**
+ * Returns array with data taken from all known {@link AbstractDbOverlay}.
+ *
+ * @param {Object.<string,boolean>} general
+ *          if true then all elements will be returned, if false then only ones
+ *          available right now in the overlay
+ *
+ * @returns {Promise} array with data from {@link AbstractDbOverlay}
+ */
+AbstractInfoWindow.prototype.getDbOverlaysData = function (general) {
+  throw new Error("Not implemented");
+};
+
+/**
+ * Abstract method (to be implemented by subclasses) for updating content.
+ *
+ * @returns {Promise}
+ */
+AbstractInfoWindow.prototype.update = function () {
+  return this._updateContent();
+};
+
+/**
+ *
+ * @param {string} params.name
+ * @param {AbstractDbOverlay} params.overlay
+ * @param {Array} params.data
+ * @returns {HTMLElement}
+ * @private
+ */
+AbstractInfoWindow.prototype._createTargetInfoDiv = function (params) {
+  var overlay = params.overlay;
+  var data = params.data;
+  var name = params.name;
+
+  var self = this;
+  var result = document.createElement("div");
+
+  var titleElement = document.createElement("h3");
+  titleElement.innerHTML = name;
+  result.appendChild(titleElement);
+  if (overlay.allowGeneralSearch()) {
+    var checkboxDiv = document.createElement("div");
+    checkboxDiv.style.float = "right";
+
+    var checkbox = document.createElement("input");
+    checkbox.id = "checkbox-" + name + "-" + this.getElementType() + "-" + this.getElementId();
+    checkbox.type = "checkbox";
+    checkbox.checked = self.isOverlayFullView(overlay.getName());
+    checkbox.onclick = function () {
+      return self.setOverlayFullView(overlay.getName(), this.checked).then(null, GuiConnector.alert);
+    };
+
+    checkboxDiv.appendChild(checkbox);
+
+    var description = document.createElement("div");
+    description.style.float = "right";
+    description.innerHTML = "Show all";
+    checkboxDiv.appendChild(description);
+    result.appendChild(checkboxDiv);
+  }
+  var count = 0;
+  for (var dataId in data) {
+    if (data.hasOwnProperty(dataId)) {
+      count++;
+    }
+  }
+
+  var table = self._createTableForTargetDiv(data, overlay);
+
+  if (count === 0 && !overlay.allowGeneralSearch() && !this.isOverlayFullView(overlay.getName())) {
+    result = null;
+  }
+  if (result !== null) {
+    result.appendChild(table);
+  }
+  return result;
+};
+
+/**
+ *
+ * @param {Array} data
+ * @param {AbstractDbOverlay} overlay
+ * @returns {HTMLElement}
+ * @private
+ */
+AbstractInfoWindow.prototype._createTableForTargetDiv = function (data, overlay) {
+  var self = this;
+  var table = document.createElement("table");
+  table.className = "minerva-window-drug-table";
+  var header = document.createElement("tr");
+  var headerCol = document.createElement("th");
+  headerCol.innerHTML = "Name";
+  header.appendChild(headerCol);
+  headerCol = document.createElement("th");
+  headerCol.innerHTML = "References";
+  header.appendChild(headerCol);
+
+  var cell;
+  table.appendChild(header);
+  var row;
+
+  var onclick = function () {
+    // ';' enforces single query (in case there are ',' characters in the name)
+    return overlay.searchByQuery(this.innerHTML + ";");
+  };
+
+  var count = 0;
+  for (var searchId in data) {
+    if (data.hasOwnProperty(searchId)) {
+
+      row = document.createElement("tr");
+      var nameContent = searchId;
+      var annotations = [];
+      if (typeof data[searchId] === "string") {
+        nameContent = data[searchId];
+      } else if (data[searchId] instanceof TargettingStructure) {
+        nameContent = data[searchId].getName();
+        var targets = data[searchId].getTargetsForIdentifiedElement(self.getIdentifiedElement());
+        for (var i = 0; i < targets.length; i++) {
+          var references = targets[i].getReferences();
+          for (var j = 0; j < references.length; j++) {
+            annotations.push(references[j]);
+          }
+        }
+      }
+      var link = Functions.createElement({
+        type: "a",
+        onclick: onclick,
+        href: "#",
+        content: nameContent
+      });
+
+      var nameTd = Functions.createElement({
+        type: "td"
+      });
+      nameTd.appendChild(link);
+      row.appendChild(nameTd);
+
+      var referencesCell = Functions.createElement({
+        type: "td"
+      });
+      referencesCell.appendChild(self.getGuiUtils().createAnnotationList(annotations, {groupAnnotations: false}));
+
+      row.appendChild(referencesCell);
+
+      table.appendChild(row);
+      count++;
+    }
+  }
+
+  if (self.isOverlayFullView(overlay.getName()) && count === 0) {
+    row = document.createElement("tr");
+    cell = document.createElement("td");
+    cell.colSpan = 2;
+    cell.innerHTML = "No results available";
+    row.appendChild(cell);
+    table.appendChild(row);
+  }
+
+  if (!self.isOverlayFullView(overlay.getName()) && count === 0 && overlay.allowGeneralSearch()) {
+    row = document.createElement("tr");
+    cell = document.createElement("td");
+    cell.colSpan = 2;
+    cell.innerHTML = "Search for available targets";
+    row.appendChild(cell);
+    table.appendChild(row);
+  }
+  return table;
+};
+
+/**
+ *
+ * @returns {PromiseLike<any> | Promise<any>}
+ */
+AbstractInfoWindow.prototype.init = function () {
+  var self = this;
+  var promises = [
+    // default settings of visualizing full information about elements
+    this.setOverlayFullView("drug", false),
+    this.setOverlayFullView("chemical", false),
+    this.setOverlayFullView("mirna", false),
+    this.setOverlayFullView("search", false),
+    // only all comments should be visible from the beginning
+    this.setOverlayFullView("comment", true)
+  ];
+
+  return Promise.all(promises).then(function () {
+    // listener called when user want to see all data about specific data overlay
+    var onOverlayFullViewChanged = function (e) {
+      var self = e.object;
+      // first change the content of the element
+      return self.update().then(function () {
+        if (e.newVal) {
+          var element = new IdentifiedElement({
+            objectId: self.getElementId(),
+            modelId: self.getCustomMap().getId(),
+            type: self.getElementType()
+          });
+          var topMap = self.getCustomMap().getTopMap();
+          return topMap.retrieveOverlayDetailDataForElement(element, self.getOverlayFullViewArray());
+        }
+      });
+
+    };
+
+    self.addPropertyChangeListener("overlayFullView", onOverlayFullViewChanged);
+
+    self._infoWindow = self.getCustomMap().getMapCanvas().createInfoWindow({
+      content: self.content,
+      position: self.getPosition(),
+      marker: self._marker
+    });
+
+    return ServerConnector.getConfiguration();
+  }).then(function (configuration) {
+    self.getGuiUtils().setConfiguration(configuration);
+    self.getGuiUtils().setMap(self.getCustomMap());
+  });
+};
+
+/**
+ *
+ * @param {GuiUtils} guiUtils
+ */
+AbstractInfoWindow.prototype.setGuiUtils = function (guiUtils) {
+  this._guiUtils = guiUtils;
+};
+
+/**
+ *
+ * @returns {GuiUtils}
+ */
+AbstractInfoWindow.prototype.getGuiUtils = function () {
+  return this._guiUtils;
+};
+
+/**
+ * Creates and returns DOM div for chemical overlay information.
+ *
+ * @param {AbstractDbOverlay} overlay
+ * @param {Chemical[]} data
+ *          data taken from chemical overlay
+ * @returns {HTMLElement} element with a div for comment overlay information
+ * @private
+ */
+AbstractInfoWindow.prototype._createChemicalInfoDiv = function (overlay, data) {
+  return this._createTargetInfoDiv({
+    overlay: overlay,
+    data: data,
+    name: "Interacting chemicals"
+  });
+};
+
+/**
+ * Creates and returns DOM div for mi rna overlay information.
+ *
+ * @param {AbstractDbOverlay} overlay
+ * @param {MiRna[]} data
+ *          data taken from mi rna overlay
+ * @returns {HTMLElement} DOM element with a div for comment overlay information
+ */
+AbstractInfoWindow.prototype._createMiRnaInfoDiv = function (overlay, data) {
+  return this._createTargetInfoDiv({
+    overlay: overlay,
+    data: data,
+    name: "Interacting Micro RNAs"
+  });
+};
+
+/**
+ *
+ * @param {IdentifiedElement} identifiedElement
+ */
+AbstractInfoWindow.prototype.setIdentifiedElement = function (identifiedElement) {
+  if (identifiedElement === undefined) {
+    throw new Error("identifiedElement cannot be undefined");
+  }
+  this._identifiedElement = identifiedElement;
+};
+
+/**
+ *
+ * @returns {IdentifiedElement}
+ */
+AbstractInfoWindow.prototype.getIdentifiedElement = function () {
+  return this._identifiedElement;
+};
+
+
+/**
+ * Method returning identifier of the object for which this window was created.
+ *
+ * @returns {string|number}
+ */
+AbstractInfoWindow.prototype.getElementId = function () {
+  return this.getIdentifiedElement().getId();
+};
+
+/**
+ * Method returning type of the object for which this window was created.
+ *
+ * @returns {string}
+ */
+AbstractInfoWindow.prototype.getElementType = function () {
+  return this.getIdentifiedElement().getType();
+};
+
+/**
+ * @returns {Point}
+ */
+AbstractInfoWindow.prototype.getPosition = function () {
+  throw new Error("Not Implemented");
+};
+
+module.exports = AbstractInfoWindow;
diff --git a/frontend-js/src/main/js/map/window/AliasInfoWindow.js b/frontend-js/src/main/js/map/window/AliasInfoWindow.js
index 5f9957d418f073468ce95763fe133a99d75c6df2..f80f8bfc7eeb1635491e921e36b5f9c8329ae146 100644
--- a/frontend-js/src/main/js/map/window/AliasInfoWindow.js
+++ b/frontend-js/src/main/js/map/window/AliasInfoWindow.js
@@ -36,10 +36,7 @@ function AliasInfoWindow(params) {
   this.setAlias(params.alias);
 
   var overlayListChanged = function () {
-    return self.getCustomMap().getAliasVisibleLayoutsData(self.getAlias().getId()).then(function (layoutAliases) {
-      self.layoutAliases = layoutAliases;
-      return self.update();
-    });
+    return self.update();
   };
 
   var dbOverlaySearchChanged = function () {
@@ -97,99 +94,147 @@ AliasInfoWindow.prototype.init = function () {
  * Creates and returns chart representing data related to alias on different
  * overlays.
  *
+ * @param {DataOverlay[]} params.overlays
+ *
  * @returns {PromiseLike<HTMLElement>} html element representing chart with data related to alias
  *          on different overlays
  */
-AliasInfoWindow.prototype.createChartDiv = function () {
+AliasInfoWindow.prototype.createChartDiv = function (params) {
+  var overlays = params.overlays;
+
   var result = document.createElement("div");
-  var rows = [];
+  var promises = [];
   var self = this;
-  return Promise.each(self.layoutAliases, function (data, i) {
-    var rowDiv = document.createElement("div");
-    if (i % 2 === 0) {
-      rowDiv.className = "mapChartRowEvenDiv";
-    } else {
-      rowDiv.className = "mapChartRowOddDiv";
-    }
-    rowDiv.style.position = "relative";
-    var nameDiv = document.createElement("div");
-    nameDiv.className = "mapChartNameDiv";
-    nameDiv.innerHTML = self.layoutNames[i] + "&nbsp;";
-    rowDiv.appendChild(nameDiv);
-
-    rows[i] = rowDiv;
-    if (data !== undefined && data !== null) {
-      return Functions.overlayToColor(data).then(function (color) {
-        var value = parseFloat(data.value);
-        var description = data.description;
-        if (description === null || description === undefined || description === "") {
-          description = "";
-          if (!isNaN(value)) {
-            description = value.toFixed(2);
+
+  overlays.forEach(function (overlay, i) {
+    promises.push(overlay.getFullAliasById(self.getAlias().getId()).then(function (data) {
+      var rowDiv = document.createElement("div");
+      if (i % 2 === 0 || self.getAlias().getLinkedSubmodelId() !== undefined) {
+        rowDiv.className = "minerva-chart-row-even";
+      } else {
+        rowDiv.className = "minerva-chart-row-odd";
+      }
+      var nameDiv = document.createElement("div");
+      nameDiv.className = "minerva-chart-name";
+      nameDiv.innerHTML = overlays[i].getName() + "&nbsp;";
+      rowDiv.appendChild(nameDiv);
+
+      if (data !== undefined && data !== null) {
+        return Functions.overlayToColor(data).then(function (color) {
+          var value = parseFloat(data.value);
+          var description = data.description;
+          if (description === null || description === undefined || description === "") {
+            description = "";
+            if (!isNaN(value)) {
+              description = value.toFixed(2);
+            }
           }
-        }
-        var leftMarginDiv = document.createElement("div");
-        leftMarginDiv.innerHTML = "&nbsp;";
-        leftMarginDiv.style.float = "left";
-        var centerBarDiv = document.createElement("div");
-        centerBarDiv.style.width = "1px";
-        centerBarDiv.style.float = "left";
-        centerBarDiv.style.background = "#000000";
-        centerBarDiv.innerHTML = "&nbsp;";
-
-        var rightBarDiv = document.createElement("div");
-        rightBarDiv.innerHTML = "&nbsp;";
-        rightBarDiv.style.float = "left";
-        rightBarDiv.style.background = color;
-        rightBarDiv.style.width = Math.abs(value * 100) + "px";
-        var offset = 100;
-        var descDiv = document.createElement("div");
-        descDiv.style.float = "right";
-        descDiv.style.textAlign = "right";
-        descDiv.style.position = "absolute";
-        descDiv.style.right = "0";
-        descDiv.innerHTML = "<span>" + description + "</span>";
-        if (!isNaN(value)) {
-          if (value > 0) {
-            offset = 100;
-            leftMarginDiv.style.width = offset + "px";
+          var leftMarginDiv = document.createElement("div");
+          leftMarginDiv.innerHTML = "&nbsp;";
+          leftMarginDiv.style.float = "left";
+          var centerBarDiv = document.createElement("div");
+          centerBarDiv.style.width = "1px";
+          centerBarDiv.style.float = "left";
+          centerBarDiv.style.background = "#000000";
+          centerBarDiv.innerHTML = "&nbsp;";
+
+          var rightBarDiv = document.createElement("div");
+          rightBarDiv.innerHTML = "&nbsp;";
+          rightBarDiv.style.float = "left";
+          rightBarDiv.style.background = color;
+          rightBarDiv.style.width = Math.abs(value * 100) + "px";
+          var offset = 100;
+          var descDiv = document.createElement("div");
+          descDiv.style.float = "right";
+          descDiv.style.textAlign = "right";
+          descDiv.style.position = "absolute";
+          descDiv.style.right = "0";
+          descDiv.innerHTML = "<span>" + description + "</span>";
+          if (!isNaN(value)) {
+            if (value > 0) {
+              offset = 100;
+              leftMarginDiv.style.width = offset + "px";
 
-            rightBarDiv.style.textAlign = "right";
+              rightBarDiv.style.textAlign = "right";
+
+              rowDiv.appendChild(leftMarginDiv);
+              rowDiv.appendChild(centerBarDiv);
+              rowDiv.appendChild(rightBarDiv);
+            } else {
+              offset = 100 + (value * 100);
+              leftMarginDiv.style.width = offset + "px";
+
+              rowDiv.appendChild(leftMarginDiv);
+              rowDiv.appendChild(rightBarDiv);
+              rowDiv.appendChild(centerBarDiv);
+            }
 
-            rowDiv.appendChild(leftMarginDiv);
-            rowDiv.appendChild(centerBarDiv);
-            rowDiv.appendChild(rightBarDiv);
           } else {
-            offset = 100 + (value * 100);
+            offset = 100;
             leftMarginDiv.style.width = offset + "px";
-
+            leftMarginDiv.style.background = color;
+            rightBarDiv.style.width = offset + "px";
+            rightBarDiv.style.background = color;
+            rightBarDiv.style.textAlign = "right";
             rowDiv.appendChild(leftMarginDiv);
-            rowDiv.appendChild(rightBarDiv);
             rowDiv.appendChild(centerBarDiv);
+            rowDiv.appendChild(rightBarDiv);
+          }
+          rowDiv.appendChild(descDiv);
+          return rowDiv;
+        });
+      } else {
+        var emptyDiv = document.createElement("div");
+        emptyDiv.innerHTML = "&nbsp;";
+        emptyDiv.style.float = "left";
+        emptyDiv.style.width = "201px";
+        rowDiv.appendChild(emptyDiv);
+        return rowDiv;
+      }
+    }));
+    if (self.getAlias().getLinkedSubmodelId() !== undefined) {
+      promises.push(new Promise.resolve(overlay).then(function (overlay) {
+        var overlayData = overlay.getAliases();
+        var overlayDataOnSubmap = [];
+        for (var j = 0; j < overlayData.length; j++) {
+          var data = overlayData[j];
+          if (data.getModelId() === self.getAlias().getLinkedSubmodelId()) {
+            overlayDataOnSubmap.push(data);
           }
-
-        } else {
-          offset = 100;
-          leftMarginDiv.style.width = offset + "px";
-          leftMarginDiv.style.background = color;
-          rightBarDiv.style.width = offset + "px";
-          rightBarDiv.style.background = color;
-          rightBarDiv.style.textAlign = "right";
-          rowDiv.appendChild(leftMarginDiv);
-          rowDiv.appendChild(centerBarDiv);
-          rowDiv.appendChild(rightBarDiv);
         }
-        rowDiv.appendChild(descDiv);
-      });
-    } else {
-      var emptyDiv = document.createElement("div");
-      emptyDiv.innerHTML = "&nbsp;";
-      emptyDiv.style.float = "left";
-      emptyDiv.style.width = "201px";
-      rowDiv.appendChild(emptyDiv);
-      return Promise.resolve();
+        return Functions.overlaysToColorDataStructure(overlayDataOnSubmap).then(function (colors) {
+          var rowDiv = document.createElement("div");
+          rowDiv.className = "minerva-chart-row-odd";
+          var nameDiv = document.createElement("div");
+          nameDiv.className = "minerva-chart-name";
+          var submapName = self.getCustomMap().getTopMap().getSubmapById(self.getAlias().getLinkedSubmodelId()).getModel().getName();
+          nameDiv.innerHTML = "Submap " + submapName;
+          rowDiv.appendChild(nameDiv);
+
+          var emptyDiv = document.createElement("div");
+          emptyDiv.style.float = "left";
+          emptyDiv.style.width = "201px";
+          rowDiv.appendChild(emptyDiv);
+
+          var totalAmount = 0;
+          for (var j = 0; j < colors.length; j++) {
+            totalAmount += colors[j].amount;
+          }
+
+          for (j = 0; j < colors.length; j++) {
+            var overlayDataDiv = document.createElement("div");
+            overlayDataDiv.innerHTML = "&nbsp;";
+            overlayDataDiv.style.float = "left";
+            overlayDataDiv.style.width = Math.floor(100*colors[j].amount / totalAmount) + "%";
+            overlayDataDiv.style.background = colors[j].color;
+            emptyDiv.appendChild(overlayDataDiv);
+          }
+          return rowDiv;
+        });
+      }));
     }
-  }).then(function () {
+  });
+  return Promise.all(promises).then(function (rows) {
     for (var i = 0; i < rows.length; i++) {
       result.appendChild(rows[i]);
     }
@@ -215,18 +260,14 @@ AliasInfoWindow.prototype.createContentDiv = function () {
 
     result.appendChild(overlayDiv);
 
-    return self.getCustomMap().getAliasVisibleLayoutsData(alias.getId()).then(function (layoutAliases) {
-      self.layoutAliases = layoutAliases;
-      return self.getCustomMap().getTopMap().getVisibleDataOverlays();
-    }).then(function (dataOverlays) {
-      self.layoutNames = [];
-      for (var i = 0; i < dataOverlays.length; i++) {
-        self.layoutNames.push(dataOverlays[i].getName());
-      }
-      return self.createChartDiv();
+    var overlays;
+
+    return self.getCustomMap().getTopMap().getVisibleDataOverlays().then(function (dataOverlays) {
+      overlays = dataOverlays;
+      return self.createChartDiv({overlays: overlays});
     }).then(function (chartDiv) {
       overlayDiv.appendChild(chartDiv);
-      return self.createGenomicDiv();
+      return self.createGenomicDiv({overlays: overlays});
     }).then(function (genomicDiv) {
       overlayDiv.appendChild(genomicDiv);
       return result;
@@ -245,15 +286,19 @@ AliasInfoWindow.prototype.createContentDiv = function () {
  *
  * @returns {Promise} array with data from {@link AbstractDbOverlay}
  */
-AliasInfoWindow.prototype.getOverlaysData = function (general) {
+AliasInfoWindow.prototype.getDbOverlaysData = function (general) {
   return this.getCustomMap().getTopMap().getOverlayDataForAlias(this.getAlias(), general);
 };
 
 /**
  *
- * @returns {PromiseLike<HTMLElement>}
+ * @param {DataOverlay[]} params.overlays
+ *
+ * @returns {Promise|PromiseLike}
  */
-AliasInfoWindow.prototype.createGenomicDiv = function () {
+AliasInfoWindow.prototype.createGenomicDiv = function (params) {
+  var overlays = params.overlays;
+
   var self = this;
 
   var result = document.createElement("div");
@@ -285,34 +330,41 @@ AliasInfoWindow.prototype.createGenomicDiv = function () {
 
   var globalGeneVariants = [];
 
-  return Promise.each(
-    self.layoutAliases,
-    function (data) {
+  var promises = [];
+  var overlaysData = [];
+
+  overlays.forEach(function (overlay) {
+    promises.push(overlay.getFullAliasById(self.getAlias().getId()));
+  });
+  return Promise.all(promises).then(function (result) {
+    promises = [];
+    overlaysData = result;
+    for (var i = 0; i < overlaysData.length; i++) {
+      var data = overlaysData[i];
       if (data !== null && data !== undefined && data.getType() === LayoutAlias.GENETIC_VARIANT) {
         geneticInformation = true;
-        return Promise.each(data.getGeneVariants(), function (variant) {
-          return self.getCustomMap().getReferenceGenome(variant.getReferenceGenomeType(),
-            variant.getReferenceGenomeVersion()).then(
-            function (genome) {
-              if (genome.getUrl() !== null && genome.getUrl() !== undefined) {
-                if (genomes[genome.getUrl()] === undefined) {
-                  genomes[genome.getUrl()] = genome;
-                  genomeUrls.push(genome.getUrl());
-                }
-              } else {
-                logger.warn("Genome for " + variant.getReferenceGenomeType() + ","
-                  + variant.getReferenceGenomeVersion() + " not loaded");
+        promises.push(Promise.each(data.getGeneVariants(), function (variant) {
+          return self.getCustomMap().getTopMap().getReferenceGenome(variant.getReferenceGenomeType(),
+            variant.getReferenceGenomeVersion()).then(function (genome) {
+            if (genome.getUrl() !== null && genome.getUrl() !== undefined) {
+              if (genomes[genome.getUrl()] === undefined) {
+                genomes[genome.getUrl()] = genome;
+                genomeUrls.push(genome.getUrl());
               }
-            },
-            function () {
+            } else {
               logger.warn("Genome for " + variant.getReferenceGenomeType() + ","
                 + variant.getReferenceGenomeVersion() + " not loaded");
+            }
+          }, function () {
+            logger.warn("Genome for " + variant.getReferenceGenomeType() + ","
+              + variant.getReferenceGenomeVersion() + " not loaded");
 
-            });
-        });
-
+          });
+        }));
       }
-    }).then(function () {
+    }
+    return Promise.all(promises);
+  }).then(function () {
     for (var i = 0; i < genomeUrls.length; i++) {
       var genome = genomes[genomeUrls[i]];
       pileupSource.splice(0, 0, {
@@ -334,7 +386,8 @@ AliasInfoWindow.prototype.createGenomicDiv = function () {
         });
       }
     }
-    return Promise.each(self.layoutAliases, function (data, i) {
+    for (i = 0; i < overlaysData.length; i++) {
+      var data = overlaysData[i];
       globalGeneVariants[i] = [];
       if (data !== null && data !== undefined && data.getType() === LayoutAlias.GENETIC_VARIANT) {
         var geneVariants = data.getGeneVariants();
@@ -349,21 +402,20 @@ AliasInfoWindow.prototype.createGenomicDiv = function () {
           pileupRange.stop = Math.max(pileupRange.stop, variant.getPosition() + length);
         }
       }
-    });
-  }).then(function () {
+    }
     if (geneticInformation) {
       if (genomeUrls.length === 0) {
         contentElement.innerHTML = "No reference genome data available on minerva platform";
       } else {
-        for (var iter = 0; iter < self.layoutAliases.length; iter++) {
-          if (globalGeneVariants[iter].length > 0) {
-            var vcfContent = self.createVcfString(globalGeneVariants[iter]);
+        for (i = 0; i < overlaysData.length; i++) {
+          if (globalGeneVariants[i].length > 0) {
+            var vcfContent = self.createVcfString(globalGeneVariants[i]);
             pileupSource.push({
               viz: pileup.viz.variants(),
               data: pileup.formats.vcf({
                 content: vcfContent
               }),
-              name: self.layoutNames[iter] + ' - Variants',
+              name: overlays[i].getName() + ' - Variants',
               options: {
                 variantHeightByFrequency: true
               }
@@ -385,6 +437,40 @@ AliasInfoWindow.prototype.createGenomicDiv = function () {
           range: pileupRange,
           tracks: pileupSource
         });
+
+
+        //Code below is a workaround - for some reason on openlayers events bound by pileup are not working properly...
+        var zoomControls = $(".zoom-controls", contentElement);
+
+        zoomControls.children().hide();
+
+        var zoomIn = $('<input type="button" value="+" class="btn-zoom-in"/>');
+        zoomIn.on("click", function () {
+          var range = self.pileup.getRange();
+          var distDiff = parseInt((range.stop - range.start + 1) / 4);
+          range.start += distDiff;
+          range.stop -= distDiff;
+
+          self.pileup.setRange(range);
+        });
+        zoomIn.appendTo(zoomControls);
+        var zoomOut = $('<input type="button" value="-" class="btn-zoom-out"/>');
+        zoomOut.on("click", function () {
+          var range = self.pileup.getRange();
+          var distDiff = parseInt((range.stop - range.start) / 2);
+          if (distDiff === 0) {
+            distDiff = 1;
+          }
+          range.start -= distDiff;
+          range.stop += distDiff;
+          if (range.start < 0) {
+            range.stop -= range.start;
+            range.start = 0;
+          }
+
+          self.pileup.setRange(range);
+        });
+        zoomOut.appendTo(zoomControls);
       }
 
       return result;
@@ -459,5 +545,4 @@ AliasInfoWindow.prototype.getPosition = function () {
   return new Point(alias.x + alias.width / 2, alias.y + alias.height / 2);
 };
 
-
 module.exports = AliasInfoWindow;
diff --git a/frontend-js/src/main/js/map/window/PointInfoWindow.js b/frontend-js/src/main/js/map/window/PointInfoWindow.js
index dc1c2d7f8bb90b04f783ce2ebd63acbad6f380ba..bf263c8e7a751e2e94ac1497e077cc2614c78f02 100644
--- a/frontend-js/src/main/js/map/window/PointInfoWindow.js
+++ b/frontend-js/src/main/js/map/window/PointInfoWindow.js
@@ -1,63 +1,63 @@
-"use strict";
-
-var Promise = require("bluebird");
-
-var AbstractInfoWindow = require('./AbstractInfoWindow');
-var IdentifiedElement = require('../data/IdentifiedElement');
-
-/**
- *
- * @param {IdentifiedElement} [params.identifiedElement]
- * @param {AbstractCustomMap} params.map
- * @param {Marker} params.marker
- * @param {PointData} params.point
- *
- * @constructor
- * @extends AbstractInfoWindow
- */
-function PointInfoWindow(params) {
-  if (params.identifiedElement === undefined) {
-    params.identifiedElement = new IdentifiedElement(params.point);
-  }
-  // call super constructor
-  AbstractInfoWindow.call(this, params);
-
-  this.pointData = params.point;
-
-}
-
-PointInfoWindow.prototype = Object.create(AbstractInfoWindow.prototype);
-PointInfoWindow.prototype.constructor = PointInfoWindow;
-
-/**
- *
- * @returns {PromiseLike<HTMLElement>}
- */
-PointInfoWindow.prototype.createContentDiv = function () {
-  var result = document.createElement("div");
-  var title = document.createElement("h3");
-  title.innerHTML = "Point: " + this.pointData.getPoint();
-  result.appendChild(title);
-
-  return Promise.resolve(result);
-};
-
-/**
- *
- * @param {Object.<string,boolean>} general
- * @returns {Promise}
- */
-PointInfoWindow.prototype.getOverlaysData = function (general) {
-  return this.getCustomMap().getTopMap().getOverlayDataForPoint(this.pointData, general);
-};
-
-/**
- *
- * @returns {Point}
- */
-PointInfoWindow.prototype.getPosition = function () {
-  return this.pointData.getPoint();
-};
-
-
-module.exports = PointInfoWindow;
+"use strict";
+
+var Promise = require("bluebird");
+
+var AbstractInfoWindow = require('./AbstractInfoWindow');
+var IdentifiedElement = require('../data/IdentifiedElement');
+
+/**
+ *
+ * @param {IdentifiedElement} [params.identifiedElement]
+ * @param {AbstractCustomMap} params.map
+ * @param {Marker} params.marker
+ * @param {PointData} params.point
+ *
+ * @constructor
+ * @extends AbstractInfoWindow
+ */
+function PointInfoWindow(params) {
+  if (params.identifiedElement === undefined) {
+    params.identifiedElement = new IdentifiedElement(params.point);
+  }
+  // call super constructor
+  AbstractInfoWindow.call(this, params);
+
+  this.pointData = params.point;
+
+}
+
+PointInfoWindow.prototype = Object.create(AbstractInfoWindow.prototype);
+PointInfoWindow.prototype.constructor = PointInfoWindow;
+
+/**
+ *
+ * @returns {PromiseLike<HTMLElement>}
+ */
+PointInfoWindow.prototype.createContentDiv = function () {
+  var result = document.createElement("div");
+  var title = document.createElement("h3");
+  title.innerHTML = "Point: " + this.pointData.getPoint();
+  result.appendChild(title);
+
+  return Promise.resolve(result);
+};
+
+/**
+ *
+ * @param {Object.<string,boolean>} general
+ * @returns {Promise}
+ */
+PointInfoWindow.prototype.getDbOverlaysData = function (general) {
+  return this.getCustomMap().getTopMap().getOverlayDataForPoint(this.pointData, general);
+};
+
+/**
+ *
+ * @returns {Point}
+ */
+PointInfoWindow.prototype.getPosition = function () {
+  return this.pointData.getPoint();
+};
+
+
+module.exports = PointInfoWindow;
diff --git a/frontend-js/src/main/js/map/window/ReactionInfoWindow.js b/frontend-js/src/main/js/map/window/ReactionInfoWindow.js
index cca0f9d2c820e3e6b6ebe8ed31a42415f8ffc07d..bd6b7c493c9be2b3b0d3539a3829c76b95bd7db0 100644
--- a/frontend-js/src/main/js/map/window/ReactionInfoWindow.js
+++ b/frontend-js/src/main/js/map/window/ReactionInfoWindow.js
@@ -1,264 +1,264 @@
-"use strict";
-
-var Promise = require("bluebird");
-
-var AbstractInfoWindow = require('./AbstractInfoWindow');
-var GuiUtils = require('../../gui/leftPanel/GuiUtils');
-var IdentifiedElement = require('../data/IdentifiedElement');
-var Reaction = require('../data/Reaction');
-var Functions = require('../../Functions');
-var logger = require('../../logger');
-
-/**
- * Class representing info window that should be opened when clicking on
- * reaction.
- */
-/**
- *
- * @param {IdentifiedElement} [params.identifiedElement]
- * @param {AbstractCustomMap} params.map
- * @param {Marker} params.marker
- * @param {Reaction} params.reaction
- *
- * @constructor
- * @extends AbstractInfoWindow
- */
-function ReactionInfoWindow(params) {
-  if (params.identifiedElement === undefined) {
-    params.identifiedElement = new IdentifiedElement(params.reaction);
-  }
-  // call super constructor
-  AbstractInfoWindow.call(this, params);
-
-  var self = this;
-
-  self.setReactionData(params.reaction);
-  if (params.reaction.getKineticLaw() !== undefined) {
-    self.addListener("onShow", function () {
-      return MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
-    });
-  }
-}
-
-ReactionInfoWindow.prototype = Object.create(AbstractInfoWindow.prototype);
-ReactionInfoWindow.prototype.constructor = ReactionInfoWindow;
-
-/**
- * Methods that creates and return html code with the content of the window.
- *
- * @returns {Promise} representing html code for content of the info window
- */
-ReactionInfoWindow.prototype.createContentDiv = function () {
-  var self = this;
-  var reaction = self.getReactionData();
-  var result = document.createElement("div");
-  var title = document.createElement("h3");
-  title.innerHTML = "Reaction: " + reaction.getReactionId();
-  result.appendChild(title);
-
-  return self.createKineticsDiv(reaction, result).then(function () {
-    result.appendChild(self.createElementsDiv(reaction));
-    return result;
-  });
-};
-
-/**
- *
- * @param {Reaction} reaction
- * @param {HTMLElement} result
- * @returns {Promise}
- */
-ReactionInfoWindow.prototype.createKineticsDiv = function (reaction, result) {
-  var self = this;
-  if (reaction.getKineticLaw() === undefined) {
-    return Promise.resolve();
-  } else {
-    var kineticLaw = reaction.getKineticLaw();
-    return Functions.loadScript('https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML').then(function () {
-      return MathJax.Hub.Config({
-        tex2jax: {
-          skipTags: ["script", "noscript", "style", "textarea", "pre", "code"]
-        }
-      });
-    }).then(function () {
-
-      result.appendChild(Functions.createElement({type: "h4", content: "Kinetic law"}));
-
-      if (kineticLaw.getMathMlPresentation() !== undefined) {
-        result.appendChild(Functions.createElement({
-          type: "div",
-          content: kineticLaw.getMathMlPresentation(),
-          xss: false
-        }));
-      } else {
-
-        result.appendChild(Functions.createElement({
-          type: "div",
-          content: "<p>Problematic MathML</p>"
-        }));
-        logger.warn("Problematic MathML: " + kineticLaw.getDefinition());
-      }
-      var promises = [];
-      for (var i = 0; i < kineticLaw.getFunctionIds().length; i++) {
-        promises.push(self.getCustomMap().getModel().getSbmlFunctionById(kineticLaw.getFunctionIds()[i]));
-      }
-      return Promise.all(promises);
-    }).then(function (functions) {
-      result.appendChild(self.createSbmlFunctionDiv(functions));
-
-      var promises = [];
-      for (var i = 0; i < kineticLaw.getParameterIds().length; i++) {
-        promises.push(self.getCustomMap().getModel().getSbmlParameterById(kineticLaw.getParameterIds()[i]));
-      }
-      return Promise.all(promises);
-    }).then(function (parameters) {
-      result.appendChild(self.createSbmlParameterDiv(parameters));
-    });
-  }
-};
-
-/**
- *
- * @param {SbmlFunction[]} functions
- * @returns {HTMLElement}
- */
-ReactionInfoWindow.prototype.createSbmlFunctionDiv = function (functions) {
-  var result = Functions.createElement({type: "div"});
-  if (functions.length > 0) {
-    result.appendChild(Functions.createElement({type: "h5", content: "Functions: "}));
-    var guiUtils = new GuiUtils();
-    var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"});
-    table.appendChild(guiUtils.createTableRow(["Name", "Definition", "Arguments"]));
-    for (var i = 0; i < functions.length; i++) {
-      var sbmlFunction = functions[i];
-      var mathML;
-      if (sbmlFunction.getMathMlPresentation() !== undefined) {
-        mathML = sbmlFunction.getMathMlPresentation();
-      } else {
-        mathML = "<p>Problematic MathML</p>";
-        logger.warn("Problematic MathML: " + sbmlFunction.getDefinition());
-      }
-      var functionArguments = sbmlFunction.getArguments().join(", ");
-      table.appendChild(guiUtils.createTableRow([sbmlFunction.getName(), mathML, functionArguments]));
-    }
-    result.appendChild(table);
-  }
-  return result;
-};
-
-/**
- *
- * @param {SbmlParameter[]} parameters
- * @returns {HTMLElement}
- */
-ReactionInfoWindow.prototype.createSbmlParameterDiv = function (parameters) {
-  var result = Functions.createElement({type: "div"});
-  if (parameters.length > 0) {
-    result.appendChild(Functions.createElement({type: "h5", content: "Parameters: "}));
-    var guiUtils = new GuiUtils();
-    var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"});
-    table.appendChild(guiUtils.createTableRow(["Name", "parameterId", "Value", "Global"]));
-    for (var i = 0; i < parameters.length; i++) {
-      var sbmlFunction = parameters[i];
-      table.appendChild(guiUtils.createTableRow([sbmlFunction.getName(), sbmlFunction.getParameterId(), sbmlFunction.getValue(), sbmlFunction.getGlobal()]));
-    }
-    result.appendChild(table);
-  }
-  return result;
-};
-
-/**
- *
- * @param {Reaction} reaction
- * @returns {HTMLElement}
- */
-ReactionInfoWindow.prototype.createElementsDiv = function (reaction) {
-  var result = Functions.createElement({type: "div"});
-  result.appendChild(Functions.createElement({type: "h5", content: "Elements: "}));
-  var guiUtils = new GuiUtils();
-  var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"});
-  table.appendChild(guiUtils.createTableRow(["Name", "Role", "elementId", "Constant", "Boundary condition", "Initial concentration", "Initial amount", "Stoichiometry"]));
-  var elements = reaction.getReactants();
-  var i, element;
-
-  function createRow(node, title) {
-    var element = node.getAlias();
-    var stoichiometry = node.getStoichiometry();
-    if (stoichiometry === undefined) {
-      stoichiometry = "";
-    }
-    return guiUtils.createTableRow([element.getName(), title, element.getElementId(), element.getConstant(), element.getBoundaryCondition(), element.getInitialConcentration(), element.getInitialAmount(), stoichiometry])
-  }
-
-  for (i = 0; i < elements.length; i++) {
-    element = elements[i].getAlias();
-    table.appendChild(createRow(elements[i], "Reactant"));
-  }
-  elements = reaction.getProducts();
-  for (i = 0; i < elements.length; i++) {
-    element = elements[i].getAlias();
-    table.appendChild(createRow(elements[i], "Product"));
-  }
-  elements = reaction.getModifiers();
-  for (i = 0; i < elements.length; i++) {
-    element = elements[i].getAlias();
-    table.appendChild(createRow(elements[i], "Modifier"));
-  }
-  result.appendChild(table);
-  return result;
-};
-
-/**
- *
- * @returns {PromiseLike<any> | Promise<any>}
- */
-ReactionInfoWindow.prototype.init = function () {
-  var self = this;
-  return Promise.resolve().then(function () {
-    return AbstractInfoWindow.prototype.init.call(self);
-  }).then(function () {
-    return self.update();
-  });
-};
-
-/**
- * Returns array with data taken from all known {@link AbstractDbOverlay}.
- *
- * @param {Object.<string,boolean>} general
- * @returns {Promise} of an array with data from {@link AbstractDbOverlay}
- */
-ReactionInfoWindow.prototype.getOverlaysData = function (general) {
-  return this.getCustomMap().getTopMap().getOverlayDataForReaction(this.getReactionData(), general);
-};
-
-/**
- *
- * @returns {Reaction}
- */
-ReactionInfoWindow.prototype.getReactionData = function () {
-  return this._reactionData;
-};
-
-/**
- *
- * @param {Reaction} reactionData
- */
-ReactionInfoWindow.prototype.setReactionData = function (reactionData) {
-  if (reactionData === undefined || reactionData === null) {
-    throw new Error("Reaction must be specified");
-  } else if (reactionData instanceof Reaction) {
-    this._reactionData = reactionData;
-  } else {
-    throw new Error("Parameter must be of Reaction type, but found" + reactionData);
-  }
-};
-
-/**
- *
- * @returns {Point}
- */
-ReactionInfoWindow.prototype.getPosition = function () {
-  return this.getReactionData().getCenter();
-};
-
-module.exports = ReactionInfoWindow;
+"use strict";
+
+var Promise = require("bluebird");
+
+var AbstractInfoWindow = require('./AbstractInfoWindow');
+var GuiUtils = require('../../gui/leftPanel/GuiUtils');
+var IdentifiedElement = require('../data/IdentifiedElement');
+var Reaction = require('../data/Reaction');
+var Functions = require('../../Functions');
+var logger = require('../../logger');
+
+/**
+ * Class representing info window that should be opened when clicking on
+ * reaction.
+ */
+/**
+ *
+ * @param {IdentifiedElement} [params.identifiedElement]
+ * @param {AbstractCustomMap} params.map
+ * @param {Marker} params.marker
+ * @param {Reaction} params.reaction
+ *
+ * @constructor
+ * @extends AbstractInfoWindow
+ */
+function ReactionInfoWindow(params) {
+  if (params.identifiedElement === undefined) {
+    params.identifiedElement = new IdentifiedElement(params.reaction);
+  }
+  // call super constructor
+  AbstractInfoWindow.call(this, params);
+
+  var self = this;
+
+  self.setReactionData(params.reaction);
+  if (params.reaction.getKineticLaw() !== undefined) {
+    self.addListener("onShow", function () {
+      return MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
+    });
+  }
+}
+
+ReactionInfoWindow.prototype = Object.create(AbstractInfoWindow.prototype);
+ReactionInfoWindow.prototype.constructor = ReactionInfoWindow;
+
+/**
+ * Methods that creates and return html code with the content of the window.
+ *
+ * @returns {Promise} representing html code for content of the info window
+ */
+ReactionInfoWindow.prototype.createContentDiv = function () {
+  var self = this;
+  var reaction = self.getReactionData();
+  var result = document.createElement("div");
+  var title = document.createElement("h3");
+  title.innerHTML = "Reaction: " + reaction.getReactionId();
+  result.appendChild(title);
+
+  return self.createKineticsDiv(reaction, result).then(function () {
+    result.appendChild(self.createElementsDiv(reaction));
+    return result;
+  });
+};
+
+/**
+ *
+ * @param {Reaction} reaction
+ * @param {HTMLElement} result
+ * @returns {Promise}
+ */
+ReactionInfoWindow.prototype.createKineticsDiv = function (reaction, result) {
+  var self = this;
+  if (reaction.getKineticLaw() === undefined) {
+    return Promise.resolve();
+  } else {
+    var kineticLaw = reaction.getKineticLaw();
+    return Functions.loadScript('https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-MML-AM_CHTML').then(function () {
+      return MathJax.Hub.Config({
+        tex2jax: {
+          skipTags: ["script", "noscript", "style", "textarea", "pre", "code"]
+        }
+      });
+    }).then(function () {
+
+      result.appendChild(Functions.createElement({type: "h4", content: "Kinetic law"}));
+
+      if (kineticLaw.getMathMlPresentation() !== undefined) {
+        result.appendChild(Functions.createElement({
+          type: "div",
+          content: kineticLaw.getMathMlPresentation(),
+          xss: false
+        }));
+      } else {
+
+        result.appendChild(Functions.createElement({
+          type: "div",
+          content: "<p>Problematic MathML</p>"
+        }));
+        logger.warn("Problematic MathML: " + kineticLaw.getDefinition());
+      }
+      var promises = [];
+      for (var i = 0; i < kineticLaw.getFunctionIds().length; i++) {
+        promises.push(self.getCustomMap().getModel().getSbmlFunctionById(kineticLaw.getFunctionIds()[i]));
+      }
+      return Promise.all(promises);
+    }).then(function (functions) {
+      result.appendChild(self.createSbmlFunctionDiv(functions));
+
+      var promises = [];
+      for (var i = 0; i < kineticLaw.getParameterIds().length; i++) {
+        promises.push(self.getCustomMap().getModel().getSbmlParameterById(kineticLaw.getParameterIds()[i]));
+      }
+      return Promise.all(promises);
+    }).then(function (parameters) {
+      result.appendChild(self.createSbmlParameterDiv(parameters));
+    });
+  }
+};
+
+/**
+ *
+ * @param {SbmlFunction[]} functions
+ * @returns {HTMLElement}
+ */
+ReactionInfoWindow.prototype.createSbmlFunctionDiv = function (functions) {
+  var result = Functions.createElement({type: "div"});
+  if (functions.length > 0) {
+    result.appendChild(Functions.createElement({type: "h5", content: "Functions: "}));
+    var guiUtils = new GuiUtils();
+    var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"});
+    table.appendChild(guiUtils.createTableRow(["Name", "Definition", "Arguments"]));
+    for (var i = 0; i < functions.length; i++) {
+      var sbmlFunction = functions[i];
+      var mathML;
+      if (sbmlFunction.getMathMlPresentation() !== undefined) {
+        mathML = sbmlFunction.getMathMlPresentation();
+      } else {
+        mathML = "<p>Problematic MathML</p>";
+        logger.warn("Problematic MathML: " + sbmlFunction.getDefinition());
+      }
+      var functionArguments = sbmlFunction.getArguments().join(", ");
+      table.appendChild(guiUtils.createTableRow([sbmlFunction.getName(), mathML, functionArguments]));
+    }
+    result.appendChild(table);
+  }
+  return result;
+};
+
+/**
+ *
+ * @param {SbmlParameter[]} parameters
+ * @returns {HTMLElement}
+ */
+ReactionInfoWindow.prototype.createSbmlParameterDiv = function (parameters) {
+  var result = Functions.createElement({type: "div"});
+  if (parameters.length > 0) {
+    result.appendChild(Functions.createElement({type: "h5", content: "Parameters: "}));
+    var guiUtils = new GuiUtils();
+    var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"});
+    table.appendChild(guiUtils.createTableRow(["Name", "parameterId", "Value", "Global"]));
+    for (var i = 0; i < parameters.length; i++) {
+      var sbmlFunction = parameters[i];
+      table.appendChild(guiUtils.createTableRow([sbmlFunction.getName(), sbmlFunction.getParameterId(), sbmlFunction.getValue(), sbmlFunction.getGlobal()]));
+    }
+    result.appendChild(table);
+  }
+  return result;
+};
+
+/**
+ *
+ * @param {Reaction} reaction
+ * @returns {HTMLElement}
+ */
+ReactionInfoWindow.prototype.createElementsDiv = function (reaction) {
+  var result = Functions.createElement({type: "div"});
+  result.appendChild(Functions.createElement({type: "h5", content: "Elements: "}));
+  var guiUtils = new GuiUtils();
+  var table = Functions.createElement({type: "div", style: "display: table;", className: "borderTable"});
+  table.appendChild(guiUtils.createTableRow(["Name", "Role", "elementId", "Constant", "Boundary condition", "Initial concentration", "Initial amount", "Stoichiometry"]));
+  var elements = reaction.getReactants();
+  var i, element;
+
+  function createRow(node, title) {
+    var element = node.getAlias();
+    var stoichiometry = node.getStoichiometry();
+    if (stoichiometry === undefined) {
+      stoichiometry = "";
+    }
+    return guiUtils.createTableRow([element.getName(), title, element.getElementId(), element.getConstant(), element.getBoundaryCondition(), element.getInitialConcentration(), element.getInitialAmount(), stoichiometry])
+  }
+
+  for (i = 0; i < elements.length; i++) {
+    element = elements[i].getAlias();
+    table.appendChild(createRow(elements[i], "Reactant"));
+  }
+  elements = reaction.getProducts();
+  for (i = 0; i < elements.length; i++) {
+    element = elements[i].getAlias();
+    table.appendChild(createRow(elements[i], "Product"));
+  }
+  elements = reaction.getModifiers();
+  for (i = 0; i < elements.length; i++) {
+    element = elements[i].getAlias();
+    table.appendChild(createRow(elements[i], "Modifier"));
+  }
+  result.appendChild(table);
+  return result;
+};
+
+/**
+ *
+ * @returns {PromiseLike<any> | Promise<any>}
+ */
+ReactionInfoWindow.prototype.init = function () {
+  var self = this;
+  return Promise.resolve().then(function () {
+    return AbstractInfoWindow.prototype.init.call(self);
+  }).then(function () {
+    return self.update();
+  });
+};
+
+/**
+ * Returns array with data taken from all known {@link AbstractDbOverlay}.
+ *
+ * @param {Object.<string,boolean>} general
+ * @returns {Promise} of an array with data from {@link AbstractDbOverlay}
+ */
+ReactionInfoWindow.prototype.getDbOverlaysData = function (general) {
+  return this.getCustomMap().getTopMap().getOverlayDataForReaction(this.getReactionData(), general);
+};
+
+/**
+ *
+ * @returns {Reaction}
+ */
+ReactionInfoWindow.prototype.getReactionData = function () {
+  return this._reactionData;
+};
+
+/**
+ *
+ * @param {Reaction} reactionData
+ */
+ReactionInfoWindow.prototype.setReactionData = function (reactionData) {
+  if (reactionData === undefined || reactionData === null) {
+    throw new Error("Reaction must be specified");
+  } else if (reactionData instanceof Reaction) {
+    this._reactionData = reactionData;
+  } else {
+    throw new Error("Parameter must be of Reaction type, but found" + reactionData);
+  }
+};
+
+/**
+ *
+ * @returns {Point}
+ */
+ReactionInfoWindow.prototype.getPosition = function () {
+  return this.getReactionData().getCenter();
+};
+
+module.exports = ReactionInfoWindow;
diff --git a/frontend-js/src/main/js/minerva.js b/frontend-js/src/main/js/minerva.js
index 8a5570401657857cd9c6d0f53cc7920d16e49b28..88c4a9baf3c732deb5eaa3f16b0fa6050360b402 100644
--- a/frontend-js/src/main/js/minerva.js
+++ b/frontend-js/src/main/js/minerva.js
@@ -335,7 +335,8 @@ function create(params) {
 
     leftPanel = new LeftPanel({
       element: functions.getElementByClassName(element, "minerva-left-panel"),
-      customMap: customMap
+      customMap: customMap,
+      configuration: params.getConfiguration()
     });
 
     var pluginManager = new PluginManager({
diff --git a/frontend-js/src/test/js/gui/AddOverlayDialog-test.js b/frontend-js/src/test/js/gui/AddOverlayDialog-test.js
index e238c5c36a8df527f130e501022c11f1b25ee935..c823a626721cbb594ba62dc30139dc1e0d652ea4 100644
--- a/frontend-js/src/test/js/gui/AddOverlayDialog-test.js
+++ b/frontend-js/src/test/js/gui/AddOverlayDialog-test.js
@@ -17,7 +17,9 @@ describe('AddOverlayDialog', function () {
       dialog = new AddOverlayDialog({
         element: testDiv,
         project: project,
-        customMap: null
+        customMap: null,
+        configuration: helper.getConfiguration(),
+        serverConnector: ServerConnector
       });
 
       dialog.setFileContent("s1\n");
diff --git a/frontend-js/src/test/js/gui/admin/EditGenomeDialog-test.js b/frontend-js/src/test/js/gui/admin/EditGenomeDialog-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..36be57ba12a2bba3917ae2b59fa8bdc66bcf0a53
--- /dev/null
+++ b/frontend-js/src/test/js/gui/admin/EditGenomeDialog-test.js
@@ -0,0 +1,153 @@
+"use strict";
+
+require("../../mocha-config");
+
+var EditGenomeDialog = require('../../../../main/js/gui/admin/EditGenomeDialog');
+var ReferenceGenome = require('../../../../main/js/map/data/ReferenceGenome');
+var ValidationError = require('../../../../main/js/ValidationError');
+var ServerConnector = require('../../ServerConnector-mock');
+
+var logger = require('../../logger');
+var Promise = require('bluebird');
+
+var chai = require('chai');
+var assert = chai.assert;
+var expect = chai.expect;
+
+/**
+ *
+ * @param {ReferenceGenome} genome
+ * @returns {EditGenomeDialog}
+ */
+function createDialog(genome) {
+  return new EditGenomeDialog({
+    element: testDiv,
+    referenceGenome: genome,
+    customMap: null,
+    serverConnector: ServerConnector
+  });
+}
+
+describe('EditGenomeDialog', function () {
+
+  describe('init', function () {
+    it('new genome', function () {
+      var genome = new ReferenceGenome();
+      var dialog = createDialog(genome);
+      return dialog.init().then(function () {
+        return dialog.destroy();
+      });
+    });
+    it('existing', function () {
+      helper.loginAsAdmin();
+      var dialog;
+      return ServerConnector.getReferenceGenome({genomeId: 154}).then(function (genome) {
+        dialog = createDialog(genome);
+        return dialog.init();
+      }).then(function () {
+        return dialog.destroy();
+      });
+    });
+  });
+
+  it('removeMapping', function () {
+    helper.loginAsAdmin();
+    var dialog;
+    return ServerConnector.getReferenceGenome({genomeId: 154}).then(function (genome) {
+      dialog = createDialog(genome);
+      return dialog.init();
+    }).then(function () {
+      dialog.askConfirmRemoval = function () {
+        return Promise.resolve({status: true});
+      };
+      assert.equal(0, logger.getWarnings().length);
+
+      var element = $("[name='removeMapping']")[0];
+      return helper.triggerJqueryEvent(element, "click");
+    }).then(function () {
+      return dialog.destroy();
+    });
+  });
+
+
+  it('on organism change', function () {
+    var genome = new ReferenceGenome();
+    var dialog = createDialog(genome);
+    return dialog.init().then(function () {
+      var element = $("[name='genomeOrganismSelect']")[0];
+      return helper.triggerJqueryEvent(element, "change");
+    }).then(function () {
+      return dialog.destroy();
+    });
+  });
+
+  it('on type change', function () {
+    var genome = new ReferenceGenome();
+    var dialog = createDialog(genome);
+    return dialog.init().then(function () {
+      var element = $("[name='genomeTypeSelect']")[0];
+      return helper.triggerJqueryEvent(element, "change");
+    }).then(function () {
+      return dialog.destroy();
+    });
+  });
+
+  it('on version change', function () {
+    var genome = new ReferenceGenome();
+    var dialog = createDialog(genome);
+    return dialog.init().then(function () {
+      var element = $("[name='genomeVersionSelect']")[0];
+      return helper.triggerJqueryEvent(element, "change");
+    }).then(function () {
+      return dialog.destroy();
+    });
+  });
+
+  describe('click cancel', function () {
+    it('new genome', function () {
+      var genome = new ReferenceGenome();
+      var dialog = createDialog(genome);
+      return dialog.init().then(function () {
+        return dialog.open();
+      }).then(function () {
+        return $("[name=cancelGenome]", testDiv)[0].onclick();
+      }).then(function () {
+        dialog.destroy();
+      });
+    });
+  });
+
+  describe('click save', function () {
+    it('existing genome', function () {
+      var dialog;
+      return ServerConnector.getReferenceGenome({
+        organism: "9606",
+        type: "UCSC",
+        version: "hg38"
+      }).then(function (genome) {
+        dialog = createDialog(genome);
+        return dialog.init();
+      }).then(function () {
+        return dialog.open();
+      }).then(function () {
+        return $("[name=saveGenome]", testDiv)[0].onclick();
+      }).then(function () {
+        dialog.destroy();
+      });
+    });
+
+    it('new genome', function () {
+      helper.loginAsAdmin();
+      var genome = new ReferenceGenome();
+      var dialog = createDialog(genome);
+      return dialog.init().then(function () {
+        return dialog.open();
+      }).then(function () {
+        return $("[name=saveGenome]", testDiv)[0].onclick();
+      }).then(function () {
+        dialog.destroy();
+      });
+    });
+  });
+
+});
diff --git a/frontend-js/src/test/js/gui/admin/GenomeAdminPanel-test.js b/frontend-js/src/test/js/gui/admin/GenomeAdminPanel-test.js
new file mode 100644
index 0000000000000000000000000000000000000000..3eb0ab70904372ca41b409736354bc6271f0b08e
--- /dev/null
+++ b/frontend-js/src/test/js/gui/admin/GenomeAdminPanel-test.js
@@ -0,0 +1,91 @@
+"use strict";
+
+require("../../mocha-config");
+
+var GenomeAdminPanel = require('../../../../main/js/gui/admin/GenomeAdminPanel');
+var ConfigurationType = require('../../../../main/js/ConfigurationType');
+var ServerConnector = require('../../ServerConnector-mock');
+var logger = require('../../logger');
+var Promise = require('bluebird');
+
+var chai = require('chai');
+var assert = chai.assert;
+
+describe('GenomeAdminPanel', function () {
+  describe('init', function () {
+    it('admin', function () {
+      helper.loginAsAdmin();
+      var mapTab;
+      return ServerConnector.getConfiguration().then(function (configuration) {
+        mapTab = new GenomeAdminPanel({
+          element: testDiv,
+          configuration: configuration,
+          serverConnector: ServerConnector
+        });
+        return mapTab.init();
+      }).then(function () {
+        assert.equal(0, logger.getWarnings().length);
+        return mapTab.destroy();
+      });
+    });
+  });
+  it('open edit dialog', function () {
+    helper.loginAsAdmin();
+    var mapTab;
+    return ServerConnector.getConfiguration().then(function (configuration) {
+      mapTab = new GenomeAdminPanel({
+        element: testDiv,
+        configuration: configuration,
+        serverConnector: ServerConnector
+      });
+      return mapTab.init();
+    }).then(function () {
+      assert.equal(0, logger.getWarnings().length);
+      var element = $("[name='editGenome']")[0];
+      return helper.triggerJqueryEvent(element, "click");
+    }).then(function () {
+      return mapTab.destroy();
+    });
+  });
+
+  it('open add genome dialog', function () {
+    helper.loginAsAdmin();
+    var mapTab;
+    return ServerConnector.getConfiguration().then(function (configuration) {
+      mapTab = new GenomeAdminPanel({
+        element: testDiv,
+        configuration: configuration,
+        serverConnector: ServerConnector
+      });
+      return mapTab.init();
+    }).then(function () {
+      assert.equal(0, logger.getWarnings().length);
+      var element = $("[name='addGenome']")[0];
+      return element.onclick();
+    }).then(function () {
+      return mapTab.destroy();
+    });
+  });
+
+  it('remove genome', function () {
+    helper.loginAsAdmin();
+    var mapTab;
+    return ServerConnector.getConfiguration().then(function (configuration) {
+      mapTab = new GenomeAdminPanel({
+        element: testDiv,
+        configuration: configuration,
+        serverConnector: ServerConnector
+      });
+      return mapTab.init();
+    }).then(function () {
+      mapTab.askConfirmRemoval = function () {
+        return Promise.resolve({status: true});
+      };
+      assert.equal(0, logger.getWarnings().length);
+      var element = $("[name='removeGenome']")[0];
+      return helper.triggerJqueryEvent(element, "click");
+    }).then(function () {
+      return mapTab.destroy();
+    });
+  });
+});
diff --git a/frontend-js/src/test/js/gui/admin/UserAdminPanel-test.js b/frontend-js/src/test/js/gui/admin/UserAdminPanel-test.js
index 494f438fb552101f4ff552f6f98f493676bc5dbe..fb675b9525b9a984701bf5569cc54b48577afd6f 100644
--- a/frontend-js/src/test/js/gui/admin/UserAdminPanel-test.js
+++ b/frontend-js/src/test/js/gui/admin/UserAdminPanel-test.js
@@ -11,6 +11,14 @@ var logger = require('../../logger');
 
 var assert = require('assert');
 
+function createUserAdminPanel(configuration) {
+  return new UsersAdminPanel({
+    element: testDiv,
+    configuration: configuration,
+    serverConnector: ServerConnector
+  });
+}
+
 describe('UsersAdminPanel', function () {
 
   describe('init', function () {
@@ -18,10 +26,7 @@ describe('UsersAdminPanel', function () {
       helper.loginAsAdmin();
       var usersTab;
       return ServerConnector.getConfiguration().then(function (configuration) {
-        usersTab = new UsersAdminPanel({
-          element: testDiv,
-          configuration: configuration
-        });
+        usersTab = createUserAdminPanel(configuration);
         return usersTab.init();
       }).then(function () {
         assert.equal(0, logger.getWarnings().length);
@@ -35,10 +40,7 @@ describe('UsersAdminPanel', function () {
         return Promise.reject(new SecurityError("Access denied."));
       };
       return ServerConnector.getConfiguration().then(function (configuration) {
-        usersTab = new UsersAdminPanel({
-          element: testDiv,
-          configuration: configuration
-        });
+        usersTab = createUserAdminPanel(configuration);
         return usersTab.init();
       }).then(function () {
         assert.equal(0, logger.getWarnings().length);
@@ -52,48 +54,39 @@ describe('UsersAdminPanel', function () {
 
   it('refresh', function () {
     helper.loginAsAdmin();
-    var mapTab;
+    var usersTab;
     return ServerConnector.getConfiguration().then(function (configuration) {
-      mapTab = new UsersAdminPanel({
-        element: testDiv,
-        configuration: configuration
-      });
-      return mapTab.init();
+      usersTab = createUserAdminPanel(configuration);
+      return usersTab.init();
     }).then(function () {
-      return mapTab.onRefreshClicked();
+      return usersTab.onRefreshClicked();
     }).then(function () {
-      return mapTab.destroy();
+      return usersTab.destroy();
     });
   });
 
   it('showEditDialog', function () {
     helper.loginAsAdmin();
-    var mapTab;
+    var usersTab;
     return ServerConnector.getConfiguration().then(function (configuration) {
-      mapTab = new UsersAdminPanel({
-        element: testDiv,
-        configuration: configuration
-      });
-      return mapTab.init();
+      usersTab = createUserAdminPanel(configuration);
+      return usersTab.init();
     }).then(function () {
-      return mapTab.showEditDialog("anonymous");
+      return usersTab.showEditDialog("anonymous");
     }).then(function () {
-      return mapTab.destroy();
+      return usersTab.destroy();
     });
   });
   it('onAddClicked', function () {
     helper.loginAsAdmin();
-    var mapTab;
+    var usersTab;
     return ServerConnector.getConfiguration().then(function (configuration) {
-      mapTab = new UsersAdminPanel({
-        element: testDiv,
-        configuration: configuration
-      });
-      return mapTab.init();
+      usersTab = createUserAdminPanel(configuration);
+      return usersTab.init();
     }).then(function () {
-      return mapTab.onAddClicked();
+      return usersTab.onAddClicked();
     }).then(function () {
-      return mapTab.destroy();
+      return usersTab.destroy();
     });
   });
 
diff --git a/frontend-js/src/test/js/gui/leftPanel/AbstractPanel-test.js b/frontend-js/src/test/js/gui/leftPanel/AbstractPanel-test.js
index da4594bbe8ea2f47df94566bbec6cb457eb25442..86f750982033c36c38f073cdd85960e07ab05f56 100644
--- a/frontend-js/src/test/js/gui/leftPanel/AbstractPanel-test.js
+++ b/frontend-js/src/test/js/gui/leftPanel/AbstractPanel-test.js
@@ -57,9 +57,10 @@ describe('AbstractDbPanel', function () {
           references: [],
           targetParticipants: []
         });
-        var htmlTag = panel.createTargetRow(target, "empty.png");
-        assert.ok(htmlTag);
-        assert.equal(1, $(".minerva-open-submap-button", $(htmlTag)).length);
+        return panel.createTargetRow(target, "empty.png").then(function (htmlTag) {
+          assert.ok(htmlTag);
+          assert.equal(1, $(".minerva-open-submap-button", $(htmlTag)).length);
+        });
       });
     });
   });
diff --git a/frontend-js/src/test/js/gui/leftPanel/GenericSearchPanel-test.js b/frontend-js/src/test/js/gui/leftPanel/GenericSearchPanel-test.js
index 5ed0a92606e7ee4375a595a98059100d9981bd24..557e044d5c3b44f91365e1465569d9b846148857 100644
--- a/frontend-js/src/test/js/gui/leftPanel/GenericSearchPanel-test.js
+++ b/frontend-js/src/test/js/gui/leftPanel/GenericSearchPanel-test.js
@@ -7,7 +7,7 @@ var Alias = require('../../../../main/js/map/data/Alias');
 var ConfigurationType = require('../../../../main/js/ConfigurationType');
 var GenericSearchPanel = require('../../../../main/js/gui/leftPanel/GenericSearchPanel');
 var PanelControlElementType = require('../../../../main/js/gui/PanelControlElementType');
-var Point= require('../../../../main/js/map/canvas/Point');
+var Point = require('../../../../main/js/map/canvas/Point');
 var ServerConnector = require('../../ServerConnector-mock');
 
 var chai = require('chai');
@@ -95,23 +95,44 @@ describe('GenericSearchPanel', function () {
 
 
   describe('createReactionElement', function () {
-    it('type in desc', function () {
-      helper.getConfiguration().getOption(ConfigurationType.SHOW_REACTION_TYPE).setValue("true");
-      var map = helper.createCustomMap();
-      helper.createSearchDbOverlay(map);
-
-      var panel = new GenericSearchPanel({
-        element: testDiv,
-        customMap: map
+    describe('type in desc', function () {
+      it('visible', function () {
+        helper.getConfiguration().getOption(ConfigurationType.SHOW_REACTION_TYPE).setValue("true");
+        var map = helper.createCustomMap();
+        helper.createSearchDbOverlay(map);
+
+        var panel = new GenericSearchPanel({
+          element: testDiv,
+          customMap: map
+        });
+        var reaction = helper.createReaction(map);
+        var reactionType = "XX TYPE";
+        reaction.setType(reactionType);
+
+        return panel.createReactionElement(reaction).then(function (div) {
+          assert.ok(div.innerHTML.indexOf(reactionType) >= 0);
+        });
       });
-      var reaction = helper.createReaction(map);
-      var reactionType = "XX TYPE";
-      reaction.setType(reactionType);
 
-      assert.ok(panel.createReactionElement(reaction).innerHTML.indexOf(reactionType) >= 0);
+      it('invisible', function () {
+        helper.getConfiguration().getOption(ConfigurationType.SHOW_REACTION_TYPE).setValue("true");
+        var map = helper.createCustomMap();
+        helper.createSearchDbOverlay(map);
+
+        var panel = new GenericSearchPanel({
+          element: testDiv,
+          customMap: map
+        });
+        var reaction = helper.createReaction(map);
+        var reactionType = "XX TYPE";
+        reaction.setType(reactionType);
+
+        helper.getConfiguration().getOption(ConfigurationType.SHOW_REACTION_TYPE).setValue("false");
+        return panel.createReactionElement(reaction).then(function (div) {
+          assert.notOk(div.innerHTML.indexOf(reactionType) >= 0);
+        });
+      });
 
-      helper.getConfiguration().getOption(ConfigurationType.SHOW_REACTION_TYPE).setValue("false");
-      assert.notOk(panel.createReactionElement(reaction).innerHTML.indexOf(reactionType) >= 0);
 
     });
   });
@@ -148,26 +169,46 @@ describe('GenericSearchPanel', function () {
         customMap: map
       });
 
-      var aliasDiv = panel.createAliasElement(alias);
-      assert.ok(aliasDiv.innerHTML);
+      return panel.createAliasElement(alias).then(function (aliasDiv) {
+        assert.ok(aliasDiv.innerHTML);
+      });
     });
 
 
-    it('full name in desc', function () {
-      var map = helper.createCustomMap();
-      helper.createSearchDbOverlay(map);
+    describe('full name in desc', function () {
+      it('visible', function () {
+        var map = helper.createCustomMap();
+        helper.createSearchDbOverlay(map);
 
-      var panel = new GenericSearchPanel({
-        element: testDiv,
-        customMap: map
+        var panel = new GenericSearchPanel({
+          element: testDiv,
+          customMap: map
+        });
+        var alias = helper.createAlias(map);
+
+        alias.setFullName("xxx");
+        return panel.createAliasElement(alias).then(function (div) {
+
+          assert.ok(div.innerHTML.indexOf("Full name") >= 0);
+        });
       });
-      var alias = helper.createAlias(map);
 
-      alias.setFullName("xxx");
-      assert.ok(panel.createAliasElement(alias).innerHTML.indexOf("Full name") >= 0);
+      it('invisible', function () {
+        var map = helper.createCustomMap();
+        helper.createSearchDbOverlay(map);
+
+        var panel = new GenericSearchPanel({
+          element: testDiv,
+          customMap: map
+        });
+        var alias = helper.createAlias(map);
 
-      alias.setFullName("");
-      assert.ok(panel.createAliasElement(alias).innerHTML.indexOf("Full name") === -1);
+        alias.setFullName("");
+        return panel.createAliasElement(alias).then(function (div) {
+          assert.ok(div.innerHTML.indexOf("Full name") === -1);
+        });
+
+      });
     });
   });
 
diff --git a/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js b/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js
index 078ec940fa008fa23dee36574751b8779acfe3b1..93f55f5850b2867e0295e4ea34d38c6a1de1588a 100644
--- a/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js
+++ b/frontend-js/src/test/js/gui/leftPanel/GuiUtils-test.js
@@ -23,7 +23,7 @@ describe('GuiUtils', function () {
     var map = helper.createCustomMap();
     helper.createSearchDbOverlay(map);
 
-    new GuiUtils();
+    new GuiUtils(helper.getConfiguration());
     assert.equal(logger.getWarnings().length, 0);
   });
 
@@ -56,17 +56,15 @@ describe('GuiUtils', function () {
     var guiUtils = createGuiUtils();
     guiUtils.setMap(map);
 
-    var aliasDiv = guiUtils.createAliasElement({
-      alias: alias
+    return guiUtils.createAliasElement({alias: alias}).then(function (aliasDiv) {
+      assert.ok(aliasDiv.innerHTML);
     });
-    assert.ok(aliasDiv.innerHTML);
   });
 
   it('createLabelText for undefined', function () {
     var map = helper.createCustomMap();
 
-    var guiUtils = new GuiUtils();
-    guiUtils.setMap(map);
+    var guiUtils = createGuiUtils(map);
 
     var res = guiUtils.createLabelText();
     assert.notOk(res.innerHTML);
@@ -75,8 +73,7 @@ describe('GuiUtils', function () {
   it('createSubMapLink', function () {
     var map = helper.createCustomMap();
 
-    var guiUtils = new GuiUtils();
-    guiUtils.setMap(map);
+    var guiUtils = createGuiUtils(map);
 
     var res = guiUtils.createSubMapLink("TEST", map.getId());
     assert.ok(res.innerHTML);
@@ -117,62 +114,85 @@ describe('GuiUtils', function () {
       var reactionId = "XX ID";
       reaction.setReactionId(reactionId);
 
-      assert.ok(guiUtils.createReactionElement({
-        reaction: reaction
-      }).innerHTML.indexOf(reactionId) >= 0);
+      return guiUtils.createReactionElement({reaction: reaction}).then(function (div) {
+        assert.ok(div.innerHTML.indexOf(reactionId) >= 0);
+      })
     });
   });
 
   describe('createAliasElement', function () {
-    it('full name in desc', function () {
+    it('full name in desc visible', function () {
       var map = helper.createCustomMap();
       helper.createSearchDbOverlay(map);
 
-      var guiUtils = new GuiUtils();
-      guiUtils.setMap(map);
+      var guiUtils = createGuiUtils(map);
       var alias = helper.createAlias(map);
 
       alias.setFullName("xxx");
-      assert.ok(guiUtils.createAliasElement({
-        alias: alias
-      }).innerHTML.indexOf("Full name") >= 0);
+      return guiUtils.createAliasElement({alias: alias}).then(function (div) {
+        assert.ok(div.innerHTML.indexOf("Full name") >= 0);
+      });
+    });
+
+    it('compartment visible', function () {
+      var map = helper.createCustomMap();
+      helper.createSearchDbOverlay(map);
+
+      var guiUtils = createGuiUtils(map);
+      var alias = helper.createAlias(map);
+      var compartment = helper.createAlias(map);
+      alias.setCompartmentId(compartment.getId());
+
+      compartment.setName("compartment_name");
+      return guiUtils.createAliasElement({alias: alias}).then(function (div) {
+        assert.ok(div.innerHTML.indexOf("compartment_name") >= 0);
+      });
+    });
+
+
+    it('full name in desc invisible', function () {
+      var map = helper.createCustomMap();
+      helper.createSearchDbOverlay(map);
+
+      var guiUtils = createGuiUtils(map);
+      var alias = helper.createAlias(map);
 
       alias.setFullName("");
-      assert.ok(guiUtils.createAliasElement({
-        alias: alias
-      }).innerHTML.indexOf("Full name") === -1);
+      return guiUtils.createAliasElement({alias: alias}).then(function (div) {
+        assert.ok(div.innerHTML.indexOf("Full name") === -1);
+      });
     });
 
     it('onclick function', function () {
       var map = helper.createCustomMap();
       helper.createSearchDbOverlay(map);
 
-      var guiUtils = new GuiUtils();
-      guiUtils.setMap(map);
+      var guiUtils = createGuiUtils(map);
       var alias = helper.createAlias(map);
 
       alias.setFullName("xxx");
-      var htmlElement = guiUtils.createAliasElement({
+      return guiUtils.createAliasElement({
         alias: alias,
         icon: "empty.png"
-      });
-
-      var img = $("img", htmlElement)[0];
+      }).then(function (htmlElement) {
+        var img = $("img", htmlElement)[0];
 
-      return img.onclick();
+        return img.onclick();
+      });
     });
   });
 
   describe('createLink', function () {
     it('normal', function () {
-      var guiUtils = new GuiUtils();
+      var guiUtils = createGuiUtils();
       var link = guiUtils.createLink("http://www.minerva.uni.lu", "PD map");
       assert.ok(link);
       assert.equal(0, logger.getWarnings().length);
     });
 
     it('with null link', function () {
-      var guiUtils = new GuiUtils();
+      var guiUtils = createGuiUtils();
+      // noinspection JSCheckFunctionSignatures
       var link = guiUtils.createLink(null, "PD map");
       assert.ok(link);
       assert.ok(logger.getWarnings().length > 0);
@@ -231,5 +251,92 @@ describe('GuiUtils', function () {
     });
   });
 
+  describe('createModificationRow', function () {
+    describe('PTM', function () {
+      it('default', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({name: "n", type: "RESIDUE", state: "PHOSPHORYLATED"});
+        assert.ok(li);
+      });
+      it('empty PTM', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({name: "n", type: "RESIDUE"});
+        assert.notOk(li);
+      });
+    });
+    describe('Modification Site', function () {
+      it('default', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({name: "n", type: "MODIFICATION_SITE", state: "PHOSPHORYLATED"});
+        assert.ok(li);
+      });
+      it('empty', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({name: "n", type: "MODIFICATION_SITE"});
+        assert.notOk(li);
+      });
+    });
+    describe('Binding Region', function () {
+      it('default', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({name: "n", type: "BINDING_REGION"});
+        assert.ok(li);
+      });
+      it('empty', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({type: "BINDING_REGION"});
+        assert.notOk(li);
+      });
+    });
+    describe('Coding Region', function () {
+      it('default', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({name: "n", type: "CODING_REGION"});
+        assert.ok(li);
+      });
+      it('empty', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({type: "CODING_REGION"});
+        assert.notOk(li);
+      });
+    });
+    describe('Protein binding region', function () {
+      it('default', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({name: "n", type: "PROTEIN_BINDING_DOMAIN"});
+        assert.ok(li);
+      });
+      it('empty', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({type: "PROTEIN_BINDING_DOMAIN"});
+        assert.notOk(li);
+      });
+    });
+    describe('Regulatory region', function () {
+      it('default', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({name: "n", type: "REGULATORY_REGION"});
+        assert.ok(li);
+      });
+      it('empty', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({type: "REGULATORY_REGION"});
+        assert.notOk(li);
+      });
+    });
+    describe('Transcription sites', function () {
+      it('default', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({name: "n", type: "TRANSCRIPTION_SITE_LEFT"});
+        assert.ok(li);
+      });
+      it('empty', function () {
+        var guiUtils = new GuiUtils(helper.getConfiguration());
+        var li = guiUtils.createModificationRow({type: "TRANSCRIPTION_SITE_LEFT"});
+        assert.notOk(li);
+      });
+    });
+  });
+
 
 });
diff --git a/frontend-js/src/test/js/gui/leftPanel/LeftPanel-test.js b/frontend-js/src/test/js/gui/leftPanel/LeftPanel-test.js
index 49e5d1811c9f9126f641863e9885e4512b86c2e2..24f4f694cb023e1e617fb0969d42a5c5e8c9f914 100644
--- a/frontend-js/src/test/js/gui/leftPanel/LeftPanel-test.js
+++ b/frontend-js/src/test/js/gui/leftPanel/LeftPanel-test.js
@@ -154,6 +154,37 @@ describe('LeftPanel', function () {
         return panel.destroy();
       });
     });
+    it('when different tab is active', function () {
+      var map;
+      var panel;
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+
+        helper.createSearchDbOverlay(map);
+        helper.createDrugDbOverlay(map);
+        helper.createChemicalDbOverlay(map);
+        helper.createMiRnaDbOverlay(map);
+
+        panel = new LeftPanel({
+          element: testDiv,
+          customMap: map
+        });
+        return panel.init();
+      }).then(function () {
+        return $('a:contains("DRUG")').click();
+      }).then(function () {
+
+        var element = new IdentifiedElement({
+          id: 329163,
+          type: "ALIAS",
+          modelId: map.getId()
+        });
+        return panel.showElementDetails(element);
+      }).then(function () {
+        assert.ok($(panel.elementInfoDiv).dialog('isOpen'));
+        return panel.destroy();
+      });
+    });
   });
 
 });
diff --git a/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js b/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js
index eaf001bb281285a649d62753e1e24a814cc89afb..e36f55db5a9818a299e1d224a32e934e2cd5459f 100644
--- a/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js
+++ b/frontend-js/src/test/js/gui/leftPanel/OverlayPanel-test.js
@@ -9,6 +9,19 @@ var chai = require('chai');
 var assert = chai.assert;
 var logger = require('../../logger');
 
+/**
+ *
+ * @param {CustomMap} map
+ * @returns {OverlayPanel}
+ */
+function createOverlayPanel(map) {
+  return new OverlayPanel({
+    element: testDiv,
+    customMap: map,
+    configuration: helper.getConfiguration()
+  });
+}
+
 describe('OverlayPanel', function () {
 
   it('constructor', function () {
@@ -138,10 +151,7 @@ describe('OverlayPanel', function () {
     it('open', function () {
       var map = helper.createCustomMap();
 
-      var panel = new OverlayPanel({
-        element: testDiv,
-        customMap: map
-      });
+      var panel = createOverlayPanel(map);
 
       return panel.openAddOverlayDialog().then(function () {
         return panel.destroy();
@@ -150,11 +160,7 @@ describe('OverlayPanel', function () {
 
     it('trigger onAddOverlay event handler', function () {
       var map = helper.createCustomMap();
-
-      var panel = new OverlayPanel({
-        element: testDiv,
-        customMap: map
-      });
+      var panel = createOverlayPanel(map);
 
       return panel.init().then(function () {
         return panel.openAddOverlayDialog();
diff --git a/frontend-js/src/test/js/helper.js b/frontend-js/src/test/js/helper.js
index bb886842375a076532515e8536e94d5b89f3d109..11fc0efa1884a43783a7801b84373de106a9b633 100644
--- a/frontend-js/src/test/js/helper.js
+++ b/frontend-js/src/test/js/helper.js
@@ -220,7 +220,14 @@ Helper.prototype.createAlias = function (map) {
   return result;
 };
 
-Helper.prototype.createLayoutAlias = function (alias) {
+/**
+ *
+ * @param {Alias} [alias]
+ * @param {string} [type]
+ *
+ * @returns {LayoutAlias}
+ */
+Helper.prototype.createLayoutAlias = function (alias, type) {
   var id;
   var modelId;
   if (alias instanceof Alias) {
@@ -237,7 +244,8 @@ Helper.prototype.createLayoutAlias = function (alias) {
       a: 23
     },
     modelId: modelId,
-    geneVariations: [{}]
+    geneVariations: [],
+    type: type
   });
 };
 
@@ -488,6 +496,12 @@ Helper.prototype.loginWithoutAccess = function () {
 };
 
 
+/**
+ *
+ * @param {HTMLElement} element
+ * @param {string} eventType
+ * @returns {Promise}
+ */
 Helper.prototype.triggerJqueryEvent = function (element, eventType) {
   var domElements = $("*");
   var promises = [];
diff --git a/frontend-js/src/test/js/map/CustomMap-test.js b/frontend-js/src/test/js/map/CustomMap-test.js
index 9c8cf3654a232c44fa8853d325fd2631a9d73fda..880efabfaac797fc04af47722fd81ac9caf3c0b3 100644
--- a/frontend-js/src/test/js/map/CustomMap-test.js
+++ b/frontend-js/src/test/js/map/CustomMap-test.js
@@ -1,1037 +1,1021 @@
-"use strict";
-
-var Promise = require("bluebird");
-
-require("../mocha-config.js");
-
-var AliasMarker = require('../../../main/js/map/marker/AliasMarker');
-var AliasSurface = require('../../../main/js/map/surface/AliasSurface');
-var Comment = require('../../../main/js/map/data/Comment');
-var ControlType = require('../../../main/js/map/ControlType');
-var CustomMap = require('../../../main/js/map/CustomMap');
-var IdentifiedElement = require('../../../main/js/map/data/IdentifiedElement');
-var MapContextMenu = require('../../../main/js/gui/MapContextMenu');
-var MolArt = require('../../../main/js/map/structure/MolArt');
-var Point = require('../../../main/js/map/canvas/Point');
-var PointData = require('../../../main/js/map/data/PointData');
-var PointMarker = require('../../../main/js/map/marker/PointMarker');
-var ReactionMarker = require('../../../main/js/map/marker/ReactionMarker');
-var ReactionSurface = require('../../../main/js/map/surface/ReactionSurface');
-
-var ServerConnector = require('./../ServerConnector-mock');
-
-var logger = require('./../logger');
-
-var chai = require('chai');
-var assert = chai.assert;
-
-describe('CustomMap', function () {
-  describe("constructor", function () {
-    it("default", function () {
-      var options = helper.createCustomMapOptions();
-      var map = new CustomMap(options);
-      assert.ok(map);
-    });
-
-    it("with submaps", function () {
-      var options = helper.createCustomMapOptions();
-
-      options.getProject().addModel(helper.createModel());
-
-      var map = new CustomMap(options);
-      assert.ok(map);
-    });
-
-    it("with session data pointing to not existing overlay", function () {
-      var options = helper.createCustomMapOptions();
-
-      ServerConnector.getSessionData(options.getProject()).setSelectedBackgroundOverlay("-1");
-
-      var map = new CustomMap(options);
-      assert.ok(map);
-    });
-  });
-
-  it("getSubmapById", function () {
-    var map = helper.createCustomMap();
-    assert.ok(map.getSubmapById(map.getId()));
-  });
-
-  it("getSubmapById (invalid)", function () {
-    var map = helper.createCustomMap();
-    assert.equal(map.getSubmapById(-1), null);
-  });
-
-  it("getSubmapById (string id)", function () {
-    var map = helper.createCustomMap();
-    assert.ok(map.getSubmapById(map.getId() + ""));
-  });
-
-  describe("openDataOverlay", function () {
-    it("for not existing id", function () {
-      var map = helper.createCustomMap();
-      try {
-        map.openDataOverlay(-1);
-        assert.ok(false);
-      } catch (exception) {
-        assert.ok(exception.message.indexOf("You have no privileges") >= 0);
-      }
-    });
-
-    it("for int id", function () {
-      var options = helper.createCustomMapOptions();
-      var layout = options.getProject().getDataOverlays()[0];
-      var map = new CustomMap(options);
-      map.openDataOverlay(layout.getId());
-      assert.equal(logger.getErrors().length, 0);
-    });
-
-    it("for overlay object", function () {
-      var options = helper.createCustomMapOptions();
-      var layout = options.getProject().getDataOverlays()[0];
-      var map = new CustomMap(options);
-      map.openDataOverlay(layout);
-      assert.equal(logger.getErrors().length, 0);
-    });
-
-    it("for string id", function () {
-      var options = helper.createCustomMapOptions();
-      var layout = options.getProject().getDataOverlays()[0];
-      var map = new CustomMap(options);
-      map.openDataOverlay(layout.getId() + "");
-      assert.equal(logger.getErrors().length, 0);
-    });
-
-    it("with background overlay", function () {
-      var map = helper.createCustomMap();
-      var layout = helper.createOverlay();
-      layout.setInitialized(true);
-      layout.setInputDataAvailable(false);
-      map.getProject().addDataOverlay(layout);
-
-      return map.openDataOverlay(layout.getId()).then(function () {
-        var vLayouts = ServerConnector.getSessionData(map.getProject()).getVisibleOverlays();
-        assert.equal(0, vLayouts.length);
-      });
-    });
-
-    it("with non background overlay", function () {
-      var project = helper.createProject();
-      var layout = helper.createOverlay();
-      layout.setInitialized(true);
-      layout.setInputDataAvailable(true);
-      project.addDataOverlay(layout);
-
-      var emptyBackground = helper.createOverlay();
-      emptyBackground.setInputDataAvailable(false);
-      emptyBackground.setName("Empty");
-      project.addDataOverlay(emptyBackground);
-
-      var map = helper.createCustomMap(project);
-
-
-      return map.openDataOverlay(layout.getId()).then(function () {
-        var backgroundId = ServerConnector.getSessionData(project).getSelectedBackgroundOverlay();
-        assert.equal(backgroundId, emptyBackground.getId());
-      });
-    });
-
-    it("check backgroundChangeListener", function () {
-      var project = helper.createProject();
-      var overlay = helper.createOverlay();
-      overlay.setInitialized(true);
-      overlay.setInputDataAvailable(true);
-      project.addDataOverlay(overlay);
-
-      var overlay2 = helper.createOverlay();
-      overlay2.setInitialized(true);
-      overlay2.setInputDataAvailable(true);
-      project.addDataOverlay(overlay2);
-
-      var emptyBackground = helper.createOverlay();
-      emptyBackground.setInputDataAvailable(false);
-      emptyBackground.setName("Empty");
-      project.addDataOverlay(emptyBackground);
-
-      var map = helper.createCustomMap(project);
-
-      var counter = 0;
-      map.addListener("onBackgroundOverlayChange", function () {
-        counter++;
-      });
-
-      return map.openDataOverlay(overlay.getId()).then(function () {
-        assert.equal(1, counter, "listener wasn't fired");
-        return map.openDataOverlay(overlay2.getId());
-      }).then(function () {
-        assert.equal(1, counter, "listener shouldn't be fired again because nothing changed");
-      });
-    });
-
-    it("simple", function () {
-      var map = helper.createCustomMap();
-      var alias = helper.createAlias(map);
-      map.getModel().addAlias(alias);
-
-      var reaction = helper.createReaction(map);
-      map.getModel().addReaction(reaction);
-
-      var layout = helper.createOverlay();
-      layout.setInputDataAvailable(true);
-      layout.setInitialized(true);
-      var layoutAlias = helper.createLayoutAlias(alias);
-      layout.addAlias(layoutAlias);
-
-      var layoutReaction = helper.createLayoutReaction(reaction);
-      layout.addReaction(layoutReaction);
-
-      map.getProject().addDataOverlay(layout);
-
-      return map.openDataOverlay(layout.getId()).then(function () {
-        return map._showSelectedDataOverlay(layout.getId(), 0, 1);
-      }).then(function () {
-        var vLayouts = ServerConnector.getSessionData(map.getProject()).getVisibleOverlays();
-        assert.equal(1, vLayouts.length);
-        assert.equal(layout.getId(), vLayouts[0]);
-
-        assert.equal(2, map.selectedLayoutOverlays[layout.getId()].length);
-        assert.ok(map.selectedLayoutOverlays[layout.getId()][0] instanceof AliasSurface);
-        assert.ok(map.selectedLayoutOverlays[layout.getId()][1] instanceof ReactionSurface);
-
-        // now hide the layout
-        return map._hideSelectedLayout(layout.getId());
-      }).then(function () {
-        assert.ok(map.selectedLayoutOverlays[layout.getId()]);
-        assert.equal(0, map.selectedLayoutOverlays[layout.getId()].length);
-      });
-
-    });
-
-    it("with submaps", function () {
-      var projectId = "complex_model_with_submaps";
-      helper.setUrl("http://test/?id=" + projectId);
-      var customMap;
-      var emptySubmodelId = 16730;
-      var filledSubmodelId = 16731;
-      var overlayId = 18083;
-
-      return ServerConnector.getProject(projectId).then(function (project) {
-        var options = helper.createCustomMapOptions(project);
-        customMap = new CustomMap(options);
-
-        return customMap.openSubmap(emptySubmodelId);
-      }).then(function () {
-        return customMap.openSubmap(filledSubmodelId);
-      }).then(function () {
-
-        var emptySubmap = customMap.getSubmapById(emptySubmodelId);
-        var filledSubmap = customMap.getSubmapById(filledSubmodelId);
-
-        return customMap.openDataOverlay(overlayId).then(function () {
-
-          assert.equal(1, customMap.selectedLayoutOverlays[overlayId].length);
-          assert.equal(1, filledSubmap.selectedLayoutOverlays[overlayId].length);
-          assert.equal(0, emptySubmap.selectedLayoutOverlays[overlayId].length);
-
-          // now hide the layout
-
-          return customMap.hideSelectedLayout(overlayId);
-        }).then(function () {
-          assert.equal(0, customMap.selectedLayoutOverlays[overlayId].length);
-          assert.equal(0, filledSubmap.selectedLayoutOverlays[overlayId].length);
-          assert.equal(0, emptySubmap.selectedLayoutOverlays[overlayId].length);
-        });
-
-      }).then(function () {
-        return customMap.destroy();
-      });
-    });
-
-    it("with submap double opened", function () {
-      var projectId = "complex_model_with_submaps";
-      helper.setUrl("http://test/?id=" + projectId);
-      var customMap, filledSubmap;
-      var filledSubmodelId = 16731;
-      var overlayId = 18083;
-
-      return ServerConnector.getProject(projectId).then(function (project) {
-        customMap = helper.createCustomMap(project);
-        return customMap.openSubmap(filledSubmodelId);
-      }).then(function () {
-        filledSubmap = customMap.getSubmapById(filledSubmodelId);
-        return customMap.openDataOverlay(overlayId);
-      }).then(function () {
-        assert.equal(1, filledSubmap.selectedLayoutOverlays[overlayId].length);
-        return customMap.openSubmap(filledSubmodelId);
-      }).then(function () {
-        //after opening submap nothing should change
-        assert.equal(1, filledSubmap.selectedLayoutOverlays[overlayId].length);
-      }).finally(function () {
-        return customMap.destroy();
-      });
-    });
-
-    it("check if info window content changed", function () {
-      var project = helper.createProject();
-      var layout = helper.createOverlay();
-      layout.setInitialized(true);
-      layout.setInputDataAvailable(true);
-      project.addDataOverlay(layout);
-
-      var map = helper.createCustomMap(project);
-
-      var alias = helper.createAlias(map);
-      var ie = helper.createIdentifiedElement(alias);
-      var marker = map.getMapCanvas().createMarker({icon: "empty.png", position: new Point(0, 0)});
-      var infoWindow;
-      return map.openInfoWindowForIdentifiedElement(ie, marker).then(function (result) {
-        infoWindow = result;
-        assert.notOk(infoWindow.getContent().innerHTML.indexOf(layout.getName()) >= 0);
-        return map.openDataOverlay(layout.getId());
-      }).then(function () {
-        assert.ok(infoWindow.getContent().innerHTML.indexOf(layout.getName()) >= 0);
-        assert.equal(logger.getErrors().length, 0);
-      });
-    });
-  });
-
-  describe("hideDataOverlay", function () {
-    it("default", function () {
-      var map = helper.createCustomMap();
-      var layout = helper.createOverlay();
-      layout.setInitialized(true);
-      layout.setInputDataAvailable(true);
-      map.getProject().addDataOverlay(layout);
-
-      return map.openDataOverlay(layout.getId()).then(function () {
-        return map.hideDataOverlay(layout.getId());
-      }).then(function () {
-        var vLayouts = ServerConnector.getSessionData(map.getProject()).getVisibleOverlays();
-        assert.equal(0, vLayouts.length);
-      });
-    });
-    it("check if info window content changed", function () {
-      var project = helper.createProject();
-      var layout = helper.createOverlay();
-      layout.setInitialized(true);
-      layout.setInputDataAvailable(true);
-      project.addDataOverlay(layout);
-
-      var map = helper.createCustomMap(project);
-
-      var alias = helper.createAlias(map);
-      var ie = helper.createIdentifiedElement(alias);
-      var marker = map.getMapCanvas().createMarker({icon: "empty.png", position: new Point(0, 0)});
-      var infoWindow;
-      return map.openInfoWindowForIdentifiedElement(ie, marker).then(function (result) {
-        infoWindow = result;
-        return map.openDataOverlay(layout.getId());
-      }).then(function () {
-        assert.ok(infoWindow.getContent().innerHTML.indexOf(layout.getName()) >= 0);
-        return map.hideDataOverlay(layout.getId());
-      }).then(function () {
-        assert.notOk(infoWindow.getContent().innerHTML.indexOf(layout.getName()) >= 0);
-        assert.equal(logger.getErrors().length, 0);
-      });
-    });
-  });
-
-
-  describe("renderOverlayCollection", function () {
-    it("for alias", function () {
-      var map = helper.createCustomMap();
-      var alias = helper.createAlias(map);
-
-      var oc = helper.createDbOverlay(map);
-
-      oc.getIdentifiedElements = function () {
-        return Promise.resolve([new IdentifiedElement({
-          objectId: alias.getId(),
-          icon: "empty.png",
-          modelId: map.getId(),
-          type: "Alias"
-        })]);
-      };
-      return map.renderOverlayCollection({
-        overlayCollection: oc
-      }).then(function () {
-        var markers = map.getMarkerSurfaceCollection().getMarkers();
-        assert.equal(1, markers.length);
-      });
-    });
-
-    it("alias re-rendering with different icon", function () {
-      var map = helper.createCustomMap();
-      var reaction = helper.createReaction(map, true);
-      var alias = helper.createAlias(map);
-      map.getModel().addAlias(alias);
-      map.getModel().addReaction(reaction);
-
-      var identifiedElement = new IdentifiedElement(alias);
-      identifiedElement.setIcon("empty.png");
-      var identifiedElement2 = new IdentifiedElement(alias);
-      identifiedElement2.setIcon("new_icon.png");
-
-      var marker;
-      var oc = helper.createDbOverlay(map);
-
-      oc.getIdentifiedElements = function () {
-        return Promise.resolve([identifiedElement, new IdentifiedElement(reaction)]);
-      };
-      return map.renderOverlayCollection({
-        overlayCollection: oc
-      }).then(function () {
-        marker = map.getMarkerSurfaceCollection().getMarker(identifiedElement);
-        oc.getIdentifiedElements = function () {
-          return Promise.resolve([identifiedElement2]);
-        };
-        assert.ok(map.getMarkerSurfaceCollection().getSurface({element: reaction, overlay: oc}));
-
-        return map.renderOverlayCollection({
-          overlayCollection: oc
-        });
-      }).then(function () {
-        assert.equal(marker.getIcon(), "new_icon.png");
-
-        assert.notOk(oc.mapOverlays["REACTION"][reaction.getId()]);
-      });
-    });
-
-    it("for set of aliases", function () {
-      var map = helper.createCustomMap();
-
-      var oc = helper.createDbOverlay(map);
-
-      var identifiedElements = [];
-      for (var i = 0; i < 3; i++) {
-        var alias = helper.createAlias(map);
-        map.getModel().addAlias(alias);
-        var ie = helper.createIdentifiedElement(alias);
-        ie.setIcon("");
-        identifiedElements.push(ie);
-      }
-
-      oc.getIdentifiedElements = function () {
-        return Promise.resolve(identifiedElements);
-      };
-
-      return map.renderOverlayCollection({
-        overlayCollection: oc
-      }).then(function () {
-        var markers = map.getMarkerSurfaceCollection().getMarkers();
-        assert.equal(3, markers.length);
-      });
-    });
-
-    it("for point", function () {
-      var map = helper.createCustomMap();
-
-      var oc = helper.createDbOverlay(map);
-
-      var javaObj = {
-        objectId: "Point2D.Double[117.685546875, 204.6923828125001]",
-        modelId: map.getId(),
-        type: "POINT",
-        icon: "marker/empty.png"
-      };
-
-      oc.getIdentifiedElements = function () {
-        return Promise.resolve([new IdentifiedElement(javaObj)]);
-      };
-
-      return map.renderOverlayCollection({
-        overlayCollection: oc
-      }).then(function () {
-        var markers = map.getMarkerSurfaceCollection().getMarkers();
-        assert.equal(1, markers.length);
-      });
-    });
-
-    it("for reaction", function () {
-      var map = helper.createCustomMap();
-      var reaction = helper.createReaction(map, true);
-      map.getModel().addReaction(reaction);
-
-      var oc = helper.createDbOverlay(map);
-
-      oc.getIdentifiedElements = function () {
-        return Promise.resolve([new IdentifiedElement(reaction)]);
-      };
-
-      return map.renderOverlayCollection({
-        overlayCollection: oc
-      }).then(function () {
-        var surfaces = map.getMarkerSurfaceCollection().getSurfaces();
-        assert.equal(1, surfaces.length);
-      });
-    });
-  });
-
-  it("refreshMarkers", function () {
-    var map = helper.createCustomMap();
-    var alias = helper.createAlias(map);
-    map.getModel().addAlias(alias);
-
-    var oc = helper.createDbOverlay(map);
-
-    oc.getIdentifiedElements = function () {
-      var element = new IdentifiedElement(alias);
-      element.setIcon("icon");
-      return Promise.resolve([element]);
-    };
-    return map.renderOverlayCollection({
-      overlayCollection: oc
-    }).then(function () {
-      return map.refreshMarkers(true);
-    }).then(function () {
-      var markers = map.getMarkerSurfaceCollection().getMarkers();
-      assert.equal(1, markers.length);
-    });
-  });
-
-  it("clearDbOverlays", function () {
-    var map = helper.createCustomMap();
-
-    var oc = helper.createDbOverlay(map);
-
-    var javaObj = {
-      objectId: "Point2D.Double[117.685546875, 204.6923828125001]",
-      modelId: map.getId(),
-      type: "POINT",
-      icon: "marker/empty.png"
-    };
-    var searchResults = [new IdentifiedElement(javaObj)];
-
-    oc.getIdentifiedElements = function () {
-      return Promise.resolve(searchResults);
-    };
-    oc.clear = function () {
-      searchResults = [];
-      return this.callListeners("onSearch", searchResults);
-    };
-
-    return map.renderOverlayCollection({
-      overlayCollection: oc
-    }).then(function () {
-
-      return map.clearDbOverlays();
-    }).then(function () {
-      var markerCount = 0;
-      for (var id in oc.pointMarkers) {
-        if (oc.pointMarkers.hasOwnProperty(id)) {
-          markerCount++;
-        }
-      }
-
-      assert.equal(0, markerCount);
-    });
-
-  });
-
-  it("getInfoWindowForIdentifiedElement ( reaction)", function () {
-    var map = helper.createCustomMap();
-    var reaction = helper.createReaction(map, true);
-    map.getModel().addReaction(reaction);
-
-    var ie = helper.createIdentifiedElement(reaction);
-    var marker = map.getMapCanvas().createMarker({icon: "empty.png", position: new Point(0, 0)});
-
-    var infoWindow = map.getInfoWindowForIdentifiedElement(ie);
-
-    assert.equal(null, infoWindow);
-    return map.openInfoWindowForIdentifiedElement(ie, marker).then(function () {
-      infoWindow = map.getInfoWindowForIdentifiedElement(ie);
-
-      assert.ok(infoWindow);
-    });
-
-  });
-
-  it("right click on map", function () {
-    var map = helper.createCustomMap();
-    map.setContextMenu(new MapContextMenu({
-      customMap: map,
-      element: testDiv,
-      molArt: new MolArt(map.getElement(), map)
-    }));
-
-    return map.getContextMenu().init().then(function () {
-      var data = {
-        stop: null,
-        point: new Point(10.0, 20.0)
-      };
-
-      assert.notOk(map.getActiveSubmapId());
-      return map.triggerEvent("map-rightclick", data);
-    }).then(function () {
-      //we need to wait because some implementations don't use promises...
-      return Promise.delay(100);
-    }).then(function () {
-      assert.equal(map.getId(), map.getActiveSubmapId());
-      return map.destroy();
-    });
-
-  });
-
-  it("left click on map", function () {
-    var map;
-    var searchOverlay;
-    return ServerConnector.getProject().then(function (project) {
-      map = helper.createCustomMap(project);
-      searchOverlay = helper.createSearchDbOverlay(map);
-
-      var data = {
-        stop: null,
-        point: new Point(184.79, 365.76)
-      };
-      map.setZoom(4);
-
-      assert.notOk(map.getActiveSubmapId());
-      return map.triggerEvent("map-click", data);
-    }).then(function () {
-      //we need to wait because some implementations don't use promises...
-      return Promise.delay(100);
-    }).then(function () {
-      assert.equal(map.getId(), map.getActiveSubmapId());
-      var element = new IdentifiedElement({id: 329171, type: "ALIAS", modelId: map.getId()});
-      assert.ok(map.getMarkerSurfaceCollection().getMarker(element));
-    });
-
-  });
-
-  it("left click on reaction", function () {
-    var map;
-    var searchOverlay;
-    return ServerConnector.getProject().then(function (project) {
-      map = helper.createCustomMap(project);
-      searchOverlay = helper.createSearchDbOverlay(map);
-
-      var data = {
-        stop: null,
-        point: new Point(457.51, 356.84)
-      };
-      map.setZoom(4);
-
-      assert.notOk(map.getActiveSubmapId());
-      return map.triggerEvent("map-click", data);
-    }).then(function () {
-      //we need to wait because some implementations don't use promises...
-      return Promise.delay(100);
-    }).then(function () {
-      assert.equal(map.getId(), map.getActiveSubmapId());
-
-      var reaction = new IdentifiedElement({id: 153521, type: "REACTION", modelId: map.getId()});
-      var surface = map.getMarkerSurfaceCollection().getSurface({element: reaction, overlay: searchOverlay});
-
-      assert.ok(surface);
-      assert.ok(surface.isShown());
-
-      var element = new IdentifiedElement({id: 329165, type: "ALIAS", modelId: map.getId()});
-      var marker = map.getMarkerSurfaceCollection().getMarker(element);
-      assert.ok(marker);
-    });
-  });
-
-  it("getAliasVisibleLayoutsData", function () {
-    var mockObject = helper.createCustomMap();
-
-    var alias = helper.createAlias();
-    mockObject.getModel().addAlias(alias);
-
-    var layout = helper.createOverlay();
-    layout.setInputDataAvailable(true);
-    layout.setInitialized(true);
-    mockObject.getProject().addDataOverlay(layout);
-
-    return mockObject.openDataOverlay(layout.getId()).then(function () {
-      return mockObject.getAliasVisibleLayoutsData(alias.getId());
-    }).then(function (layoutAliases) {
-      assert.equal(layoutAliases.length, 1);
-    });
-  });
-
-  it("changed coordinates in map", function () {
-    var map = helper.createCustomMap();
-    var oldCenter = map.getCenter();
-    var newCenter = new Point(3, 87);
-    map.setCenter(newCenter);
-    map.triggerEvent("map-center_changed");
-
-    var center = ServerConnector.getSessionData(map.getProject()).getCenter(map.getModel());
-    assert.ok(center !== oldCenter);
-    assert.ok(center instanceof Point);
-  });
-
-  it("refreshComments", function () {
-    var map = helper.createCustomMap();
-    map.getModel().setId(15781);
-    helper.createCommentDbOverlay(map);
-
-    ServerConnector.getSessionData().setShowComments(true);
-    return map.refreshComments().then(function () {
-      assert.notOk(map.getMarkerSurfaceCollection().getMarker(new IdentifiedElement({
-        id: '(241.01,372.35)',
-        modelId: map.getId(),
-        type: "POINT"
-      })));
-      assert.ok(map.getMarkerSurfaceCollection().getMarker(new IdentifiedElement({
-        id: '(643.96,144.09)',
-        modelId: map.getId(),
-        type: "POINT"
-      })));
-      assert.notOk(map.getMarkerSurfaceCollection().getMarker(new IdentifiedElement({
-        id: '(216.65,370.00)',
-        modelId: map.getId(),
-        type: "POINT"
-      })));
-      assert.notOk(map.getMarkerSurfaceCollection().getMarker(new IdentifiedElement({
-        id: 'unkId',
-        modelId: map.getId(),
-        type: "POINT"
-      })));
-    });
-  });
-
-  it("hide comments", function () {
-    var map = helper.createCustomMap();
-    map.getModel().setId(15781);
-    helper.createCommentDbOverlay(map);
-
-    ServerConnector.getSessionData().setShowComments(true);
-    return map.refreshComments().then(function () {
-      ServerConnector.getSessionData().setShowComments(false);
-      return map.refreshComments();
-    }).then(function () {
-      assert.notOk(map.getMarkerSurfaceCollection().getMarker(new IdentifiedElement({
-        id: '(241.01, 372.35)',
-        modelId: map.getId(),
-        type: "POINT"
-      })));
-    });
-  });
-
-  it("openCommentDialog", function () {
-    var map = helper.createCustomMap();
-    map.getModel().setId(15781);
-    map.setActiveSubmapId(15781);
-    map.setActiveSubmapClickCoordinates(new Point(2, 12));
-    return map.openCommentDialog().then(function () {
-      var types = map.getCommentDialog().getTypes();
-      assert.equal(types.length, 6);
-      var selected = map.getCommentDialog().getSelectedType();
-      assert.ok(selected === "<General>");
-
-      map.getCommentDialog().setSelectedType(1);
-      selected = map.getCommentDialog().getSelectedType();
-      assert.notOk(selected === "<General>");
-
-      map.getCommentDialog().setSelectedType(2);
-      selected = map.getCommentDialog().getSelectedType();
-      assert.notOk(selected === "<General>");
-    }).then(function () {
-      map.getCommentDialog().destroy();
-    });
-  });
-
-  describe("addComment", function () {
-    it("default", function () {
-      var map;
-      return ServerConnector.getProject().then(function (project) {
-        map = helper.createCustomMap(project);
-        helper.createCommentDbOverlay(map);
-        map.setActiveSubmapId(map.getId());
-        map.setActiveSubmapClickCoordinates(new Point(2, 12));
-        return map.openCommentDialog();
-      }).then(function () {
-        return map.getCommentDialog().addComment();
-      }).then(function (comments) {
-        assert.equal(0, comments.length);
-        map.getCommentDialog().destroy();
-      });
-    });
-
-    it("when comments are visible", function () {
-      var map;
-      return ServerConnector.getProject().then(function (project) {
-        map = helper.createCustomMap(project);
-        helper.createCommentDbOverlay(map);
-        map.setActiveSubmapId(map.getId());
-        map.setActiveSubmapClickCoordinates(new Point(2, 12));
-        return map.openCommentDialog();
-      }).then(function () {
-        ServerConnector.getSessionData().setShowComments(true);
-        return map.getCommentDialog().addComment();
-      }).then(function (comments) {
-        assert.ok(comments.length > 0);
-        map.getCommentDialog().destroy();
-      });
-    });
-
-    it("add for protein", function () {
-      var map;
-      return ServerConnector.getProject().then(function (project) {
-        map = helper.createCustomMap(project);
-        helper.createCommentDbOverlay(map);
-        map.setActiveSubmapId(map.getId());
-        map.setActiveSubmapClickCoordinates(new Point(2, 12));
-        return map.openCommentDialog();
-      }).then(function () {
-        var dialog = map.getCommentDialog();
-        dialog.setSelectedType(1);
-        return dialog.addComment();
-      }).then(function () {
-        map.getCommentDialog().destroy();
-      });
-    });
-  });
-
-  it("retrieveOverlayDetailDataForElement for comment", function () {
-    var map = helper.createCustomMap();
-    helper.createCommentDbOverlay(map);
-
-    var alias = helper.createAlias(map);
-    alias.setId(329157);
-    map.getModel().addAlias(alias);
-
-    var ie = new IdentifiedElement(alias);
-
-    return map.retrieveOverlayDetailDataForElement(ie, {
-      comment: true
-    }).then(function (details) {
-      assert.ok(details);
-      assert.equal(details.length, 1);
-      assert.equal(details[0].length, 1);
-      assert.ok(details[0][0] instanceof Comment);
-    });
-  });
-
-  it("getOverlayDataForIdentifiedElement", function () {
-    var map = helper.createCustomMap();
-    var commentOverlay = helper.createCommentDbOverlay(map);
-
-    var alias = helper.createAlias(map);
-    alias.setId(329157);
-    map.getModel().addAlias(alias);
-
-    var ie = new IdentifiedElement(alias);
-
-    return map.getOverlayDataForIdentifiedElement(ie, {
-      comment: true
-    }).then(function (details) {
-      assert.equal(details.length, 1);
-
-      var overlayData = details[0];
-      assert.equal(overlayData.overlay, commentOverlay);
-      assert.ok(overlayData.data);
-      assert.equal(overlayData.data.length, 1);
-      assert.ok(overlayData.data[0] instanceof Comment);
-    });
-  });
-
-  it("openSubmap", function () {
-    var options = helper.createCustomMapOptions();
-
-    var submodel = helper.createModel();
-    options.getProject().addModel(submodel);
-
-    var map = new CustomMap(options);
-
-    map.openSubmap(submodel.getId());
-    map.destroy();
-  });
-
-  describe("setCenter", function () {
-    it("default", function () {
-      var options = helper.createCustomMapOptions();
-
-      var map = new CustomMap(options);
-
-      map.setCenter(new Point(10, 20));
-      assert.ok(ServerConnector.getSessionData().getCenter(map.getModel()));
-    });
-
-    it("on submap", function () {
-      var options = helper.createCustomMapOptions();
-
-      var submodel = helper.createModel();
-      options.getProject().addModel(submodel);
-
-      var map = new CustomMap(options);
-      map.openSubmap(submodel.getId());
-      var submap = map.getSubmapById(submodel.getId());
-      submap.setCenter(new Point(10, 20));
-      assert.ok(ServerConnector.getSessionData().getCenter(submodel));
-      map.destroy();
-    });
-  });
-
-  it("setZoom", function () {
-    var options = helper.createCustomMapOptions();
-
-    var map = new CustomMap(options);
-
-    map.setZoom(3);
-    assert.equal(3, ServerConnector.getSessionData().getZoomLevel(map.getModel()));
-  });
-
-  it("removeSelection when invalid model selected", function () {
-    var options = helper.createCustomMapOptions();
-
-    var map = new CustomMap(options);
-    map.setActiveSubmapId(-1);
-
-    try {
-      map.removeSelection();
-      assert.ok(false);
-    } catch (e) {
-      assert.ok(e.message.indexOf("Cannot find submap") >= 0);
-    }
-  });
-
-  describe("_openInfoWindowForIdentifiedElement", function () {
-    it("for AliasMarker", function () {
-      var map;
-      var alias, marker;
-      return ServerConnector.getProject().then(function (project) {
-        map = helper.createCustomMap(project);
-        return map.getModel().getAliasById(329171);
-      }).then(function (result) {
-        alias = result;
-
-        var identifiedElement = new IdentifiedElement(alias);
-        identifiedElement.setIcon("empty.png");
-
-        marker = new AliasMarker({
-          element: identifiedElement,
-          map: map
-        });
-
-        return marker.init();
-      }).then(function () {
-        assert.equal(null, map.getAliasInfoWindowById(alias.getId()));
-        return map._openInfoWindowForIdentifiedElement(marker).then(function () {
-          assert.ok(map.getAliasInfoWindowById(alias.getId()));
-        });
-      });
-
-    });
-    it("for ReactionMarker", function () {
-      var map;
-      var reaction, marker;
-      return ServerConnector.getProject().then(function (project) {
-        map = helper.createCustomMap(project);
-        return map.getModel().getReactionById(153510);
-      }).then(function (result) {
-        reaction = result;
-
-        marker = new ReactionMarker({
-          element: new IdentifiedElement(reaction),
-          map: map
-        });
-        return marker.init();
-      }).then(function () {
-        assert.equal(null, map.getReactionInfoWindowById(reaction.getId()));
-        return map._openInfoWindowForIdentifiedElement(marker);
-      }).then(function () {
-        assert.ok(map.getReactionInfoWindowById(reaction.getId()));
-      });
-
-    });
-    it("for PointMarker", function () {
-
-      var mockObject = helper.createCustomMap();
-
-      mockObject.getOverlayDataForPoint = function () {
-        return Promise.resolve([]);
-      };
-
-      var point = new Point(2, 3.45);
-      var pointData = new PointData(point, mockObject.getId());
-
-      var pointMarker = new PointMarker({
-        element: new IdentifiedElement(pointData),
-        map: mockObject
-      });
-
-      return pointMarker.init().then(function () {
-        assert.equal(null, mockObject.getPointInfoWindowById(pointData.getId()));
-        return mockObject._openInfoWindowForIdentifiedElement(pointMarker.getIdentifiedElement());
-      }).then(function () {
-        assert.ok(mockObject.getPointInfoWindowById(pointData.getId()));
-      });
-    });
-  });
-
-  describe("init", function () {
-    it("invalid background overlay", function () {
-      var options = helper.createCustomMapOptions();
-      ServerConnector.getSessionData(options.getProject()).setSelectedBackgroundOverlay("bla");
-      var map = new CustomMap(options);
-      return map.init().then(function () {
-        assert.false("Error expected");
-      }, function () {
-        map.destroy();
-      })
-    });
-
-    it("non-existing background overlay", function () {
-      var options = helper.createCustomMapOptions();
-      ServerConnector.getSessionData(options.getProject()).setSelectedBackgroundOverlay(-1);
-      var map = new CustomMap(options);
-      return map.init().then(function () {
-        assert.ok(ServerConnector.getSessionData(options.getProject()).getSelectedBackgroundOverlay() > 0);
-        return map.destroy();
-      })
-    });
-
-    it("with session data overlays", function () {
-      var project = helper.createProject();
-      var overlay1 = helper.createOverlay();
-      overlay1.setInputDataAvailable(true);
-      project.addDataOverlay(overlay1);
-
-      var options = helper.createCustomMapOptions(project);
-      ServerConnector.getSessionData(options.getProject()).setVisibleOverlays([overlay1.getId()]);
-      var map = new CustomMap(options);
-      return map.init().then(function () {
-        return map.getVisibleDataOverlays();
-      }).then(function (overlays) {
-        assert.equal(1, overlays.length);
-        map.destroy();
-      })
-    });
-
-  });
-
-  describe("appendElementsPointingToSubmap", function () {
-    it("point to reaction", function () {
-      helper.setUrl("http://test/?id=complex_model_with_submaps");
-      return ServerConnector.getProject().then(function (project) {
-        var map = helper.createCustomMap(project);
-        var oc = helper.createSearchDbOverlay(map);
-
-        var reaction = new IdentifiedElement({id: 161955, modelId: 16729, type: "REACTION"});
-
-        return map.appendElementsPointingToSubmap([reaction], oc).then(function (elements) {
-          for (var i = 0; i < elements.length; i++) {
-            var element = elements[i];
-            //alias pointing to reaction should have an icon
-            if (element.type === "ALIAS") {
-              assert.ok(element.getIcon() !== undefined);
-            }
-          }
-        });
-      });
-    });
-  });
-  describe("logo link", function () {
-    it("left logo click", function () {
-      var map = helper.createCustomMap();
-      return map.getControl(ControlType.LOGO_2_IMG).onclick()
-    });
-    it("right logo click", function () {
-      var map = helper.createCustomMap();
-      return map.getControl(ControlType.LOGO_IMG).onclick()
-    });
-  });
-});
+"use strict";
+
+var Promise = require("bluebird");
+
+require("../mocha-config.js");
+
+var AliasMarker = require('../../../main/js/map/marker/AliasMarker');
+var AliasSurface = require('../../../main/js/map/surface/AliasSurface');
+var Comment = require('../../../main/js/map/data/Comment');
+var ControlType = require('../../../main/js/map/ControlType');
+var CustomMap = require('../../../main/js/map/CustomMap');
+var IdentifiedElement = require('../../../main/js/map/data/IdentifiedElement');
+var MapContextMenu = require('../../../main/js/gui/MapContextMenu');
+var MolArt = require('../../../main/js/map/structure/MolArt');
+var Point = require('../../../main/js/map/canvas/Point');
+var PointData = require('../../../main/js/map/data/PointData');
+var PointMarker = require('../../../main/js/map/marker/PointMarker');
+var ReactionMarker = require('../../../main/js/map/marker/ReactionMarker');
+var ReactionSurface = require('../../../main/js/map/surface/ReactionSurface');
+
+var ServerConnector = require('./../ServerConnector-mock');
+
+var logger = require('./../logger');
+
+var chai = require('chai');
+var assert = chai.assert;
+
+describe('CustomMap', function () {
+  describe("constructor", function () {
+    it("default", function () {
+      var options = helper.createCustomMapOptions();
+      var map = new CustomMap(options);
+      assert.ok(map);
+    });
+
+    it("with submaps", function () {
+      var options = helper.createCustomMapOptions();
+
+      options.getProject().addModel(helper.createModel());
+
+      var map = new CustomMap(options);
+      assert.ok(map);
+    });
+
+    it("with session data pointing to not existing overlay", function () {
+      var options = helper.createCustomMapOptions();
+
+      ServerConnector.getSessionData(options.getProject()).setSelectedBackgroundOverlay("-1");
+
+      var map = new CustomMap(options);
+      assert.ok(map);
+    });
+  });
+
+  it("getSubmapById", function () {
+    var map = helper.createCustomMap();
+    assert.ok(map.getSubmapById(map.getId()));
+  });
+
+  it("getSubmapById (invalid)", function () {
+    var map = helper.createCustomMap();
+    assert.equal(map.getSubmapById(-1), null);
+  });
+
+  it("getSubmapById (string id)", function () {
+    var map = helper.createCustomMap();
+    assert.ok(map.getSubmapById(map.getId() + ""));
+  });
+
+  describe("openDataOverlay", function () {
+    it("for not existing id", function () {
+      var map = helper.createCustomMap();
+      try {
+        map.openDataOverlay(-1);
+        assert.ok(false);
+      } catch (exception) {
+        assert.ok(exception.message.indexOf("You have no privileges") >= 0);
+      }
+    });
+
+    it("for int id", function () {
+      var options = helper.createCustomMapOptions();
+      var layout = options.getProject().getDataOverlays()[0];
+      var map = new CustomMap(options);
+      map.openDataOverlay(layout.getId());
+      assert.equal(logger.getErrors().length, 0);
+    });
+
+    it("for overlay object", function () {
+      var options = helper.createCustomMapOptions();
+      var layout = options.getProject().getDataOverlays()[0];
+      var map = new CustomMap(options);
+      map.openDataOverlay(layout);
+      assert.equal(logger.getErrors().length, 0);
+    });
+
+    it("for string id", function () {
+      var options = helper.createCustomMapOptions();
+      var layout = options.getProject().getDataOverlays()[0];
+      var map = new CustomMap(options);
+      map.openDataOverlay(layout.getId() + "");
+      assert.equal(logger.getErrors().length, 0);
+    });
+
+    it("with background overlay", function () {
+      var map = helper.createCustomMap();
+      var layout = helper.createOverlay();
+      layout.setInitialized(true);
+      layout.setInputDataAvailable(false);
+      map.getProject().addDataOverlay(layout);
+
+      return map.openDataOverlay(layout.getId()).then(function () {
+        var vLayouts = ServerConnector.getSessionData(map.getProject()).getVisibleOverlays();
+        assert.equal(0, vLayouts.length);
+      });
+    });
+
+    it("with non background overlay", function () {
+      var project = helper.createProject();
+      var layout = helper.createOverlay();
+      layout.setInitialized(true);
+      layout.setInputDataAvailable(true);
+      project.addDataOverlay(layout);
+
+      var emptyBackground = helper.createOverlay();
+      emptyBackground.setInputDataAvailable(false);
+      emptyBackground.setName("Empty");
+      project.addDataOverlay(emptyBackground);
+
+      var map = helper.createCustomMap(project);
+
+
+      return map.openDataOverlay(layout.getId()).then(function () {
+        var backgroundId = ServerConnector.getSessionData(project).getSelectedBackgroundOverlay();
+        assert.equal(backgroundId, emptyBackground.getId());
+      });
+    });
+
+    it("check backgroundChangeListener", function () {
+      var project = helper.createProject();
+      var overlay = helper.createOverlay();
+      overlay.setInitialized(true);
+      overlay.setInputDataAvailable(true);
+      project.addDataOverlay(overlay);
+
+      var overlay2 = helper.createOverlay();
+      overlay2.setInitialized(true);
+      overlay2.setInputDataAvailable(true);
+      project.addDataOverlay(overlay2);
+
+      var emptyBackground = helper.createOverlay();
+      emptyBackground.setInputDataAvailable(false);
+      emptyBackground.setName("Empty");
+      project.addDataOverlay(emptyBackground);
+
+      var map = helper.createCustomMap(project);
+
+      var counter = 0;
+      map.addListener("onBackgroundOverlayChange", function () {
+        counter++;
+      });
+
+      return map.openDataOverlay(overlay.getId()).then(function () {
+        assert.equal(1, counter, "listener wasn't fired");
+        return map.openDataOverlay(overlay2.getId());
+      }).then(function () {
+        assert.equal(1, counter, "listener shouldn't be fired again because nothing changed");
+      });
+    });
+
+    it("simple", function () {
+      var map = helper.createCustomMap();
+      var alias = helper.createAlias(map);
+      map.getModel().addAlias(alias);
+
+      var reaction = helper.createReaction(map);
+      map.getModel().addReaction(reaction);
+
+      var layout = helper.createOverlay();
+      layout.setInputDataAvailable(true);
+      layout.setInitialized(true);
+      var layoutAlias = helper.createLayoutAlias(alias);
+      layout.addAlias(layoutAlias);
+
+      var layoutReaction = helper.createLayoutReaction(reaction);
+      layout.addReaction(layoutReaction);
+
+      map.getProject().addDataOverlay(layout);
+
+      return map.openDataOverlay(layout.getId()).then(function () {
+        return map._showSelectedDataOverlay(layout.getId(), 0, 1);
+      }).then(function () {
+        var vLayouts = ServerConnector.getSessionData(map.getProject()).getVisibleOverlays();
+        assert.equal(1, vLayouts.length);
+        assert.equal(layout.getId(), vLayouts[0]);
+
+        assert.equal(2, map.selectedLayoutOverlays[layout.getId()].length);
+        var surface1 = map.selectedLayoutOverlays[layout.getId()][0];
+        var surface2 = map.selectedLayoutOverlays[layout.getId()][1];
+        assert.ok(surface1 instanceof AliasSurface || surface2 instanceof AliasSurface);
+        assert.ok(surface1 instanceof ReactionSurface || surface2 instanceof ReactionSurface);
+
+        // now hide the layout
+        return map._hideSelectedLayout(layout.getId());
+      }).then(function () {
+        assert.ok(map.selectedLayoutOverlays[layout.getId()]);
+        assert.equal(0, map.selectedLayoutOverlays[layout.getId()].length);
+      });
+
+    });
+
+    it("with submaps", function () {
+      var projectId = "complex_model_with_submaps";
+      helper.setUrl("http://test/?id=" + projectId);
+      var customMap;
+      var emptySubmodelId = 16730;
+      var filledSubmodelId = 16731;
+      var overlayId = 18083;
+
+      return ServerConnector.getProject(projectId).then(function (project) {
+        var options = helper.createCustomMapOptions(project);
+        customMap = new CustomMap(options);
+
+        return customMap.openSubmap(emptySubmodelId);
+      }).then(function () {
+        return customMap.openSubmap(filledSubmodelId);
+      }).then(function () {
+
+        var emptySubmap = customMap.getSubmapById(emptySubmodelId);
+        var filledSubmap = customMap.getSubmapById(filledSubmodelId);
+
+        return customMap.openDataOverlay(overlayId).then(function () {
+
+          assert.equal(2, customMap.selectedLayoutOverlays[overlayId].length);
+          assert.equal(1, filledSubmap.selectedLayoutOverlays[overlayId].length);
+          assert.equal(0, emptySubmap.selectedLayoutOverlays[overlayId].length);
+
+          // now hide the layout
+
+          return customMap.hideSelectedLayout(overlayId);
+        }).then(function () {
+          assert.equal(0, customMap.selectedLayoutOverlays[overlayId].length);
+          assert.equal(0, filledSubmap.selectedLayoutOverlays[overlayId].length);
+          assert.equal(0, emptySubmap.selectedLayoutOverlays[overlayId].length);
+        });
+
+      }).then(function () {
+        return customMap.destroy();
+      });
+    });
+
+    it("with submap double opened", function () {
+      var projectId = "complex_model_with_submaps";
+      helper.setUrl("http://test/?id=" + projectId);
+      var customMap, filledSubmap;
+      var filledSubmodelId = 16731;
+      var overlayId = 18083;
+
+      return ServerConnector.getProject(projectId).then(function (project) {
+        customMap = helper.createCustomMap(project);
+        return customMap.openSubmap(filledSubmodelId);
+      }).then(function () {
+        filledSubmap = customMap.getSubmapById(filledSubmodelId);
+        return customMap.openDataOverlay(overlayId);
+      }).then(function () {
+        assert.equal(1, filledSubmap.selectedLayoutOverlays[overlayId].length);
+        return customMap.openSubmap(filledSubmodelId);
+      }).then(function () {
+        //after opening submap nothing should change
+        assert.equal(1, filledSubmap.selectedLayoutOverlays[overlayId].length);
+      }).finally(function () {
+        return customMap.destroy();
+      });
+    });
+
+    it("check if info window content changed", function () {
+      var project = helper.createProject();
+      var layout = helper.createOverlay();
+      layout.setInitialized(true);
+      layout.setInputDataAvailable(true);
+      project.addDataOverlay(layout);
+
+      var map = helper.createCustomMap(project);
+
+      var alias = helper.createAlias(map);
+      var ie = helper.createIdentifiedElement(alias);
+      var marker = map.getMapCanvas().createMarker({icon: "empty.png", position: new Point(0, 0)});
+      var infoWindow;
+      return map.openInfoWindowForIdentifiedElement(ie, marker).then(function (result) {
+        infoWindow = result;
+        assert.notOk(infoWindow.getContent().innerHTML.indexOf(layout.getName()) >= 0);
+        return map.openDataOverlay(layout.getId());
+      }).then(function () {
+        assert.ok(infoWindow.getContent().innerHTML.indexOf(layout.getName()) >= 0);
+        assert.equal(logger.getErrors().length, 0);
+      });
+    });
+  });
+
+  describe("hideDataOverlay", function () {
+    it("default", function () {
+      var map = helper.createCustomMap();
+      var layout = helper.createOverlay();
+      layout.setInitialized(true);
+      layout.setInputDataAvailable(true);
+      map.getProject().addDataOverlay(layout);
+
+      return map.openDataOverlay(layout.getId()).then(function () {
+        return map.hideDataOverlay(layout.getId());
+      }).then(function () {
+        var vLayouts = ServerConnector.getSessionData(map.getProject()).getVisibleOverlays();
+        assert.equal(0, vLayouts.length);
+      });
+    });
+    it("check if info window content changed", function () {
+      var project = helper.createProject();
+      var layout = helper.createOverlay();
+      layout.setInitialized(true);
+      layout.setInputDataAvailable(true);
+      project.addDataOverlay(layout);
+
+      var map = helper.createCustomMap(project);
+
+      var alias = helper.createAlias(map);
+      var ie = helper.createIdentifiedElement(alias);
+      var marker = map.getMapCanvas().createMarker({icon: "empty.png", position: new Point(0, 0)});
+      var infoWindow;
+      return map.openInfoWindowForIdentifiedElement(ie, marker).then(function (result) {
+        infoWindow = result;
+        return map.openDataOverlay(layout.getId());
+      }).then(function () {
+        assert.ok(infoWindow.getContent().innerHTML.indexOf(layout.getName()) >= 0);
+        return map.hideDataOverlay(layout.getId());
+      }).then(function () {
+        assert.notOk(infoWindow.getContent().innerHTML.indexOf(layout.getName()) >= 0);
+        assert.equal(logger.getErrors().length, 0);
+      });
+    });
+  });
+
+
+  describe("renderOverlayCollection", function () {
+    it("for alias", function () {
+      var map = helper.createCustomMap();
+      var alias = helper.createAlias(map);
+
+      var oc = helper.createDbOverlay(map);
+
+      oc.getIdentifiedElements = function () {
+        return Promise.resolve([new IdentifiedElement({
+          objectId: alias.getId(),
+          icon: "empty.png",
+          modelId: map.getId(),
+          type: "Alias"
+        })]);
+      };
+      return map.renderOverlayCollection({
+        overlayCollection: oc
+      }).then(function () {
+        var markers = map.getMarkerSurfaceCollection().getMarkers();
+        assert.equal(1, markers.length);
+      });
+    });
+
+    it("alias re-rendering with different icon", function () {
+      var map = helper.createCustomMap();
+      var reaction = helper.createReaction(map, true);
+      var alias = helper.createAlias(map);
+      map.getModel().addAlias(alias);
+      map.getModel().addReaction(reaction);
+
+      var identifiedElement = new IdentifiedElement(alias);
+      identifiedElement.setIcon("empty.png");
+      var identifiedElement2 = new IdentifiedElement(alias);
+      identifiedElement2.setIcon("new_icon.png");
+
+      var marker;
+      var oc = helper.createDbOverlay(map);
+
+      oc.getIdentifiedElements = function () {
+        return Promise.resolve([identifiedElement, new IdentifiedElement(reaction)]);
+      };
+      return map.renderOverlayCollection({
+        overlayCollection: oc
+      }).then(function () {
+        marker = map.getMarkerSurfaceCollection().getMarker(identifiedElement);
+        oc.getIdentifiedElements = function () {
+          return Promise.resolve([identifiedElement2]);
+        };
+        assert.ok(map.getMarkerSurfaceCollection().getSurface({element: reaction, overlay: oc}));
+
+        return map.renderOverlayCollection({
+          overlayCollection: oc
+        });
+      }).then(function () {
+        assert.equal(marker.getIcon(), "new_icon.png");
+
+        assert.notOk(oc.mapOverlays["REACTION"][reaction.getId()]);
+      });
+    });
+
+    it("for set of aliases", function () {
+      var map = helper.createCustomMap();
+
+      var oc = helper.createDbOverlay(map);
+
+      var identifiedElements = [];
+      for (var i = 0; i < 3; i++) {
+        var alias = helper.createAlias(map);
+        map.getModel().addAlias(alias);
+        var ie = helper.createIdentifiedElement(alias);
+        ie.setIcon("");
+        identifiedElements.push(ie);
+      }
+
+      oc.getIdentifiedElements = function () {
+        return Promise.resolve(identifiedElements);
+      };
+
+      return map.renderOverlayCollection({
+        overlayCollection: oc
+      }).then(function () {
+        var markers = map.getMarkerSurfaceCollection().getMarkers();
+        assert.equal(3, markers.length);
+      });
+    });
+
+    it("for point", function () {
+      var map = helper.createCustomMap();
+
+      var oc = helper.createDbOverlay(map);
+
+      var javaObj = {
+        objectId: "Point2D.Double[117.685546875, 204.6923828125001]",
+        modelId: map.getId(),
+        type: "POINT",
+        icon: "marker/empty.png"
+      };
+
+      oc.getIdentifiedElements = function () {
+        return Promise.resolve([new IdentifiedElement(javaObj)]);
+      };
+
+      return map.renderOverlayCollection({
+        overlayCollection: oc
+      }).then(function () {
+        var markers = map.getMarkerSurfaceCollection().getMarkers();
+        assert.equal(1, markers.length);
+      });
+    });
+
+    it("for reaction", function () {
+      var map = helper.createCustomMap();
+      var reaction = helper.createReaction(map, true);
+      map.getModel().addReaction(reaction);
+
+      var oc = helper.createDbOverlay(map);
+
+      oc.getIdentifiedElements = function () {
+        return Promise.resolve([new IdentifiedElement(reaction)]);
+      };
+
+      return map.renderOverlayCollection({
+        overlayCollection: oc
+      }).then(function () {
+        var surfaces = map.getMarkerSurfaceCollection().getSurfaces();
+        assert.equal(1, surfaces.length);
+      });
+    });
+  });
+
+  it("refreshMarkers", function () {
+    var map = helper.createCustomMap();
+    var alias = helper.createAlias(map);
+    map.getModel().addAlias(alias);
+
+    var oc = helper.createDbOverlay(map);
+
+    oc.getIdentifiedElements = function () {
+      var element = new IdentifiedElement(alias);
+      element.setIcon("icon");
+      return Promise.resolve([element]);
+    };
+    return map.renderOverlayCollection({
+      overlayCollection: oc
+    }).then(function () {
+      return map.refreshMarkers(true);
+    }).then(function () {
+      var markers = map.getMarkerSurfaceCollection().getMarkers();
+      assert.equal(1, markers.length);
+    });
+  });
+
+  it("clearDbOverlays", function () {
+    var map = helper.createCustomMap();
+
+    var oc = helper.createDbOverlay(map);
+
+    var javaObj = {
+      objectId: "Point2D.Double[117.685546875, 204.6923828125001]",
+      modelId: map.getId(),
+      type: "POINT",
+      icon: "marker/empty.png"
+    };
+    var searchResults = [new IdentifiedElement(javaObj)];
+
+    oc.getIdentifiedElements = function () {
+      return Promise.resolve(searchResults);
+    };
+    oc.clear = function () {
+      searchResults = [];
+      return this.callListeners("onSearch", searchResults);
+    };
+
+    return map.renderOverlayCollection({
+      overlayCollection: oc
+    }).then(function () {
+
+      return map.clearDbOverlays();
+    }).then(function () {
+      var markerCount = 0;
+      for (var id in oc.pointMarkers) {
+        if (oc.pointMarkers.hasOwnProperty(id)) {
+          markerCount++;
+        }
+      }
+
+      assert.equal(0, markerCount);
+    });
+
+  });
+
+  it("getInfoWindowForIdentifiedElement ( reaction)", function () {
+    var map = helper.createCustomMap();
+    var reaction = helper.createReaction(map, true);
+    map.getModel().addReaction(reaction);
+
+    var ie = helper.createIdentifiedElement(reaction);
+    var marker = map.getMapCanvas().createMarker({icon: "empty.png", position: new Point(0, 0)});
+
+    var infoWindow = map.getInfoWindowForIdentifiedElement(ie);
+
+    assert.equal(null, infoWindow);
+    return map.openInfoWindowForIdentifiedElement(ie, marker).then(function () {
+      infoWindow = map.getInfoWindowForIdentifiedElement(ie);
+
+      assert.ok(infoWindow);
+    });
+
+  });
+
+  it("right click on map", function () {
+    var map = helper.createCustomMap();
+    map.setContextMenu(new MapContextMenu({
+      customMap: map,
+      element: testDiv,
+      molArt: new MolArt(map.getElement(), map)
+    }));
+
+    return map.getContextMenu().init().then(function () {
+      var data = {
+        stop: null,
+        point: new Point(10.0, 20.0)
+      };
+
+      assert.notOk(map.getActiveSubmapId());
+      return map.triggerEvent("map-rightclick", data);
+    }).then(function () {
+      //we need to wait because some implementations don't use promises...
+      return Promise.delay(100);
+    }).then(function () {
+      assert.equal(map.getId(), map.getActiveSubmapId());
+      return map.destroy();
+    });
+
+  });
+
+  it("left click on map", function () {
+    var map;
+    var searchOverlay;
+    return ServerConnector.getProject().then(function (project) {
+      map = helper.createCustomMap(project);
+      searchOverlay = helper.createSearchDbOverlay(map);
+
+      var data = {
+        stop: null,
+        point: new Point(184.79, 365.76)
+      };
+      map.setZoom(4);
+
+      assert.notOk(map.getActiveSubmapId());
+      return map.triggerEvent("map-click", data);
+    }).then(function () {
+      //we need to wait because some implementations don't use promises...
+      return Promise.delay(100);
+    }).then(function () {
+      assert.equal(map.getId(), map.getActiveSubmapId());
+      var element = new IdentifiedElement({id: 329171, type: "ALIAS", modelId: map.getId()});
+      assert.ok(map.getMarkerSurfaceCollection().getMarker(element));
+    });
+
+  });
+
+  it("left click on reaction", function () {
+    var map;
+    var searchOverlay;
+    return ServerConnector.getProject().then(function (project) {
+      map = helper.createCustomMap(project);
+      searchOverlay = helper.createSearchDbOverlay(map);
+
+      var data = {
+        stop: null,
+        point: new Point(457.51, 356.84)
+      };
+      map.setZoom(4);
+
+      assert.notOk(map.getActiveSubmapId());
+      return map.triggerEvent("map-click", data);
+    }).then(function () {
+      //we need to wait because some implementations don't use promises...
+      return Promise.delay(100);
+    }).then(function () {
+      assert.equal(map.getId(), map.getActiveSubmapId());
+
+      var reaction = new IdentifiedElement({id: 153521, type: "REACTION", modelId: map.getId()});
+      var surface = map.getMarkerSurfaceCollection().getSurface({element: reaction, overlay: searchOverlay});
+
+      assert.ok(surface);
+      assert.ok(surface.isShown());
+
+      var element = new IdentifiedElement({id: 329165, type: "ALIAS", modelId: map.getId()});
+      var marker = map.getMarkerSurfaceCollection().getMarker(element);
+      assert.ok(marker);
+    });
+  });
+
+  it("changed coordinates in map", function () {
+    var map = helper.createCustomMap();
+    var oldCenter = map.getCenter();
+    var newCenter = new Point(3, 87);
+    map.setCenter(newCenter);
+    map.triggerEvent("map-center_changed");
+
+    var center = ServerConnector.getSessionData(map.getProject()).getCenter(map.getModel());
+    assert.ok(center !== oldCenter);
+    assert.ok(center instanceof Point);
+  });
+
+  it("refreshComments", function () {
+    var map = helper.createCustomMap();
+    map.getModel().setId(15781);
+    helper.createCommentDbOverlay(map);
+
+    ServerConnector.getSessionData().setShowComments(true);
+    return map.refreshComments().then(function () {
+      assert.notOk(map.getMarkerSurfaceCollection().getMarker(new IdentifiedElement({
+        id: '(241.01,372.35)',
+        modelId: map.getId(),
+        type: "POINT"
+      })));
+      assert.ok(map.getMarkerSurfaceCollection().getMarker(new IdentifiedElement({
+        id: '(643.96,144.09)',
+        modelId: map.getId(),
+        type: "POINT"
+      })));
+      assert.notOk(map.getMarkerSurfaceCollection().getMarker(new IdentifiedElement({
+        id: '(216.65,370.00)',
+        modelId: map.getId(),
+        type: "POINT"
+      })));
+      assert.notOk(map.getMarkerSurfaceCollection().getMarker(new IdentifiedElement({
+        id: 'unkId',
+        modelId: map.getId(),
+        type: "POINT"
+      })));
+    });
+  });
+
+  it("hide comments", function () {
+    var map = helper.createCustomMap();
+    map.getModel().setId(15781);
+    helper.createCommentDbOverlay(map);
+
+    ServerConnector.getSessionData().setShowComments(true);
+    return map.refreshComments().then(function () {
+      ServerConnector.getSessionData().setShowComments(false);
+      return map.refreshComments();
+    }).then(function () {
+      assert.notOk(map.getMarkerSurfaceCollection().getMarker(new IdentifiedElement({
+        id: '(241.01, 372.35)',
+        modelId: map.getId(),
+        type: "POINT"
+      })));
+    });
+  });
+
+  it("openCommentDialog", function () {
+    var map = helper.createCustomMap();
+    map.getModel().setId(15781);
+    map.setActiveSubmapId(15781);
+    map.setActiveSubmapClickCoordinates(new Point(2, 12));
+    return map.openCommentDialog().then(function () {
+      var types = map.getCommentDialog().getTypes();
+      assert.equal(types.length, 6);
+      var selected = map.getCommentDialog().getSelectedType();
+      assert.ok(selected === "<General>");
+
+      map.getCommentDialog().setSelectedType(1);
+      selected = map.getCommentDialog().getSelectedType();
+      assert.notOk(selected === "<General>");
+
+      map.getCommentDialog().setSelectedType(2);
+      selected = map.getCommentDialog().getSelectedType();
+      assert.notOk(selected === "<General>");
+    }).then(function () {
+      map.getCommentDialog().destroy();
+    });
+  });
+
+  describe("addComment", function () {
+    it("default", function () {
+      var map;
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        helper.createCommentDbOverlay(map);
+        map.setActiveSubmapId(map.getId());
+        map.setActiveSubmapClickCoordinates(new Point(2, 12));
+        return map.openCommentDialog();
+      }).then(function () {
+        return map.getCommentDialog().addComment();
+      }).then(function (comments) {
+        assert.equal(0, comments.length);
+        map.getCommentDialog().destroy();
+      });
+    });
+
+    it("when comments are visible", function () {
+      var map;
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        helper.createCommentDbOverlay(map);
+        map.setActiveSubmapId(map.getId());
+        map.setActiveSubmapClickCoordinates(new Point(2, 12));
+        return map.openCommentDialog();
+      }).then(function () {
+        ServerConnector.getSessionData().setShowComments(true);
+        return map.getCommentDialog().addComment();
+      }).then(function (comments) {
+        assert.ok(comments.length > 0);
+        map.getCommentDialog().destroy();
+      });
+    });
+
+    it("add for protein", function () {
+      var map;
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        helper.createCommentDbOverlay(map);
+        map.setActiveSubmapId(map.getId());
+        map.setActiveSubmapClickCoordinates(new Point(2, 12));
+        return map.openCommentDialog();
+      }).then(function () {
+        var dialog = map.getCommentDialog();
+        dialog.setSelectedType(1);
+        return dialog.addComment();
+      }).then(function () {
+        map.getCommentDialog().destroy();
+      });
+    });
+  });
+
+  it("retrieveOverlayDetailDataForElement for comment", function () {
+    var map = helper.createCustomMap();
+    helper.createCommentDbOverlay(map);
+
+    var alias = helper.createAlias(map);
+    alias.setId(329157);
+    map.getModel().addAlias(alias);
+
+    var ie = new IdentifiedElement(alias);
+
+    return map.retrieveOverlayDetailDataForElement(ie, {
+      comment: true
+    }).then(function (details) {
+      assert.ok(details);
+      assert.equal(details.length, 1);
+      assert.equal(details[0].length, 1);
+      assert.ok(details[0][0] instanceof Comment);
+    });
+  });
+
+  it("getOverlayDataForIdentifiedElement", function () {
+    var map = helper.createCustomMap();
+    var commentOverlay = helper.createCommentDbOverlay(map);
+
+    var alias = helper.createAlias(map);
+    alias.setId(329157);
+    map.getModel().addAlias(alias);
+
+    var ie = new IdentifiedElement(alias);
+
+    return map.getOverlayDataForIdentifiedElement(ie, {
+      comment: true
+    }).then(function (details) {
+      assert.equal(details.length, 1);
+
+      var overlayData = details[0];
+      assert.equal(overlayData.overlay, commentOverlay);
+      assert.ok(overlayData.data);
+      assert.equal(overlayData.data.length, 1);
+      assert.ok(overlayData.data[0] instanceof Comment);
+    });
+  });
+
+  it("openSubmap", function () {
+    var options = helper.createCustomMapOptions();
+
+    var submodel = helper.createModel();
+    options.getProject().addModel(submodel);
+
+    var map = new CustomMap(options);
+
+    map.openSubmap(submodel.getId());
+    map.destroy();
+  });
+
+  describe("setCenter", function () {
+    it("default", function () {
+      var options = helper.createCustomMapOptions();
+
+      var map = new CustomMap(options);
+
+      map.setCenter(new Point(10, 20));
+      assert.ok(ServerConnector.getSessionData().getCenter(map.getModel()));
+    });
+
+    it("on submap", function () {
+      var options = helper.createCustomMapOptions();
+
+      var submodel = helper.createModel();
+      options.getProject().addModel(submodel);
+
+      var map = new CustomMap(options);
+      map.openSubmap(submodel.getId());
+      var submap = map.getSubmapById(submodel.getId());
+      submap.setCenter(new Point(10, 20));
+      assert.ok(ServerConnector.getSessionData().getCenter(submodel));
+      map.destroy();
+    });
+  });
+
+  it("setZoom", function () {
+    var options = helper.createCustomMapOptions();
+
+    var map = new CustomMap(options);
+
+    map.setZoom(3);
+    assert.equal(3, ServerConnector.getSessionData().getZoomLevel(map.getModel()));
+  });
+
+  it("removeSelection when invalid model selected", function () {
+    var options = helper.createCustomMapOptions();
+
+    var map = new CustomMap(options);
+    map.setActiveSubmapId(-1);
+
+    try {
+      map.removeSelection();
+      assert.ok(false);
+    } catch (e) {
+      assert.ok(e.message.indexOf("Cannot find submap") >= 0);
+    }
+  });
+
+  describe("_openInfoWindowForIdentifiedElement", function () {
+    it("for AliasMarker", function () {
+      var map;
+      var alias, marker;
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        return map.getModel().getAliasById(329171);
+      }).then(function (result) {
+        alias = result;
+
+        var identifiedElement = new IdentifiedElement(alias);
+        identifiedElement.setIcon("empty.png");
+
+        marker = new AliasMarker({
+          element: identifiedElement,
+          map: map
+        });
+
+        return marker.init();
+      }).then(function () {
+        assert.equal(null, map.getAliasInfoWindowById(alias.getId()));
+        return map._openInfoWindowForIdentifiedElement(marker).then(function () {
+          assert.ok(map.getAliasInfoWindowById(alias.getId()));
+        });
+      });
+
+    });
+    it("for ReactionMarker", function () {
+      var map;
+      var reaction, marker;
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        return map.getModel().getReactionById(153510);
+      }).then(function (result) {
+        reaction = result;
+
+        marker = new ReactionMarker({
+          element: new IdentifiedElement(reaction),
+          map: map
+        });
+        return marker.init();
+      }).then(function () {
+        assert.equal(null, map.getReactionInfoWindowById(reaction.getId()));
+        return map._openInfoWindowForIdentifiedElement(marker);
+      }).then(function () {
+        assert.ok(map.getReactionInfoWindowById(reaction.getId()));
+      });
+
+    });
+    it("for PointMarker", function () {
+
+      var mockObject = helper.createCustomMap();
+
+      mockObject.getOverlayDataForPoint = function () {
+        return Promise.resolve([]);
+      };
+
+      var point = new Point(2, 3.45);
+      var pointData = new PointData(point, mockObject.getId());
+
+      var pointMarker = new PointMarker({
+        element: new IdentifiedElement(pointData),
+        map: mockObject
+      });
+
+      return pointMarker.init().then(function () {
+        assert.equal(null, mockObject.getPointInfoWindowById(pointData.getId()));
+        return mockObject._openInfoWindowForIdentifiedElement(pointMarker.getIdentifiedElement());
+      }).then(function () {
+        assert.ok(mockObject.getPointInfoWindowById(pointData.getId()));
+      });
+    });
+  });
+
+  describe("init", function () {
+    it("invalid background overlay", function () {
+      var options = helper.createCustomMapOptions();
+      ServerConnector.getSessionData(options.getProject()).setSelectedBackgroundOverlay("bla");
+      var map = new CustomMap(options);
+      return map.init().then(function () {
+        assert.false("Error expected");
+      }, function () {
+        map.destroy();
+      })
+    });
+
+    it("non-existing background overlay", function () {
+      var options = helper.createCustomMapOptions();
+      ServerConnector.getSessionData(options.getProject()).setSelectedBackgroundOverlay(-1);
+      var map = new CustomMap(options);
+      return map.init().then(function () {
+        assert.ok(ServerConnector.getSessionData(options.getProject()).getSelectedBackgroundOverlay() > 0);
+        return map.destroy();
+      })
+    });
+
+    it("with session data overlays", function () {
+      var project = helper.createProject();
+      var overlay1 = helper.createOverlay();
+      overlay1.setInputDataAvailable(true);
+      project.addDataOverlay(overlay1);
+
+      var options = helper.createCustomMapOptions(project);
+      ServerConnector.getSessionData(options.getProject()).setVisibleOverlays([overlay1.getId()]);
+      var map = new CustomMap(options);
+      return map.init().then(function () {
+        return map.getVisibleDataOverlays();
+      }).then(function (overlays) {
+        assert.equal(1, overlays.length);
+        map.destroy();
+      })
+    });
+
+  });
+
+  describe("appendElementsPointingToSubmap", function () {
+    it("point to reaction", function () {
+      helper.setUrl("http://test/?id=complex_model_with_submaps");
+      return ServerConnector.getProject().then(function (project) {
+        var map = helper.createCustomMap(project);
+        var oc = helper.createSearchDbOverlay(map);
+
+        var reaction = new IdentifiedElement({id: 161955, modelId: 16729, type: "REACTION"});
+
+        return map.appendElementsPointingToSubmap([reaction], oc).then(function (elements) {
+          for (var i = 0; i < elements.length; i++) {
+            var element = elements[i];
+            //alias pointing to reaction should have an icon
+            if (element.type === "ALIAS") {
+              assert.ok(element.getIcon() !== undefined);
+            }
+          }
+        });
+      });
+    });
+  });
+  describe("logo link", function () {
+    it("left logo click", function () {
+      var map = helper.createCustomMap();
+      return map.getControl(ControlType.LOGO_2_IMG).onclick()
+    });
+    it("right logo click", function () {
+      var map = helper.createCustomMap();
+      return map.getControl(ControlType.LOGO_IMG).onclick()
+    });
+  });
+});
diff --git a/frontend-js/src/test/js/map/canvas/GoogleMaps/GoogleMapsApiCanvas-test.js b/frontend-js/src/test/js/map/canvas/GoogleMaps/GoogleMapsApiCanvas-test.js
index a95bd3d3adbf145d9ba74b55f38378bf4ac5eaaa..c91cf90576e5a09a1396eb0d8e05641f4c1e09f4 100644
--- a/frontend-js/src/test/js/map/canvas/GoogleMaps/GoogleMapsApiCanvas-test.js
+++ b/frontend-js/src/test/js/map/canvas/GoogleMaps/GoogleMapsApiCanvas-test.js
@@ -208,11 +208,41 @@ describe('GoogleMapsApiCanvas', function () {
       strokeColor: "#330000",
       strokeOpacity: 0.5,
       strokeWeight: 1.0,
-      id:"1",
+      id: "1",
       fillColor: "#00FF00",
-      bounds: new Bounds(new Point(0,0), new Point(2,2))
+      bounds: new Bounds(new Point(0, 0), new Point(2, 2))
+    });
+    return google.maps.event.trigger(rectangle.getGoogleRectangles()[0], "click");
+  });
+
+  it("set rectangle bounds", function () {
+    var canvas = new GoogleMapsApiCanvas(testDiv, testOptions);
+    var rectangle = canvas.createRectangle({
+      fillOpacity: 0.7,
+      strokeColor: "#330000",
+      strokeOpacity: 0.5,
+      strokeWeight: 1.0,
+      id: "1",
+      fillColor: "#00FF00",
+      bounds: new Bounds(new Point(10, 10), new Point(20, 200))
+    });
+    rectangle.setBounds(new Bounds(new Point(100, 10), new Point(150, 200)));
+    var newBounds = rectangle.getBounds();
+    assert.closeTo(newBounds.getTopLeft().distanceTo(new Point(100, 10)), 0, helper.EPSILON);
+    assert.closeTo(newBounds.getRightBottom().distanceTo(new Point(150, 200)), 0, helper.EPSILON);
+  });
+
+  it("create rectangle with gradient", function () {
+    var canvas = new GoogleMapsApiCanvas(testDiv, testOptions);
+    var rectangle = canvas.createRectangle({
+      fillOpacity: 0.7,
+      strokeColor: "#330000",
+      strokeOpacity: 0.5,
+      strokeWeight: 1.0,
+      id: "1",
+      fillGradient: [{color: "#00FF00", amount: 1}, {color: "#00aa00", amount: 5}],
+      bounds: new Bounds(new Point(10, 10), new Point(20, 200))
     });
-    return google.maps.event.trigger(rectangle.getGoogleRectangle(), "click");
   });
 
 });
diff --git a/frontend-js/src/test/js/map/canvas/Point-test.js b/frontend-js/src/test/js/map/canvas/Point-test.js
index 16da526d4eec5381fd92b33c906755d23b712362..cca9e5a71078120124a44476fcd6bb8dd344e47e 100644
--- a/frontend-js/src/test/js/map/canvas/Point-test.js
+++ b/frontend-js/src/test/js/map/canvas/Point-test.js
@@ -28,6 +28,19 @@ describe('Point', function () {
       assert.equal(point.y, point2.y);
     });
   });
+  describe("distanceTo", function () {
+    it("the same", function () {
+      var point = new Point(12, 3);
+      assert.closeTo(point.distanceTo(point), 0, helper.EPSILON);
+    });
+    it("different", function () {
+      var point = new Point(12, 3);
+      var point2 = new Point(15, 7);
+      assert.closeTo(point.distanceTo(point2), 5, helper.EPSILON);
+      assert.closeTo(point.distanceTo(new Point(15, 3)), 3, helper.EPSILON);
+      assert.closeTo(point.distanceTo(new Point(12, -1)), 4, helper.EPSILON);
+    });
+  });
 
   it("toString", function () {
     var point = new Point(12, 3);
diff --git a/frontend-js/src/test/js/map/data/ReferenceGenome-test.js b/frontend-js/src/test/js/map/data/ReferenceGenome-test.js
index b001486d62b6f371b27916007a138f003e4ae8dc..204ff22eed48a35bf6068a6a7dd7badda613dc63 100644
--- a/frontend-js/src/test/js/map/data/ReferenceGenome-test.js
+++ b/frontend-js/src/test/js/map/data/ReferenceGenome-test.js
@@ -10,7 +10,16 @@ describe('ReferenceGenome', function () {
         type: "TYP",
         version: "v3",
         localUrl: "http://google.pl/",
-        sourceUrl: "http://google.pl/"
+        sourceUrl: "http://google.pl/",
+        organism: {
+          "annotatorClassName": "",
+          "descriptionByType": "",
+          "descriptionByTypeRelation": "",
+          "id": 517528,
+          "link": "http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8822",
+          "resource": "8822",
+          "type": "TAXONOMY"
+        }
       };
       var genome = new ReferenceGenome(data);
       assert.equal(genome.getType(), data.type);
@@ -21,7 +30,16 @@ describe('ReferenceGenome', function () {
     it("simple", function () {
       var data = {
         sourceUrl: "http://google.pl/",
-        geneMapping: [{}]
+        geneMapping: [{}],
+        organism: {
+          "annotatorClassName": "",
+          "descriptionByType": "",
+          "descriptionByTypeRelation": "",
+          "id": 517528,
+          "link": "http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8822",
+          "resource": "8822",
+          "type": "TAXONOMY"
+        }
       };
       var genome = new ReferenceGenome(data);
       assert.equal(genome.getUrl(), data.sourceUrl);
@@ -37,8 +55,5 @@ describe('ReferenceGenome', function () {
       var genome = new ReferenceGenome(null);
       assert.ok(genome);
     });
-
   });
-
-
 });
diff --git a/frontend-js/src/test/js/map/surface/AliasSurface-test.js b/frontend-js/src/test/js/map/surface/AliasSurface-test.js
index 92ec4e60627ac61e2e6b09ae1a93b56ef40c7d48..4c98a6eb0db1934f67c8ddf5868744e2b0377a93 100644
--- a/frontend-js/src/test/js/map/surface/AliasSurface-test.js
+++ b/frontend-js/src/test/js/map/surface/AliasSurface-test.js
@@ -13,10 +13,9 @@ describe('AliasSurface', function () {
     it("default", function () {
       var map = helper.createCustomMap();
       var alias = helper.createAlias(map);
-      var layoutAlias = helper.createLayoutAlias(alias);
 
       var result = new AliasSurface({
-        overlayAlias: layoutAlias,
+        overlayData: [helper.createLayoutAlias(alias)],
         alias: alias,
         map: map,
         startX: 1,
@@ -30,10 +29,9 @@ describe('AliasSurface', function () {
     it("no bounds", function () {
       var map = helper.createCustomMap();
       var alias = helper.createAlias(map);
-      var layoutAlias = helper.createLayoutAlias(alias);
 
       var result = new AliasSurface({
-        overlayAlias: layoutAlias,
+        overlayData: [helper.createLayoutAlias(alias)],
         alias: alias,
         map: map
       });
@@ -55,6 +53,7 @@ describe('AliasSurface', function () {
         alias = result;
         surface = new AliasSurface({
           alias: result,
+          overlayData: [helper.createLayoutAlias(alias)],
           map: map
         });
         return surface.init();
@@ -71,7 +70,7 @@ describe('AliasSurface', function () {
       var map = helper.createCustomMap();
       var alias = helper.createAlias(map);
       var surface = new AliasSurface({
-        overlayAlias: helper.createLayoutAlias(alias),
+        overlayData: [helper.createLayoutAlias(alias)],
         alias: alias,
         map: map,
         startX: 1,
@@ -97,6 +96,7 @@ describe('AliasSurface', function () {
         alias = result;
         surface = new AliasSurface({
           alias: result,
+          overlayData: [helper.createLayoutAlias(result)],
           map: map,
           onClick: function () {
             clicked = true;
diff --git a/frontend-js/src/test/js/map/window/AliasInfoWindow-test.js b/frontend-js/src/test/js/map/window/AliasInfoWindow-test.js
index ab23b3e855eef90f8a7455d0b3485b5670fbcfe1..85c8f1ca153eba39ac234e5ed51849a6f58734da 100644
--- a/frontend-js/src/test/js/map/window/AliasInfoWindow-test.js
+++ b/frontend-js/src/test/js/map/window/AliasInfoWindow-test.js
@@ -7,7 +7,9 @@ var Promise = require("bluebird");
 var functions = require('../../../../main/js/Functions');
 
 var Alias = require('../../../../main/js/map/data/Alias');
+var LayoutAlias = require('../../../../main/js/map/data/LayoutAlias');
 var Drug = require('../../../../main/js/map/data/Drug');
+var GeneVariant = require('../../../../main/js/map/data/GeneVariant');
 var AliasInfoWindow = require('../../../../main/js/map/window/AliasInfoWindow');
 var IdentifiedElement = require('../../../../main/js/map/data/IdentifiedElement');
 var DataOverlay = require('../../../../main/js/map/data/DataOverlay');
@@ -219,107 +221,110 @@ describe('AliasInfoWindow', function () {
     });
   });
 
-  xit("createGeneticsDiv", function () {
-    var map;
-    var overlay;
-
-    var layoutAlias;
-    var win;
-
-    return ServerConnector.getProject().then(function (project) {
-      map = helper.createCustomMap(project);
-      overlay = new DataOverlay(18077, "xxx");
-      return overlay.init();
-    }).then(function () {
-      return overlay.getFullAliasById(overlay.getAliases()[0].getId());
-    }).then(function (data) {
-      layoutAlias = data;
-      return map.getModel().getAliasById(layoutAlias.getId());
-    }).then(function (alias) {
-      win = new AliasInfoWindow({
-        alias: alias,
-        map: map,
-        marker: helper.createMarker({element: alias, map: map})
+  describe("createGeneticsDiv", function () {
+    it("on top map", function () {
+      var map;
+      var overlay;
+
+      var layoutAlias;
+      var win;
+
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        overlay = new DataOverlay(18077, "xxx");
+        return overlay.init();
+      }).then(function () {
+        return overlay.getFullAliasById(overlay.getAliases()[0].getId());
+      }).then(function (data) {
+        layoutAlias = data;
+        return map.getModel().getAliasById(layoutAlias.getId());
+      }).then(function (alias) {
+        win = new AliasInfoWindow({
+          alias: alias,
+          map: map,
+          marker: helper.createMarker({element: alias, map: map})
+        });
+        return win.init();
+      }).then(function () {
+        var overlay = helper.createOverlay();
+        overlay.addAlias(layoutAlias);
+        return win.createGenomicDiv({overlays: [overlay]});
+      }).then(function (div) {
+        assert.ok(div);
+        assert.ok(div.innerHTML.indexOf("No reference genome data available on minerva platform") === -1);
+        win.destroy();
       });
-      return win.init();
-    }).then(function () {
-      win.layoutAliases = [layoutAlias];
-      win.layoutNames = ["xxx"];
-      return win.createGenomicDiv();
-    }).then(function (div) {
-      assert.ok(div);
-      assert.ok(div.innerHTML.indexOf("No reference genome data available on minerva platform") === -1);
-      win.destroy();
-    });
-
-  });
-
-  it("createGeneticsDiv with no genetic data", function () {
-    var map;
 
-    var win;
-    var aliasId = 329173;
-
-    return ServerConnector.getProject().then(function (project) {
-      map = helper.createCustomMap(project);
-      var overlay = new DataOverlay(18077, "xxx");
-      return overlay.init();
-    }).then(function () {
-      return map.getModel().getAliasById(aliasId);
-    }).then(function (alias) {
-      win = new AliasInfoWindow({
-        alias: alias,
-        map: map,
-        marker: helper.createMarker({element: alias, map: map})
-      });
-      return win.init();
-    }).then(function () {
-      win.layoutAliases = [undefined];
-      return win.createGenomicDiv();
-    }).then(function (div) {
-      assert.ok(div);
-      assert.ok(div.innerHTML.indexOf("No reference genome data available on minerva platform") === -1);
-      win.destroy();
     });
 
-  });
-
-  it("createGeneticsDivForUnknownOrganism", function () {
-    var map;
-    var overlay;
+    it("with no genetic data", function () {
+      var map;
+
+      var win;
+      var aliasId = 329173;
+
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        var overlay = new DataOverlay(18077, "xxx");
+        return overlay.init();
+      }).then(function () {
+        return map.getModel().getAliasById(aliasId);
+      }).then(function (alias) {
+        win = new AliasInfoWindow({
+          alias: alias,
+          map: map,
+          marker: helper.createMarker({element: alias, map: map})
+        });
+        return win.init();
+      }).then(function () {
+        var overlays = [helper.createOverlay()];
+        return win.createGenomicDiv({overlays: overlays});
+      }).then(function (div) {
+        assert.ok(div);
+        assert.ok(div.innerHTML.indexOf("No reference genome data available on minerva platform") === -1);
+        win.destroy();
+      });
 
-    var layoutAlias;
-    var win;
+    });
 
-    return ServerConnector.getProject().then(function (project) {
-      project.setOrganism({
-        type: "TAXONOMY",
-        resource: "123456"
+    it("for unknown organism", function () {
+      var map;
+      var overlay;
+
+      var layoutAlias;
+      var win;
+
+      return ServerConnector.getProject().then(function (project) {
+        project.setOrganism({
+          type: "TAXONOMY",
+          resource: "123456"
+        });
+        map = helper.createCustomMap(project);
+        overlay = new DataOverlay(18077, "xxx");
+        return overlay.init();
+      }).then(function () {
+        return overlay.getFullAliasById(overlay.getAliases()[0].getId());
+      }).then(function (data) {
+        layoutAlias = data;
+        return map.getModel().getAliasById(layoutAlias.getId());
+      }).then(function (alias) {
+        win = new AliasInfoWindow({
+          alias: alias,
+          map: map,
+          marker: helper.createMarker({element: alias, map: map})
+        });
+        return win.init();
+      }).then(function () {
+        var overlay = helper.createOverlay();
+        overlay.addAlias(layoutAlias);
+        return win.createGenomicDiv({overlays: [overlay]});
+      }).then(function (div) {
+        assert.ok(div);
+        assert.ok(div.innerHTML.indexOf("No reference genome data available on minerva platform") >= -1);
+        win.destroy();
       });
-      map = helper.createCustomMap(project);
-      overlay = new DataOverlay(18077, "xxx");
-      return overlay.init();
-    }).then(function () {
-      return overlay.getFullAliasById(overlay.getAliases()[0].getId());
-    }).then(function (data) {
-      layoutAlias = data;
-      return map.getModel().getAliasById(layoutAlias.getId());
-    }).then(function (alias) {
-      win = new AliasInfoWindow({
-        alias: alias,
-        map: map,
-        marker: helper.createMarker({element: alias, map: map})
-      });
-      return win.init();
-    }).then(function () {
-      win.layoutAliases = [layoutAlias];
-      return win.createGenomicDiv();
-    }).then(function (div) {
-      assert.ok(div);
-      assert.ok(div.innerHTML.indexOf("No reference genome data available on minerva platform") >= -1);
-      win.destroy();
-    });
 
+    });
   });
 
   it("createWaitingContentDiv", function () {
@@ -336,29 +341,104 @@ describe('AliasInfoWindow', function () {
     assert.ok(functions.isDomElement(aliasWindow.createWaitingContentDiv()));
   });
 
-  it("createChartDiv ", function () {
-    var map, ie, aliasWindow;
-    return ServerConnector.getProject().then(function (project) {
-      map = helper.createCustomMap(project);
-      ie = new IdentifiedElement({
-        id: 329170,
-        modelId: map.getId(),
-        type: "ALIAS"
+  describe("createChartDiv ", function () {
+    it("on submap map", function () {
+      helper.setUrl("http://test/?id=complex_model_with_submaps");
+
+      var map, submap, overlay, win, aliasOnSubmap, alias;
+
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        submap = map.getSubmapById(16731);
+        overlay = new DataOverlay(18077, "xxx");
+        overlay.setInitialized(true);
+        return map.openSubmap(submap.getId());
+      }).then(function () {
+        return map.getModel().getAliasById(345339);
+      }).then(function (data) {
+        alias = data;
+        return submap.getModel().getAliasById(345337);
+      }).then(function (data) {
+        aliasOnSubmap = data;
+        win = new AliasInfoWindow({
+          alias: alias,
+          map: map,
+          marker: helper.createMarker({element: alias, map: map})
+        });
+        return win.init();
+      }).then(function () {
+        var layoutAlias = helper.createLayoutAlias(aliasOnSubmap);
+        layoutAlias.setType(LayoutAlias.GENERIC);
+        var overlay = helper.createOverlay();
+        overlay.addAlias(layoutAlias);
+        return win.createChartDiv({overlays: [overlay]});
+      }).then(function (div) {
+        assert.ok(div);
+        win.destroy();
+        return map.destroy();
       });
 
-      return map.getModel().getByIdentifiedElement(ie, true);
-    }).then(function (alias) {
-      aliasWindow = new AliasInfoWindow({
-        alias: alias,
-        map: map,
-        marker: helper.createMarker({element: alias, map: map})
+    });
+
+    it("default ", function () {
+      var map, ie, aliasWindow;
+      return ServerConnector.getProject().then(function (project) {
+        map = helper.createCustomMap(project);
+        ie = new IdentifiedElement({
+          id: 329170,
+          modelId: map.getId(),
+          type: "ALIAS"
+        });
+
+        return map.getModel().getByIdentifiedElement(ie, true);
+      }).then(function (alias) {
+        aliasWindow = new AliasInfoWindow({
+          alias: alias,
+          map: map,
+          marker: helper.createMarker({element: alias, map: map})
+        });
+        var overlay = helper.createOverlay();
+        overlay.addAlias(helper.createLayoutAlias(alias, LayoutAlias.GENERIC));
+        var overlays = [overlay, helper.createOverlay()];
+
+        return aliasWindow.createChartDiv({overlays: overlays});
+      }).then(function (div) {
+        assert.ok(div);
       });
-      aliasWindow.layoutAliases = [helper.createLayoutAlias(alias), null];
-      aliasWindow.layoutNames = ["x", "y"];
-      return aliasWindow.createChartDiv();
-    }).then(function (div) {
-      assert.ok(div);
     });
   });
 
+  it("createVcfString ", function () {
+    var map = helper.createCustomMap();
+    var alias = helper.createAlias(map);
+    var aliasWindow = new AliasInfoWindow({
+      alias: alias,
+      map: map,
+      marker: helper.createMarker({element: alias, map: map})
+    });
+
+    var nullVal = null;
+
+    var variant = new GeneVariant({
+      contig: "11",
+      modifiedDna: "T",
+      originalDna: "C",
+      position: 233067,
+      referenceGenomeType: "UCSC",
+      referenceGenomeVersion: "hg19",
+      allelFrequency: nullVal,
+      variantIdentifier: nullVal
+    });
+    var variant2 = new GeneVariant({
+      contig: "11",
+      modifiedDna: "T",
+      originalDna: "C",
+      position: 233068,
+      referenceGenomeType: "UCSC",
+      referenceGenomeVersion: "hg19"
+    });
+    var str = aliasWindow.createVcfString([variant, variant2]);
+    assert.ok(str.indexOf("null") === -1, "null shouldn't appear in vcf format");
+  });
+
 });
diff --git a/frontend-js/testFiles/apiCalls/genomics/154/DELETE_token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/154/DELETE_token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..9e26dfeeb6e641a33dae4961196235bdb965b21b
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/154/DELETE_token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/154/geneMapping/97/DELETE_token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/154/geneMapping/97/DELETE_token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..9e26dfeeb6e641a33dae4961196235bdb965b21b
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/154/geneMapping/97/DELETE_token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/43/DELETE_token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/43/DELETE_token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..9e26dfeeb6e641a33dae4961196235bdb965b21b
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/43/DELETE_token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/POST_organismId=9606&sourceUrl=ftp%3A%2F%2Fhgdownload.cse.ucsc.edu%2FgoldenPath%2Fhg18%2FbigZips%2Fhg18.2bit&type=UCSC&version=hg38&token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/POST_organismId=9606&sourceUrl=ftp%3A%2F%2Fhgdownload.cse.ucsc.edu%2FgoldenPath%2Fhg18%2FbigZips%2Fhg18.2bit&type=UCSC&version=hg38&token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..9e26dfeeb6e641a33dae4961196235bdb965b21b
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/POST_organismId=9606&sourceUrl=ftp%3A%2F%2Fhgdownload.cse.ucsc.edu%2FgoldenPath%2Fhg18%2FbigZips%2Fhg18.2bit&type=UCSC&version=hg38&token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/1570291/genomeTypes/UCSC/versions/eboVir3/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/1570291/genomeTypes/UCSC/versions/eboVir3/token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..140c6ea04591e5dd06e8bb7c00d10d267cbaf709
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/1570291/genomeTypes/UCSC/versions/eboVir3/token=MOCK_TOKEN_ID&
@@ -0,0 +1 @@
+{"downloadProgress":100.0,"geneMapping":[],"idObject":1830,"localUrl":"../minerva-big//9395/eboVir3.2bit","organism":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":1150730,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=1570291","resource":"1570291","type":"TAXONOMY"},"sourceUrl":"ftp://hgdownload.cse.ucsc.edu/goldenPath/eboVir3/bigZips/eboVir3.2bit","type":"UCSC","version":"eboVir3"}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/8822/genomeTypes/UCSC/versions/token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/8822/genomeTypes/UCSC/versions/token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..106569c7531bf23cc379e199e01d23a6e29dfbe4
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/8822/genomeTypes/UCSC/versions/token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+[{"version":"aptMan1"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/8822/genomeTypes/token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/8822/genomeTypes/token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..239f1b00f1ba0895c5aaf49f1da4478b95881d7f
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/8822/genomeTypes/token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+[{"type":"UCSC"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..c97ec2eab979ae2109713be27a6441842db4e0d3
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+[{"url":"ftp://hgdownload.cse.ucsc.edu/goldenPath/hg18/bigZips/hg18.2bit"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..c97ec2eab979ae2109713be27a6441842db4e0d3
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38.getAvailableRemoteUrls/token=MOCK_TOKEN_ID&
@@ -0,0 +1 @@
+[{"url":"ftp://hgdownload.cse.ucsc.edu/goldenPath/hg18/bigZips/hg18.2bit"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38/token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38/token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..d6e3f651ae1e7ccd4ce1a774931527624d8eeb9a
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38/token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+{"downloadProgress":100.0,"geneMapping":[],"idObject":1563,"localUrl":"../minerva-big//5280/hg38.2bit","organism":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":927074,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9606","resource":"9606","type":"TAXONOMY"},"sourceUrl":"ftp://hgdownload.cse.ucsc.edu/goldenPath/hg38/bigZips/hg38.2bit","type":"UCSC","version":"hg38"}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38/token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..d6e3f651ae1e7ccd4ce1a774931527624d8eeb9a
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/hg38/token=MOCK_TOKEN_ID&
@@ -0,0 +1 @@
+{"downloadProgress":100.0,"geneMapping":[],"idObject":1563,"localUrl":"../minerva-big//5280/hg38.2bit","organism":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":927074,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9606","resource":"9606","type":"TAXONOMY"},"sourceUrl":"ftp://hgdownload.cse.ucsc.edu/goldenPath/hg38/bigZips/hg38.2bit","type":"UCSC","version":"hg38"}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..f885fbf47775e1a6cf8962609b34bb3a075acb1f
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+[{"version":"hg38"},{"version":"hg24may2000"},{"version":"hg19"},{"version":"hg18"},{"version":"hg17"},{"version":"hg16"},{"version":"hg15june2000"},{"version":"hg13"},{"version":"hg12"},{"version":"hg11"},{"version":"hg10"},{"version":"10april2003"},{"version":"hg8"},{"version":"hg7"},{"version":"hg6"},{"version":"hg5"},{"version":"hg4"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..f885fbf47775e1a6cf8962609b34bb3a075acb1f
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/UCSC/versions/token=MOCK_TOKEN_ID&
@@ -0,0 +1 @@
+[{"version":"hg38"},{"version":"hg24may2000"},{"version":"hg19"},{"version":"hg18"},{"version":"hg17"},{"version":"hg16"},{"version":"hg15june2000"},{"version":"hg13"},{"version":"hg12"},{"version":"hg11"},{"version":"hg10"},{"version":"10april2003"},{"version":"hg8"},{"version":"hg7"},{"version":"hg6"},{"version":"hg5"},{"version":"hg4"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..239f1b00f1ba0895c5aaf49f1da4478b95881d7f
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+[{"type":"UCSC"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..239f1b00f1ba0895c5aaf49f1da4478b95881d7f
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/9606/genomeTypes/token=MOCK_TOKEN_ID&
@@ -0,0 +1 @@
+[{"type":"UCSC"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..b386c9e5c8cf2a34248768230292b29582764ee8
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+[{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7070","resource":"7070","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8049","resource":"8049","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8962","resource":"8962","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=10090","resource":"10090","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7234","resource":"7234","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=60711","resource":"60711","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7230","resource":"7230","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=47144","resource":"47144","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9615","resource":"9615","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=43780","resource":"43780","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9813","resource":"9813","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7238","resource":"7238","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7237","resource":"7237","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8128","resource":"8128","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7955","resource":"7955","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=30538","resource":"30538","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7718","resource":"7718","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9581","resource":"9581","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=10141","resource":"10141","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=10181","resource":"10181","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8090","resource":"8090","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=482537","resource":"482537","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7245","resource":"7245","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9986","resource":"9986","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7244","resource":"7244","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9103","resource":"9103","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9940","resource":"9940","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8496","resource":"8496","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9541","resource":"9541","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7240","resource":"7240","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=120498","resource":"120498","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=59729","resource":"59729","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9305","resource":"9305","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=6239","resource":"6239","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9669","resource":"9669","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9823","resource":"9823","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=6238","resource":"6238","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=212257","resource":"212257","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=1570291","resource":"1570291","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=13146","resource":"13146","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9031","resource":"9031","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9395","resource":"9395","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=135651","resource":"135651","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9796","resource":"9796","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=281687","resource":"281687","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=61622","resource":"61622","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9597","resource":"9597","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9476","resource":"9476","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7897","resource":"7897","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9913","resource":"9913","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8822","resource":"8822","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7217","resource":"7217","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=10029","resource":"10029","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=54126","resource":"54126","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7260","resource":"7260","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=143292","resource":"143292","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8479","resource":"8479","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7222","resource":"7222","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9685","resource":"9685","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7220","resource":"7220","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7868","resource":"7868","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9807","resource":"9807","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9606","resource":"9606","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7227","resource":"7227","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9767","resource":"9767","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=10116","resource":"10116","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=31032","resource":"31032","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=94438","resource":"94438","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=31234","resource":"31234","type":"TAXONOMY"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/taxonomies/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/taxonomies/token=MOCK_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..b386c9e5c8cf2a34248768230292b29582764ee8
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/taxonomies/token=MOCK_TOKEN_ID&
@@ -0,0 +1 @@
+[{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7070","resource":"7070","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8049","resource":"8049","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8962","resource":"8962","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=10090","resource":"10090","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7234","resource":"7234","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=60711","resource":"60711","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7230","resource":"7230","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=47144","resource":"47144","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9615","resource":"9615","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=43780","resource":"43780","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9813","resource":"9813","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7238","resource":"7238","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7237","resource":"7237","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8128","resource":"8128","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7955","resource":"7955","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=30538","resource":"30538","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7718","resource":"7718","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9581","resource":"9581","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=10141","resource":"10141","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=10181","resource":"10181","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8090","resource":"8090","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=482537","resource":"482537","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7245","resource":"7245","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9986","resource":"9986","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7244","resource":"7244","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9103","resource":"9103","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9940","resource":"9940","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8496","resource":"8496","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9541","resource":"9541","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7240","resource":"7240","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=120498","resource":"120498","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=59729","resource":"59729","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9305","resource":"9305","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=6239","resource":"6239","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9669","resource":"9669","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9823","resource":"9823","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=6238","resource":"6238","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=212257","resource":"212257","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=1570291","resource":"1570291","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=13146","resource":"13146","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9031","resource":"9031","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9395","resource":"9395","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=135651","resource":"135651","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9796","resource":"9796","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=281687","resource":"281687","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=61622","resource":"61622","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9597","resource":"9597","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9476","resource":"9476","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7897","resource":"7897","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9913","resource":"9913","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8822","resource":"8822","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7217","resource":"7217","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=10029","resource":"10029","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=54126","resource":"54126","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7260","resource":"7260","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=143292","resource":"143292","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=8479","resource":"8479","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7222","resource":"7222","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9685","resource":"9685","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7220","resource":"7220","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7868","resource":"7868","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9807","resource":"9807","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9606","resource":"9606","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=7227","resource":"7227","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9767","resource":"9767","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=10116","resource":"10116","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=31032","resource":"31032","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=94438","resource":"94438","type":"TAXONOMY"},{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":0,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=31234","resource":"31234","type":"TAXONOMY"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/genomics/token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/genomics/token=ADMIN_TOKEN_ID&
new file mode 100644
index 0000000000000000000000000000000000000000..3d404fc2fc06ba770f05a5ef09943f23cfe110d5
--- /dev/null
+++ b/frontend-js/testFiles/apiCalls/genomics/token=ADMIN_TOKEN_ID&
@@ -0,0 +1 @@
+[{"downloadProgress":100.0,"geneMapping":[{"downloadProgress":100.0,"idObject":97,"localUrl":null,"name":"refGene","sourceUrl":"http://pg-sandbox.uni.lu/data/refGene.txt.bb"}],"idObject":154,"localUrl":null,"organism":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":523719,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9606","resource":"9606","type":"TAXONOMY"},"sourceUrl":"ftp://hgdownload.cse.ucsc.edu/goldenPath/hg19/bigZips/hg19.2bit","type":"UCSC","version":"hg19"},{"downloadProgress":100.0,"geneMapping":[],"idObject":1563,"localUrl":"../minerva-big//5280/hg38.2bit","organism":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":927074,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9606","resource":"9606","type":"TAXONOMY"},"sourceUrl":"ftp://hgdownload.cse.ucsc.edu/goldenPath/hg38/bigZips/hg38.2bit","type":"UCSC","version":"hg38"},{"downloadProgress":100.0,"geneMapping":[],"idObject":1829,"localUrl":"../minerva-big//9387/hg18.2bit","organism":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":1150729,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9606","resource":"9606","type":"TAXONOMY"},"sourceUrl":"ftp://hgdownload.cse.ucsc.edu/goldenPath/hg18/bigZips/hg18.2bit","type":"UCSC","version":"hg18"}]
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345325&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345325&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345325&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345325&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345330&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345330&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345330&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345330&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345330,345331,345337&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345330,345331,345337&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345330,345331,345337&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345330,345331,345337&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345331&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345331&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345331&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345331&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345334&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345334&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345334&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345334&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345337&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345337&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345337&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345337&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345339&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345339&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId&id=345339&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/complex_model_with_submaps/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=345339&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/drug_target_sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=436152&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/drug_target_sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=436152&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/drug_target_sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=436152&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/drug_target_sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=436152&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/PATCH_project.disease.resource=D010300&project.disease.type=MESH_2012&project.mapCanvasType=OPEN_LAYERS&project.name=UNKNOWN DISEASE MAP&project.organism.resource=9606&project.organism.type=TAXONOMY&project.version=2.01&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/PATCH_project.disease.resource=D010300&project.disease.type=MESH_2012&project.mapCanvasType=OPEN_LAYERS&project.name=UNKNOWN DISEASE MAP&project.organism.resource=1570291&project.organism.type=TAXONOMY&project.version=2.01&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/PATCH_project.disease.resource=D010300&project.disease.type=MESH_2012&project.mapCanvasType=OPEN_LAYERS&project.name=UNKNOWN DISEASE MAP&project.organism.resource=9606&project.organism.type=TAXONOMY&project.version=2.01&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/PATCH_project.disease.resource=D010300&project.disease.type=MESH_2012&project.mapCanvasType=OPEN_LAYERS&project.name=UNKNOWN DISEASE MAP&project.organism.resource=1570291&project.organism.type=TAXONOMY&project.version=2.01&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=-1&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=-1&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=-1&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=-1&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329157&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329157&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329157&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329157&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329159&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329159&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329159&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329159&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329163&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329163&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329163&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329163&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329167&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329167&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329167&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329167&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329168,329173&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329168,329173&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329168,329173&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329168,329173&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329170&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329170&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329170&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329170&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329171&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329171&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329171&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329171&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329173&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329173&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId&id=329173&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/models/all/bioEntities/elements/columns=id,bounds,modelId,linkedSubmodel&id=329173&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/overlays/POST_fileId=6792&googleLicenseConsent=false&token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/overlays/POST_fileId=6792&googleLicenseConsent=false&type=GENERIC&token=MOCK_TOKEN_ID&
similarity index 100%
rename from frontend-js/testFiles/apiCalls/projects/sample/overlays/POST_fileId=6792&googleLicenseConsent=false&token=MOCK_TOKEN_ID&
rename to frontend-js/testFiles/apiCalls/projects/sample/overlays/POST_fileId=6792&googleLicenseConsent=false&type=GENERIC&token=MOCK_TOKEN_ID&
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/token=ADMIN_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/token=ADMIN_TOKEN_ID&
index 54a367141609387d8ebac9b32d849ccdf1fecf6d..d69e034815d9f87b6c3f02422e81e4f8730270a8 100644
--- a/frontend-js/testFiles/apiCalls/projects/sample/token=ADMIN_TOKEN_ID&
+++ b/frontend-js/testFiles/apiCalls/projects/sample/token=ADMIN_TOKEN_ID&
@@ -1 +1 @@
-{"version":"0","disease":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":1104479,"link":"http://bioportal.bioontology.org/ontologies/1351?p=terms&conceptid=D010300","resource":"D010300","type":"MESH_2012"},"organism":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":1104480,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9606","resource":"9606","type":"TAXONOMY"},"idObject":14898,"status":"Ok","directory":"5e8ff9bf55ba3508199d22e984129be6","progress":100.0,"notifyEmail":"","warnings":true,"errors":false,"name":"UNKNOWN DISEASE MAP","projectId":"sample","mapCanvasType":"OPEN_LAYERS","overviewImageViews":[],"topOverviewImage":null}
\ No newline at end of file
+{"version":"0","disease":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":1104479,"link":"http://bioportal.bioontology.org/ontologies/1351?p=terms&conceptid=D010300","resource":"D010300","type":"MESH_2012"},"organism":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":1104480,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=1570291","resource":"1570291","type":"TAXONOMY"},"idObject":14898,"status":"Ok","directory":"5e8ff9bf55ba3508199d22e984129be6","progress":100.0,"notifyEmail":"","warnings":true,"errors":false,"name":"UNKNOWN DISEASE MAP","projectId":"sample","mapCanvasType":"OPEN_LAYERS","overviewImageViews":[],"topOverviewImage":null}
\ No newline at end of file
diff --git a/frontend-js/testFiles/apiCalls/projects/sample/token=MOCK_TOKEN_ID& b/frontend-js/testFiles/apiCalls/projects/sample/token=MOCK_TOKEN_ID&
index 54a367141609387d8ebac9b32d849ccdf1fecf6d..d69e034815d9f87b6c3f02422e81e4f8730270a8 100644
--- a/frontend-js/testFiles/apiCalls/projects/sample/token=MOCK_TOKEN_ID&
+++ b/frontend-js/testFiles/apiCalls/projects/sample/token=MOCK_TOKEN_ID&
@@ -1 +1 @@
-{"version":"0","disease":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":1104479,"link":"http://bioportal.bioontology.org/ontologies/1351?p=terms&conceptid=D010300","resource":"D010300","type":"MESH_2012"},"organism":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":1104480,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=9606","resource":"9606","type":"TAXONOMY"},"idObject":14898,"status":"Ok","directory":"5e8ff9bf55ba3508199d22e984129be6","progress":100.0,"notifyEmail":"","warnings":true,"errors":false,"name":"UNKNOWN DISEASE MAP","projectId":"sample","mapCanvasType":"OPEN_LAYERS","overviewImageViews":[],"topOverviewImage":null}
\ No newline at end of file
+{"version":"0","disease":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":1104479,"link":"http://bioportal.bioontology.org/ontologies/1351?p=terms&conceptid=D010300","resource":"D010300","type":"MESH_2012"},"organism":{"annotatorClassName":"","descriptionByType":"","descriptionByTypeRelation":"","id":1104480,"link":"http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id=1570291","resource":"1570291","type":"TAXONOMY"},"idObject":14898,"status":"Ok","directory":"5e8ff9bf55ba3508199d22e984129be6","progress":100.0,"notifyEmail":"","warnings":true,"errors":false,"name":"UNKNOWN DISEASE MAP","projectId":"sample","mapCanvasType":"OPEN_LAYERS","overviewImageViews":[],"topOverviewImage":null}
\ No newline at end of file
diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java
index fc0c60226ee53ec1162bbe8ac3ba1857b1c2e037..e9c36488291281e137c013eb169494cc7b015b52 100644
--- a/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java
+++ b/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java
@@ -120,7 +120,7 @@ public class ApplySimpleLayoutModelCommand extends ApplyLayoutModelCommand {
     Set<Species> elementToAlign = new HashSet<>();
     Map<Compartment, Set<Element>> elementsByStaticCompartment = new HashMap<>();
     for (Element element : elements) {
-      if (element.getWidth() == 0) {
+      if (element.getWidth() == null || element.getWidth() == 0) {
         element.setWidth(SPECIES_WIDTH);
         element.setHeight(SPECIES_HEIGHT);
 
@@ -360,7 +360,9 @@ public class ApplySimpleLayoutModelCommand extends ApplyLayoutModelCommand {
   protected Dimension2D estimateDimension(Collection<BioEntity> bioEntites) {
     double suggestedSize = Math.max(100 * bioEntites.size() / 4,
         Math.sqrt((SPECIES_WIDTH + 10) * (SPECIES_HEIGHT + 10) * bioEntites.size()));
-    suggestedSize = Math.max(suggestedSize, 2 * (SPECIES_WIDTH + 10));
+    if (bioEntites.size() > 0) {
+      suggestedSize = Math.max(suggestedSize, 2 * (SPECIES_WIDTH + 10));
+    }
     return new DoubleDimension(suggestedSize, suggestedSize);
   }
 
diff --git a/model-command/src/test/java/lcsb/mapviewer/commands/AllCommandsTests.java b/model-command/src/test/java/lcsb/mapviewer/commands/AllCommandsTests.java
index 8b883cd54a6e6b0a4db8e65d87d5fe9a01f5c220..71fece55e50d88007800b32758fccf88ecfc7090 100644
--- a/model-command/src/test/java/lcsb/mapviewer/commands/AllCommandsTests.java
+++ b/model-command/src/test/java/lcsb/mapviewer/commands/AllCommandsTests.java
@@ -1,5 +1,6 @@
 package lcsb.mapviewer.commands;
 
+import lcsb.mapviewer.commands.layout.AllLayoutTests;
 import lcsb.mapviewer.commands.properties.AllPropertyCommandTests;
 
 import org.junit.runner.RunWith;
@@ -7,12 +8,13 @@ import org.junit.runners.Suite;
 import org.junit.runners.Suite.SuiteClasses;
 
 @RunWith(Suite.class)
-@SuiteClasses({ AllPropertyCommandTests.class, //
-		ColorModelCommandTest.class, //
-		CopyCommandTest.class, //
-		CreateHierarchyCommandTest.class, //
-		MoveElementsCommandTest.class, //
-		SubModelCommandTest.class,//
+@SuiteClasses({ AllLayoutTests.class, //
+    AllPropertyCommandTests.class, //
+    ColorModelCommandTest.class, //
+    CopyCommandTest.class, //
+    CreateHierarchyCommandTest.class, //
+    MoveElementsCommandTest.class, //
+    SubModelCommandTest.class,//
 })
 public class AllCommandsTests {
 
diff --git a/model-command/src/test/java/lcsb/mapviewer/commands/CreateHierarchyCommandTest.java b/model-command/src/test/java/lcsb/mapviewer/commands/CreateHierarchyCommandTest.java
index 97eb95a6f99283ae3bffc29295bf0cdd4f7837f6..7047e094100318c2aba0bf6b41fe80272a288b7f 100644
--- a/model-command/src/test/java/lcsb/mapviewer/commands/CreateHierarchyCommandTest.java
+++ b/model-command/src/test/java/lcsb/mapviewer/commands/CreateHierarchyCommandTest.java
@@ -1,306 +1,307 @@
-package lcsb.mapviewer.commands;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.common.exception.InvalidStateException;
-import lcsb.mapviewer.converter.ConverterParams;
-import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
-import lcsb.mapviewer.model.map.compartment.Compartment;
-import lcsb.mapviewer.model.map.compartment.PathwayCompartment;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.Species;
-
-public class CreateHierarchyCommandTest extends CommandTestFunctions {
-	Logger logger = Logger.getLogger(CreateHierarchyCommandTest.class);
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testCyclicComplexes() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/cyclic_hierarchy_problem.xml", false);
-
-			new CreateHierarchyCommand(model, 8, 80).execute();
-
-			Species alias = model.getElementByElementId("sa5033");
-
-			Set<Element> parents = new HashSet<Element>();
-			while (alias.getComplex() != null) {
-				assertFalse("Cyclic nesting", parents.contains(alias.getComplex()));
-				alias = alias.getComplex();
-				parents.add(alias);
-			}
-
-			Set<String> levels = new HashSet<>();
-			for (Element a : model.getElements()) {
-				levels.add(a.getVisibilityLevel());
-			}
-			assertTrue(levels.size() > 2);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCreateHierachy() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
-
-			new CreateHierarchyCommand(model, 2, 2).execute();
-			// check if second call will throw an exception...
-			new CreateHierarchyCommand(model, 2, 2).execute();
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCreateHierachy2() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
-
-			new CreateHierarchyCommand(model, 2, 2).execute();
-
-			boolean artifitial = false;
-			for (Compartment a : model.getCompartments()) {
-				if (a instanceof PathwayCompartment) {
-					artifitial = true;
-				}
-			}
-			assertTrue("No hierarchical structure element found", artifitial);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRecreateHierachy() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
-
-			int aliasSize0 = model.getCompartments().size();
-
-			new CreateHierarchyCommand(model, 2, 2).execute();
-
-			int aliasSize = model.getCompartments().size();
-
-			assertTrue(aliasSize0 != aliasSize);
-			new CreateHierarchyCommand(model, 2, 2).execute();
-
-			int aliasSize2 = model.getCompartments().size();
-
-			assertEquals(aliasSize, aliasSize2);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testParenting() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
-
-			new CreateHierarchyCommand(model, 2, 2).execute();
-
-			assertFalse(model.getElementByElementId("sa1").getCompartment() instanceof PathwayCompartment);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCreateComponentsMinVisibility() throws Exception {
-		try {
-			double zoomFactor = 39.0625;
-			int levels = 6;
-
-			Model model = getModelForFile("testFiles/other_full/GSTP1 subnetwork_220214.xml", false);
-
-			new CreateHierarchyCommand(model, levels, zoomFactor).execute();
-
-			for (Compartment compartment : model.getCompartments()) {
-				if (compartment.getCompartment() == null) {
-					int visibilityLevel = Integer.valueOf(compartment.getVisibilityLevel());
-					assertTrue(
-							"Alias " + compartment.getElementId() + " is not visible at levels highers than " + compartment.getVisibilityLevel(), visibilityLevel <= 1);
-				}
-			}
-
-			for (Species species : model.getSpeciesList()) {
-				if (species.getCompartment() == null) {
-					int visibilityLevel = Integer.valueOf(species.getVisibilityLevel());
-					assertTrue("Alias " + species.getElementId() + " is not visible at levels highers than " + species.getVisibilityLevel(), visibilityLevel <= 1);
-				}
-			}
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCreateComponentsMaxVisibility() throws Exception {
-		try {
-			double zoomFactor = 39.0625;
-			int levels = 6;
-
-			Model model = getModelForFile("testFiles/other_full/GSTP1 subnetwork_220214.xml", false);
-
-			new CreateHierarchyCommand(model, levels, zoomFactor).execute();
-
-			for (Element element : model.getElements()) {
-				int visibilityLevel = Integer.valueOf(element.getVisibilityLevel());
-				assertTrue(
-						"Alias " + element.getElementId() + " is not visible even at the bottom level (visibility: " + element.getVisibilityLevel() + ") ",
-						visibilityLevel <= levels);
-			}
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCompactComplexesInNestedView() throws Exception {
-		Model model;
-		try {
-			model = getModelForFile("testFiles/problematic/compact_complex_view_problem.xml", false);
-			Element alias = model.getElementByElementId("sa1");
-			Object parent1 = alias.getCompartment();
-			new CreateHierarchyCommand(model, 3, 16).execute();
-			Object parent2 = alias.getCompartment();
-			assertEquals(parent1, parent2);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testRecallHierachyCreation() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
-
-			CreateHierarchyCommand command = new CreateHierarchyCommand(model, 2, 2);
-			command.execute();
-			try {
-				command.execute();
-				fail("Exception expected");
-			} catch (InvalidStateException e) {
-
-			}
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testClear() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
-
-			CreateHierarchyCommand command = new CreateHierarchyCommand(model, 2, 2);
-			command.clean();
-			for (Element alias : model.getElements()) {
-				assertNull(alias.getCompartment());
-			}
-			for (Compartment alias : model.getCompartments()) {
-				assertNull(alias.getCompartment());
-				assertTrue(alias.getElements().isEmpty());
-			}
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testNestedProblem() throws Exception {
-		try {
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			Model model = parser.createModel(new ConverterParams().filename("testFiles/nested_test.xml").sizeAutoAdjust(true));
-
-			double zoomFactor = Math.max(model.getHeight(), model.getWidth()) / (256);
-			int zoomLevels = (int) Math.ceil(Math.log(zoomFactor) / Math.log(2));
-
-			CreateHierarchyCommand command = new CreateHierarchyCommand(model, zoomLevels, zoomFactor);
-			command.execute();
-
-			for (Element alias : model.getElements()) {
-				Element parentAlias = alias.getCompartment();
-				if (parentAlias != null) {
-					int parentVisibilityLevel = Integer.valueOf(parentAlias.getVisibilityLevel());
-					int aliasVisibilityLevel = Integer.valueOf(alias.getVisibilityLevel());
-					assertTrue(aliasVisibilityLevel >= parentVisibilityLevel);
-				}
-				if (alias instanceof Species) {
-					parentAlias = ((Species) alias).getComplex();
-					if (parentAlias != null) {
-						int parentVisibilityLevel = Integer.valueOf(parentAlias.getVisibilityLevel());
-						int aliasVisibilityLevel = Integer.valueOf(alias.getVisibilityLevel());
-						assertTrue(aliasVisibilityLevel >= parentVisibilityLevel);
-					}
-				}
-			}
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testDisconnectedChildInComplex() throws Exception {
-		try {
-			Model model = getModelForFile("testFiles/problematic/disconnected_child_in_complex.xml", false);
-
-			new CreateHierarchyCommand(model, 8, 80).execute();
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xmlString = parser.toXml(model);
-			// logger.debug(xmlString);
-
-			InputStream stream = new ByteArrayInputStream(xmlString.getBytes(StandardCharsets.UTF_8));
-
-			parser.createModel(new ConverterParams().inputStream(stream));
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.commands;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.common.exception.InvalidStateException;
+import lcsb.mapviewer.converter.ConverterParams;
+import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
+import lcsb.mapviewer.model.map.compartment.Compartment;
+import lcsb.mapviewer.model.map.compartment.PathwayCompartment;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Species;
+
+public class CreateHierarchyCommandTest extends CommandTestFunctions {
+  Logger logger = Logger.getLogger(CreateHierarchyCommandTest.class);
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testCyclicComplexes() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/cyclic_hierarchy_problem.xml", false);
+
+      new CreateHierarchyCommand(model, 8, 80).execute();
+
+      Species alias = model.getElementByElementId("sa5033");
+
+      Set<Element> parents = new HashSet<Element>();
+      while (alias.getComplex() != null) {
+        assertFalse("Cyclic nesting", parents.contains(alias.getComplex()));
+        alias = alias.getComplex();
+        parents.add(alias);
+      }
+
+      Set<String> levels = new HashSet<>();
+      for (Element a : model.getElements()) {
+        levels.add(a.getVisibilityLevel());
+      }
+      assertTrue(levels.size() > 2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCreateHierachy() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
+
+      new CreateHierarchyCommand(model, 2, 2).execute();
+      // check if second call will throw an exception...
+      new CreateHierarchyCommand(model, 2, 2).execute();
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCreateHierachy2() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
+
+      new CreateHierarchyCommand(model, 2, 2).execute();
+
+      boolean artifitial = false;
+      for (Compartment a : model.getCompartments()) {
+        if (a instanceof PathwayCompartment) {
+          artifitial = true;
+        }
+      }
+      assertTrue("No hierarchical structure element found", artifitial);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRecreateHierachy() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
+
+      int aliasSize0 = model.getCompartments().size();
+
+      new CreateHierarchyCommand(model, 2, 2).execute();
+
+      int aliasSize = model.getCompartments().size();
+
+      assertTrue(aliasSize0 != aliasSize);
+      new CreateHierarchyCommand(model, 2, 2).execute();
+
+      int aliasSize2 = model.getCompartments().size();
+
+      assertEquals(aliasSize, aliasSize2);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testParenting() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
+
+      new CreateHierarchyCommand(model, 2, 2).execute();
+
+      assertFalse(model.getElementByElementId("sa1").getCompartment() instanceof PathwayCompartment);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCreateComponentsMinVisibility() throws Exception {
+    try {
+      double zoomFactor = 39.0625;
+      int levels = 6;
+
+      Model model = getModelForFile("testFiles/other_full/GSTP1 subnetwork_220214.xml", false);
+
+      new CreateHierarchyCommand(model, levels, zoomFactor).execute();
+
+      for (Compartment compartment : model.getCompartments()) {
+        if (compartment.getCompartment() == null) {
+          int visibilityLevel = Integer.valueOf(compartment.getVisibilityLevel());
+          assertTrue("Alias " + compartment.getElementId() + " is not visible at levels highers than "
+              + compartment.getVisibilityLevel(), visibilityLevel <= 1);
+        }
+      }
+
+      for (Species species : model.getSpeciesList()) {
+        if (species.getCompartment() == null) {
+          int visibilityLevel = Integer.valueOf(species.getVisibilityLevel());
+          assertTrue("Alias " + species.getElementId() + " is not visible at levels highers than "
+              + species.getVisibilityLevel(), visibilityLevel <= 1);
+        }
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCreateComponentsMaxVisibility() throws Exception {
+    try {
+      double zoomFactor = 39.0625;
+      int levels = 6;
+
+      Model model = getModelForFile("testFiles/other_full/GSTP1 subnetwork_220214.xml", false);
+
+      new CreateHierarchyCommand(model, levels, zoomFactor).execute();
+
+      for (Element element : model.getElements()) {
+        int visibilityLevel = Integer.valueOf(element.getVisibilityLevel());
+        assertTrue("Alias " + element.getElementId() + " is not visible even at the bottom level (visibility: "
+            + element.getVisibilityLevel() + ") ", visibilityLevel <= levels);
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCompactComplexesInNestedView() throws Exception {
+    Model model;
+    try {
+      model = getModelForFile("testFiles/problematic/compact_complex_view_problem.xml", false);
+      Element alias = model.getElementByElementId("sa1");
+      Object parent1 = alias.getCompartment();
+      new CreateHierarchyCommand(model, 3, 16).execute();
+      Object parent2 = alias.getCompartment();
+      assertEquals(parent1, parent2);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRecallHierachyCreation() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
+
+      CreateHierarchyCommand command = new CreateHierarchyCommand(model, 2, 2);
+      command.execute();
+      try {
+        command.execute();
+        fail("Exception expected");
+      } catch (InvalidStateException e) {
+
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testClear() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/artifitial_compartments.xml", false);
+
+      CreateHierarchyCommand command = new CreateHierarchyCommand(model, 2, 2);
+      command.clean();
+      for (Element alias : model.getElements()) {
+        assertNull(alias.getCompartment());
+      }
+      for (Compartment alias : model.getCompartments()) {
+        assertNull(alias.getCompartment());
+        assertTrue(alias.getElements().isEmpty());
+      }
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testNestedProblem() throws Exception {
+    try {
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      Model model = parser
+          .createModel(new ConverterParams().filename("testFiles/nested_test.xml").sizeAutoAdjust(true));
+
+      double zoomFactor = Math.max(model.getHeight(), model.getWidth()) / (256);
+      int zoomLevels = (int) Math.ceil(Math.log(zoomFactor) / Math.log(2));
+
+      CreateHierarchyCommand command = new CreateHierarchyCommand(model, zoomLevels, zoomFactor);
+      command.execute();
+
+      for (Element alias : model.getElements()) {
+        Element parentAlias = alias.getCompartment();
+        if (parentAlias != null) {
+          int parentVisibilityLevel = Integer.valueOf(parentAlias.getVisibilityLevel());
+          int aliasVisibilityLevel = Integer.valueOf(alias.getVisibilityLevel());
+          assertTrue(aliasVisibilityLevel >= parentVisibilityLevel);
+        }
+        if (alias instanceof Species) {
+          parentAlias = ((Species) alias).getComplex();
+          if (parentAlias != null) {
+            int parentVisibilityLevel = Integer.valueOf(parentAlias.getVisibilityLevel());
+            int aliasVisibilityLevel = Integer.valueOf(alias.getVisibilityLevel());
+            assertTrue(aliasVisibilityLevel >= parentVisibilityLevel);
+          }
+        }
+      }
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDisconnectedChildInComplex() throws Exception {
+    try {
+      Model model = getModelForFile("testFiles/problematic/disconnected_child_in_complex.xml", false);
+
+      new CreateHierarchyCommand(model, 8, 80).execute();
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xmlString = parser.toXml(model);
+      // logger.debug(xmlString);
+
+      InputStream stream = new ByteArrayInputStream(xmlString.getBytes(StandardCharsets.UTF_8));
+
+      parser.createModel(new ConverterParams().inputStream(stream));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/MiriamType.java b/model/src/main/java/lcsb/mapviewer/model/map/MiriamType.java
index df278007811d37f0e1e98a41c87c472b6aef0b22..910ab16ccbbc81a2b71d3af5f628c83b8ab205a7 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/MiriamType.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/MiriamType.java
@@ -373,6 +373,14 @@ public enum MiriamType {
       "urn:miriam:refseq", //
       new Class<?>[] { Protein.class, Gene.class, Rna.class }, "MIR:00000039"),
 
+  /**
+   * Rhea: http://www.rhea-db.org/.
+   */
+  RHEA("Rhea", //
+      "http://www.rhea-db.org/", //
+      "urn:miriam:rhea", //
+      new Class<?>[] { Reaction.class }, "MIR:00000082"),
+
   /**
    * SGD: http://www.yeastgenome.org/.
    */
@@ -494,7 +502,7 @@ public enum MiriamType {
   private String commonName;
 
   /**
-   * url to homepage of given resource type.
+   * url to home page of given resource type.
    */
   private String dbHomepage;
 
@@ -504,9 +512,9 @@ public enum MiriamType {
   private String registryIdentifier;
 
   /**
-   * Valid uris to this resource.
+   * Valid URIs to this resource.
    */
-  private List<String> uris = new ArrayList<String>();
+  private List<String> uris = new ArrayList<>();
 
   /**
    * Classes that can be annotated by this resource.
@@ -523,7 +531,7 @@ public enum MiriamType {
    * Constructor that initialize enum object.
    * 
    * @param dbHomePage
-   *          homepage of the resource {@link #dbHomepage}
+   *          home page of the resource {@link #dbHomepage}
    * @param commonName
    *          {@link #commonName}
    * @param uris
@@ -541,7 +549,7 @@ public enum MiriamType {
    * Constructor that initialize enum object.
    * 
    * @param dbHomePage
-   *          homepage of the resource {@link #dbHomepage}
+   *          home page of the resource {@link #dbHomepage}
    * @param commonName
    *          {@link #commonName}
    * @param uris
@@ -573,7 +581,7 @@ public enum MiriamType {
    * Constructor that initialize enum object.
    * 
    * @param dbHomePage
-   *          homepage of the resource {@link #dbHomepage}
+   *          home page of the resource {@link #dbHomepage}
    * @param commonName
    *          {@link #commonName}
    * @param uri
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/AntisenseRna.java b/model/src/main/java/lcsb/mapviewer/model/map/species/AntisenseRna.java
index 2208709e2dcc5975e740f76c339de0e5dedbf255..006ad5fb82dfa7268d4d17e02d6888ce551d257b 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/AntisenseRna.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/AntisenseRna.java
@@ -1,113 +1,113 @@
-package lcsb.mapviewer.model.map.species;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.persistence.DiscriminatorValue;
-import javax.persistence.Entity;
-import javax.persistence.OneToMany;
-
-import org.hibernate.annotations.Cascade;
-import org.hibernate.annotations.CascadeType;
-import org.hibernate.annotations.LazyCollection;
-import org.hibernate.annotations.LazyCollectionOption;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
-
-/**
- * Entity representing antisense rna element on the map.
- * 
- * @author Piotr Gawron
- *
- */
-@Entity
-@DiscriminatorValue("ANTISENSE_RNA_ALIAS")
-public class AntisenseRna extends Species {
-
-	/**
-	 * 
-	 */
-	private static final long				 serialVersionUID	= 1L;
-
-	/**
-	 * List of {@link AntisenseRnaRegion regions} related to this
-	 * {@link AntisenseRna}.
-	 */
-	@Cascade({ CascadeType.ALL })
-	@OneToMany(mappedBy = "species")
-	@LazyCollection(LazyCollectionOption.FALSE)
-	private List<AntisenseRnaRegion> regions					= new ArrayList<>();
-
-	/**
-	 * Empty constructor required by hibernate.
-	 */
-	AntisenseRna() {
-	}
-
-	/**
-	 * Constructor that creates a copy of the element given in the parameter.
-	 * 
-	 * @param original
-	 *          original object that will be used for creating copy
-	 */
-	public AntisenseRna(AntisenseRna original) {
-		super(original);
-		for (AntisenseRnaRegion region : original.getRegions()) {
-			addRegion(new AntisenseRnaRegion(region));
-		}
-	}
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param elementId
-	 *          uniqe (within model) element identifier
-	 */
-	public AntisenseRna(String elementId) {
-		setElementId(elementId);
-	}
-
-	/**
-	 * Adds {@link AntisenseRnaRegion} to the object.
-	 * 
-	 * @param antisenseRnaRegion
-	 *          alement to be added
-	 */
-	public void addRegion(AntisenseRnaRegion antisenseRnaRegion) {
-		regions.add(antisenseRnaRegion);
-		antisenseRnaRegion.setSpecies(this);
-	}
-
-	@Override
-	public AntisenseRna copy() {
-		if (this.getClass() == AntisenseRna.class) {
-			return new AntisenseRna(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-	}
-
-	/**
-	 * @return the regions
-	 * @see #regions
-	 */
-	public List<AntisenseRnaRegion> getRegions() {
-		return regions;
-	}
-
-	/**
-	 * @param regions
-	 *          the regions to set
-	 * @see #regions
-	 */
-	public void setRegions(List<AntisenseRnaRegion> regions) {
-		this.regions = regions;
-	}
-
-	@Override
-	public String getStringType() {
-		return "Antisense RNA";
-	}
-
-}
+package lcsb.mapviewer.model.map.species;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.CascadeType;
+import org.hibernate.annotations.LazyCollection;
+import org.hibernate.annotations.LazyCollectionOption;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * Entity representing antisense rna element on the map.
+ * 
+ * @author Piotr Gawron
+ *
+ */
+@Entity
+@DiscriminatorValue("ANTISENSE_RNA_ALIAS")
+public class AntisenseRna extends Species {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * List of {@link AntisenseRnaRegion regions} related to this
+   * {@link AntisenseRna}.
+   */
+  @Cascade({ CascadeType.ALL })
+  @OneToMany(mappedBy = "species")
+  @LazyCollection(LazyCollectionOption.FALSE)
+  private List<ModificationResidue> regions = new ArrayList<>();
+
+  /**
+   * Empty constructor required by hibernate.
+   */
+  AntisenseRna() {
+  }
+
+  /**
+   * Constructor that creates a copy of the element given in the parameter.
+   * 
+   * @param original
+   *          original object that will be used for creating copy
+   */
+  public AntisenseRna(AntisenseRna original) {
+    super(original);
+    for (ModificationResidue region : original.getRegions()) {
+      addRegion(region.copy());
+    }
+  }
+
+  /**
+   * Default constructor.
+   * 
+   * @param elementId
+   *          unique (within model) element identifier
+   */
+  public AntisenseRna(String elementId) {
+    setElementId(elementId);
+  }
+
+  /**
+   * Adds {@link AntisenseRnaRegion} to the object.
+   * 
+   * @param antisenseRnaRegion
+   *          region to be added
+   */
+  public void addRegion(ModificationResidue antisenseRnaRegion) {
+    regions.add(antisenseRnaRegion);
+    antisenseRnaRegion.setSpecies(this);
+  }
+
+  @Override
+  public AntisenseRna copy() {
+    if (this.getClass() == AntisenseRna.class) {
+      return new AntisenseRna(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+  }
+
+  /**
+   * @return the regions
+   * @see #regions
+   */
+  public List<ModificationResidue> getRegions() {
+    return regions;
+  }
+
+  /**
+   * @param regions
+   *          the regions to set
+   * @see #regions
+   */
+  public void setRegions(List<ModificationResidue> regions) {
+    this.regions = regions;
+  }
+
+  @Override
+  public String getStringType() {
+    return "Antisense RNA";
+  }
+
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/AntisenseRnaComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/species/AntisenseRnaComparator.java
index 95e2a358541cc7f2eec77865c0aeb23607793708..65f2b00630491ee2b5a9f73cece0e63ebe70906c 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/AntisenseRnaComparator.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/AntisenseRnaComparator.java
@@ -8,7 +8,7 @@ import org.apache.log4j.Logger;
 import lcsb.mapviewer.common.Comparator;
 import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.common.comparator.StringSetComparator;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
 
 /**
  * Comparator class used for comparing {@link AntisenseRna} objects.
@@ -56,18 +56,21 @@ public class AntisenseRnaComparator extends Comparator<AntisenseRna> {
   protected int internalCompare(AntisenseRna arg0, AntisenseRna arg1) {
     StringSetComparator stringSetComparator = new StringSetComparator();
 
-    Set<String> set1 = new HashSet<String>();
-    Set<String> set2 = new HashSet<String>();
+    Set<String> set1 = new HashSet<>();
+    Set<String> set2 = new HashSet<>();
 
-    for (AntisenseRnaRegion region : arg0.getRegions()) {
+    for (ModificationResidue region : arg0.getRegions()) {
       set1.add(region.toString());
     }
 
-    for (AntisenseRnaRegion region : arg1.getRegions()) {
+    for (ModificationResidue region : arg1.getRegions()) {
       set2.add(region.toString());
     }
 
     if (stringSetComparator.compare(set1, set2) != 0) {
+      logger.debug(set1);
+      logger.debug(set2);
+      logger.debug("Regions mismatch");
       return stringSetComparator.compare(set1, set2);
     }
 
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/Gene.java b/model/src/main/java/lcsb/mapviewer/model/map/species/Gene.java
index db6c9cb8404aee7cbd002d25fd9ed5a30ce5e2ba..ae7a0cfc64e435a40828a9c69884e9822fb3a722 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/Gene.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/Gene.java
@@ -1,113 +1,113 @@
-package lcsb.mapviewer.model.map.species;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.persistence.DiscriminatorValue;
-import javax.persistence.Entity;
-import javax.persistence.OneToMany;
-
-import org.hibernate.annotations.Cascade;
-import org.hibernate.annotations.CascadeType;
-import org.hibernate.annotations.LazyCollection;
-import org.hibernate.annotations.LazyCollectionOption;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-
-/**
- * Entity representing gene element on the map.
- * 
- * @author Piotr Gawron
- *
- */
-@Entity
-@DiscriminatorValue("GENE_ALIAS")
-public class Gene extends Species {
-
-	/**
-	 * 
-	 */
-	private static final long					serialVersionUID		 = 1L;
-
-	/**
-	 * List of modifications for the Gene.
-	 */
-	@Cascade({ CascadeType.ALL })
-	@OneToMany(mappedBy = "species", orphanRemoval = true)
-	@LazyCollection(LazyCollectionOption.FALSE)
-	private List<ModificationResidue>	modificationResidues = new ArrayList<>();
-
-	/**
-	 * Empty constructor required by hibernate.
-	 */
-	Gene() {
-	}
-
-	/**
-	 * Constructor that creates a copy of the element given in the parameter.
-	 * 
-	 * @param original
-	 *          original object that will be used for creating copy
-	 */
-	public Gene(Gene original) {
-		super(original);
-		for (ModificationResidue mr : original.getModificationResidues()) {
-			addModificationResidue(new ModificationResidue(mr));
-		}
-	}
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param elementId
-	 *          uniqe (within model) element identifier
-	 */
-	public Gene(String elementId) {
-		setElementId(elementId);
-	}
-
-	/**
-	 * Adds {@link ModificationResidue}.
-	 * 
-	 * @param modificationResidue
-	 *          {@link ModificationResidue} to be added
-	 */
-	public void addModificationResidue(ModificationResidue modificationResidue) {
-		modificationResidues.add(modificationResidue);
-		modificationResidue.setSpecies(this);
-
-	}
-
-	@Override
-	public Gene copy() {
-		if (this.getClass() == Gene.class) {
-			return new Gene(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-	}
-
-	/**
-	 * @return the modificationResidues
-	 * @see #modificationResidues
-	 */
-	public List<ModificationResidue> getModificationResidues() {
-		return modificationResidues;
-	}
-
-	/**
-	 * @param modificationResidues
-	 *          the modificationResidues to set
-	 * @see #modificationResidues
-	 */
-	public void setModificationResidues(List<ModificationResidue> modificationResidues) {
-		this.modificationResidues = modificationResidues;
-	}
-
-	@Override
-	public String getStringType() {
-		return "Gene";
-	}
-
-}
+package lcsb.mapviewer.model.map.species;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.CascadeType;
+import org.hibernate.annotations.LazyCollection;
+import org.hibernate.annotations.LazyCollectionOption;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * Entity representing gene element on the map.
+ * 
+ * @author Piotr Gawron
+ *
+ */
+@Entity
+@DiscriminatorValue("GENE_ALIAS")
+public class Gene extends Species {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * List of modifications for the Gene.
+   */
+  @Cascade({ CascadeType.ALL })
+  @OneToMany(mappedBy = "species", orphanRemoval = true)
+  @LazyCollection(LazyCollectionOption.FALSE)
+  private List<ModificationResidue> modificationResidues = new ArrayList<>();
+
+  /**
+   * Empty constructor required by hibernate.
+   */
+  Gene() {
+  }
+
+  /**
+   * Constructor that creates a copy of the element given in the parameter.
+   * 
+   * @param original
+   *          original object that will be used for creating copy
+   */
+  public Gene(Gene original) {
+    super(original);
+    for (ModificationResidue mr : original.getModificationResidues()) {
+      addModificationResidue(mr.copy());
+    }
+  }
+
+  /**
+   * Default constructor.
+   * 
+   * @param elementId
+   *          uniqe (within model) element identifier
+   */
+  public Gene(String elementId) {
+    setElementId(elementId);
+  }
+
+  /**
+   * Adds {@link ModificationResidue}.
+   * 
+   * @param modificationResidue
+   *          {@link ModificationResidue} to be added
+   */
+  public void addModificationResidue(ModificationResidue modificationResidue) {
+    modificationResidues.add(modificationResidue);
+    modificationResidue.setSpecies(this);
+
+  }
+
+  @Override
+  public Gene copy() {
+    if (this.getClass() == Gene.class) {
+      return new Gene(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+  }
+
+  /**
+   * @return the modificationResidues
+   * @see #modificationResidues
+   */
+  public List<ModificationResidue> getModificationResidues() {
+    return modificationResidues;
+  }
+
+  /**
+   * @param modificationResidues
+   *          the modificationResidues to set
+   * @see #modificationResidues
+   */
+  public void setModificationResidues(List<ModificationResidue> modificationResidues) {
+    this.modificationResidues = modificationResidues;
+  }
+
+  @Override
+  public String getStringType() {
+    return "Gene";
+  }
+
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/GeneComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/species/GeneComparator.java
index 89b0aa38e0296cdd2206d121d925d35e6fafbfc5..95aa3b734ff7aea7c1473e60e1b462defbbf6bdd 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/GeneComparator.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/GeneComparator.java
@@ -68,6 +68,10 @@ public class GeneComparator extends Comparator<Gene> {
     }
 
     if (stringSetComparator.compare(set1, set2) != 0) {
+      logger.debug(set1);
+      logger.debug(set2);
+      logger.debug("Different modifications");
+      logger.debug("---");
       return stringSetComparator.compare(set1, set2);
     }
 
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/Protein.java b/model/src/main/java/lcsb/mapviewer/model/map/species/Protein.java
index 9e891ddd9df99c9d85a2449c86e9a43128b29295..8f4cf0ecf0a03b4f32d08841098ae30bd48d7c3d 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/Protein.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/Protein.java
@@ -58,7 +58,7 @@ public abstract class Protein extends Species {
     super(original);
     this.structuralState = original.getStructuralState();
     for (ModificationResidue mr : original.getModificationResidues()) {
-      addModificationResidue(new ModificationResidue(mr));
+      addModificationResidue(mr.copy());
     }
   }
 
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/ProteinComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/species/ProteinComparator.java
index b397b9b4f3b38f956c0a93a9232b45cc6e9e5fb8..976ef785d5b84a01b76c804f4442627397036484 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/ProteinComparator.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/ProteinComparator.java
@@ -78,6 +78,8 @@ public class ProteinComparator extends Comparator<Protein> {
     }
 
     if (stringSetComparator.compare(set1, set2) != 0) {
+      logger.debug(set1);
+      logger.debug(set2);
       logger.debug("modification residues different");
       return stringSetComparator.compare(set1, set2);
     }
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/Rna.java b/model/src/main/java/lcsb/mapviewer/model/map/species/Rna.java
index 7e3df3a906a00b7f102efc0839a795430a03405a..69c46c396d598d23cf6c6e6cf5f9571693dff6ee 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/Rna.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/Rna.java
@@ -1,113 +1,113 @@
-package lcsb.mapviewer.model.map.species;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.persistence.DiscriminatorValue;
-import javax.persistence.Entity;
-import javax.persistence.OneToMany;
-
-import org.hibernate.annotations.Cascade;
-import org.hibernate.annotations.CascadeType;
-import org.hibernate.annotations.LazyCollection;
-import org.hibernate.annotations.LazyCollectionOption;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
-
-/**
- * Entity representing rna element on the map.
- * 
- * @author Piotr Gawron
- *
- */
-@Entity
-@DiscriminatorValue("RNA_ALIAS")
-public class Rna extends Species {
-
-	/**
-	 * 
-	 */
-	private static final long	serialVersionUID = 1L;
-
-	/**
-	 * List of rna regions (some rna sequences) in this object.
-	 */
-	@Cascade({ CascadeType.ALL })
-	@OneToMany(mappedBy = "species", orphanRemoval = true)
-	@LazyCollection(LazyCollectionOption.FALSE)
-	private List<RnaRegion>		regions					 = new ArrayList<>();
-
-	/**
-	 * Empty constructor required by hibernate.
-	 */
-	Rna() {
-	}
-
-	/**
-	 * Constructor that creates a copy of the element given in the parameter.
-	 * 
-	 * @param original
-	 *          original object that will be used for creating copy
-	 */
-	public Rna(Rna original) {
-		super(original);
-		for (RnaRegion region : original.getRegions()) {
-			addRegion(new RnaRegion(region));
-		}
-	}
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param elementId
-	 *          uniqe (within model) element identifier
-	 */
-	public Rna(String elementId) {
-		super();
-		setElementId(elementId);
-	}
-
-	/**
-	 * Adds {@link RnaRegion}.
-	 * 
-	 * @param rnaRegion
-	 *          object to be added
-	 */
-	public void addRegion(RnaRegion rnaRegion) {
-		regions.add(rnaRegion);
-		rnaRegion.setSpecies(this);
-	}
-
-	@Override
-	public Rna copy() {
-		if (this.getClass() == Rna.class) {
-			return new Rna(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-	}
-
-	/**
-	 * @return the regions
-	 * @see #regions
-	 */
-	public List<RnaRegion> getRegions() {
-		return regions;
-	}
-
-	/**
-	 * @param regions
-	 *          the regions to set
-	 * @see #regions
-	 */
-	public void setRegions(List<RnaRegion> regions) {
-		this.regions = regions;
-	}
-
-	@Override
-	public String getStringType() {
-		return "RNA";
-	}
-
-}
+package lcsb.mapviewer.model.map.species;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import javax.persistence.OneToMany;
+
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.CascadeType;
+import org.hibernate.annotations.LazyCollection;
+import org.hibernate.annotations.LazyCollectionOption;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+/**
+ * Entity representing rna element on the map.
+ * 
+ * @author Piotr Gawron
+ *
+ */
+@Entity
+@DiscriminatorValue("RNA_ALIAS")
+public class Rna extends Species {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * List of rna regions (some rna sequences) in this object.
+   */
+  @Cascade({ CascadeType.ALL })
+  @OneToMany(mappedBy = "species", orphanRemoval = true)
+  @LazyCollection(LazyCollectionOption.FALSE)
+  private List<ModificationResidue> regions = new ArrayList<>();
+
+  /**
+   * Empty constructor required by hibernate.
+   */
+  Rna() {
+  }
+
+  /**
+   * Constructor that creates a copy of the element given in the parameter.
+   * 
+   * @param original
+   *          original object that will be used for creating copy
+   */
+  public Rna(Rna original) {
+    super(original);
+    for (ModificationResidue region : original.getRegions()) {
+      addRegion(region.copy());
+    }
+  }
+
+  /**
+   * Default constructor.
+   * 
+   * @param elementId
+   *          uniqe (within model) element identifier
+   */
+  public Rna(String elementId) {
+    super();
+    setElementId(elementId);
+  }
+
+  /**
+   * Adds {@link RnaRegion}.
+   * 
+   * @param rnaRegion
+   *          object to be added
+   */
+  public void addRegion(ModificationResidue rnaRegion) {
+    regions.add(rnaRegion);
+    rnaRegion.setSpecies(this);
+  }
+
+  @Override
+  public Rna copy() {
+    if (this.getClass() == Rna.class) {
+      return new Rna(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+  }
+
+  /**
+   * @return the regions
+   * @see #regions
+   */
+  public List<ModificationResidue> getRegions() {
+    return regions;
+  }
+
+  /**
+   * @param regions
+   *          the regions to set
+   * @see #regions
+   */
+  public void setRegions(List<ModificationResidue> regions) {
+    this.regions = regions;
+  }
+
+  @Override
+  public String getStringType() {
+    return "RNA";
+  }
+
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/RnaComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/species/RnaComparator.java
index a16fbb967e9cdc64cb31a4f67b8bb8aecb0c0f54..34efa599e5714460b60117568647c8ae2369cfd0 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/RnaComparator.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/RnaComparator.java
@@ -8,7 +8,7 @@ import org.apache.log4j.Logger;
 import lcsb.mapviewer.common.Comparator;
 import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.common.comparator.StringSetComparator;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
 
 /**
  * Comparator class used for comparing {@link Rna} objects.
@@ -59,15 +59,18 @@ public class RnaComparator extends Comparator<Rna> {
     Set<String> set1 = new HashSet<>();
     Set<String> set2 = new HashSet<>();
 
-    for (RnaRegion region : arg0.getRegions()) {
+    for (ModificationResidue region : arg0.getRegions()) {
       set1.add(region.toString());
     }
 
-    for (RnaRegion region : arg1.getRegions()) {
+    for (ModificationResidue region : arg1.getRegions()) {
       set2.add(region.toString());
     }
 
     if (stringSetComparator.compare(set1, set2) != 0) {
+      logger.debug("Regions different");
+      logger.debug(set1);
+      logger.debug(set2);
       return stringSetComparator.compare(set1, set2);
     }
 
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/AbstractRegionModification.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/AbstractRegionModification.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec63373addb301c960fba06c46a9b40a0b2e7219
--- /dev/null
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/AbstractRegionModification.java
@@ -0,0 +1,102 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import java.text.DecimalFormat;
+
+import javax.persistence.Column;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+
+@Entity
+@DiscriminatorValue("ABSTRACT_REGION_MODIFICATION")
+public abstract class AbstractRegionModification extends ModificationResidue {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default size of the object (in graphical representation).
+   */
+  private static final double DEFAULT_SIZE = 10;
+
+  /**
+   * Width of the region in the graphic representation.
+   */
+  @Column(name = "width")
+  private double width = DEFAULT_SIZE;
+
+  /**
+   * Height of the region in the graphic representation.
+   */
+  @Column(name = "height")
+  private double height = DEFAULT_SIZE;
+
+  public AbstractRegionModification() {
+    super();
+  }
+
+  public AbstractRegionModification(AbstractRegionModification mr) {
+    super(mr);
+    this.width = mr.getWidth();
+    this.height = mr.getHeight();
+  }
+
+  @Override
+  public String toString() {
+    DecimalFormat format = new DecimalFormat("#.##");
+    String position;
+    if (getPosition() == null) {
+      position = null;
+    } else {
+      position = "Point2D[" + format.format(getPosition().getX()) + "," + format.format(getPosition().getY()) + "]";
+    }
+    String result = "[" + this.getClass().getSimpleName() + "]: " + getIdModificationResidue() + "," + getName() + ","
+        + getWidth() + "," + getHeight() + "," + position;
+    return result;
+  }
+
+  public double getWidth() {
+    return width;
+  }
+
+  public void setWidth(double width) {
+    this.width = width;
+  }
+
+  /**
+   * Update data in this object from parameter (only if values in parameter object
+   * are valid).
+   * 
+   * @param mr
+   *          object from which we are updating data
+   */
+  public void update(AbstractRegionModification mr) {
+    if (this.getIdModificationResidue() != null && !this.getIdModificationResidue().equals("")
+        && !this.getIdModificationResidue().equals(mr.getIdModificationResidue())) {
+      throw new InvalidArgumentException("Cannot update from mr with different id");
+    }
+    if (mr.getWidth() > 0 && mr.getWidth() != DEFAULT_SIZE) {
+      this.setWidth(mr.getWidth());
+    }
+    if (mr.getHeight() > 0 && mr.getHeight() != DEFAULT_SIZE) {
+      this.setHeight(mr.getHeight());
+    }
+    if (mr.getName() != null) {
+      this.setName(mr.getName());
+    }
+    if (mr.getPosition() != null) {
+      this.setPosition(mr.getPosition());
+    }
+  }
+
+  public double getHeight() {
+    return height;
+  }
+
+  public void setHeight(double height) {
+    this.height = height;
+  }
+}
\ No newline at end of file
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/AbstractSiteModification.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/AbstractSiteModification.java
new file mode 100644
index 0000000000000000000000000000000000000000..d0249cea6281efb73da01a857a48fe80c72e932d
--- /dev/null
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/AbstractSiteModification.java
@@ -0,0 +1,51 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import java.text.DecimalFormat;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+
+@Entity
+@DiscriminatorValue("ABSTRACT_SITE_MODIFICATION")
+public abstract class AbstractSiteModification extends ModificationResidue {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+  
+  /**
+   * State in which this modification is.
+   */
+  @Enumerated(EnumType.STRING)
+  protected ModificationState state = null;
+
+  public AbstractSiteModification() {
+    super();
+  }
+
+  public AbstractSiteModification(AbstractSiteModification mr) {
+    super(mr);
+    this.state = mr.getState();
+  }
+
+  public ModificationState getState() {
+    return state;
+  }
+
+  public void setState(ModificationState state) {
+    this.state = state;
+  }
+
+  @Override
+  public String toString() {
+    DecimalFormat format = new DecimalFormat("#.##");
+    String result = getIdModificationResidue() + "," + getName() + "," + getState() + ",Point2D["
+        + format.format(getPosition().getX()) + "," + format.format(getPosition().getY()) + "]";
+    return result;
+  }
+
+
+}
\ No newline at end of file
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegion.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegion.java
deleted file mode 100644
index ed51da8943b7682fb0ee357f8d9c5b7ee01377fc..0000000000000000000000000000000000000000
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegion.java
+++ /dev/null
@@ -1,341 +0,0 @@
-package lcsb.mapviewer.model.map.species.field;
-
-import java.io.Serializable;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
-import javax.persistence.Table;
-
-import org.apache.log4j.Logger;
-import org.hibernate.annotations.Cascade;
-import org.hibernate.annotations.CascadeType;
-
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.AntisenseRna;
-
-/**
- * This structure contains information about antisense rna region (rna fragment
- * of interest) for a specific {@link AntisenseRna}.
- * 
- * @author Piotr Gawron
- * 
- */
-@Entity
-@Table(name = "antisense_rna_region_table")
-@org.hibernate.annotations.GenericGenerator(name = "test-increment-strategy", strategy = "increment")
-public class AntisenseRnaRegion implements Serializable, ElementModification {
-
-	/**
-	 * 
-	 */
-	private static final long			 serialVersionUID			= 1L;
-
-	/**
-	 * Default size of the object (in graphical representation).
-	 */
-	private static final double		 DEFAULT_SIZE					= 0.1;
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger					 logger								= Logger.getLogger(AntisenseRnaRegion.class);
-
-	/**
-	 * Unique identifier in the database.
-	 */
-	@Id
-	@GeneratedValue(strategy = GenerationType.IDENTITY)
-	@Column(name = "iddb", unique = true, nullable = false)
-	private int										 id;
-
-	/**
-	 * String identifier of the element. Unique in the model.
-	 */
-	@Column(name = "idantisensernaregion")
-	private String								 idAntisenseRnaRegion	= "";
-
-	/**
-	 * Name of the region.
-	 */
-	@Column(name = "name")
-	private String								 name									= "";
-
-	/**
-	 * Defines a state of the region (for instance ubiquitinated etc).
-	 * 
-	 * @see ModificationState
-	 */
-	@Column(name = "state")
-	private ModificationState			 state								= null;
-
-	/**
-	 * Type of the region in the rna. There are three possible values:
-	 * <ul>
-	 * <li>Coding region,</li>
-	 * <li>Protein binding domain,</li>
-	 * <li>Modification site.</li>
-	 * </ul>
-	 */
-	@Column(name = "type")
-	private AntisenseRnaRegionType type;
-
-	/**
-	 * Size of the region in the graphic representation.
-	 */
-	@Column(name = "size")
-	private double								 size									= DEFAULT_SIZE;
-
-	/**
-	 * Position on the species in graphic representation.
-	 */
-	@Column(name = "pos")
-	private Double								 pos;
-
-	/**
-	 * Defines a species where the region belongs to.
-	 */
-	@Cascade({ CascadeType.ALL })
-	@ManyToOne(fetch = FetchType.LAZY)
-	@JoinColumn(name = "idSpeciesDb")
-	private AntisenseRna					 species;
-
-	/**
-	 * Default constructor.
-	 */
-	public AntisenseRnaRegion() {
-
-	}
-
-	/**
-	 * Constructor that initialize object with the data from the parameter.
-	 * 
-	 * @param original
-	 *          object from which we initialize data
-	 */
-	public AntisenseRnaRegion(AntisenseRnaRegion original) {
-		this.idAntisenseRnaRegion = original.idAntisenseRnaRegion;
-		this.name = original.name;
-		this.size = original.size;
-		this.pos = original.pos;
-		this.type = original.type;
-	}
-
-	/**
-	 * Creates a copy of current object.
-	 * 
-	 * @return copy of the object
-	 */
-	public AntisenseRnaRegion copy() {
-		if (this.getClass() == AntisenseRnaRegion.class) {
-			return new AntisenseRnaRegion(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-
-	}
-
-	/**
-	 * Sets size from the string.
-	 * 
-	 * @param text
-	 *          size to parse and set
-	 * @see #size
-	 */
-	public void setSize(String text) {
-		try {
-			size = Double.parseDouble(text);
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid angle: " + text, e);
-		}
-	}
-
-	/**
-	 * Sets position from the string.
-	 * 
-	 * @param text
-	 *          position to parse and set
-	 * @see #pos
-	 */
-	public void setPos(String text) {
-		try {
-			pos = Double.parseDouble(text);
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid pos: " + text, e);
-		}
-	}
-
-	/**
-	 * Update data in this object from parameter (only if values in parameter
-	 * object are valid).
-	 * 
-	 * @param mr
-	 *          object from which we are updating data
-	 */
-	public void update(AntisenseRnaRegion mr) {
-		if (this.idAntisenseRnaRegion != null && !this.idAntisenseRnaRegion.equals("") && !this.idAntisenseRnaRegion.equals(mr.getIdAntisenseRnaRegion())) {
-			throw new InvalidArgumentException("Cannot update from mr with different id");
-		}
-		this.size = mr.getSize();
-		if (mr.getState() != null) {
-			this.state = mr.getState();
-		}
-		if (mr.getName() != null) {
-			this.name = mr.getName();
-		}
-		if (mr.getPos() != null) {
-			this.setPos(mr.getPos());
-		}
-
-	}
-
-	@Override
-	public String toString() {
-		String result = getIdAntisenseRnaRegion() + "," + getName() + "," + getType() + "," + getPos() + "," + getSize() + ",";
-		return result;
-	}
-
-	/**
-	 * @return the idAntisenseRnaRegion
-	 * @see #idAntisenseRnaRegion
-	 */
-	public String getIdAntisenseRnaRegion() {
-		return idAntisenseRnaRegion;
-	}
-
-	/**
-	 * @param idAntisenseRnaRegion
-	 *          the id to set
-	 * @see #idAntisenseRnaRegion
-	 */
-	public void setIdAntisenseRnaRegion(String idAntisenseRnaRegion) {
-		this.idAntisenseRnaRegion = idAntisenseRnaRegion;
-	}
-
-	/**
-	 * @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;
-	}
-
-	/**
-	 * @return the state
-	 * @see #state
-	 */
-	public ModificationState getState() {
-		return state;
-	}
-
-	/**
-	 * @param state
-	 *          the state to set
-	 * @see #state
-	 */
-	public void setState(ModificationState state) {
-		this.state = state;
-	}
-
-	/**
-	 * @return the type
-	 * @see #type
-	 */
-	public AntisenseRnaRegionType getType() {
-		return type;
-	}
-
-	/**
-	 * @param type
-	 *          the type to set
-	 * @see #type
-	 */
-	public void setType(AntisenseRnaRegionType type) {
-		this.type = type;
-	}
-
-	/**
-	 * @return the size
-	 * @see #size
-	 */
-	public double getSize() {
-		return size;
-	}
-
-	/**
-	 * @param size
-	 *          the size to set
-	 * @see #size
-	 */
-	public void setSize(double size) {
-		this.size = size;
-	}
-
-	/**
-	 * @return the pos
-	 * @see #pos
-	 */
-	public Double getPos() {
-		return pos;
-	}
-
-	/**
-	 * @param pos
-	 *          the pos to set
-	 * @see #pos
-	 */
-	public void setPos(Double pos) {
-		this.pos = pos;
-	}
-
-	/**
-	 * @return the species
-	 * @see #species
-	 */
-	public AntisenseRna getSpecies() {
-		return species;
-	}
-
-	/**
-	 * @param species
-	 *          the species to set
-	 * @see #species
-	 */
-	public void setSpecies(AntisenseRna species) {
-		this.species = species;
-	}
-
-	/**
-	 * @return the id
-	 * @see #id
-	 */
-	public int getId() {
-		return id;
-	}
-
-	/**
-	 * @param id
-	 *          the id to set
-	 * @see #id
-	 */
-	public void setId(int id) {
-		this.id = id;
-	}
-
-}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegionType.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegionType.java
deleted file mode 100644
index 727ad5d4c831018249c9a185d943573f29d03f0e..0000000000000000000000000000000000000000
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegionType.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package lcsb.mapviewer.model.map.species.field;
-
-import lcsb.mapviewer.model.map.species.AntisenseRna;
-
-/**
- * Enum that enlists types of available modification regions in
- * {@link AntisenseRna}.
- * 
- * @author Piotr Gawron
- * 
- */
-public enum AntisenseRnaRegionType {
-
-	/**
-	 * Modification site.
-	 */
-	MODIFICATION_SITE("Modification Site"), //
-
-	/**
-	 * Coding region.
-	 */
-	CODING_REGION("CodingRegion"), //
-
-	/**
-	 * Protein binding domain.
-	 */
-	PROTEIN_BINDING_DOMAIN("proteinBindingDomain");
-
-	/**
-	 * Name of the type.
-	 */
-	private String name;
-
-	/**
-	 * Default constructor.
-	 * 
-	 * @param name
-	 *          name of the type
-	 */
-	AntisenseRnaRegionType(String name) {
-		this.name = name;
-	}
-
-	/**
-	 * @return the name
-	 * @see #name
-	 */
-	public String getName() {
-		return name;
-	}
-
-	/**
-	 * Returns {@link AntisenseRnaRegionType} identified by name.
-	 * 
-	 * @param name
-	 *          name of the region
-	 * @return {@link AntisenseRnaRegionType} identified by name
-	 */
-	public static AntisenseRnaRegionType getTypeByString(String name) {
-		for (AntisenseRnaRegionType type : values()) {
-			if (type.getName().equalsIgnoreCase(name)) {
-				return type;
-			}
-		}
-		return null;
-	}
-}
\ No newline at end of file
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/BindingRegion.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/BindingRegion.java
new file mode 100644
index 0000000000000000000000000000000000000000..daa42fe4e3ddd4606d56a1ce00fad124a894af5b
--- /dev/null
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/BindingRegion.java
@@ -0,0 +1,69 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import java.io.Serializable;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * This structure contains information about Binding Region for one of the
+ * following {@link Species}:
+ * <ul>
+ * <li>{@link Protein}</li>
+ * </ul>
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+@Entity
+@DiscriminatorValue("BINDING_REGION")
+public class BindingRegion extends AbstractRegionModification implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(BindingRegion.class);
+
+  /**
+   * Default constructor.
+   */
+  public BindingRegion() {
+
+  }
+
+  /**
+   * Constructor that initialize object with the data from the parameter.
+   * 
+   * @param original
+   *          object from which we initialize data
+   */
+  public BindingRegion(BindingRegion original) {
+    super(original);
+  }
+
+  /**
+   * Creates a copy of current object.
+   * 
+   * @return copy of the object
+   */
+  public BindingRegion copy() {
+    if (this.getClass() == BindingRegion.class) {
+      return new BindingRegion(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+
+  }
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/CodingRegion.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/CodingRegion.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a10b406425a8c4a391a12bc52174c1e704600a2
--- /dev/null
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/CodingRegion.java
@@ -0,0 +1,73 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import java.io.Serializable;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * This structure contains information about Coding Region for one of the
+ * following {@link Species}:
+ * <ul>
+ * <li>{@link Rna}</li>
+ * <li>{@link AntisenseRna}</li>
+ * <li>{@link Gene}</li>
+ * </ul>
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+@Entity
+@DiscriminatorValue("CODING_REGION")
+public class CodingRegion extends AbstractRegionModification implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(CodingRegion.class);
+
+  /**
+   * Default constructor.
+   */
+  public CodingRegion() {
+
+  }
+
+  /**
+   * Constructor that initialize object with the data from the parameter.
+   * 
+   * @param original
+   *          object from which we initialize data
+   */
+  public CodingRegion(CodingRegion original) {
+    super(original);
+  }
+
+  /**
+   * Creates a copy of current object.
+   * 
+   * @return copy of the object
+   */
+  public CodingRegion copy() {
+    if (this.getClass() == CodingRegion.class) {
+      return new CodingRegion(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+
+  }
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/ElementModification.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/ElementModification.java
deleted file mode 100644
index 97db98c8d9f2a005cfaf9a2d6b5715df44d8d3a4..0000000000000000000000000000000000000000
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/field/ElementModification.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package lcsb.mapviewer.model.map.species.field;
-
-public interface ElementModification {
-	ModificationState getState();
-
-	String getName();
-}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationResidue.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationResidue.java
index e0f7ef54909a29f5703805be25b011d87db2e966..4c8e7b3e37488f08699432ae4285de7fe39e745f 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationResidue.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationResidue.java
@@ -1,266 +1,181 @@
-package lcsb.mapviewer.model.map.species.field;
-
-import java.io.Serializable;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
-import javax.persistence.Table;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.Species;
-
-/**
- * This class represent modification residue in protein and gene. However, it is
- * sometimes also used for storing information about AntisenseRna/Rna regions...
- * (due to CellDesigner xml strange structure).
- * 
- * @author Piotr Gawron
- * 
- */
-@Entity
-@Table(name = "modification_residue_table")
-@org.hibernate.annotations.GenericGenerator(name = "test-increment-strategy", strategy = "increment")
-public class ModificationResidue implements Serializable, ElementModification {
-
-	/**
-	 * 
-	 */
-	private static final long	serialVersionUID			= 1L;
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger			logger								= Logger.getLogger(ModificationResidue.class.getName());
-
-	/**
-	 * Unique identifier in the database.
-	 */
-	@Id
-	@GeneratedValue(strategy = GenerationType.IDENTITY)
-	@Column(name = "iddb", unique = true, nullable = false)
-	private int								id;
-
-	/**
-	 * Identifier of the modification. Must be unique in single map model.
-	 */
-	private String						idModificationResidue	= "";
-
-	/**
-	 * Name of the modification.
-	 */
-	private String						name									= "";
-
-	/**
-	 * Some strange param in CellDesigner. No idea what is it for.
-	 */
-	private String						side									= "";
-
-	/**
-	 * State in which this modification is.
-	 */
-	private ModificationState	state									= null;
-
-	/**
-	 * Where this modification is located (on which side of the border).
-	 */
-	private Double						angle									= null;
-
-	/**
-	 * How big is this modification (used only for some types of the
-	 * modification).
-	 */
-	private Double						size									= null;
-
-	/**
-	 * Species to which this modification belong to.
-	 */
-	@ManyToOne(fetch = FetchType.LAZY)
-	@JoinColumn(name = "idSpeciesDb", nullable = false)
-	private Species						species;
-
-	/**
-	 * Default constructor.
-	 */
-	public ModificationResidue() {
-	}
-
-	/**
-	 * Constructor that initaize object with the data taken from the parameter.
-	 * 
-	 * @param mr
-	 *          original object from which data is taken
-	 */
-	public ModificationResidue(ModificationResidue mr) {
-		this.idModificationResidue = mr.idModificationResidue;
-		this.name = mr.name;
-		this.angle = mr.angle;
-		this.size = mr.size;
-		this.side = mr.side;
-		this.state = mr.state;
-	}
-
-	@Override
-	public String toString() {
-		String result = getIdModificationResidue() + "," + getName() + "," + getState() + "," + getAngle() + "," + getSize() + "," + getSide() + ",";
-		return result;
-	}
-
-	/**
-	 * Creates copy of the object.
-	 * 
-	 * @return copy of the object.
-	 */
-	public ModificationResidue copy() {
-		if (this.getClass() == ModificationResidue.class) {
-			return new ModificationResidue(this);
-		} else {
-			throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
-		}
-	}
-
-	/**
-	 * @return the idModificationResidue
-	 * @see #id
-	 */
-	public int getId() {
-		return id;
-	}
-
-	/**
-	 * @param id
-	 *          the idModificationResidue to set
-	 * @see #id
-	 */
-	public void setId(int id) {
-		this.id = id;
-	}
-
-	/**
-	 * @return the id
-	 * @see #idModificationResidue
-	 */
-	public String getIdModificationResidue() {
-		return idModificationResidue;
-	}
-
-	/**
-	 * @param idModificationResidue
-	 *          the id to set
-	 * @see #idModificationResidue
-	 */
-	public void setIdModificationResidue(String idModificationResidue) {
-		this.idModificationResidue = idModificationResidue;
-	}
-
-	/**
-	 * @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;
-	}
-
-	/**
-	 * @return the side
-	 * @see #side
-	 */
-	public String getSide() {
-		return side;
-	}
-
-	/**
-	 * @param side
-	 *          the side to set
-	 * @see #side
-	 */
-	public void setSide(String side) {
-		this.side = side;
-	}
-
-	/**
-	 * @return the state
-	 * @see #state
-	 */
-	public ModificationState getState() {
-		return state;
-	}
-
-	/**
-	 * @param state
-	 *          the state to set
-	 * @see #state
-	 */
-	public void setState(ModificationState state) {
-		this.state = state;
-	}
-
-	/**
-	 * @return the angle
-	 * @see #angle
-	 */
-	public Double getAngle() {
-		return angle;
-	}
-
-	/**
-	 * @param angle
-	 *          the angle to set
-	 * @see #angle
-	 */
-	public void setAngle(Double angle) {
-		this.angle = angle;
-	}
-
-	/**
-	 * @return the size
-	 * @see #size
-	 */
-	public Double getSize() {
-		return size;
-	}
-
-	/**
-	 * @param size
-	 *          the size to set
-	 * @see #size
-	 */
-	public void setSize(Double size) {
-		this.size = size;
-	}
-
-	/**
-	 * @return the species
-	 * @see #species
-	 */
-	public Species getSpecies() {
-		return species;
-	}
-
-	/**
-	 * @param species
-	 *          the species to set
-	 * @see #species
-	 */
-	public void setSpecies(Species species) {
-		this.species = species;
-	}
-
-}
+package lcsb.mapviewer.model.map.species.field;
+
+import java.awt.geom.Point2D;
+import java.io.Serializable;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.DiscriminatorColumn;
+import javax.persistence.DiscriminatorType;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+import org.apache.log4j.Logger;
+import org.hibernate.annotations.Type;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * This class represent modification residue in a {@link Species}.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+
+@Entity
+@Table(name = "modification_residue_table")
+@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
+@DiscriminatorColumn(name = "modification_type", discriminatorType = DiscriminatorType.STRING)
+@DiscriminatorValue("GENERIC_MODIFICATION_RESIDUE")
+@org.hibernate.annotations.GenericGenerator(name = "test-increment-strategy", strategy = "increment")
+public class ModificationResidue implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(ModificationResidue.class.getName());
+
+  /**
+   * Unique identifier in the database.
+   */
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "iddb", unique = true, nullable = false)
+  private int id;
+
+  /**
+   * Identifier of the modification. Must be unique in single map model.
+   */
+  private String idModificationResidue = "";
+
+  /**
+   * Name of the modification.
+   */
+  private String name = "";
+
+  @Column(name = "position")
+  @Type(type = "lcsb.mapviewer.persist.mapper.Point2DMapper")
+  private Point2D position = null;
+
+  /**
+   * Species to which this modification belong to.
+   */
+  @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
+  @JoinColumn(name = "idSpeciesDb", nullable = false)
+  private Species species;
+
+  /**
+   * Default constructor.
+   */
+  public ModificationResidue() {
+  }
+
+  /**
+   * Constructor that initialize object with the data taken from the parameter.
+   * 
+   * @param mr
+   *          original object from which data is taken
+   */
+  public ModificationResidue(ModificationResidue mr) {
+    this.idModificationResidue = mr.idModificationResidue;
+    this.name = mr.name;
+    this.position = mr.position;
+  }
+
+  /**
+   * @return the idModificationResidue
+   * @see #id
+   */
+  public int getId() {
+    return id;
+  }
+
+  /**
+   * @param id
+   *          the idModificationResidue to set
+   * @see #id
+   */
+  public void setId(int id) {
+    this.id = id;
+  }
+
+  /**
+   * @return the id
+   * @see #idModificationResidue
+   */
+  public String getIdModificationResidue() {
+    return idModificationResidue;
+  }
+
+  /**
+   * @param idModificationResidue
+   *          the id to set
+   * @see #idModificationResidue
+   */
+  public void setIdModificationResidue(String idModificationResidue) {
+    this.idModificationResidue = idModificationResidue;
+  }
+
+  /**
+   * @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;
+  }
+
+  /**
+   * @return the species
+   * @see #species
+   */
+  public Species getSpecies() {
+    return species;
+  }
+
+  /**
+   * @param species
+   *          the species to set
+   * @see #species
+   */
+  public void setSpecies(Species species) {
+    this.species = species;
+  }
+
+  public Point2D getPosition() {
+    return position;
+  }
+
+  public void setPosition(Point2D position) {
+    this.position = position;
+  }
+
+  public ModificationResidue copy() {
+    throw new NotImplementedException();
+  }
+
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationSite.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationSite.java
new file mode 100644
index 0000000000000000000000000000000000000000..52b13b58659872ee34278be3e53a197531cf5fa7
--- /dev/null
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationSite.java
@@ -0,0 +1,54 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * This structure contains information about Modification Site for one of the
+ * following {@link Species}:
+ * <ul>
+ * <li>{@link Rna}</li>
+ * <li>{@link AntisenseRna}</li>
+ * <li>{@link Gene}</li>
+ * </ul>
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+@Entity
+@DiscriminatorValue("MODIFICATION_SITE")
+public class ModificationSite extends AbstractSiteModification {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  public ModificationSite() {
+    super();
+  }
+
+  public ModificationSite(ModificationSite site) {
+    super(site);
+  }
+
+  /**
+   * Creates copy of the object.
+   * 
+   * @return copy of the object.
+   */
+  public ModificationSite copy() {
+    if (this.getClass() == ModificationSite.class) {
+      return new ModificationSite(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+  }
+
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationState.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationState.java
index da3b3308eb7a20fc2ffceded6f2e4e184988d6c2..32184f55ee6f54583dc71029f7058f89e65c5872 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationState.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/ModificationState.java
@@ -1,152 +1,152 @@
-package lcsb.mapviewer.model.map.species.field;
-
-/**
- * Defines a type of modification (in protein or rna). Possible values are:
- * <ul>
- * <li>{@link ModificationState#ACETYLATED ACETYLATED},</li>
- * <li>{@link ModificationState#DONT_CARE DON'T CARE},</li>
- * <li>{@link ModificationState#EMPTY EMPTY},</li>
- * <li>{@link ModificationState#GLYCOSYLATED GLYCOSYLATED},</li>
- * <li>{@link ModificationState#HYDROXYLATED HYDROXYLATED},</li>
- * <li>{@link ModificationState#METHYLATED METHYLATED},</li>
- * <li>{@link ModificationState#MYRISTOYLATED MYRISTOYLATED},</li>
- * <li>{@link ModificationState#PALMYTOYLATED PALMYTOYLATED},</li>
- * <li>{@link ModificationState#PHOSPHORYLATED PHOSPHORYLATED},</li>
- * <li>{@link ModificationState#PRENYLATED PRENYLATED},</li>
- * <li>{@link ModificationState#PROTONATED PROTONATED},</li>
- * <li>{@link ModificationState#SULFATED SULFATED},</li>
- * <li>{@link ModificationState#UBIQUITINATED UBIQUITINATED},</li>
- * <li>{@link ModificationState#UNKNOWN UNKNOWN}.</li>
- * </ul>
- * 
- * @author Piotr Gawron
- * 
- */
-public enum ModificationState {
-	
-	/**
-	 * Phosporylated state.
-	 */
-	PHOSPHORYLATED("phosphorylated", "P"), //
-
-	/**
-	 * Acetylated state.
-	 */
-	ACETYLATED("acetylated", "Ac"), //
-
-	/**
-	 * Ubiquitinated state.
-	 */
-	UBIQUITINATED("ubiquitinated", "Ub"), //
-
-	/**
-	 * Methylated state.
-	 */
-	METHYLATED("methylated", "Me"), //
-
-	/**
-	 * Hydroxylated state.
-	 */
-	HYDROXYLATED("hydroxylated", "OH"), //
-
-	/**
-	 * Myristoylated state.
-	 */
-	MYRISTOYLATED("myristoylated", "My"), //
-
-	/**
-	 * Sulfated state.
-	 */
-	SULFATED("sulfated", "S"), //
-
-	/**
-	 * Prenylated state.
-	 */
-	PRENYLATED("prenylated", "Pr"), //
-
-	/**
-	 * Glycosylated state.
-	 */
-	GLYCOSYLATED("glycosylated", "G"), //
-
-	/**
-	 * Palmytoylated state.
-	 */
-	PALMYTOYLATED("palmytoylated", "Pa"), //
-
-	/**
-	 * Unknown state.
-	 */
-	UNKNOWN("unknown", "?"), //
-
-	/**
-	 * Empty state.
-	 */
-	EMPTY("empty", ""), //
-
-	/**
-	 * Protonated state.
-	 */
-	PROTONATED("protonated", "H"), //
-
-	/**
-	 * We don't care in which state it is.
-	 */
-	DONT_CARE("don't care", "*");
-
-	/**
-	 * Full name of the modification.
-	 */
-
-	private String fullName;
-	/**
-	 * Abbreviation used for the modification.
-	 */
-	private String abbreviation;
-
-	/**
-	 * Default constructor with the name and abbreviation.
-	 * 
-	 * @param name
-	 *          name used for this state
-	 * @param abbreviation
-	 *          abbreviation used in this state
-	 */
-	ModificationState(String name, String abbreviation) {
-		this.fullName = name;
-		this.abbreviation = abbreviation;
-	}
-
-	/**
-	 * @return the fullName
-	 * @see #fullName
-	 */
-	public String getFullName() {
-		return fullName;
-	}
-
-	/**
-	 * @return the abbreviation
-	 * @see #abbreviation
-	 */
-	public String getAbbreviation() {
-		return abbreviation;
-	}
-
-	/**
-	 * Returns {@link ModificationState} identified by the full name.
-	 * 
-	 * @param name
-	 *          full name of the state
-	 * @return {@link ModificationState} identified by the full name
-	 */
-	public static ModificationState getByName(String name) {
-		for (ModificationState state : values()) {
-			if (state.getFullName().equalsIgnoreCase(name)) {
-				return state;
-			}
-		}
-		return null;
-	}
-
-}
+package lcsb.mapviewer.model.map.species.field;
+
+/**
+ * Defines a type of modification (in protein or rna). Possible values are:
+ * <ul>
+ * <li>{@link ModificationState#ACETYLATED ACETYLATED},</li>
+ * <li>{@link ModificationState#DONT_CARE DON'T CARE},</li>
+ * <li>{@link ModificationState#EMPTY EMPTY},</li>
+ * <li>{@link ModificationState#GLYCOSYLATED GLYCOSYLATED},</li>
+ * <li>{@link ModificationState#HYDROXYLATED HYDROXYLATED},</li>
+ * <li>{@link ModificationState#METHYLATED METHYLATED},</li>
+ * <li>{@link ModificationState#MYRISTOYLATED MYRISTOYLATED},</li>
+ * <li>{@link ModificationState#PALMYTOYLATED PALMYTOYLATED},</li>
+ * <li>{@link ModificationState#PHOSPHORYLATED PHOSPHORYLATED},</li>
+ * <li>{@link ModificationState#PRENYLATED PRENYLATED},</li>
+ * <li>{@link ModificationState#PROTONATED PROTONATED},</li>
+ * <li>{@link ModificationState#SULFATED SULFATED},</li>
+ * <li>{@link ModificationState#UBIQUITINATED UBIQUITINATED},</li>
+ * <li>{@link ModificationState#UNKNOWN UNKNOWN}.</li>
+ * </ul>
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public enum ModificationState {
+
+  /**
+   * Phosporylated state.
+   */
+  PHOSPHORYLATED("phosphorylated", "P"), //
+
+  /**
+   * Acetylated state.
+   */
+  ACETYLATED("acetylated", "Ac"), //
+
+  /**
+   * Ubiquitinated state.
+   */
+  UBIQUITINATED("ubiquitinated", "Ub"), //
+
+  /**
+   * Methylated state.
+   */
+  METHYLATED("methylated", "Me"), //
+
+  /**
+   * Hydroxylated state.
+   */
+  HYDROXYLATED("hydroxylated", "OH"), //
+
+  /**
+   * Myristoylated state.
+   */
+  MYRISTOYLATED("myristoylated", "My"), //
+
+  /**
+   * Sulfated state.
+   */
+  SULFATED("sulfated", "S"), //
+
+  /**
+   * Prenylated state.
+   */
+  PRENYLATED("prenylated", "Pr"), //
+
+  /**
+   * Glycosylated state.
+   */
+  GLYCOSYLATED("glycosylated", "G"), //
+
+  /**
+   * Palmytoylated state.
+   */
+  PALMYTOYLATED("palmytoylated", "Pa"), //
+
+  /**
+   * Unknown state.
+   */
+  UNKNOWN("unknown", "?"), //
+
+  /**
+   * Empty state.
+   */
+  EMPTY("empty", ""), //
+
+  /**
+   * Protonated state.
+   */
+  PROTONATED("protonated", "H"), //
+
+  /**
+   * We don't care in which state it is.
+   */
+  DONT_CARE("don't care", "*");
+
+  /**
+   * Full name of the modification.
+   */
+
+  private String fullName;
+  /**
+   * Abbreviation used for the modification.
+   */
+  private String abbreviation;
+
+  /**
+   * Default constructor with the name and abbreviation.
+   * 
+   * @param name
+   *          name used for this state
+   * @param abbreviation
+   *          abbreviation used in this state
+   */
+  ModificationState(String name, String abbreviation) {
+    this.fullName = name;
+    this.abbreviation = abbreviation;
+  }
+
+  /**
+   * @return the fullName
+   * @see #fullName
+   */
+  public String getFullName() {
+    return fullName;
+  }
+
+  /**
+   * @return the abbreviation
+   * @see #abbreviation
+   */
+  public String getAbbreviation() {
+    return abbreviation;
+  }
+
+  /**
+   * Returns {@link ModificationState} identified by the full name.
+   * 
+   * @param name
+   *          full name of the state
+   * @return {@link ModificationState} identified by the full name
+   */
+  public static ModificationState getByName(String name) {
+    for (ModificationState state : values()) {
+      if (state.getFullName().equalsIgnoreCase(name)) {
+        return state;
+      }
+    }
+    return null;
+  }
+
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/ProteinBindingDomain.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/ProteinBindingDomain.java
new file mode 100644
index 0000000000000000000000000000000000000000..92d9ea58f22dc937cbac59020022de6a79f51d43
--- /dev/null
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/ProteinBindingDomain.java
@@ -0,0 +1,71 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import java.io.Serializable;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * This structure contains information about Protein Binding Domain for one of
+ * the following {@link Species}:
+ * <ul>
+ * <li>{@link Rna}</li>
+ * <li>{@link AntisenseRna}</li>
+ * </ul>
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+@Entity
+@DiscriminatorValue("PROTEIN_BINDING_DOMAIN")
+public class ProteinBindingDomain extends AbstractRegionModification implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(ProteinBindingDomain.class);
+
+  /**
+   * Default constructor.
+   */
+  public ProteinBindingDomain() {
+
+  }
+
+  /**
+   * Constructor that initialize object with the data from the parameter.
+   * 
+   * @param original
+   *          object from which we initialize data
+   */
+  public ProteinBindingDomain(ProteinBindingDomain original) {
+    super(original);
+  }
+
+  /**
+   * Creates a copy of current object.
+   * 
+   * @return copy of the object
+   */
+  public ProteinBindingDomain copy() {
+    if (this.getClass() == ProteinBindingDomain.class) {
+      return new ProteinBindingDomain(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+
+  }
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/RegulatoryRegion.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/RegulatoryRegion.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd47c43c8b6eeb0e806de8e8fcbba6be39abca89
--- /dev/null
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/RegulatoryRegion.java
@@ -0,0 +1,69 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import java.io.Serializable;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * This structure contains information about Regulatory Region for one of the
+ * following {@link Species}:
+ * <ul>
+ * <li>{@link Gene}</li>
+ * </ul>
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+@Entity
+@DiscriminatorValue("REGULATORY_REGION")
+public class RegulatoryRegion extends AbstractRegionModification implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(RegulatoryRegion.class);
+
+  /**
+   * Default constructor.
+   */
+  public RegulatoryRegion() {
+
+  }
+
+  /**
+   * Constructor that initialize object with the data from the parameter.
+   * 
+   * @param original
+   *          object from which we initialize data
+   */
+  public RegulatoryRegion(RegulatoryRegion original) {
+    super(original);
+  }
+
+  /**
+   * Creates a copy of current object.
+   * 
+   * @return copy of the object
+   */
+  public RegulatoryRegion copy() {
+    if (this.getClass() == RegulatoryRegion.class) {
+      return new RegulatoryRegion(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+
+  }
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/Residue.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/Residue.java
new file mode 100644
index 0000000000000000000000000000000000000000..d93cc8956d07f82c5b61648d481c9d6de4c20b25
--- /dev/null
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/Residue.java
@@ -0,0 +1,45 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.Protein;
+
+/**
+ * This structure contains information about Residue for one of {@link Protein}.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+@Entity
+@DiscriminatorValue("RESIDUE")
+public class Residue extends AbstractSiteModification {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  public Residue() {
+    super();
+  }
+
+  public Residue(Residue residue) {
+    super(residue);
+  }
+
+  /**
+   * Creates copy of the object.
+   * 
+   * @return copy of the object.
+   */
+  public Residue copy() {
+    if (this.getClass() == Residue.class) {
+      return new Residue(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+  }
+
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/RnaRegion.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/RnaRegion.java
deleted file mode 100644
index 9c5e32a201e2f8d6e4f84d40db4b6af0beab72e1..0000000000000000000000000000000000000000
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/field/RnaRegion.java
+++ /dev/null
@@ -1,327 +0,0 @@
-package lcsb.mapviewer.model.map.species.field;
-
-import java.io.Serializable;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
-import javax.persistence.Table;
-
-import org.apache.log4j.Logger;
-
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.model.map.species.Rna;
-
-/**
- * This structure contains information about rna region (rna fragment of
- * interest) for a specific {@link Rna}.
- * 
- * @author Piotr Gawron
- * 
- */
-@Entity
-@Table(name = "rna_region_table")
-@org.hibernate.annotations.GenericGenerator(name = "test-increment-strategy", strategy = "increment")
-public class RnaRegion implements Serializable, ElementModification {
-
-	/**
-	 * 
-	 */
-	private static final long		serialVersionUID = 1L;
-
-	/**
-	 * Default {@link #size} of the region.
-	 */
-	private static final double	DEFAULT_SIZE		 = 0.1;
-
-	/**
-	 * Default class logger.
-	 */
-	@SuppressWarnings("unused")
-	private static Logger				logger					 = Logger.getLogger(RnaRegion.class.getName());
-
-	/**
-	 * Unique identifier in the database.
-	 */
-	@Id
-	@GeneratedValue(strategy = GenerationType.IDENTITY)
-	@Column(name = "iddb", unique = true, nullable = false)
-	private int									id;
-
-	/**
-	 * Identifier of the region. Unique in the
-	 * {@link lcsb.mapviewer.model.map.model.Model}.
-	 */
-	@Column(name = "idrnaregion")
-	private String							idRnaRegion			 = "";
-	/**
-	 * Type of the region in the rna. There are three possible values:
-	 * <ul>
-	 * <li>Coding region,</li>
-	 * <li>Protein binding domain,</li>
-	 * <li>Modification site.</li>
-	 * </ul>
-	 */
-
-	@Column(name = "type")
-	private String							type						 = "";
-
-	/**
-	 * Defines a state of the region (for instance ubiquitinated etc).
-	 * 
-	 * @see ModificationState
-	 */
-	@Column(name = "state")
-	private ModificationState		state						 = null;
-
-	/**
-	 * Name of the region.
-	 */
-	@Column(name = "name")
-	private String							name						 = "";
-
-	/**
-	 * Size of the region in the graphic representation.
-	 */
-	@Column(name = "size")
-	private double							size						 = DEFAULT_SIZE;
-
-	/**
-	 * Position on the species in graphic representation.
-	 */
-	@Column(name = "pos")
-	private Double							pos;
-
-	/**
-	 * Defines a species where the region belongs to.
-	 */
-	@ManyToOne(fetch = FetchType.LAZY)
-	@JoinColumn(name = "idSpeciesDb")
-	private Rna									species;
-
-	/**
-	 * Default constructor.
-	 */
-	public RnaRegion() {
-
-	}
-
-	/**
-	 * Creates object with the data taken from paramter region.
-	 * 
-	 * @param mr
-	 *          original {@link RnaRegion}
-	 */
-	public RnaRegion(RnaRegion mr) {
-		this.id = mr.id;
-		this.idRnaRegion = mr.idRnaRegion;
-		this.size = mr.size;
-		setPos(mr.getPos());
-		this.type = mr.type;
-		this.state = mr.state;
-		this.name = mr.name;
-	}
-
-	/**
-	 * Sets {@link #size}.
-	 * 
-	 * @param text
-	 *          new size value in string format
-	 */
-	public void setSize(String text) {
-		try {
-			size = Double.parseDouble(text);
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid angle: " + text, e);
-		}
-
-	}
-
-	/**
-	 * Sets {@link #pos}.
-	 * 
-	 * @param text
-	 *          new {@link #pos} value in string format
-	 */
-	public void setPos(String text) {
-		try {
-			setPos(Double.parseDouble(text));
-		} catch (NumberFormatException e) {
-			throw new InvalidArgumentException("Invalid pos: " + text, e);
-		}
-
-	}
-
-	/**
-	 * Updates fields in the object with the data given in the parameter rna
-	 * region.
-	 * 
-	 * @param mr
-	 *          {@link RnaRegion} from which data will be used to update
-	 */
-	public void update(RnaRegion mr) {
-		if (this.idRnaRegion != null && !this.idRnaRegion.equals("") && !this.idRnaRegion.equals(mr.getIdRnaRegion())) {
-			throw new InvalidArgumentException("Cannot update from mr with different id");
-		}
-		this.size = mr.getSize();
-		if (mr.getState() != null) {
-			this.state = mr.getState();
-		}
-		if (mr.getName() != null) {
-			this.name = mr.getName();
-		}
-		if (mr.getPos() != null) {
-			this.setPos(mr.getPos());
-		}
-
-	}
-
-	@Override
-	public String toString() {
-		String result = "" + getIdRnaRegion() + "," + getType() + "," + getPos() + "," + getSize() + "," + getState() + ",";
-		return result;
-
-	}
-
-	/**
-	 * @return the idRnaRegion
-	 * @see #idRnaRegion
-	 */
-	public int getId() {
-		return id;
-	}
-
-	/**
-	 * @param id
-	 *          the idRnaRegion to set
-	 * @see #id
-	 */
-	public void setId(int id) {
-		this.id = id;
-	}
-
-	/**
-	 * @return the id
-	 * @see #id
-	 */
-	public String getIdRnaRegion() {
-		return idRnaRegion;
-	}
-
-	/**
-	 * @param id
-	 *          the id to set
-	 * @see #id
-	 */
-	public void setIdRnaRegion(String id) {
-		this.idRnaRegion = id;
-	}
-
-	/**
-	 * @return the type
-	 * @see #type
-	 */
-	public String getType() {
-		return type;
-	}
-
-	/**
-	 * @param type
-	 *          the type to set
-	 * @see #type
-	 */
-	public void setType(String type) {
-		this.type = type;
-	}
-
-	/**
-	 * @return the state
-	 * @see #state
-	 */
-	public ModificationState getState() {
-		return state;
-	}
-
-	/**
-	 * @param state
-	 *          the state to set
-	 * @see #state
-	 */
-	public void setState(ModificationState state) {
-		this.state = state;
-	}
-
-	/**
-	 * @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;
-	}
-
-	/**
-	 * @return the size
-	 * @see #size
-	 */
-	public double getSize() {
-		return size;
-	}
-
-	/**
-	 * @param size
-	 *          the size to set
-	 * @see #size
-	 */
-	public void setSize(double size) {
-		this.size = size;
-	}
-
-	/**
-	 * @return the pos
-	 * @see #pos
-	 */
-	public Double getPos() {
-		return pos;
-	}
-
-	/**
-	 * @param pos
-	 *          the pos to set
-	 * @see #pos
-	 */
-	public void setPos(Double pos) {
-		this.pos = pos;
-	}
-
-	/**
-	 * @return the species
-	 * @see #species
-	 */
-	public Rna getSpecies() {
-		return species;
-	}
-
-	/**
-	 * @param species
-	 *          the species to set
-	 * @see #species
-	 */
-	public void setSpecies(Rna species) {
-		this.species = species;
-	}
-
-}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/field/TranscriptionSite.java b/model/src/main/java/lcsb/mapviewer/model/map/species/field/TranscriptionSite.java
new file mode 100644
index 0000000000000000000000000000000000000000..e878a893d5d2c8efbb0a7221af064282ae113313
--- /dev/null
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/field/TranscriptionSite.java
@@ -0,0 +1,107 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import java.io.Serializable;
+
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.Entity;
+
+import org.apache.log4j.Logger;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.Gene;
+import lcsb.mapviewer.model.map.species.Species;
+
+/**
+ * This structure contains information about Transcription Site for one of the
+ * following {@link Species}:
+ * <ul>
+ * <li>{@link Gene}</li>
+ * </ul>
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+@Entity
+@DiscriminatorValue("TRANSCRIPTION_SITE")
+public class TranscriptionSite extends AbstractRegionModification implements Serializable {
+
+  /**
+   * 
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private static Logger logger = Logger.getLogger(TranscriptionSite.class);
+
+  private String direction = null;
+
+  private Boolean active = false;
+
+  /**
+   * Default constructor.
+   */
+  public TranscriptionSite() {
+
+  }
+
+  /**
+   * Constructor that initialize object with the data from the parameter.
+   * 
+   * @param original
+   *          object from which we initialize data
+   */
+  public TranscriptionSite(TranscriptionSite original) {
+    super(original);
+    this.direction = original.getDirection();
+    this.active = original.getActive();
+  }
+
+  @Override
+  public void update(AbstractRegionModification mr) {
+    TranscriptionSite original = (TranscriptionSite) mr;
+    if (original.getDirection() != null) {
+      this.direction = original.getDirection();
+    }
+    if (original.getActive() != null) {
+      this.active = original.getActive();
+    }
+  }
+
+  /**
+   * Creates a copy of current object.
+   * 
+   * @return copy of the object
+   */
+  public TranscriptionSite copy() {
+    if (this.getClass() == TranscriptionSite.class) {
+      return new TranscriptionSite(this);
+    } else {
+      throw new NotImplementedException("Method copy() should be overriden in class " + this.getClass());
+    }
+
+  }
+
+  public String getDirection() {
+    return direction;
+  }
+
+  public void setDirection(String direction) {
+    this.direction = direction;
+  }
+
+  public Boolean getActive() {
+    return active;
+  }
+
+  public void setActive(Boolean active) {
+    this.active = active;
+  }
+
+  @Override
+  public String toString() {
+    return super.toString() + "," + getActive() + "," + getDirection();
+  }
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java b/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java
index bc5e5dba08c7250e48850868b56e480021de61b1..d5aba762cb692d4f3db40571f07f0a586eca8ac5 100644
--- a/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java
+++ b/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementType.java
@@ -1,277 +1,302 @@
-package lcsb.mapviewer.model.user;
-
-/**
- * This enumerate defines all possible configuration parameter that are
- * configurable by the user.
- * 
- * @author Piotr Gawron
- * 
- */
-public enum ConfigurationElementType {
-
-  /**
-   * Email address used for sending email from the system.
-   */
-  EMAIL_ADDRESS("E-mail address", "your.account@domain.com", ConfigurationElementEditType.EMAIL, true,
-      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
-
-  /**
-   * Login for the email account.
-   */
-  EMAIL_LOGIN("E-mail server login", "your@login", ConfigurationElementEditType.STRING, true,
-      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
-
-  /**
-   * Password for the email account.
-   */
-  EMAIL_PASSWORD("E-mail server password", "email.secret.password", ConfigurationElementEditType.PASSWORD, true,
-      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
-
-  /**
-   * Address of the IMAP server.
-   */
-  EMAIL_IMAP_SERVER("IMAP server", "your.imap.domain.com", ConfigurationElementEditType.STRING, true,
-      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
-
-  /**
-   * Address of the SMTP server.
-   */
-  EMAIL_SMTP_SERVER("SMTP server", "your.smtp.domain.com", ConfigurationElementEditType.STRING, true,
-      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
-
-  /**
-   * Port used for SMTP connection (sending e-mails).
-   */
-  EMAIL_SMTP_PORT("SMTP port", "25", ConfigurationElementEditType.INTEGER, true,
-      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
-
-  /**
-   * Default map that should be presented if no map is selected by user side.
-   */
-  DEFAULT_MAP("Default Project Id", "empty", ConfigurationElementEditType.STRING, false,
-      ConfigurationElementTypeGroup.SERVER_CONFIGURATION), //
-
-  /**
-   * Logo presented in the system.
-   */
-  LOGO_IMG("Logo icon", "udl.png", ConfigurationElementEditType.URL, false,
-      ConfigurationElementTypeGroup.LEGEND_AND_LOGO), //
-
-  /**
-   * Address connected to the logo.
-   */
-  LOGO_LINK("Logo link (after click)", "http://wwwen.uni.lu/", ConfigurationElementEditType.URL, false,
-      ConfigurationElementTypeGroup.LEGEND_AND_LOGO), //
-
-  /**
-   * Maximum distance (in pixels) that is allowed during finding closest element
-   * on the map.
-   */
-  SEARCH_DISTANCE("Max distance for clicking on element (px)", "10", ConfigurationElementEditType.DOUBLE, false,
-      ConfigurationElementTypeGroup.POINT_AND_CLICK),
-
-  /**
-   * Email used for requesting an account (in client side).
-   */
-  REQUEST_ACCOUNT_EMAIL("Email used for requesting an account", "your.email@domain.com",
-      ConfigurationElementEditType.EMAIL, false, ConfigurationElementTypeGroup.EMAIL_NOTIFICATION),
-
-  /**
-   * Max number of results in search box.
-   */
-  SEARCH_RESULT_NUMBER("Max number of results (this value indicates the max number of elements that will be returned from search - not the number of aggregated elements in the search box).", "100", ConfigurationElementEditType.INTEGER, false,
-      ConfigurationElementTypeGroup.POINT_AND_CLICK),
-
-  /**
-   * Google Analytics tracking ID used for statistics. This tracking ID should
-   * look like "UA-000000-01". More information about tracking ID can be found
-   * <a href="https://support.google.com/analytics/answer/1032385?hl=en"> here
-   * </a>.
-   */
-  GOOGLE_ANALYTICS_IDENTIFIER("Google Analytics tracking ID used for statistics", "",
-      ConfigurationElementEditType.STRING, false, ConfigurationElementTypeGroup.SERVER_CONFIGURATION),
-
-  /**
-   * Description of the logo presented in the system.
-   */
-  LOGO_TEXT("Logo description", "University of Luxembourg", ConfigurationElementEditType.STRING, false,
-      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
-
-  /**
-   * Domain allowed to connect via x-frame technology.
-   */
-  X_FRAME_DOMAIN("Domain allowed to connect via x-frame technology", "", ConfigurationElementEditType.URL, false,
-      ConfigurationElementTypeGroup.SERVER_CONFIGURATION),
-
-  /**
-   * Relative directory (in webapps folder) where big files will be stored.
-   */
-  BIG_FILE_STORAGE_DIR("Path to store big files", "minerva-big/", ConfigurationElementEditType.STRING, false,
-      ConfigurationElementTypeGroup.SERVER_CONFIGURATION),
-
-  /**
-   * File where legend 1/4 is stored.
-   */
-  LEGEND_FILE_1("Legend 1 image file", "resources/images/legend_a.png", ConfigurationElementEditType.URL, false,
-      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
-
-  /**
-   * File where legend 2/4 is stored.
-   */
-  LEGEND_FILE_2("Legend 2 image file", "resources/images/legend_b.png", ConfigurationElementEditType.URL, false,
-      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
-
-  /**
-   * File where legend 3/4 is stored.
-   */
-  LEGEND_FILE_3("Legend 3 image file", "resources/images/legend_c.png", ConfigurationElementEditType.URL, false,
-      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
-
-  /**
-   * File where legend 4/4 is stored.
-   */
-  LEGEND_FILE_4("Legend 4 image file", "resources/images/legend_d.png", ConfigurationElementEditType.URL, false,
-      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
-
-  /**
-   * File where legend 4/4 is stored.
-   */
-  USER_MANUAL_FILE("User manual file", "resources/other/user_guide.pdf", ConfigurationElementEditType.URL, false,
-      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
-
-  /**
-   * Color used for negative overlay values.
-   */
-  MIN_COLOR_VAL("Overlay color for negative values", "FF0000", ConfigurationElementEditType.COLOR, false,
-      ConfigurationElementTypeGroup.OVERLAYS),
-
-  /**
-   * Color used for positive overlay values.
-   */
-  MAX_COLOR_VAL("Overlay color for postive values", "0000FF", ConfigurationElementEditType.COLOR, false,
-      ConfigurationElementTypeGroup.OVERLAYS),
-
-  /**
-   * Color used for undefined overlay values.
-   */
-  SIMPLE_COLOR_VAL("Overlay color when no values are defined", "00FF00", ConfigurationElementEditType.COLOR, false,
-      ConfigurationElementTypeGroup.OVERLAYS),
-
-  /**
-   * Color used for 0 overlay value.
-   */
-  NEUTRAL_COLOR_VAL("Overlay color for value=0", "FFFFFF", ConfigurationElementEditType.COLOR, false,
-      ConfigurationElementTypeGroup.OVERLAYS),
-
-  /**
-   * Opacity of data overlay objects in the frontend.
-   */
-  OVERLAY_OPACITY("Opacity used when drwaing data overlays (value between 0.0-1.0)", "0.8",
-      ConfigurationElementEditType.DOUBLE, false, ConfigurationElementTypeGroup.OVERLAYS),
-
-  /**
-   * Default content of the email when requesting for an account in the system.
-   */
-  REQUEST_ACCOUNT_DEFAULT_CONTENT("Email content used for requesting an account",
-      "Dear Disease map team,\nI would like to request an account in the system.\nKind regards",
-      ConfigurationElementEditType.TEXT, false, ConfigurationElementTypeGroup.EMAIL_NOTIFICATION),
-
-  DEFAULT_VIEW_PROJECT("Default user privilege for: " + PrivilegeType.VIEW_PROJECT.getCommonName(), "true",
-      ConfigurationElementEditType.BOOLEAN, true, ConfigurationElementTypeGroup.DEFAULT_USER_PRIVILEGES),
-
-  DEFAULT_EDIT_COMMENTS_PROJECT("Default user privilege for: " + PrivilegeType.EDIT_COMMENTS_PROJECT.getCommonName(),
-      "false", ConfigurationElementEditType.BOOLEAN, true, ConfigurationElementTypeGroup.DEFAULT_USER_PRIVILEGES),
-
-  DEFAULT_LAYOUT_MANAGEMENT("Default user privilege for: " + PrivilegeType.LAYOUT_MANAGEMENT.getCommonName(), "false",
-      ConfigurationElementEditType.BOOLEAN, true, ConfigurationElementTypeGroup.DEFAULT_USER_PRIVILEGES),
-
-  SHOW_REACTION_TYPE("Show reaction type when browsing map", "true",
-      ConfigurationElementEditType.BOOLEAN, false, ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
-
-  GOOGLE_MAPS_API_KEY("By providing this Google Maps Platform API key I declare that I am aware that "
-      + "I am a Customer of the Google Maps Platform and I agree to the terms of the <a href=\"https://cloud.google.com/maps-platform/terms/\"  target='_blank'>license of Google Maps Platform</a>." +
-      "In particular, I warrant that neither any of the maps nor publicly available data overlays "
-      + "(\"General overlays\") on this MINERVA server contain Protected Health Information (as defined in and subject to HIPAA).",
-      "", ConfigurationElementEditType.STRING, false, ConfigurationElementTypeGroup.SERVER_CONFIGURATION),
-
-  /**
-   * Terms of use.
-   */
-  TERMS_OF_USE("URL of platform Terms of Use file", "", ConfigurationElementEditType.URL, false, ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
-
-  ;
-
-  /**
-   * Default value of the configuration parameter (it will be used only when value
-   * doesn't exist in the DAO).
-   */
-  private String defaultValue = "";
-
-  /**
-   * Common name used for visualization (query user).
-   */
-  private String commonName = "";
-
-  /**
-   * How we want to edit specific parameter.
-   */
-  private ConfigurationElementEditType editType = null;
-
-  private boolean serverSide = true;
-  private ConfigurationElementTypeGroup group = null;
-
-  /**
-   * Default constructor.
-   *
-   * @param commonName
-   *          common name used for this parameter
-   * @param editType
-   *          type defining how we want to edit this configuration parameter
-   * @param defaultVal
-   *          default value assigned to this parameter
-   */
-  ConfigurationElementType(String commonName, String defaultVal, ConfigurationElementEditType editType,
-      boolean serverSide, ConfigurationElementTypeGroup group) {
-    this.defaultValue = defaultVal;
-    this.commonName = commonName;
-    this.editType = editType;
-    this.serverSide = serverSide;
-    this.group = group;
-  }
-
-  /**
-   * @return the defaultValue
-   * @see #defaultValue
-   */
-  public String getDefaultValue() {
-    return defaultValue;
-  }
-
-  /**
-   * @return the commonName
-   * @see #commonName
-   */
-  public String getCommonName() {
-    return commonName;
-  }
-
-  /**
-   * @return the editType
-   * @see #editType
-   */
-  public ConfigurationElementEditType getEditType() {
-    return editType;
-  }
-
-  /**
-   * @return the serverSide
-   * @see #serverSide
-   */
-  public boolean isServerSide() {
-    return serverSide;
-  }
-
-  public ConfigurationElementTypeGroup getGroup() {
-    return group;
-  }
-}
+package lcsb.mapviewer.model.user;
+
+/**
+ * This enumerate defines all possible configuration parameter that are
+ * configurable by the user.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public enum ConfigurationElementType {
+
+  /**
+   * Email address used for sending email from the system.
+   */
+  EMAIL_ADDRESS("E-mail address", "your.account@domain.com", ConfigurationElementEditType.EMAIL, true,
+      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
+
+  /**
+   * Login for the email account.
+   */
+  EMAIL_LOGIN("E-mail server login", "your@login", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
+
+  /**
+   * Password for the email account.
+   */
+  EMAIL_PASSWORD("E-mail server password", "email.secret.password", ConfigurationElementEditType.PASSWORD, true,
+      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
+
+  /**
+   * Address of the IMAP server.
+   */
+  EMAIL_IMAP_SERVER("IMAP server", "your.imap.domain.com", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
+
+  /**
+   * Address of the SMTP server.
+   */
+  EMAIL_SMTP_SERVER("SMTP server", "your.smtp.domain.com", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
+
+  /**
+   * Port used for SMTP connection (sending e-mails).
+   */
+  EMAIL_SMTP_PORT("SMTP port", "25", ConfigurationElementEditType.INTEGER, true,
+      ConfigurationElementTypeGroup.EMAIL_NOTIFICATION), //
+
+  /**
+   * Default map that should be presented if no map is selected by user side.
+   */
+  DEFAULT_MAP("Default Project Id", "empty", ConfigurationElementEditType.STRING, false,
+      ConfigurationElementTypeGroup.SERVER_CONFIGURATION), //
+
+  /**
+   * Logo presented in the system.
+   */
+  LOGO_IMG("Logo icon", "udl.png", ConfigurationElementEditType.URL, false,
+      ConfigurationElementTypeGroup.LEGEND_AND_LOGO), //
+
+  /**
+   * Address connected to the logo.
+   */
+  LOGO_LINK("Logo link (after click)", "http://wwwen.uni.lu/", ConfigurationElementEditType.URL, false,
+      ConfigurationElementTypeGroup.LEGEND_AND_LOGO), //
+
+  /**
+   * Maximum distance (in pixels) that is allowed during finding closest element
+   * on the map.
+   */
+  SEARCH_DISTANCE("Max distance for clicking on element (px)", "10", ConfigurationElementEditType.DOUBLE, false,
+      ConfigurationElementTypeGroup.POINT_AND_CLICK),
+
+  /**
+   * Email used for requesting an account (in client side).
+   */
+  REQUEST_ACCOUNT_EMAIL("Email used for requesting an account", "your.email@domain.com",
+      ConfigurationElementEditType.EMAIL, false, ConfigurationElementTypeGroup.EMAIL_NOTIFICATION),
+
+  /**
+   * Max number of results in search box.
+   */
+  SEARCH_RESULT_NUMBER(
+      "Max number of results (this value indicates the max number of elements that will be returned from search - not the number of aggregated elements in the search box).",
+      "100", ConfigurationElementEditType.INTEGER, false, ConfigurationElementTypeGroup.POINT_AND_CLICK),
+
+  /**
+   * Google Analytics tracking ID used for statistics. This tracking ID should
+   * look like "UA-000000-01". More information about tracking ID can be found
+   * <a href="https://support.google.com/analytics/answer/1032385?hl=en"> here
+   * </a>.
+   */
+  GOOGLE_ANALYTICS_IDENTIFIER("Google Analytics tracking ID used for statistics", "",
+      ConfigurationElementEditType.STRING, false, ConfigurationElementTypeGroup.SERVER_CONFIGURATION),
+
+  /**
+   * Description of the logo presented in the system.
+   */
+  LOGO_TEXT("Logo description", "University of Luxembourg", ConfigurationElementEditType.STRING, false,
+      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
+
+  /**
+   * Domain allowed to connect via x-frame technology.
+   */
+  X_FRAME_DOMAIN("Domain allowed to connect via x-frame technology", "", ConfigurationElementEditType.URL, false,
+      ConfigurationElementTypeGroup.SERVER_CONFIGURATION),
+
+  /**
+   * Relative directory (in webapps folder) where big files will be stored.
+   */
+  BIG_FILE_STORAGE_DIR("Path to store big files", "minerva-big/", ConfigurationElementEditType.STRING, false,
+      ConfigurationElementTypeGroup.SERVER_CONFIGURATION),
+
+  /**
+   * File where legend 1/4 is stored.
+   */
+  LEGEND_FILE_1("Legend 1 image file", "resources/images/legend_a.png", ConfigurationElementEditType.URL, false,
+      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
+
+  /**
+   * File where legend 2/4 is stored.
+   */
+  LEGEND_FILE_2("Legend 2 image file", "resources/images/legend_b.png", ConfigurationElementEditType.URL, false,
+      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
+
+  /**
+   * File where legend 3/4 is stored.
+   */
+  LEGEND_FILE_3("Legend 3 image file", "resources/images/legend_c.png", ConfigurationElementEditType.URL, false,
+      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
+
+  /**
+   * File where legend 4/4 is stored.
+   */
+  LEGEND_FILE_4("Legend 4 image file", "resources/images/legend_d.png", ConfigurationElementEditType.URL, false,
+      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
+
+  /**
+   * File where legend 4/4 is stored.
+   */
+  USER_MANUAL_FILE("User manual file", "resources/other/user_guide.pdf", ConfigurationElementEditType.URL, false,
+      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
+
+  /**
+   * Color used for negative overlay values.
+   */
+  MIN_COLOR_VAL("Overlay color for negative values", "FF0000", ConfigurationElementEditType.COLOR, false,
+      ConfigurationElementTypeGroup.OVERLAYS),
+
+  /**
+   * Color used for positive overlay values.
+   */
+  MAX_COLOR_VAL("Overlay color for postive values", "0000FF", ConfigurationElementEditType.COLOR, false,
+      ConfigurationElementTypeGroup.OVERLAYS),
+
+  /**
+   * Color used for undefined overlay values.
+   */
+  SIMPLE_COLOR_VAL("Overlay color when no values are defined", "00FF00", ConfigurationElementEditType.COLOR, false,
+      ConfigurationElementTypeGroup.OVERLAYS),
+
+  /**
+   * Color used for 0 overlay value.
+   */
+  NEUTRAL_COLOR_VAL("Overlay color for value=0", "FFFFFF", ConfigurationElementEditType.COLOR, false,
+      ConfigurationElementTypeGroup.OVERLAYS),
+
+  /**
+   * Opacity of data overlay objects in the frontend.
+   */
+  OVERLAY_OPACITY("Opacity used when drwaing data overlays (value between 0.0-1.0)", "0.8",
+      ConfigurationElementEditType.DOUBLE, false, ConfigurationElementTypeGroup.OVERLAYS),
+
+  /**
+   * Default content of the email when requesting for an account in the system.
+   */
+  REQUEST_ACCOUNT_DEFAULT_CONTENT("Email content used for requesting an account",
+      "Dear Disease map team,\nI would like to request an account in the system.\nKind regards",
+      ConfigurationElementEditType.TEXT, false, ConfigurationElementTypeGroup.EMAIL_NOTIFICATION),
+
+  DEFAULT_VIEW_PROJECT("Default user privilege for: " + PrivilegeType.VIEW_PROJECT.getCommonName(), "true",
+      ConfigurationElementEditType.BOOLEAN, true, ConfigurationElementTypeGroup.DEFAULT_USER_PRIVILEGES),
+
+  DEFAULT_EDIT_COMMENTS_PROJECT("Default user privilege for: " + PrivilegeType.EDIT_COMMENTS_PROJECT.getCommonName(),
+      "false", ConfigurationElementEditType.BOOLEAN, true, ConfigurationElementTypeGroup.DEFAULT_USER_PRIVILEGES),
+
+  DEFAULT_LAYOUT_MANAGEMENT("Default user privilege for: " + PrivilegeType.LAYOUT_MANAGEMENT.getCommonName(), "false",
+      ConfigurationElementEditType.BOOLEAN, true, ConfigurationElementTypeGroup.DEFAULT_USER_PRIVILEGES),
+
+  SHOW_REACTION_TYPE("Show reaction type when browsing map", "true", ConfigurationElementEditType.BOOLEAN, false,
+      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
+
+  GOOGLE_MAPS_API_KEY("By providing this Google Maps Platform API key I declare that I am aware that "
+      + "I am a Customer of the Google Maps Platform and I agree to the terms of the <a href=\"https://cloud.google.com/maps-platform/terms/\"  target='_blank'>license of Google Maps Platform</a>."
+      + "In particular, I warrant that neither any of the maps nor publicly available data overlays "
+      + "(\"General overlays\") on this MINERVA server contain Protected Health Information (as defined in and subject to HIPAA).",
+      "", ConfigurationElementEditType.STRING, false, ConfigurationElementTypeGroup.SERVER_CONFIGURATION),
+
+  /**
+   * Terms of use.
+   */
+  TERMS_OF_USE("URL of platform Terms of Use file", "", ConfigurationElementEditType.URL, false,
+      ConfigurationElementTypeGroup.LEGEND_AND_LOGO),
+
+  LDAP_ADDRESS("LDAP address", "", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
+  LDAP_PORT("LDAP port", "389", ConfigurationElementEditType.INTEGER, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
+  LDAP_SSL("LDAP uses SSL", "false", ConfigurationElementEditType.BOOLEAN, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
+  LDAP_BIND_DN("LDAP bind DN", "", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
+  LDAP_PASSWORD("LDAP password", "", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
+  LDAP_BASE_DN("LDAP base DN", "", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
+  LDAP_OBJECT_CLASS("LDAP filter objectClass", "*", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
+  LDAP_FIRST_NAME_ATTRIBUTE("LDAP first name attribute", "givenName", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
+  LDAP_LAST_NAME_ATTRIBUTE("LDAP last name attribute", "sn", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
+  LDAP_EMAIL_ATTRIBUTE("LDAP email attribute", "mail", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION),//
+  LDAP_FILTER("LDAP filter ", "(memberof=cn=minerva,cn=groups,cn=accounts,dc=uni,dc=lu)", ConfigurationElementEditType.STRING, true,
+      ConfigurationElementTypeGroup.LDAP_CONFIGURATION), //
+
+  ;
+
+  /**
+   * Default value of the configuration parameter (it will be used only when value
+   * doesn't exist in the DAO).
+   */
+  private String defaultValue = "";
+
+  /**
+   * Common name used for visualization (query user).
+   */
+  private String commonName = "";
+
+  /**
+   * How we want to edit specific parameter.
+   */
+  private ConfigurationElementEditType editType = null;
+
+  private boolean serverSide = true;
+  private ConfigurationElementTypeGroup group = null;
+
+  /**
+   * Default constructor.
+   *
+   * @param commonName
+   *          common name used for this parameter
+   * @param editType
+   *          type defining how we want to edit this configuration parameter
+   * @param defaultVal
+   *          default value assigned to this parameter
+   */
+  ConfigurationElementType(String commonName, String defaultVal, ConfigurationElementEditType editType,
+      boolean serverSide, ConfigurationElementTypeGroup group) {
+    this.defaultValue = defaultVal;
+    this.commonName = commonName;
+    this.editType = editType;
+    this.serverSide = serverSide;
+    this.group = group;
+  }
+
+  /**
+   * @return the defaultValue
+   * @see #defaultValue
+   */
+  public String getDefaultValue() {
+    return defaultValue;
+  }
+
+  /**
+   * @return the commonName
+   * @see #commonName
+   */
+  public String getCommonName() {
+    return commonName;
+  }
+
+  /**
+   * @return the editType
+   * @see #editType
+   */
+  public ConfigurationElementEditType getEditType() {
+    return editType;
+  }
+
+  /**
+   * @return the serverSide
+   * @see #serverSide
+   */
+  public boolean isServerSide() {
+    return serverSide;
+  }
+
+  public ConfigurationElementTypeGroup getGroup() {
+    return group;
+  }
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementTypeGroup.java b/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementTypeGroup.java
index baa88ee2973d221024b8e8ed3780fa01c87745b3..6ca381ccc848f511f60eb71cef88e54ea648a14c 100644
--- a/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementTypeGroup.java
+++ b/model/src/main/java/lcsb/mapviewer/model/user/ConfigurationElementTypeGroup.java
@@ -7,6 +7,7 @@ public enum ConfigurationElementTypeGroup {
   OVERLAYS("Overlays"), //
   POINT_AND_CLICK("Point and click"), //
   SERVER_CONFIGURATION("Server configuration"),//
+  LDAP_CONFIGURATION("LDAP configuration"),//
 
   ;
   private String commonName;
diff --git a/model/src/main/java/lcsb/mapviewer/model/user/User.java b/model/src/main/java/lcsb/mapviewer/model/user/User.java
index fdb5e080a10f840dda1a19bc7330acf051c72602..1add1fd25fd0f31d5ee946814b9f0b82b54f7c62 100644
--- a/model/src/main/java/lcsb/mapviewer/model/user/User.java
+++ b/model/src/main/java/lcsb/mapviewer/model/user/User.java
@@ -118,8 +118,13 @@ public class User implements Serializable {
    */
   private boolean removed = false;
 
-    @Column(name="terms_of_use_consent")
-    private boolean                     termsOfUseConsent = false;
+  /**
+   * User is connected to LDAP directory.
+   */
+  private boolean connectedToLdap = false;
+
+  @Column(name = "terms_of_use_consent")
+  private boolean termsOfUseConsent = false;
 
   /**
    * Set of user privileges.
@@ -378,4 +383,12 @@ public class User implements Serializable {
     this.termsOfUseConsent = termsOfUseConsent;
   }
 
+  public boolean isConnectedToLdap() {
+    return connectedToLdap;
+  }
+
+  public void setConnectedToLdap(boolean connectedToLdap) {
+    this.connectedToLdap = connectedToLdap;
+  }
+
 }
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/AntisenseRnaComparatorTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/AntisenseRnaComparatorTest.java
index 690e5c3e23d2e03934ca30e16ceeedd2feede7bd..c601f66be96c713282958e1b5413a23e8d66d9fa 100644
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/AntisenseRnaComparatorTest.java
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/AntisenseRnaComparatorTest.java
@@ -4,14 +4,15 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.awt.geom.Point2D;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
 
 import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegionType;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
 
 public class AntisenseRnaComparatorTest {
 
@@ -77,13 +78,12 @@ public class AntisenseRnaComparatorTest {
   public AntisenseRna createAntisenseRna() {
     AntisenseRna result = new AntisenseRna();
 
-    AntisenseRnaRegion region1 = new AntisenseRnaRegion();
+    CodingRegion region1 = new CodingRegion();
     result.addRegion(region1);
-    region1.setIdAntisenseRnaRegion("a");
+    region1.setIdModificationResidue("a");
     region1.setName("name");
-    region1.setPos("1");
-    region1.setSize("2");
-    region1.setType(AntisenseRnaRegionType.CODING_REGION);
+    region1.setPosition(new Point2D.Double(0, 1));
+    region1.setWidth(2);
     return result;
   }
 
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/AntisenseRnaTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/AntisenseRnaTest.java
index a6c6ec3bfb23423caa372d4515fdf251d876711f..f52284cd4f8e1d5ba73d85d9854e48c779c6c85b 100644
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/AntisenseRnaTest.java
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/AntisenseRnaTest.java
@@ -1,93 +1,94 @@
-package lcsb.mapviewer.model.map.species;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
-
-public class AntisenseRnaTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new AntisenseRna());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor1() {
-		try {
-			AntisenseRna original = new AntisenseRna();
-			original.addRegion(new AntisenseRnaRegion());
-			AntisenseRna aRna = new AntisenseRna(original);
-			assertNotNull(aRna);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			AntisenseRna aRna = new AntisenseRna("id");
-			assertNotNull(aRna.getStringType());
-
-			List<AntisenseRnaRegion> regions = new ArrayList<>();
-
-			aRna.setRegions(regions);
-
-			assertEquals(regions, aRna.getRegions());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCopy() {
-		try {
-			AntisenseRna aRna = new AntisenseRna().copy();
-			assertNotNull(aRna);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		try {
-			AntisenseRna element = Mockito.spy(AntisenseRna.class);
-			element.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.model.map.species;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+public class AntisenseRnaTest {
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testSerialization() {
+    try {
+      SerializationUtils.serialize(new AntisenseRna());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor1() {
+    try {
+      AntisenseRna original = new AntisenseRna();
+      original.addRegion(new CodingRegion());
+      AntisenseRna aRna = new AntisenseRna(original);
+      assertNotNull(aRna);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetters() {
+    try {
+      AntisenseRna aRna = new AntisenseRna("id");
+      assertNotNull(aRna.getStringType());
+
+      List<ModificationResidue> regions = new ArrayList<>();
+
+      aRna.setRegions(regions);
+
+      assertEquals(regions, aRna.getRegions());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCopy() {
+    try {
+      AntisenseRna aRna = new AntisenseRna().copy();
+      assertNotNull(aRna);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidCopy() {
+    try {
+      AntisenseRna element = Mockito.spy(AntisenseRna.class);
+      element.copy();
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/GeneComparatorTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/GeneComparatorTest.java
index 5d41302f56152bf90f730b765d50726423ca4301..95104c0be61d61a9a7db9307787413c0661fabc1 100644
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/GeneComparatorTest.java
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/GeneComparatorTest.java
@@ -1,110 +1,112 @@
-package lcsb.mapviewer.model.map.species;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-public class GeneComparatorTest {
-
-	GeneComparator comparator = new GeneComparator();
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testEquals() {
-		try {
-			Gene gene1 = createGene();
-			Gene gene2 = createGene();
-
-			assertEquals(0, comparator.compare(gene1, gene1));
-
-			assertEquals(0, comparator.compare(gene1, gene2));
-			assertEquals(0, comparator.compare(gene2, gene1));
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			fail("Unknowne exception occurred");
-		}
-	}
-
-	@Test
-	public void testDifferent() {
-		try {
-			Gene gene1 = createGene();
-			Gene gene2 = createGene();
-			gene1.getModificationResidues().get(0).setName("bla");
-			assertTrue(comparator.compare(gene1, gene2) != 0);
-			assertTrue(comparator.compare(gene2, gene1) != 0);
-
-			gene1 = createGene();
-			gene2 = createGene();
-			gene1.getModificationResidues().clear();
-			assertTrue(comparator.compare(gene1, gene2) != 0);
-			assertTrue(comparator.compare(gene2, gene1) != 0);
-
-			gene1 = createGene();
-			gene2 = createGene();
-			assertTrue(comparator.compare(null, gene2) != 0);
-			assertTrue(comparator.compare(gene2, null) != 0);
-			assertTrue(comparator.compare(null, null) == 0);
-
-			Gene gene = createGene();
-			gene.setName("n");
-			assertTrue(comparator.compare(gene, gene2) != 0);
-
-			assertTrue(comparator.compare(gene, Mockito.mock(Gene.class)) != 0);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			fail("Unknowne exception occurred");
-		}
-	}
-
-	public Gene createGene() {
-		Gene result = new Gene();
-		result.setHypothetical(true);
-
-		ModificationResidue residue = new ModificationResidue();
-		result.addModificationResidue(residue);
-
-		residue.setIdModificationResidue("a");
-		residue.setName("name");
-		residue.setAngle(1.0);
-		residue.setSize(2.0);
-		residue.setSide("23");
-		residue.setState(ModificationState.ACETYLATED);
-		return result;
-	}
-
-	@Test
-	public void testInvalid() {
-		try {
-			Gene object = Mockito.mock(Gene.class);
-
-			comparator.compare(object, object);
-
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			fail("Unknowne exception occurred");
-		}
-	}
-
-}
+package lcsb.mapviewer.model.map.species;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.awt.geom.Point2D;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.field.AbstractSiteModification;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+
+public class GeneComparatorTest {
+
+  GeneComparator comparator = new GeneComparator();
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testEquals() {
+    try {
+      Gene gene1 = createGene();
+      Gene gene2 = createGene();
+
+      assertEquals(0, comparator.compare(gene1, gene1));
+
+      assertEquals(0, comparator.compare(gene1, gene2));
+      assertEquals(0, comparator.compare(gene2, gene1));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail("Unknowne exception occurred");
+    }
+  }
+
+  @Test
+  public void testDifferent() {
+    try {
+      Gene gene1 = createGene();
+      Gene gene2 = createGene();
+      gene1.getModificationResidues().get(0).setName("bla");
+      assertTrue(comparator.compare(gene1, gene2) != 0);
+      assertTrue(comparator.compare(gene2, gene1) != 0);
+
+      gene1 = createGene();
+      gene2 = createGene();
+      gene1.getModificationResidues().clear();
+      assertTrue(comparator.compare(gene1, gene2) != 0);
+      assertTrue(comparator.compare(gene2, gene1) != 0);
+
+      gene1 = createGene();
+      gene2 = createGene();
+      assertTrue(comparator.compare(null, gene2) != 0);
+      assertTrue(comparator.compare(gene2, null) != 0);
+      assertTrue(comparator.compare(null, null) == 0);
+
+      Gene gene = createGene();
+      gene.setName("n");
+      assertTrue(comparator.compare(gene, gene2) != 0);
+
+      assertTrue(comparator.compare(gene, Mockito.mock(Gene.class)) != 0);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail("Unknowne exception occurred");
+    }
+  }
+
+  public Gene createGene() {
+    Gene result = new Gene();
+    result.setHypothetical(true);
+
+    AbstractSiteModification residue = new ModificationSite();
+    result.addModificationResidue(residue);
+
+    residue.setIdModificationResidue("a");
+    residue.setName("name");
+    residue.setPosition(new Point2D.Double(10, 20));
+    residue.setState(ModificationState.ACETYLATED);
+    return result;
+  }
+
+  @Test
+  public void testInvalid() {
+    try {
+      Gene object = Mockito.mock(Gene.class);
+
+      comparator.compare(object, object);
+
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail("Unknowne exception occurred");
+    }
+  }
+
+}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/GeneTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/GeneTest.java
index ec7c48dcd1948de83831f7f46b5f41332b7af6aa..5dd200337e5c9606ec99b7c20c0d4aca07f77c9d 100644
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/GeneTest.java
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/GeneTest.java
@@ -1,90 +1,91 @@
-package lcsb.mapviewer.model.map.species;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-
-public class GeneTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new Gene());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor1() {
-		try {
-			Gene original = new Gene();
-			original.addModificationResidue(new ModificationResidue());
-			Gene gene = new Gene(original);
-			assertNotNull(gene);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			List<ModificationResidue> modificationResidues = new ArrayList<>();
-			Gene gene = new Gene("id");
-			assertNotNull(gene.getStringType());
-			gene.setModificationResidues(modificationResidues);
-			assertEquals(modificationResidues, gene.getModificationResidues());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCopy() {
-		try {
-			Gene degraded = new Gene().copy();
-			assertNotNull(degraded);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		try {
-			Gene gene = Mockito.spy(Gene.class);
-			gene.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.model.map.species;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+
+public class GeneTest {
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testSerialization() {
+    try {
+      SerializationUtils.serialize(new Gene());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor1() {
+    try {
+      Gene original = new Gene();
+      original.addModificationResidue(new ModificationSite());
+      Gene gene = new Gene(original);
+      assertNotNull(gene);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetters() {
+    try {
+      List<ModificationResidue> modificationResidues = new ArrayList<>();
+      Gene gene = new Gene("id");
+      assertNotNull(gene.getStringType());
+      gene.setModificationResidues(modificationResidues);
+      assertEquals(modificationResidues, gene.getModificationResidues());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCopy() {
+    try {
+      Gene degraded = new Gene().copy();
+      assertNotNull(degraded);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidCopy() {
+    try {
+      Gene gene = Mockito.spy(Gene.class);
+      gene.copy();
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinComparatorTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinComparatorTest.java
index 177a924e8376767b092d0b42bcd0d659ce06b228..e07e6d0e81ea684b57e326e9463dc66c13aed0b5 100644
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinComparatorTest.java
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinComparatorTest.java
@@ -1,136 +1,138 @@
-package lcsb.mapviewer.model.map.species;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-
-public class ProteinComparatorTest {
-
-	ProteinComparator comparator = new ProteinComparator();
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testEquals() {
-		try {
-			GenericProtein protein1 = createProtein();
-			GenericProtein protein2 = createProtein();
-
-			assertEquals(0, comparator.compare(protein1, protein1));
-
-			assertEquals(0, comparator.compare(protein1, protein2));
-			assertEquals(0, comparator.compare(protein2, protein1));
-
-			assertEquals(0, comparator.compare(null, null));
-
-			assertEquals(0, comparator.compare(new TruncatedProtein(), new TruncatedProtein()));
-			assertEquals(0, comparator.compare(new ReceptorProtein(), new ReceptorProtein()));
-			assertEquals(0, comparator.compare(new IonChannelProtein(), new IonChannelProtein()));
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUnknownProteinImplementations() {
-		try {
-			Protein protein1 = Mockito.mock(Protein.class);
-			assertEquals(0, comparator.compare(protein1, protein1));
-
-			fail("Exception expected");
-
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testDifferent() {
-		try {
-			GenericProtein protein1 = createProtein();
-			GenericProtein protein2 = createProtein();
-			assertTrue(comparator.compare(null, protein2) != 0);
-			assertTrue(comparator.compare(protein2, null) != 0);
-
-			protein1.getModificationResidues().get(0).setName("bla");
-			assertTrue(comparator.compare(protein1, protein2) != 0);
-			assertTrue(comparator.compare(protein2, protein1) != 0);
-
-			protein1 = createProtein();
-			protein2 = createProtein();
-			protein1.getModificationResidues().clear();
-			assertTrue(comparator.compare(protein1, protein2) != 0);
-			assertTrue(comparator.compare(protein2, protein1) != 0);
-
-			protein1 = createProtein();
-			protein2 = createProtein();
-			assertTrue(comparator.compare(null, protein2) != 0);
-			assertTrue(comparator.compare(protein2, null) != 0);
-			assertTrue(comparator.compare(null, null) == 0);
-
-			assertTrue(comparator.compare(protein2, new GenericProtein()) != 0);
-
-			protein1 = createProtein();
-			protein2 = createProtein();
-			protein1.setName("a");
-			assertTrue(comparator.compare(protein1, protein2) != 0);
-			assertTrue(comparator.compare(protein2, protein1) != 0);
-
-			protein1 = createProtein();
-			protein2 = createProtein();
-			protein1.setStructuralState("a");
-			assertTrue(comparator.compare(protein1, protein2) != 0);
-			assertTrue(comparator.compare(protein2, protein1) != 0);
-
-			protein1 = createProtein();
-			protein2 = createProtein();
-			protein1.setHomodimer(1);
-			assertTrue(comparator.compare(protein1, protein2) != 0);
-			assertTrue(comparator.compare(protein2, protein1) != 0);
-
-			assertTrue(comparator.compare(new GenericProtein(), new TruncatedProtein()) != 0);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			fail("Unknowne exception occurred");
-		}
-	}
-
-	public GenericProtein createProtein() {
-		GenericProtein result = new GenericProtein();
-		result.setHomodimer(12);
-		result.setStructuralState("id1");
-		result.setHypothetical(true);
-
-		ModificationResidue residue = new ModificationResidue();
-		result.addModificationResidue(residue);
-
-		residue.setIdModificationResidue("a");
-		residue.setName("name");
-		residue.setAngle(1.0);
-		residue.setSize(2.0);
-		residue.setSide("23");
-		residue.setState(ModificationState.DONT_CARE);
-		return result;
-	}
-
-}
+package lcsb.mapviewer.model.map.species;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+import lcsb.mapviewer.model.map.species.field.Residue;
+
+public class ProteinComparatorTest {
+  Logger logger=  Logger.getLogger(ProteinComparatorTest.class);
+
+  ProteinComparator comparator = new ProteinComparator();
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testEquals() {
+    try {
+      GenericProtein protein1 = createProtein();
+      GenericProtein protein2 = createProtein();
+
+      assertEquals(0, comparator.compare(protein1, protein1));
+
+      assertEquals(0, comparator.compare(protein1, protein2));
+      assertEquals(0, comparator.compare(protein2, protein1));
+
+      assertEquals(0, comparator.compare(null, null));
+
+      assertEquals(0, comparator.compare(new TruncatedProtein(), new TruncatedProtein()));
+      assertEquals(0, comparator.compare(new ReceptorProtein(), new ReceptorProtein()));
+      assertEquals(0, comparator.compare(new IonChannelProtein(), new IonChannelProtein()));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testUnknownProteinImplementations() {
+    try {
+      Protein protein1 = Mockito.mock(Protein.class);
+      assertEquals(0, comparator.compare(protein1, protein1));
+
+      fail("Exception expected");
+
+    } catch (NotImplementedException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testDifferent() {
+    try {
+      GenericProtein protein1 = createProtein();
+      GenericProtein protein2 = createProtein();
+      assertTrue(comparator.compare(null, protein2) != 0);
+      assertTrue(comparator.compare(protein2, null) != 0);
+
+      protein1.getModificationResidues().get(0).setName("bla");
+      assertTrue(comparator.compare(protein1, protein2) != 0);
+      assertTrue(comparator.compare(protein2, protein1) != 0);
+
+      protein1 = createProtein();
+      protein2 = createProtein();
+      protein1.getModificationResidues().clear();
+      assertTrue(comparator.compare(protein1, protein2) != 0);
+      assertTrue(comparator.compare(protein2, protein1) != 0);
+
+      protein1 = createProtein();
+      protein2 = createProtein();
+      assertTrue(comparator.compare(null, protein2) != 0);
+      assertTrue(comparator.compare(protein2, null) != 0);
+      assertTrue(comparator.compare(null, null) == 0);
+
+      assertTrue(comparator.compare(protein2, new GenericProtein()) != 0);
+
+      protein1 = createProtein();
+      protein2 = createProtein();
+      protein1.setName("a");
+      assertTrue(comparator.compare(protein1, protein2) != 0);
+      assertTrue(comparator.compare(protein2, protein1) != 0);
+
+      protein1 = createProtein();
+      protein2 = createProtein();
+      protein1.setStructuralState("a");
+      assertTrue(comparator.compare(protein1, protein2) != 0);
+      assertTrue(comparator.compare(protein2, protein1) != 0);
+
+      protein1 = createProtein();
+      protein2 = createProtein();
+      protein1.setHomodimer(1);
+      assertTrue(comparator.compare(protein1, protein2) != 0);
+      assertTrue(comparator.compare(protein2, protein1) != 0);
+
+      assertTrue(comparator.compare(new GenericProtein(), new TruncatedProtein()) != 0);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail("Unknowne exception occurred");
+    }
+  }
+
+  public GenericProtein createProtein() {
+    GenericProtein result = new GenericProtein();
+    result.setHomodimer(12);
+    result.setStructuralState("id1");
+    result.setHypothetical(true);
+
+    Residue residue = new Residue();
+    result.addModificationResidue(residue);
+
+    residue.setIdModificationResidue("a");
+    residue.setName("name");
+    residue.setPosition(new Point2D.Double(10, 20));
+    residue.setState(ModificationState.DONT_CARE);
+    return result;
+  }
+
+}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinTest.java
index 0a3a22c3db5bead5e7b859bc3383ec3b2a0dfd2d..6485005ac77f0f3eeab4762ca8ebaec10ad0096b 100644
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinTest.java
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/ProteinTest.java
@@ -1,105 +1,106 @@
-package lcsb.mapviewer.model.map.species;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-
-public class ProteinTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new GenericProtein());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor1() {
-		try {
-			GenericProtein protein = new GenericProtein();
-			protein.setStructuralState("srt");
-			List<ModificationResidue> residues = new ArrayList<>();
-			residues.add(new ModificationResidue());
-
-			protein.setModificationResidues(residues);
-			Protein protein2 = new GenericProtein(protein);
-			assertNotNull(protein2);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testSetStructuralState() {
-		try {
-			GenericProtein protein = new GenericProtein();
-			protein.setStructuralState("str");
-			protein.setStructuralState("str1");
-
-			assertEquals("str1", protein.getStructuralState());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			GenericProtein protein = new GenericProtein("id");
-			assertNotNull(protein.getStringType());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCopy() {
-		try {
-			GenericProtein protein = new GenericProtein().copy();
-			assertNotNull(protein);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		try {
-			GenericProtein mock = Mockito.spy(GenericProtein.class);
-			mock.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.model.map.species;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.Residue;
+
+public class ProteinTest {
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testSerialization() {
+    try {
+      SerializationUtils.serialize(new GenericProtein());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor1() {
+    try {
+      GenericProtein protein = new GenericProtein();
+      protein.setStructuralState("srt");
+      List<ModificationResidue> residues = new ArrayList<>();
+      residues.add(new Residue());
+
+      protein.setModificationResidues(residues);
+      Protein protein2 = new GenericProtein(protein);
+      assertNotNull(protein2);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testSetStructuralState() {
+    try {
+      GenericProtein protein = new GenericProtein();
+      protein.setStructuralState("str");
+      protein.setStructuralState("str1");
+
+      assertEquals("str1", protein.getStructuralState());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetters() {
+    try {
+      GenericProtein protein = new GenericProtein("id");
+      assertNotNull(protein.getStringType());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCopy() {
+    try {
+      GenericProtein protein = new GenericProtein().copy();
+      assertNotNull(protein);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidCopy() {
+    try {
+      GenericProtein mock = Mockito.spy(GenericProtein.class);
+      mock.copy();
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/RnaComparatorTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/RnaComparatorTest.java
index 3ead55dee76b0c53b570b725795334aed2bfa48c..59ec62d18149ad8f01eefbaed3e55a38d7d679be 100644
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/RnaComparatorTest.java
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/RnaComparatorTest.java
@@ -1,108 +1,108 @@
-package lcsb.mapviewer.model.map.species;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
-
-public class RnaComparatorTest {
-
-	RnaComparator comparator = new RnaComparator();
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testEquals() {
-		try {
-			Rna aRna1 = createRna();
-			Rna aRna2 = createRna();
-
-			assertEquals(0, comparator.compare(aRna1, aRna1));
-
-			assertEquals(0, comparator.compare(aRna1, aRna2));
-			assertEquals(0, comparator.compare(aRna2, aRna1));
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			fail("Unknowne exception occurred");
-		}
-	}
-
-	@Test
-	public void testDifferent() {
-		try {
-			Rna aRna1 = createRna();
-			Rna aRna2 = createRna();
-			aRna1.getRegions().get(0).setState(ModificationState.ACETYLATED);
-			assertTrue(comparator.compare(aRna1, aRna2) != 0);
-			assertTrue(comparator.compare(aRna2, aRna1) != 0);
-
-			aRna1 = createRna();
-			aRna2 = createRna();
-			aRna1.getRegions().clear();
-			assertTrue(comparator.compare(aRna1, aRna2) != 0);
-			assertTrue(comparator.compare(aRna2, aRna1) != 0);
-
-			aRna1 = createRna();
-			aRna2 = createRna();
-			assertTrue(comparator.compare(null, aRna2) != 0);
-			assertTrue(comparator.compare(aRna2, null) != 0);
-			assertTrue(comparator.compare(null, null) == 0);
-
-			Rna rna = createRna();
-			rna.setName("n");
-			assertTrue(comparator.compare(rna, aRna2) != 0);
-
-			assertTrue(comparator.compare(rna, Mockito.mock(Rna.class)) != 0);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			fail("Unknowne exception occurred");
-		}
-	}
-
-	public Rna createRna() {
-		Rna result = new Rna();
-		result.setHypothetical(true);
-
-		RnaRegion region1 = new RnaRegion();
-		result.addRegion(region1);
-		region1.setIdRnaRegion("a");
-		region1.setState(ModificationState.DONT_CARE);
-		region1.setPos("1");
-		region1.setSize("2");
-		region1.setType("type");
-		return result;
-	}
-
-	@Test
-	public void testInvalid() {
-		try {
-			Rna object = Mockito.mock(Rna.class);
-
-			comparator.compare(object, object);
-
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			fail("Unknowne exception occurred");
-		}
-	}
-
-}
+package lcsb.mapviewer.model.map.species;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.awt.geom.Point2D;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+
+public class RnaComparatorTest {
+
+  RnaComparator comparator = new RnaComparator();
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testEquals() {
+    try {
+      Rna aRna1 = createRna();
+      Rna aRna2 = createRna();
+
+      assertEquals(0, comparator.compare(aRna1, aRna1));
+
+      assertEquals(0, comparator.compare(aRna1, aRna2));
+      assertEquals(0, comparator.compare(aRna2, aRna1));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail("Unknowne exception occurred");
+    }
+  }
+
+  @Test
+  public void testDifferent() {
+    try {
+      Rna aRna1 = createRna();
+      Rna aRna2 = createRna();
+      aRna1.getRegions().get(0).setName("X");
+      assertTrue(comparator.compare(aRna1, aRna2) != 0);
+      assertTrue(comparator.compare(aRna2, aRna1) != 0);
+
+      aRna1 = createRna();
+      aRna2 = createRna();
+      aRna1.getRegions().clear();
+      assertTrue(comparator.compare(aRna1, aRna2) != 0);
+      assertTrue(comparator.compare(aRna2, aRna1) != 0);
+
+      aRna1 = createRna();
+      aRna2 = createRna();
+      assertTrue(comparator.compare(null, aRna2) != 0);
+      assertTrue(comparator.compare(aRna2, null) != 0);
+      assertTrue(comparator.compare(null, null) == 0);
+
+      Rna rna = createRna();
+      rna.setName("n");
+      assertTrue(comparator.compare(rna, aRna2) != 0);
+
+      assertTrue(comparator.compare(rna, Mockito.mock(Rna.class)) != 0);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail("Unknowne exception occurred");
+    }
+  }
+
+  public Rna createRna() {
+    Rna result = new Rna();
+    result.setHypothetical(true);
+
+    CodingRegion region1 = new CodingRegion();
+    result.addRegion(region1);
+    region1.setIdModificationResidue("a");
+    region1.setPosition(new Point2D.Double(0, 10));
+    region1.setWidth(2.0);
+    return result;
+  }
+
+  @Test
+  public void testInvalid() {
+    try {
+      Rna object = Mockito.mock(Rna.class);
+
+      comparator.compare(object, object);
+
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      fail("Unknowne exception occurred");
+    }
+  }
+
+}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/RnaTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/RnaTest.java
index 6cde518d7d1b34b28ab957e6af989c077ffc3f52..948f46dcb1d15bb69d13a8cf2e4b2f08068e51e8 100644
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/RnaTest.java
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/RnaTest.java
@@ -1,105 +1,106 @@
-package lcsb.mapviewer.model.map.species;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
-
-public class RnaTest {
-	Logger logger = Logger.getLogger(RnaTest.class);
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new Rna());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor1() {
-		try {
-			Rna rna = new Rna("d");
-			assertNotNull(rna);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor() {
-		try {
-			Rna rna = new Rna("d");
-			rna.addRegion(new RnaRegion());
-			Rna rna2 = new Rna(rna);
-			assertEquals(rna.getRegions().size(), rna2.getRegions().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			Rna rna = new Rna(new Rna());
-			assertNotNull(rna.getStringType());
-			List<RnaRegion> regions = new ArrayList<>();
-
-			rna.setRegions(regions);
-
-			assertEquals(regions, rna.getRegions());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCopy() {
-		try {
-			Rna rna = new Rna().copy();
-			assertNotNull(rna);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		try {
-			Rna object = Mockito.spy(Rna.class);
-			object.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.model.map.species;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+
+public class RnaTest {
+  Logger logger = Logger.getLogger(RnaTest.class);
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testSerialization() {
+    try {
+      SerializationUtils.serialize(new Rna());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor1() {
+    try {
+      Rna rna = new Rna("d");
+      assertNotNull(rna);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor() {
+    try {
+      Rna rna = new Rna("d");
+      rna.addRegion(new CodingRegion());
+      Rna rna2 = new Rna(rna);
+      assertEquals(rna.getRegions().size(), rna2.getRegions().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetters() {
+    try {
+      Rna rna = new Rna(new Rna());
+      assertNotNull(rna.getStringType());
+      List<ModificationResidue> regions = new ArrayList<>();
+
+      rna.setRegions(regions);
+
+      assertEquals(regions, rna.getRegions());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCopy() {
+    try {
+      Rna rna = new Rna().copy();
+      assertNotNull(rna);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidCopy() {
+    try {
+      Rna object = Mockito.spy(Rna.class);
+      object.copy();
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/field/AllFieldTests.java b/model/src/test/java/lcsb/mapviewer/model/map/species/field/AllFieldTests.java
index 512ff1dab965e61c18b8a36b9adea44420f8d296..ccfe28648a77f1097d3fb50b297c674baf59fc4e 100644
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/field/AllFieldTests.java
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/field/AllFieldTests.java
@@ -5,12 +5,11 @@ import org.junit.runners.Suite;
 import org.junit.runners.Suite.SuiteClasses;
 
 @RunWith(Suite.class)
-@SuiteClasses({ AntisenseRnaRegionTest.class, //
-		AntisenseRnaRegionTypeTest.class, //
+@SuiteClasses({ CodingRegionTest.class, //
 		ModificationStateTest.class, //
-		ModificationResidueTest.class, //
+		ResidueTest.class, //
 		PositionToCompartmentTest.class, //
-		RnaRegionTest.class,//
+		ProteinBindingDomainTest.class,//
 		StructureTest.class,//
 		UniprotRecordTest.class,//
 })
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegionTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegionTest.java
deleted file mode 100644
index 2821caabaf1b371a94d8804c4bcd47cb40167fa4..0000000000000000000000000000000000000000
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegionTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package lcsb.mapviewer.model.map.species.field;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.AntisenseRna;
-
-public class AntisenseRnaRegionTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new AntisenseRnaRegion());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor1() {
-		try {
-			AntisenseRnaRegion antisenseRna = new AntisenseRnaRegion();
-			AntisenseRnaRegion antisenseRna2 = new AntisenseRnaRegion(antisenseRna);
-			assertNotNull(antisenseRna2);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdate() {
-		try {
-			AntisenseRnaRegion antisenseRna = new AntisenseRnaRegion();
-			antisenseRna.setState(ModificationState.EMPTY);
-			antisenseRna.setName("as");
-			antisenseRna.setPos(3.0);
-			AntisenseRnaRegion antisenseRna2 = new AntisenseRnaRegion();
-			antisenseRna2.update(antisenseRna);
-			assertEquals(antisenseRna.getState(), antisenseRna2.getState());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidUpdate() {
-		try {
-			AntisenseRnaRegion antisenseRna = new AntisenseRnaRegion();
-			AntisenseRnaRegion antisenseRna2 = new AntisenseRnaRegion();
-			antisenseRna.setIdAntisenseRnaRegion("@1");
-			antisenseRna2.setIdAntisenseRnaRegion("@");
-			antisenseRna2.update(antisenseRna);
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			AntisenseRnaRegion region = new AntisenseRnaRegion(new AntisenseRnaRegion());
-			int id = 91;
-			AntisenseRna species = new AntisenseRna("id");
-			double pos = 4.6;
-			double size = 5.3;
-			AntisenseRnaRegionType type = AntisenseRnaRegionType.CODING_REGION;
-			String name = "nam";
-			String idAntisenseRnaRegion = "iddd";
-
-			region.setId(id);
-			region.setSpecies(species);
-			region.setPos(pos);
-			region.setSize(size);
-			region.setType(type);
-			region.setName(name);
-			region.setIdAntisenseRnaRegion(idAntisenseRnaRegion);
-			region.setState(ModificationState.ACETYLATED);
-
-			assertEquals(id, region.getId());
-			assertEquals(species, region.getSpecies());
-			assertEquals(pos, region.getPos(), Configuration.EPSILON);
-			assertEquals(size, region.getSize(), Configuration.EPSILON);
-			assertEquals(type, region.getType());
-			assertEquals(name, region.getName());
-			assertEquals(idAntisenseRnaRegion, region.getIdAntisenseRnaRegion());
-
-			assertEquals(ModificationState.ACETYLATED, region.getState());
-
-			try {
-				region.setSize("text");
-				fail("Exception expected");
-			} catch (InvalidArgumentException e) {
-			}
-
-			try {
-				region.setPos("text");
-				fail("Exception expected");
-			} catch (InvalidArgumentException e) {
-			}
-
-			region.setSize("1.0");
-			region.setPos("1.0");
-			assertEquals(1.0, region.getPos(), Configuration.EPSILON);
-			assertEquals(1.0, region.getSize(), Configuration.EPSILON);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testToString() {
-		try {
-			assertNotNull(new AntisenseRnaRegion().toString());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCopy() {
-		try {
-			AntisenseRnaRegion degraded = new AntisenseRnaRegion().copy();
-			assertNotNull(degraded);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		try {
-			new AntisenseRnaRegion() {
-
-				/**
-				 * 
-				 */
-				private static final long serialVersionUID = 1L;
-			}.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegionTypeTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegionTypeTest.java
deleted file mode 100644
index c5a7537e0ebf47c63246848b760005b0bb93a7b0..0000000000000000000000000000000000000000
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/field/AntisenseRnaRegionTypeTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package lcsb.mapviewer.model.map.species.field;
-
-import static org.junit.Assert.*;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-
-public class AntisenseRnaRegionTypeTest {
-
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testEnum() {
-		try {
-			for (AntisenseRnaRegionType type : AntisenseRnaRegionType.values()) {
-				assertNotNull(type);
-
-				// for coverage tests
-				AntisenseRnaRegionType.valueOf(type.name());
-				assertNotNull(type.getName());
-
-			}
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testEnumGetTypeByString() {
-		try {
-			assertNotNull(AntisenseRnaRegionType.getTypeByString("proteinBindingDomain"));
-			assertNull(AntisenseRnaRegionType.getTypeByString("antisenseRnaDomainzz"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-
-}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/field/CodingRegionTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/field/CodingRegionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..42287fa3fe2efa098a2260a751252904b9557c66
--- /dev/null
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/field/CodingRegionTest.java
@@ -0,0 +1,147 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.awt.geom.Point2D;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+
+public class CodingRegionTest {
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testSerialization() {
+    try {
+      SerializationUtils.serialize(new CodingRegion());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor1() {
+    try {
+      CodingRegion antisenseRna = new CodingRegion();
+      CodingRegion antisenseRna2 = new CodingRegion(antisenseRna);
+      assertNotNull(antisenseRna2);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testUpdate() {
+    try {
+      CodingRegion antisenseRna = new CodingRegion();
+      antisenseRna.setName("as");
+      antisenseRna.setPosition(new Point2D.Double(10, 0));
+      CodingRegion antisenseRna2 = new CodingRegion();
+      antisenseRna2.update(antisenseRna);
+      assertEquals(antisenseRna.getName(), antisenseRna2.getName());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidUpdate() {
+    try {
+      CodingRegion antisenseRna = new CodingRegion();
+      CodingRegion antisenseRna2 = new CodingRegion();
+      antisenseRna.setIdModificationResidue("@1");
+      antisenseRna2.setIdModificationResidue("@");
+      antisenseRna2.update(antisenseRna);
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetters() {
+    try {
+      CodingRegion region = new CodingRegion(new CodingRegion());
+      int id = 91;
+      AntisenseRna species = new AntisenseRna("id");
+      Point2D position = new Point2D.Double(10, 20);
+      double width = 5.3;
+      String name = "nam";
+      String idCodingRegion = "iddd";
+
+      region.setId(id);
+      region.setSpecies(species);
+      region.setPosition(position);
+      region.setWidth(width);
+      region.setName(name);
+      region.setIdModificationResidue(idCodingRegion);
+
+      assertEquals(id, region.getId());
+      assertEquals(species, region.getSpecies());
+      assertEquals(position.distance(region.getPosition()), 0, Configuration.EPSILON);
+      assertEquals(width, region.getWidth(), Configuration.EPSILON);
+      assertEquals(name, region.getName());
+      assertEquals(idCodingRegion, region.getIdModificationResidue());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testToString() {
+    try {
+      assertNotNull(new CodingRegion().toString());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCopy() {
+    try {
+      CodingRegion degraded = new CodingRegion().copy();
+      assertNotNull(degraded);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testInvalidCopy() {
+    try {
+      Mockito.mock(CodingRegion.class, Mockito.CALLS_REAL_METHODS).copy();
+      fail("Exception expected");
+    } catch (NotImplementedException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/field/ModificationResidueTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/field/ModificationResidueTest.java
deleted file mode 100644
index 6b839c1379ca9b15929e1bf14355a74450f52961..0000000000000000000000000000000000000000
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/field/ModificationResidueTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package lcsb.mapviewer.model.map.species.field;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import lcsb.mapviewer.common.exception.NotImplementedException;
-import lcsb.mapviewer.model.map.species.GenericProtein;
-import lcsb.mapviewer.model.map.species.Species;
-
-public class ModificationResidueTest {
-
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testGetters() {
-		ModificationResidue mr = new ModificationResidue();
-		Species species = new GenericProtein("id");
-		int id = 94;
-
-		mr.setSpecies(species);
-		mr.setId(id);
-
-		assertEquals(species, mr.getSpecies());
-		assertEquals(id, mr.getId());
-	}
-
-	@Test
-	public void testCopy() {
-		ModificationResidue mr = new ModificationResidue().copy();
-		assertNotNull(mr);
-	}
-
-	@Test
-	public void testInvalidCopy() {
-		ModificationResidue mr = Mockito.spy(ModificationResidue.class);
-		try {
-			mr.copy();
-			fail("Exception expected");
-		} catch (NotImplementedException e) {
-
-		}
-	}
-
-}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/field/ProteinBindingDomainTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/field/ProteinBindingDomainTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1211018e2de52140c3f0979573c6e3b780a43ffb
--- /dev/null
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/field/ProteinBindingDomainTest.java
@@ -0,0 +1,100 @@
+package lcsb.mapviewer.model.map.species.field;
+
+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 java.awt.geom.Point2D;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.model.map.species.Rna;
+
+public class ProteinBindingDomainTest {
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testSerialization() {
+    try {
+      SerializationUtils.serialize(new ProteinBindingDomain());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testConstructor() {
+    try {
+      ProteinBindingDomain region = new ProteinBindingDomain(new ProteinBindingDomain());
+      assertNotNull(region);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testUpdate() {
+    try {
+      ProteinBindingDomain region = new ProteinBindingDomain();
+      ProteinBindingDomain region2 = new ProteinBindingDomain();
+      region2.setName("asd");
+      region2.setPosition(new Point2D.Double(0, 10));
+      region.update(region2);
+      assertEquals(region2.getName(), region.getName());
+      assertTrue(region2.getPosition().distance(region.getPosition()) <= Configuration.EPSILON);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testUpdate2() {
+    try {
+      ProteinBindingDomain region = new ProteinBindingDomain();
+      region.setIdModificationResidue("1");
+      ProteinBindingDomain region2 = new ProteinBindingDomain();
+      region2.setIdModificationResidue("2");
+      region.update(region2);
+      fail("Exception expected");
+    } catch (InvalidArgumentException e) {
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetters() {
+    try {
+      ProteinBindingDomain region = new ProteinBindingDomain();
+      double size = 2.5;
+      int id = 58;
+      Rna species = new Rna("id");
+      region.setWidth(size);
+      region.setSpecies(species);
+      region.setId(id);
+      assertEquals(id, region.getId());
+      assertEquals(size, region.getWidth(), Configuration.EPSILON);
+      assertEquals(species, region.getSpecies());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/field/ResidueTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/field/ResidueTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ff9289bb272fc7d157b285c995a4110b309b6218
--- /dev/null
+++ b/model/src/test/java/lcsb/mapviewer/model/map/species/field/ResidueTest.java
@@ -0,0 +1,50 @@
+package lcsb.mapviewer.model.map.species.field;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import lcsb.mapviewer.common.exception.NotImplementedException;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.Species;
+
+public class ResidueTest {
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+  }
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testGetters() {
+    Residue mr = new Residue();
+    Species species = new GenericProtein("id");
+    int id = 94;
+
+    mr.setSpecies(species);
+    mr.setId(id);
+
+    assertEquals(species, mr.getSpecies());
+    assertEquals(id, mr.getId());
+  }
+
+  @Test
+  public void testCopy() {
+    Residue mr = new Residue().copy();
+    assertNotNull(mr);
+  }
+
+}
diff --git a/model/src/test/java/lcsb/mapviewer/model/map/species/field/RnaRegionTest.java b/model/src/test/java/lcsb/mapviewer/model/map/species/field/RnaRegionTest.java
deleted file mode 100644
index 11e0edc346820fc24d8807caa425f8ed8d7e138e..0000000000000000000000000000000000000000
--- a/model/src/test/java/lcsb/mapviewer/model/map/species/field/RnaRegionTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package lcsb.mapviewer.model.map.species.field;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-import org.apache.commons.lang3.SerializationUtils;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.model.map.species.Rna;
-
-public class RnaRegionTest {
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testSerialization() {
-		try {
-			SerializationUtils.serialize(new RnaRegion());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testConstructor() {
-		try {
-			RnaRegion region = new RnaRegion(new RnaRegion());
-			assertNotNull(region);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testSetSize() {
-		try {
-			RnaRegion region = new RnaRegion();
-			try {
-				region.setSize("as");
-				fail("Exception expected");
-			} catch (InvalidArgumentException e) {
-			}
-			region.setSize("0.0");
-			assertEquals(0.0, region.getSize(), Configuration.EPSILON);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testSetPos() {
-		try {
-			RnaRegion region = new RnaRegion();
-			try {
-				region.setPos("as");
-				fail("Exception expected");
-			} catch (InvalidArgumentException e) {
-			}
-			region.setPos("1.0");
-			assertEquals(1.0, region.getPos(), Configuration.EPSILON);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdate() {
-		try {
-			RnaRegion region = new RnaRegion();
-			RnaRegion region2 = new RnaRegion();
-			region2.setState(ModificationState.ACETYLATED);
-			region2.setName("asd");
-			region2.setPos(2.2);
-			region.update(region2);
-			assertEquals(region2.getName(), region.getName());
-			assertEquals(region2.getPos(), region.getPos());
-			assertEquals(region2.getState(), region.getState());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testUpdate2() {
-		try {
-			RnaRegion region = new RnaRegion();
-			region.setIdRnaRegion("1");
-			RnaRegion region2 = new RnaRegion();
-			region2.setIdRnaRegion("2");
-			region.update(region2);
-			fail("Exception expected");
-		} catch (InvalidArgumentException e) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetters() {
-		try {
-			RnaRegion region = new RnaRegion();
-			double size = 2.5;
-			int id = 58;
-			Rna species = new Rna("id");
-			region.setSize(size);
-			region.setSpecies(species);
-			region.setId(id);
-			assertEquals(id, region.getId());
-			assertEquals(size, region.getSize(), Configuration.EPSILON);
-			assertEquals(species, region.getSpecies());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-}
diff --git a/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/XML/ModelContructor.java b/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/XML/ModelContructor.java
index fcd3f3e28dd180b3cacaa43ffa99ac353be42ed1..f2e88b01525577ae8be00329fa34db31aff8f33b 100644
--- a/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/XML/ModelContructor.java
+++ b/pathvisio/src/main/java/lcsb/mapviewer/wikipathway/XML/ModelContructor.java
@@ -20,6 +20,7 @@ import lcsb.mapviewer.common.Pair;
 import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.common.exception.InvalidStateException;
 import lcsb.mapviewer.converter.ConverterException;
+import lcsb.mapviewer.converter.model.celldesigner.geometry.CellDesignerAliasConverter;
 import lcsb.mapviewer.converter.model.celldesigner.reaction.ReactionLineData;
 import lcsb.mapviewer.converter.model.celldesigner.types.ModifierType;
 import lcsb.mapviewer.converter.model.celldesigner.types.ModifierTypeUtils;
@@ -58,7 +59,10 @@ import lcsb.mapviewer.model.map.species.Rna;
 import lcsb.mapviewer.model.map.species.SimpleMolecule;
 import lcsb.mapviewer.model.map.species.Species;
 import lcsb.mapviewer.model.map.species.Unknown;
+import lcsb.mapviewer.model.map.species.field.AbstractSiteModification;
 import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.Residue;
 import lcsb.mapviewer.modelutils.map.ElementUtils;
 import lcsb.mapviewer.wikipathway.model.DataNode;
 import lcsb.mapviewer.wikipathway.model.Edge;
@@ -82,1045 +86,1069 @@ import lcsb.mapviewer.wikipathway.utils.Geo;
  */
 public class ModelContructor {
 
-	/**
-	 * CellDesigner util class used for retrieving information about modifier
-	 * graphics.
-	 */
-	private ModifierTypeUtils				 mtu															 = new ModifierTypeUtils();
-
-	/**
-	 * Default color used by complexes.
-	 */
-	private static final Color			 DEFAULT_COMPLEX_ALIAS_COLOR			 = new Color(102, 255, 255);
-
-	/**
-	 * How much of central line is used by and operator that joins reactants.
-	 */
-	private static final int				 AND_OPERATOR_CENTRAL_LINE_RATIO	 = 10;
-
-	/**
-	 * How much of central line is used by split operator that split products.
-	 */
-	private static final int				 SPLIT_OPERATOR_CENTRAL_LINE_RATIO = 10;
-
-	/**
-	 * Epsilon used for double comparison.
-	 */
-	private static final double			 EPSILON													 = 1e-6;
-
-	/**
-	 * Default class logger.
-	 */
-	private Logger									 logger														 = Logger.getLogger(ModelContructor.class);
-
-	/**
-	 * Parser used for extracting {@link MiriamData references} from GPML model.
-	 */
-	private BiopaxParser						 biopaxParser											 = new BiopaxParser();
-
-	/**
-	 * List of {@link Shape#shape shapes} that are not supported to be part of a
-	 * {@link Complex complex}.
-	 */
-	private static final Set<String> INALID_COMPLEX_SHAPE_CHILDREN		 = new HashSet<>();
-
-	static {
-		INALID_COMPLEX_SHAPE_CHILDREN.add("Rectangle");
-		INALID_COMPLEX_SHAPE_CHILDREN.add("Oval");
-		INALID_COMPLEX_SHAPE_CHILDREN.add("RoundedRectangle");
-		INALID_COMPLEX_SHAPE_CHILDREN.add("Golgi Apparatus");
-		INALID_COMPLEX_SHAPE_CHILDREN.add("Brace");
-		INALID_COMPLEX_SHAPE_CHILDREN.add("Sarcoplasmic Reticulum");
-		INALID_COMPLEX_SHAPE_CHILDREN.add("Mitochondria");
-		INALID_COMPLEX_SHAPE_CHILDREN.add("Endoplasmic Reticulum");
-		INALID_COMPLEX_SHAPE_CHILDREN.add("Arc");
-		INALID_COMPLEX_SHAPE_CHILDREN.add("Triangle");
-		INALID_COMPLEX_SHAPE_CHILDREN.add("Hexagon");
-	}
-
-	/**
-	 * This function splits {@link PolylineData} into two parts. It also assumes
-	 * that last segment on the left part is equal to the length of the first
-	 * segment on the right side.
-	 * 
-	 * @param pd
-	 *          line to split
-	 * @return pair of lines into which parameter was split to
-	 */
-	protected Pair<PolylineData, PolylineData> splitPolyline(PolylineData pd) {
-		PolylineData p1 = new PolylineData();
-		PolylineData p2 = new PolylineData();
-		p1.setColor(pd.getColor());
-		p2.setColor(pd.getColor());
-
-		List<Line2D> lines = pd.getLines();
-		double lenght = 0.0;
-		for (Line2D line : lines) {
-			lenght += Geo.lineLen(line);
-		}
-		if (lenght > Configuration.EPSILON) {
-			double tmp = 0.0;
-			boolean first = true;
-			for (Line2D line : lines) {
-				if (tmp + Geo.lineLen(line) > lenght / 2) {
-					if (first) {
-						double a = (lenght / 2 - tmp) / Geo.lineLen(line);
-						double x = line.getX1() + a * (line.getX2() - line.getX1());
-						double y = line.getY1() + a * (line.getY2() - line.getY1());
-						p1.addPoint((Point2D) line.getP1().clone());
-						p1.addPoint(new Point2D.Double(x, y));
-						p2.addPoint(new Point2D.Double(x, y));
-						first = false;
-					}
-					p2.addPoint((Point2D) line.getP2().clone());
-					tmp += Geo.lineLen(line);
-				} else {
-					p1.addPoint((Point2D) line.getP1().clone());
-					tmp += Geo.lineLen(line);
-				}
-			}
-		} else { // we have line with empty length
-			p1.addPoint((Point2D) pd.getBeginPoint().clone());
-			p1.addPoint((Point2D) pd.getBeginPoint().clone());
-			p2.addPoint((Point2D) pd.getBeginPoint().clone());
-			p2.addPoint((Point2D) pd.getBeginPoint().clone());
-		}
-
-		// and now make sure that we have equal distances from left and right
-		double leftDist = p1.getEndPoint().distance(p1.getPoints().get(p1.getPoints().size() - 2));
-		double rightDist = p2.getEndPoint().distance(p2.getPoints().get(p2.getPoints().size() - 2));
-		if (Math.abs(leftDist - rightDist) > Configuration.EPSILON) {
-			if (leftDist > rightDist) {
-				double ratio = rightDist / leftDist;
-				double dx = p1.getPoints().get(p1.getPoints().size() - 1).getX() - p1.getPoints().get(p1.getPoints().size() - 2).getX();
-				double dy = p1.getPoints().get(p1.getPoints().size() - 1).getY() - p1.getPoints().get(p1.getPoints().size() - 2).getY();
-				double x = p1.getPoints().get(p1.getPoints().size() - 2).getX() + dx * ratio;
-				double y = p1.getPoints().get(p1.getPoints().size() - 2).getY() + dy * ratio;
-				Point2D newPoint = new Point2D.Double(x, y);
-				p1.addPoint(p1.getPoints().size() - 1, newPoint);
-			} else {
-				double ratio = leftDist / rightDist;
-				double dx = p2.getPoints().get(0).getX() - p2.getPoints().get(1).getX();
-				double dy = p2.getPoints().get(0).getY() - p2.getPoints().get(1).getY();
-				double x = p2.getPoints().get(1).getX() + dx * ratio;
-				double y = p2.getPoints().get(1).getY() + dy * ratio;
-				Point2D newPoint = new Point2D.Double(x, y);
-				p2.addPoint(1, newPoint);
-			}
-		}
-		return new Pair<PolylineData, PolylineData>(p1, p2);
-	}
-
-	/**
-	 * Support class to send less parameters in functions.
-	 * 
-	 * @author Jan Badura
-	 */
-	private final class Data {
-		/**
-		 * Map between graphId and aliases created from gpml elements.
-		 */
-		private Map<String, Element> id2alias;
-
-		/**
-		 * Default layer.
-		 */
-		private Layer								 layer;
-
-		/**
-		 * Default constructor.
-		 */
-		private Data() {
-			id2alias = new HashMap<String, Element>();
-			layer = new Layer();
-			layer.setVisible(true);
-			layer.setLayerId("1");
-			layer.setName("defaultLayer");
-		}
-	}
-
-	/**
-	 * This function creates Species from DataNode.
-	 * 
-	 * @param dataNode
-	 *          object from which species is created
-	 * @param data
-	 *          ...
-	 * @return {@link Species} created from input {@link DataNode}
-	 */
-	protected Species createAlias(DataNode dataNode, Data data) {
-		Species res = null;
-		String type = dataNode.getType();
-		if (type == null || type.equals("")) {
-			type = null;
-		}
-
-		if (type != null && type.equalsIgnoreCase("Metabolite")) {
-			res = new SimpleMolecule(dataNode.getGraphId());
-		} else if (type != null && type.equalsIgnoreCase("GeneProduct")) {
-			res = new Gene(dataNode.getGraphId());
-		} else if (type != null && type.equalsIgnoreCase("Pathway")) {
-			res = new Phenotype(dataNode.getGraphId());
-		} else if (type != null && type.equalsIgnoreCase("Rna")) {
-			res = new Rna(dataNode.getGraphId());
-		} else if (type != null && type.equalsIgnoreCase("Protein")) {
-			res = new GenericProtein(dataNode.getGraphId());
-		} else if (type != null && type.equalsIgnoreCase("Complex")) {
-			res = new Complex(dataNode.getGraphId());
-		} else if (type != null && type.equalsIgnoreCase("None")) {
-			res = new Unknown(dataNode.getGraphId());
-		} else {
-			logger.warn("[" + dataNode.getGraphId() + "]\tUnknown species type: " + type + ". Using Unknown");
-			res = new Unknown(dataNode.getGraphId());
-		}
-
-		res.addMiriamData(dataNode.getReferences());
-		res.setName(dataNode.getName());
-		return res;
-	}
-
-	/**
-	 * This function adds ComplexSpecies to model from graph. ComplexName is set
-	 * as groupId from .gpml
-	 * 
-	 * @param model
-	 *          to this model complexes will be added
-	 * @param graph
-	 *          gpml data model
-	 * @param data
-	 *          ...
-	 */
-	protected void addComplexSpecies(Model model, Graph graph, Data data) {
-		for (Group group : graph.getGroups()) {
-			Complex alias = new Complex(group.getGraphId());
-			alias.setName(group.getGraphId());
-			if ("Complex".equalsIgnoreCase(group.getStyle())) {
-				alias.setHypothetical(false);
-			} else {
-				alias.setHypothetical(true);
-			}
-
-			Rectangle2D rec = group.getRectangle();
-			if (rec == null) {
-				rec = new Rectangle2D.Double(0, 0, 0, 0);
-			}
-			alias.setX(rec.getX());
-			alias.setY(rec.getY());
-			alias.setWidth(rec.getWidth());
-			alias.setHeight(rec.getHeight());
-			alias.setColor(DEFAULT_COMPLEX_ALIAS_COLOR);
-
-			data.id2alias.put(group.getGraphId(), alias);
-			model.addElement(alias);
-		}
-	}
-
-	/**
-	 * This function adds Species, TextLabels, Compartments and Shapes from graph.
-	 * 
-	 * @param model
-	 *          model to which species will be added
-	 * @param graph
-	 *          gpml data model
-	 * @param data
-	 *          ...
-	 */
-	protected void addElement(Model model, Graph graph, Data data) {
-		for (DataNode dataNode : graph.getDataNodes()) {
-			Species species = createAlias(dataNode, data);
-			species.addMiriamData(biopaxParser.getMiriamData(graph.getBiopaxData(), dataNode.getBiopaxReference()));
-
-			Element alias = updateAlias(dataNode, species);
-
-			data.id2alias.put(dataNode.getGraphId(), alias);
-			model.addElement(alias);
-		}
-		for (Label label : graph.getLabels()) {
-			if (label.isTreatAsNode()) {
-				Species species = createSpecies(label);
-				species.addMiriamData(biopaxParser.getMiriamData(graph.getBiopaxData(), label.getBiopaxReference()));
-
-				Element alias = updateAlias(label, species);
-
-				data.id2alias.put(label.getGraphId(), alias);
-				model.addElement(alias);
-			} else {
-				LayerText text = createText(label);
-				data.layer.addLayerText(text);
-			}
-		}
-		for (Shape shape : graph.getShapes()) {
-			if (shape.isTreatAsNode()) {
-				Species species = createSpecies(shape);
-				species.addMiriamData(biopaxParser.getMiriamData(graph.getBiopaxData(), shape.getBiopaxReference()));
-
-				Element alias = updateAlias(shape, species);
-
-				data.id2alias.put(shape.getGraphId(), alias);
-				model.addElement(alias);
-
-			} else {
-				if (!shape.isCompartment()) {
-					if (shape.getShape().equalsIgnoreCase("oval")) {
-						LayerOval oval = createOval(shape);
-						data.layer.addLayerOval(oval);
-					} else {
-						LayerRect rect = createRectangle(shape);
-						data.layer.addLayerRect(rect);
-					}
-				} else {
-					Compartment compartment = new Compartment(shape.getGraphId());
-					Element cmpAl = updateAlias(shape, compartment);
-					model.addElement(cmpAl);
-				}
-			}
-		}
-
-		for (State state : graph.getStates()) {
-			// TODO this might not work
-			Element species = data.id2alias.get(state.getGraphRef());
-			if (state.getType() != null) {
-				ModificationResidue mr = new ModificationResidue();
-				mr.setIdModificationResidue(state.getGraphId());
-				mr.setState(state.getType());
-				Double angle = null;
-				// CHECKSTYLE:OFF during to graphical transformation
-				// right side of the element
-				if (state.getRelX() >= 1.0 - Configuration.EPSILON) {
-					angle = 0 + (state.getRelY() + 1.0) / 2;
-					// bottom side of the element
-				} else if (state.getRelY() >= 1.0 - Configuration.EPSILON) {
-					angle = 1 + 1 - (state.getRelX() + 1.0) / 2;
-				} else if (state.getRelX() <= -1.0 + Configuration.EPSILON) {
-					// left side of the element
-					angle = 2 + 1 - (state.getRelY() + 1.0) / 2;
-				} else if (state.getRelY() <= -1.0 + Configuration.EPSILON) {
-					// top side of the element
-					angle = 3 + (state.getRelX() + 1.0) / 2;
-				} else {
-					logger.warn(state.getWarningPrefix() + "Unknown localisation on element for modification. RelX: " + state.getRelX() + ", RelY: " + state.getRelY());
-					angle = 0.0;
-				}
-				angle /= 4.0;
-				// CHECKSTYLE:ON
-				mr.setAngle(angle);
-
-				if (species instanceof Protein) {
-					((Protein) species).addModificationResidue(mr);
-				} else if (species instanceof Gene) {
-					((Gene) species).addModificationResidue(mr);
-				} else {
-					logger.warn(state.getWarningPrefix() + "state for " + species.getClass().getSimpleName() + " is not supported.");
-				}
-			} else if (state.getStructuralState() != null) {
-				if (species instanceof Protein) {
-					Protein protein = ((Protein) species);
-					if (protein.getStructuralState() == null) {
-						protein.setStructuralState(state.getStructuralState());
-					} else {
-						logger.warn(state.getWarningPrefix() + " tries to override another state: " + protein.getStructuralState());
-					}
-				} else {
-					logger.warn(state.getWarningPrefix() + "structural state for " + species.getClass().getSimpleName() + " is not supported.");
-				}
-			}
-		}
-	}
-
-	/**
-	 * Creates {@link LayerRect} object from {@link Shape}.
-	 * 
-	 * @param shape
-	 *          source gpml object to be transformed
-	 * @return {@link LayerRect} obtained from {@link Shape} object
-	 */
-	public LayerRect createRectangle(Shape shape) {
-		LayerRect rect = new LayerRect();
-		Rectangle2D rec = shape.getRectangle();
-		rect.setX(rec.getX());
-		rect.setY(rec.getY());
-		rect.setHeight(rec.getHeight());
-		rect.setWidth(rec.getWidth());
-		rect.setColor(shape.getColor());
-		return rect;
-	}
-
-	/**
-	 * Creates {@link LayerOval} object from {@link Shape}.
-	 * 
-	 * @param shape
-	 *          source gpml object to be transformed
-	 * @return {@link LayerOval} obtained from {@link Shape} object
-	 */
-	public LayerOval createOval(Shape shape) {
-		LayerOval oval = new LayerOval();
-		Rectangle2D rec = shape.getRectangle();
-		oval.setX(rec.getX());
-		oval.setY(rec.getY());
-		oval.setHeight(rec.getHeight());
-		oval.setWidth(rec.getWidth());
-		oval.setColor(shape.getColor());
-		return oval;
-	}
-
-	/**
-	 * Creates {@link LayerText} from {@link Label}.
-	 * 
-	 * @param label
-	 *          object from which result will be created
-	 * @return {@link LayerText} from {@link Label}
-	 */
-	public LayerText createText(Label label) {
-		Rectangle2D rec = label.getRectangle();
-
-		LayerText text = new LayerText();
-		text.setX(rec.getX());
-		text.setY(rec.getY());
-		text.setHeight(rec.getHeight());
-		text.setWidth(rec.getWidth());
-		text.setColor(label.getColor());
-		if (text.getColor().equals(Color.WHITE)) {
-			text.setColor(Color.BLACK);
-		}
-		text.setNotes(label.getName());
-		return text;
-	}
-
-	/**
-	 * Creates alias for {@link GraphicalPathwayElement}. Type of the alias is
-	 * defined by the parameter {@link Species}
-	 * 
-	 * @param gpmlElement
-	 *          object from which alias will be create
-	 * @param alias
-	 *          specie for which alias will be created
-	 * @return {@link Species} created from input {@link Label}
-	 */
-	public Element updateAlias(GraphicalPathwayElement gpmlElement, Element alias) {
-		if (alias instanceof Compartment) {
-			if (((Shape) gpmlElement).getShape().equalsIgnoreCase("oval")) {
-				alias = new OvalCompartment((Compartment) alias);
-			} else {
-				alias = new SquareCompartment((Compartment) alias);
-			}
-			String name = ((Shape) gpmlElement).getTextLabel();
-			if (name == null) {
-				name = "";
-			}
-			alias.setName(name);
-		}
-
-		Rectangle2D rec = gpmlElement.getRectangle();
-		alias.setX(rec.getX());
-		alias.setY(rec.getY());
-		alias.setWidth(rec.getWidth());
-		alias.setHeight(rec.getHeight());
-		alias.setColor(gpmlElement.getFillColor());
-		return alias;
-	}
-
-	/**
-	 * Creates {@link Unknown species} from {@link Label}.
-	 * 
-	 * @param label
-	 *          original label from which output should be created
-	 * @return {@link Unknown} object created from input {@link Label}
-	 */
-	private Species createSpecies(Label label) {
-		logger.warn(label.getWarningPrefix() + " Label cannot be part of reaction. Tranforming to Unknown");
-
-		Species res = new Unknown(label.getGraphId());
-		res.setName(label.getName());
-		return res;
-	}
-
-	/**
-	 * Creates {@link Unknown species} from {@link Shape}.
-	 * 
-	 * @param shape
-	 *          original label from which output should be created
-	 * @return {@link Unknown} object created from input {@link Label}
-	 */
-	private Species createSpecies(Shape shape) {
-		logger.warn(shape.getWarningPrefix() + " Shape can not be part of reaction. Tranforming to Unknown");
-
-		Species res = new Unknown(shape.getGraphId());
-		res.setName(shape.getName());
-		return res;
-	}
-
-	/**
-	 * This function add Species to right Complexes.
-	 * 
-	 * @param graph
-	 *          gpml data model
-	 * @param data
-	 *          ...
-	 * @throws UnknownChildClassException
-	 *           thrown when complex contain invalid child
-	 */
-	protected void putSpeciesIntoComplexes(Graph graph, Data data) throws UnknownChildClassException {
-		for (Group group : graph.getGroups()) {
-
-			Complex complexSpecies = (Complex) data.id2alias.get(group.getGraphId());
-			for (PathwayElement pe : group.getNodes()) {
-				Element species = data.id2alias.get(pe.getGraphId());
-				if (species != null) {
-					if (species instanceof Species) {
-
-						Species speciesAlias = (Species) species;
-						speciesAlias.setComplex(complexSpecies);
-						complexSpecies.addSpecies(speciesAlias);
-					}
-					// we have label
-				} else if (graph.getLabelByGraphId(pe.getGraphId()) != null) {
-					Label label = graph.getLabelByGraphId(pe.getGraphId());
-					// if complex has generic name then change it into label
-					if (complexSpecies.getName().equals(group.getGraphId())) {
-						complexSpecies.setName(label.getTextLabel());
-					} else {
-						// if there are more labels than one then merge labels
-						complexSpecies.setName(complexSpecies.getName() + "\n" + label.getTextLabel());
-					}
-				} else if (graph.getShapeByGraphId(pe.getGraphId()) != null) {
-					Shape shape = graph.getShapeByGraphId(pe.getGraphId());
-					if (INALID_COMPLEX_SHAPE_CHILDREN.contains(shape.getShape())) {
-						logger.warn(shape.getWarningPrefix() + shape.getShape() + " cannot be part of a complex. Skipping.");
-					} else {
-						throw new UnknownChildClassException(
-								"Unknown class type with id \"" + pe.getGraphId() + "\": " + shape.getShape() + ". Group id: " + group.getGraphId());
-					}
-				} else {
-					throw new UnknownChildClassException("Cannot find child with id: " + pe.getGraphId() + ". Group id: " + group.getGraphId());
-				}
-			}
-		}
-	}
-
-	/**
-	 * This function creates {@link Reaction} from {@link Interaction} from graph.
-	 * 
-	 * @param interaction
-	 *          gpml interaction
-	 * @param graph
-	 *          gpml data model
-	 * @param data
-	 *          ...
-	 * @return reaction created from gpml {@link Interaction}
-	 */
-	protected Reaction createReactionFromInteraction(Interaction interaction, Graph graph, Data data) {
-		InteractionMapping mapping = InteractionMapping.getInteractionMapping(interaction.getType(), interaction.getLine().getType());
-		if (mapping == null) {
-			throw new InvalidArgumentException("Unknown interaction type: " + interaction.getType());
-		}
-		Reaction reaction = createReactionByType(mapping.getModelReactionType());
-		reaction.setIdReaction(interaction.getGraphId());
-		reaction.setReversible(mapping.isReversible());
-
-		reaction.addMiriamData(interaction.getReferences());
-		for (String ref : interaction.getBiopaxReferences()) {
-			BiopaxPublication publication = graph.getBiopaxData().getPublicationByReference(ref);
-			MiriamData md = biopaxParser.createMiriamData(publication);
-			if (md != null) {
-				reaction.addMiriamData(md);
-			}
-		}
-
-		PolylineData pd = interaction.getLine();
-
-		Pair<PolylineData, PolylineData> pair = splitPolyline(pd);
-		PolylineData pdfirstpart = pair.getLeft();
-		PolylineData pdsecondpart = pair.getRight();
-
-		Reactant reactant = new Reactant();
-		reactant.setElement(data.id2alias.get(interaction.getStart()));
-		reactant.setLine(pdfirstpart);
-		reaction.addReactant(reactant);
-
-		Product product = new Product();
-		product.setElement(data.id2alias.get(interaction.getEnd()));
-		product.setLine(pdsecondpart);
-		reaction.addProduct(product);
-
-		for (Edge e : interaction.getReactants()) {
-			Reactant reac = createReactantFromEdge(data, e);
-			reaction.addReactant(reac);
-		}
-
-		for (Edge e : interaction.getProducts()) {
-			Product pro = createProductFromEdge(data, e);
-			reaction.addProduct(pro);
-		}
-
-		double centralLength = pdfirstpart.getPoints().get(pdfirstpart.getPoints().size() - 2).distance(pdfirstpart.getEndPoint()) * 2;
-
-		if (reaction.getReactants().size() > 1) {
-			PolylineData operatorLine = new PolylineData();
-			operatorLine.setColor(pdfirstpart.getColor());
-			operatorLine.addPoint((Point2D) pdfirstpart.getEndPoint().clone());
-			operatorLine.addPoint((Point2D) pdfirstpart.getEndPoint().clone());
-			pdfirstpart.trimEnd(centralLength / AND_OPERATOR_CENTRAL_LINE_RATIO);
-			operatorLine.setStartPoint((Point2D) pdfirstpart.getEndPoint().clone());
-			NodeOperator andOperator;
-			// heterodimer association use association operator
-			if (reaction instanceof HeterodimerAssociationReaction) {
-				andOperator = new AssociationOperator();
-				// all other reaction just force and operator between inputs
-			} else {
-				andOperator = new AndOperator();
-			}
-			andOperator.addInput(reactant);
-			andOperator.setLine(operatorLine);
-			for (int i = 1; i < reaction.getReactants().size(); i++) {
-				Reactant r = reaction.getReactants().get(i);
-				r.getLine().addPoint((Point2D) pdfirstpart.getEndPoint().clone());
-				andOperator.addInput(r);
-			}
-			reaction.addNode(andOperator);
-		}
-
-		if (reaction.getProducts().size() > 1) {
-			PolylineData operatorLine = new PolylineData();
-			operatorLine.setColor(pdsecondpart.getColor());
-
-			operatorLine.addPoint((Point2D) pdsecondpart.getBeginPoint().clone());
-			pdsecondpart.trimBegin(centralLength / SPLIT_OPERATOR_CENTRAL_LINE_RATIO);
-			operatorLine.addPoint((Point2D) pdsecondpart.getBeginPoint().clone());
-			SplitOperator splitOperator = new SplitOperator();
-			splitOperator.addOutput(product);
-			splitOperator.setLine(operatorLine);
-			for (int i = 1; i < reaction.getProducts().size(); i++) {
-				Product r = reaction.getProducts().get(i);
-				r.getLine().addPoint(0, (Point2D) pdsecondpart.getBeginPoint().clone());
-				splitOperator.addOutput(r);
-			}
-			reaction.addNode(splitOperator);
-		}
-
-		for (Edge e : interaction.getModifiers()) {
-			Modifier mod = createModifierFromEdge(data, e);
-			reaction.addModifier(mod);
-		}
-		if (reaction instanceof TwoReactantReactionInterface && reaction.getReactants().size() < 2) {
-			logger.warn("Reaction should contain at least 2 reactants. GraphId: " + interaction.getGraphId());
-			reaction = new UnknownTransitionReaction(reaction);
-		}
-		if (reaction instanceof ReducedNotation
-				&& ((reaction.getReactants().size() > 1) || reaction.getProducts().size() > 1 || reaction.getModifiers().size() > 0)) {
-			logger.warn("Reaction should contain only one reactant and one product. GraphId: " + interaction.getGraphId());
-			reaction = new UnknownTransitionReaction(reaction);
-		}
-		ReactionLineData rld = ReactionLineData.getByReactionType(reaction.getClass());
-		if (rld == null) {
-			throw new InvalidArgumentException("Don't know how to process reaction type: " + reaction.getClass());
-		}
-		for (AbstractNode node : reaction.getNodes()) {
-			if (!(node instanceof Modifier)) {
-				node.getLine().setType(rld.getLineType());
-			}
-		}
-		for (Product p : reaction.getProducts()) {
-			p.getLine().getEndAtd().setArrowType(rld.getProductArrowType());
-			if (rld.getProductLineTrim() > 0) {
-				p.getLine().trimEnd(rld.getProductLineTrim());
-			}
-
-		}
-		if (reaction.isReversible()) {
-			for (Reactant r : reaction.getReactants()) {
-				r.getLine().getBeginAtd().setArrowType(rld.getProductArrowType());
-				if (rld.getProductLineTrim() > 0) {
-					r.getLine().trimBegin(rld.getProductLineTrim());
-				}
-			}
-		}
-
-		ModifierTypeUtils mtu = new ModifierTypeUtils();
-		for (Modifier m : reaction.getModifiers()) {
-			m.getLine().setEndPoint(m.getLine().getPoints().get(m.getLine().getPoints().size() - 2));
-			m.getLine().setEndPoint(mtu.getAnchorPointOnReactionRect(reaction, mtu.getTargetLineIndexByModifier(m)));
-		}
-
-		return reaction;
-	}
-
-	/**
-	 * Creates {@link Reactant} from gpml edge.
-	 * 
-	 * @param data
-	 *          ...
-	 * @param e
-	 *          edge
-	 * @return {@link Reactant} from gpml edge
-	 */
-	protected Reactant createReactantFromEdge(Data data, Edge e) {
-		String id = null;
-		if (data.id2alias.containsKey(e.getStart())) {
-			id = e.getStart();
-		} else if (data.id2alias.containsKey(e.getEnd())) {
-			id = e.getEnd();
-		}
-		if (id == null) {
-			throw new InvalidStateException("This reactant is invalid");
-		}
-
-		Reactant reac = new Reactant();
-		reac.setElement(data.id2alias.get(id));
-		reac.setLine(e.getLine());
-
-		// if somebody drew the reaction in reverse order (starting from reaction
-		// and going to the product) then reverse the order of points: order should
-		// be from reactant to the product
-		if (id.equals(e.getEnd())) {
-			reac.setLine(reac.getLine().reverse());
-		}
-		return reac;
-	}
-
-	/**
-	 * Creates {@link Product} from gpml edge.
-	 * 
-	 * @param data
-	 *          ...
-	 * @param e
-	 *          edge
-	 * @return {@link Product} from gpml edge
-	 */
-	protected Product createProductFromEdge(Data data, Edge e) {
-		String id = null;
-		if (data.id2alias.containsKey(e.getStart())) {
-			id = e.getStart();
-		} else if (data.id2alias.containsKey(e.getEnd())) {
-			id = e.getEnd();
-		}
-		if (id == null) {
-			throw new InvalidStateException("This product is invalid");
-		}
-		Product pro = new Product();
-		pro.setElement(data.id2alias.get(id));
-		pro.setLine(e.getLine());
-		// if somebody drew the reaction in reverse order (starting from reaction
-		// and going to the product) then reverse the order of points: order should
-		// be from reactant to the product
-		if (id.equals(e.getStart())) {
-			pro.setLine(pro.getLine().reverse());
-		}
-		return pro;
-	}
-
-	/**
-	 * Creates {@link Modifier} from gpml edge.
-	 * 
-	 * @param data
-	 *          ...
-	 * @param e
-	 *          edge
-	 * @return {@link Modifier} from gpml edge
-	 */
-	protected Modifier createModifierFromEdge(Data data, Edge e) {
-		InteractionMapping modifierMapping = InteractionMapping.getInteractionMapping(e.getType(), e.getLine().getType());
-		if (modifierMapping == null) {
-			throw new InvalidArgumentException("Unknown interaction type: " + e.getType());
-		}
-
-		Class<? extends ReactionNode> modifierType = null;
-		String id = null;
-		if (data.id2alias.containsKey(e.getStart())) {
-			modifierType = modifierMapping.getModelInputReactionNodeType();
-			id = e.getStart();
-		} else if (data.id2alias.containsKey(e.getEnd())) {
-			modifierType = modifierMapping.getModelOutputReactionNodeType();
-			id = e.getEnd();
-		}
-		if (id == null) {
-			throw new InvalidStateException("This modifier is invalid");
-		}
-
-		Modifier mod = createModifierByType(modifierType, (Species) data.id2alias.get(id));
-
-		ModifierType mt = mtu.getModifierTypeForClazz(mod.getClass());
-
-		e.getLine().setEndAtd(mt.getAtd());
-		e.getLine().setType(mt.getLineType());
-		mod.setLine(e.getLine());
-		return mod;
-	}
-
-	/**
-	 * Creates {@link Reaction} for a given class type.
-	 * 
-	 * @param reactionType
-	 *          type of reaction to create
-	 * @return new instance of the reactionType
-	 */
-	private Reaction createReactionByType(Class<? extends Reaction> reactionType) {
-		try {
-			Reaction result = reactionType.getConstructor().newInstance();
-			return result;
-		} catch (Exception e) {
-			throw new InvalidArgumentException("Cannot create reaction.", e);
-		}
-	}
-
-	/**
-	 * Creates {@link Modifier} for a given class type.
-	 * 
-	 * @param modifierType
-	 *          type of modifier in reaction to create
-	 * @param alias
-	 *          {@link Species alias } to which modifier is attached
-	 * @return new instance of the modifierType
-	 */
-	private Modifier createModifierByType(Class<? extends ReactionNode> modifierType, Species alias) {
-		try {
-			Modifier result = (Modifier) modifierType.getConstructor(Element.class).newInstance(alias);
-			return result;
-		} catch (Exception e) {
-			throw new InvalidArgumentException("Cannot create modifier.", e);
-		}
-	}
-
-	/**
-	 * This function creates {@link Model} from {@link Graph}.
-	 * 
-	 * @param graph
-	 *          object with data obtained from gpml
-	 * @return {@link Model} object representing gpml
-	 * @throws ConverterException
-	 *           exception thrown when conversion from graph couldn't be performed
-	 * 
-	 */
-	public Model getModel(Graph graph) throws ConverterException {
-		try {
-			Data data = new Data();
-			Model model = new ModelFullIndexed(null);
-			model.setWidth(graph.getBoardWidth());
-			model.setHeight(graph.getBoardHeight());
-
-			model.setIdModel("1");
-			model.getLayers().add(data.layer);
-
-			addComplexSpecies(model, graph, data);
-			addElement(model, graph, data);
-			putSpeciesIntoComplexes(graph, data);
-
-			for (Interaction interaction : graph.getInteractions()) {
-				Reaction reaction = createReactionFromInteraction(interaction, graph, data);
-				model.addReaction(reaction);
-			}
-
-			removeEmptyComplexes(model);
-
-			fixCompartmentAliases(model);
-
-			StringBuilder tmp = new StringBuilder();
-			for (String string : graph.getComments()) {
-				tmp.append(string + "\n");
-			}
-			String notes = tmp.toString();
-			boolean different = false;
-			do {
-				String newNotes = StringEscapeUtils.unescapeHtml4(notes);
-				different = newNotes.compareTo(notes) != 0;
-				notes = newNotes;
-			} while (different);
-			if (notes != null) {
-				notes = StringEscapeUtils.unescapeHtml4(notes);
-			}
-			model.setNotes(notes);
-			StringBuilder references = new StringBuilder("");
-			for (String string : graph.getBiopaxReferences()) {
-				references.append(string + ", ");
-			}
-			if (references.length() > 0) {
-				logger.warn("[Biopax, " + references.toString() + "]\tModel annotations are not supported.");
-			}
-
-			assignNamesToComplexes(model);
-			assignNamesToCompartments(model);
-
-			data.layer.addLayerLines(createLines(graph));
-
-			putAliasesIntoCompartments(model);
-
-			return model;
-		} catch (UnknownChildClassException e) {
-			throw new ConverterException(e);
-		}
-	}
-
-	/**
-	 * Method that put {@link Species aliases} that are not assigned into any
-	 * {@link Compartment} into a proper compartment.
-	 * 
-	 * @param model
-	 *          model where aliases will be modifed
-	 */
-	private void putAliasesIntoCompartments(Model model) {
-		for (Element alias : model.getElements()) {
-			if (alias.getCompartment() == null) {
-				if (alias instanceof Species) {
-					Compartment selectedAlias = null;
-					for (Compartment cAlias : model.getCompartments()) {
-						if (cAlias.cross(alias)) {
-							if (selectedAlias == null) {
-								selectedAlias = cAlias;
-							} else if (selectedAlias.getSize() > cAlias.getSize()) {
-								selectedAlias = cAlias;
-							}
-						}
-					}
-					if (selectedAlias != null) {
-						selectedAlias.addElement(alias);
-					}
-				}
-			}
-		}
-	}
-
-	/**
-	 * Removes empty complexes (with size 0) from model.
-	 * 
-	 * @param model
-	 *          model where operation is performed
-	 */
-	private void removeEmptyComplexes(Model model) {
-		Set<Element> aliasesInReaction = new HashSet<>();
-		for (Reaction reaction : model.getReactions()) {
-			for (ReactionNode node : reaction.getReactionNodes()) {
-				aliasesInReaction.add(node.getElement());
-			}
-		}
-		List<Element> toRemove = new ArrayList<>();
-		ElementUtils eu = new ElementUtils();
-		for (Element alias : model.getElements()) {
-			if (alias instanceof Complex) {
-				Complex cAlias = (Complex) alias;
-				if (cAlias.getSize() <= EPSILON && cAlias.getAllChildren().size() == 0) {
-					if (aliasesInReaction.contains(alias)) {
-						logger.warn(eu.getElementTag(alias) + "Empty element is invalid, but it's a part of reaction.");
-					} else {
-						toRemove.add(alias);
-						logger.warn(eu.getElementTag(alias) + "Empty element is invalid");
-					}
-				}
-			}
-		}
-		for (Element alias : toRemove) {
-			model.removeElement(alias);
-		}
-	}
-
-	/**
-	 * Tries to find a name to assign to complexes if complexes don't contain
-	 * them.
-	 * 
-	 * @param model
-	 *          model where complexes are placed
-	 */
-	private void assignNamesToComplexes(Model model) {
-		for (Element alias : model.getElements()) {
-			if (alias instanceof Complex) {
-				if (alias.getName() == null || (alias.getName().isEmpty())) {
-					for (Layer layer : model.getLayers()) {
-						LayerText toRemove = null;
-						for (LayerText lt : layer.getTexts()) {
-							if (alias.contains(lt)) {
-								alias.setName(lt.getNotes());
-								toRemove = lt;
-								break;
-							}
-						}
-						if (toRemove != null) {
-							layer.removeLayerText(toRemove);
-							break;
-						}
-					}
-				}
-			}
-		}
-	}
-
-	/**
-	 * Tries to find a name to assign to compartments if comparments don't contain
-	 * them.
-	 * 
-	 * @param model
-	 *          model where compartments are placed
-	 */
-	private void assignNamesToCompartments(Model model) {
-		for (Element alias : model.getElements()) {
-			if (alias instanceof Compartment) {
-				if (alias.getName() == null || alias.getName().isEmpty()) {
-					for (Layer layer : model.getLayers()) {
-						LayerText toRemove = null;
-						for (LayerText lt : layer.getTexts()) {
-							if (alias.contains(lt)) {
-								alias.setName(lt.getNotes());
-								toRemove = lt;
-								break;
-							}
-						}
-						if (toRemove != null) {
-							layer.removeLayerText(toRemove);
-							break;
-						}
-					}
-				}
-			}
-		}
-	}
-
-	/**
-	 * Creates list of {@link LayerLine} in the model from gpml model.
-	 * 
-	 * @param graph
-	 *          gpml model
-	 * @return list of {@link LayerLine}
-	 */
-	private Collection<PolylineData> createLines(Graph graph) {
-		List<PolylineData> result = new ArrayList<PolylineData>();
-		for (PolylineData pd : graph.getLines()) {
-			result.add(pd);
-		}
-		return result;
-	}
-
-	/**
-	 * By default gpml doesn't offer information about compartments structure.
-	 * This function fixes assignments to compartment and compartment aliases.
-	 * 
-	 * @param model
-	 *          model where assignments are fixed.
-	 */
-	private void fixCompartmentAliases(Model model) {
-		List<Compartment> aliases = model.getCompartments();
-		// clear all assignments
-		for (Compartment compartmentAlias : aliases) {
-			compartmentAlias.getElements().clear();
-		}
-
-		for (Element alias : model.getElements()) {
-			// elements inside complexes shouldn't be considered
-			if (alias instanceof Species) {
-				if (((Species) alias).getComplex() != null) {
-					continue;
-				}
-			}
-			Compartment parentAlias = null;
-			for (Compartment compartmentAlias : aliases) {
-				if (compartmentAlias.contains(alias)) {
-					if (parentAlias == null) {
-						parentAlias = compartmentAlias;
-					} else if (parentAlias.getSize() > compartmentAlias.getSize()) {
-						parentAlias = compartmentAlias;
-					}
-				}
-			}
-			if (parentAlias != null) {
-				parentAlias.addElement(alias);
-				alias.setCompartment(parentAlias);
-			}
-		}
-	}
+  /**
+   * CellDesigner util class used for retrieving information about modifier
+   * graphics.
+   */
+  private ModifierTypeUtils mtu = new ModifierTypeUtils();
+
+  /**
+   * Default color used by complexes.
+   */
+  private static final Color DEFAULT_COMPLEX_ALIAS_COLOR = new Color(102, 255, 255);
+
+  /**
+   * How much of central line is used by and operator that joins reactants.
+   */
+  private static final int AND_OPERATOR_CENTRAL_LINE_RATIO = 10;
+
+  /**
+   * How much of central line is used by split operator that split products.
+   */
+  private static final int SPLIT_OPERATOR_CENTRAL_LINE_RATIO = 10;
+
+  /**
+   * Epsilon used for double comparison.
+   */
+  private static final double EPSILON = 1e-6;
+
+  /**
+   * Default class logger.
+   */
+  private Logger logger = Logger.getLogger(ModelContructor.class);
+
+  /**
+   * Parser used for extracting {@link MiriamData references} from GPML model.
+   */
+  private BiopaxParser biopaxParser = new BiopaxParser();
+
+  /**
+   * List of {@link Shape#shape shapes} that are not supported to be part of a
+   * {@link Complex complex}.
+   */
+  private static final Set<String> INALID_COMPLEX_SHAPE_CHILDREN = new HashSet<>();
+
+  static {
+    INALID_COMPLEX_SHAPE_CHILDREN.add("Rectangle");
+    INALID_COMPLEX_SHAPE_CHILDREN.add("Oval");
+    INALID_COMPLEX_SHAPE_CHILDREN.add("RoundedRectangle");
+    INALID_COMPLEX_SHAPE_CHILDREN.add("Golgi Apparatus");
+    INALID_COMPLEX_SHAPE_CHILDREN.add("Brace");
+    INALID_COMPLEX_SHAPE_CHILDREN.add("Sarcoplasmic Reticulum");
+    INALID_COMPLEX_SHAPE_CHILDREN.add("Mitochondria");
+    INALID_COMPLEX_SHAPE_CHILDREN.add("Endoplasmic Reticulum");
+    INALID_COMPLEX_SHAPE_CHILDREN.add("Arc");
+    INALID_COMPLEX_SHAPE_CHILDREN.add("Triangle");
+    INALID_COMPLEX_SHAPE_CHILDREN.add("Hexagon");
+  }
+
+  /**
+   * This function splits {@link PolylineData} into two parts. It also assumes
+   * that last segment on the left part is equal to the length of the first
+   * segment on the right side.
+   * 
+   * @param pd
+   *          line to split
+   * @return pair of lines into which parameter was split to
+   */
+  protected Pair<PolylineData, PolylineData> splitPolyline(PolylineData pd) {
+    PolylineData p1 = new PolylineData();
+    PolylineData p2 = new PolylineData();
+    p1.setColor(pd.getColor());
+    p2.setColor(pd.getColor());
+
+    List<Line2D> lines = pd.getLines();
+    double lenght = 0.0;
+    for (Line2D line : lines) {
+      lenght += Geo.lineLen(line);
+    }
+    if (lenght > Configuration.EPSILON) {
+      double tmp = 0.0;
+      boolean first = true;
+      for (Line2D line : lines) {
+        if (tmp + Geo.lineLen(line) > lenght / 2) {
+          if (first) {
+            double a = (lenght / 2 - tmp) / Geo.lineLen(line);
+            double x = line.getX1() + a * (line.getX2() - line.getX1());
+            double y = line.getY1() + a * (line.getY2() - line.getY1());
+            p1.addPoint((Point2D) line.getP1().clone());
+            p1.addPoint(new Point2D.Double(x, y));
+            p2.addPoint(new Point2D.Double(x, y));
+            first = false;
+          }
+          p2.addPoint((Point2D) line.getP2().clone());
+          tmp += Geo.lineLen(line);
+        } else {
+          p1.addPoint((Point2D) line.getP1().clone());
+          tmp += Geo.lineLen(line);
+        }
+      }
+    } else { // we have line with empty length
+      p1.addPoint((Point2D) pd.getBeginPoint().clone());
+      p1.addPoint((Point2D) pd.getBeginPoint().clone());
+      p2.addPoint((Point2D) pd.getBeginPoint().clone());
+      p2.addPoint((Point2D) pd.getBeginPoint().clone());
+    }
+
+    // and now make sure that we have equal distances from left and right
+    double leftDist = p1.getEndPoint().distance(p1.getPoints().get(p1.getPoints().size() - 2));
+    double rightDist = p2.getEndPoint().distance(p2.getPoints().get(p2.getPoints().size() - 2));
+    if (Math.abs(leftDist - rightDist) > Configuration.EPSILON) {
+      if (leftDist > rightDist) {
+        double ratio = rightDist / leftDist;
+        double dx = p1.getPoints().get(p1.getPoints().size() - 1).getX()
+            - p1.getPoints().get(p1.getPoints().size() - 2).getX();
+        double dy = p1.getPoints().get(p1.getPoints().size() - 1).getY()
+            - p1.getPoints().get(p1.getPoints().size() - 2).getY();
+        double x = p1.getPoints().get(p1.getPoints().size() - 2).getX() + dx * ratio;
+        double y = p1.getPoints().get(p1.getPoints().size() - 2).getY() + dy * ratio;
+        Point2D newPoint = new Point2D.Double(x, y);
+        p1.addPoint(p1.getPoints().size() - 1, newPoint);
+      } else {
+        double ratio = leftDist / rightDist;
+        double dx = p2.getPoints().get(0).getX() - p2.getPoints().get(1).getX();
+        double dy = p2.getPoints().get(0).getY() - p2.getPoints().get(1).getY();
+        double x = p2.getPoints().get(1).getX() + dx * ratio;
+        double y = p2.getPoints().get(1).getY() + dy * ratio;
+        Point2D newPoint = new Point2D.Double(x, y);
+        p2.addPoint(1, newPoint);
+      }
+    }
+    return new Pair<PolylineData, PolylineData>(p1, p2);
+  }
+
+  /**
+   * Support class to send less parameters in functions.
+   * 
+   * @author Jan Badura
+   */
+  private final class Data {
+    /**
+     * Map between graphId and aliases created from gpml elements.
+     */
+    private Map<String, Element> id2alias;
+
+    /**
+     * Default layer.
+     */
+    private Layer layer;
+
+    /**
+     * Default constructor.
+     */
+    private Data() {
+      id2alias = new HashMap<String, Element>();
+      layer = new Layer();
+      layer.setVisible(true);
+      layer.setLayerId("1");
+      layer.setName("defaultLayer");
+    }
+  }
+
+  /**
+   * This function creates Species from DataNode.
+   * 
+   * @param dataNode
+   *          object from which species is created
+   * @param data
+   *          ...
+   * @return {@link Species} created from input {@link DataNode}
+   */
+  protected Species createAlias(DataNode dataNode, Data data) {
+    Species res = null;
+    String type = dataNode.getType();
+    if (type == null || type.equals("")) {
+      type = null;
+    }
+
+    if (type != null && type.equalsIgnoreCase("Metabolite")) {
+      res = new SimpleMolecule(dataNode.getGraphId());
+    } else if (type != null && type.equalsIgnoreCase("GeneProduct")) {
+      res = new Gene(dataNode.getGraphId());
+    } else if (type != null && type.equalsIgnoreCase("Pathway")) {
+      res = new Phenotype(dataNode.getGraphId());
+    } else if (type != null && type.equalsIgnoreCase("Rna")) {
+      res = new Rna(dataNode.getGraphId());
+    } else if (type != null && type.equalsIgnoreCase("Protein")) {
+      res = new GenericProtein(dataNode.getGraphId());
+    } else if (type != null && type.equalsIgnoreCase("Complex")) {
+      res = new Complex(dataNode.getGraphId());
+    } else if (type != null && type.equalsIgnoreCase("None")) {
+      res = new Unknown(dataNode.getGraphId());
+    } else {
+      logger.warn("[" + dataNode.getGraphId() + "]\tUnknown species type: " + type + ". Using Unknown");
+      res = new Unknown(dataNode.getGraphId());
+    }
+
+    res.addMiriamData(dataNode.getReferences());
+    res.setName(dataNode.getName());
+    return res;
+  }
+
+  /**
+   * This function adds ComplexSpecies to model from graph. ComplexName is set as
+   * groupId from .gpml
+   * 
+   * @param model
+   *          to this model complexes will be added
+   * @param graph
+   *          gpml data model
+   * @param data
+   *          ...
+   */
+  protected void addComplexSpecies(Model model, Graph graph, Data data) {
+    for (Group group : graph.getGroups()) {
+      Complex alias = new Complex(group.getGraphId());
+      alias.setName(group.getGraphId());
+      if ("Complex".equalsIgnoreCase(group.getStyle())) {
+        alias.setHypothetical(false);
+      } else {
+        alias.setHypothetical(true);
+      }
+
+      Rectangle2D rec = group.getRectangle();
+      if (rec == null) {
+        rec = new Rectangle2D.Double(0, 0, 0, 0);
+      }
+      alias.setX(rec.getX());
+      alias.setY(rec.getY());
+      alias.setWidth((int) rec.getWidth());
+      alias.setHeight((int) rec.getHeight());
+      alias.setColor(DEFAULT_COMPLEX_ALIAS_COLOR);
+
+      data.id2alias.put(group.getGraphId(), alias);
+      model.addElement(alias);
+    }
+  }
+
+  /**
+   * This function adds Species, TextLabels, Compartments and Shapes from graph.
+   * 
+   * @param model
+   *          model to which species will be added
+   * @param graph
+   *          gpml data model
+   * @param data
+   *          ...
+   */
+  protected void addElement(Model model, Graph graph, Data data) {
+    for (DataNode dataNode : graph.getDataNodes()) {
+      Species species = createAlias(dataNode, data);
+      species.addMiriamData(biopaxParser.getMiriamData(graph.getBiopaxData(), dataNode.getBiopaxReference()));
+
+      Element alias = updateAlias(dataNode, species);
+
+      data.id2alias.put(dataNode.getGraphId(), alias);
+      model.addElement(alias);
+    }
+    for (Label label : graph.getLabels()) {
+      if (label.isTreatAsNode()) {
+        Species species = createSpecies(label);
+        species.addMiriamData(biopaxParser.getMiriamData(graph.getBiopaxData(), label.getBiopaxReference()));
+
+        Element alias = updateAlias(label, species);
+
+        data.id2alias.put(label.getGraphId(), alias);
+        model.addElement(alias);
+      } else {
+        LayerText text = createText(label);
+        data.layer.addLayerText(text);
+      }
+    }
+    for (Shape shape : graph.getShapes()) {
+      if (shape.isTreatAsNode()) {
+        Species species = createSpecies(shape);
+        species.addMiriamData(biopaxParser.getMiriamData(graph.getBiopaxData(), shape.getBiopaxReference()));
+
+        Element alias = updateAlias(shape, species);
+
+        data.id2alias.put(shape.getGraphId(), alias);
+        model.addElement(alias);
+
+      } else {
+        if (!shape.isCompartment()) {
+          if (shape.getShape().equalsIgnoreCase("oval")) {
+            LayerOval oval = createOval(shape);
+            data.layer.addLayerOval(oval);
+          } else {
+            LayerRect rect = createRectangle(shape);
+            data.layer.addLayerRect(rect);
+          }
+        } else {
+          Compartment compartment = new Compartment(shape.getGraphId());
+          Element cmpAl = updateAlias(shape, compartment);
+          model.addElement(cmpAl);
+        }
+      }
+    }
+
+    for (State state : graph.getStates()) {
+      // TODO this might not work
+      Element species = data.id2alias.get(state.getGraphRef());
+      if (state.getType() != null) {
+        AbstractSiteModification mr = null;
+
+        if (species instanceof Protein) {
+          mr = new Residue();
+          ((Protein) species).addModificationResidue(mr);
+        } else if (species instanceof Gene) {
+          mr = new ModificationSite();
+          ((Gene) species).addModificationResidue(mr);
+        } else {
+          logger.warn(
+              state.getWarningPrefix() + "state for " + species.getClass().getSimpleName() + " is not supported.");
+        }
+        if (mr != null) {
+          mr.setIdModificationResidue(state.getGraphId());
+          mr.setState(state.getType());
+
+          Double x = state.getRelX() * species.getWidth() / 2 + species.getCenterX();
+          Double y = state.getRelY() * species.getHeight() / 2 + species.getCenterY();
+          mr.setPosition(new Point2D.Double(x, y));
+          adjustModificationCoordinates(species);
+        }
+      } else if (state.getStructuralState() != null) {
+        if (species instanceof Protein) {
+          Protein protein = ((Protein) species);
+          if (protein.getStructuralState() == null) {
+            protein.setStructuralState(state.getStructuralState());
+          } else {
+            logger.warn(state.getWarningPrefix() + " tries to override another state: " + protein.getStructuralState());
+          }
+        } else {
+          logger.warn(state.getWarningPrefix() + "structural state for " + species.getClass().getSimpleName()
+              + " is not supported.");
+        }
+      }
+    }
+  }
+
+  /**
+   * {@link ModificationResidue} in element might have slightly off coordinates
+   * (due to different symbol shapes). For that we need to align them to match our
+   * model.
+   * 
+   * @param species
+   */
+  protected void adjustModificationCoordinates(Element species) {
+    if (species instanceof Protein) {
+      Protein protein = (Protein) species;
+      if (protein.getModificationResidues().size() > 0) {
+        CellDesignerAliasConverter converter = new CellDesignerAliasConverter(species, true);
+        for (ModificationResidue mr : protein.getModificationResidues()) {
+          double angle = converter.getAngleForPoint(species, mr.getPosition());
+          mr.setPosition(converter.getResidueCoordinates(species, angle));
+        }
+      }
+    } else if (species instanceof Gene) {
+      Gene gene = (Gene) species;
+      if (gene.getModificationResidues().size() > 0) {
+        CellDesignerAliasConverter converter = new CellDesignerAliasConverter(species, true);
+        for (ModificationResidue mr : gene.getModificationResidues()) {
+          double angle = converter.getAngleForPoint(species, mr.getPosition());
+          mr.setPosition(converter.getResidueCoordinates(species, angle));
+        }
+      }
+
+    }
+  }
+
+  /**
+   * Creates {@link LayerRect} object from {@link Shape}.
+   * 
+   * @param shape
+   *          source gpml object to be transformed
+   * @return {@link LayerRect} obtained from {@link Shape} object
+   */
+  public LayerRect createRectangle(Shape shape) {
+    LayerRect rect = new LayerRect();
+    Rectangle2D rec = shape.getRectangle();
+    rect.setX(rec.getX());
+    rect.setY(rec.getY());
+    rect.setHeight(rec.getHeight());
+    rect.setWidth(rec.getWidth());
+    rect.setColor(shape.getColor());
+    return rect;
+  }
+
+  /**
+   * Creates {@link LayerOval} object from {@link Shape}.
+   * 
+   * @param shape
+   *          source gpml object to be transformed
+   * @return {@link LayerOval} obtained from {@link Shape} object
+   */
+  public LayerOval createOval(Shape shape) {
+    LayerOval oval = new LayerOval();
+    Rectangle2D rec = shape.getRectangle();
+    oval.setX(rec.getX());
+    oval.setY(rec.getY());
+    oval.setHeight(rec.getHeight());
+    oval.setWidth(rec.getWidth());
+    oval.setColor(shape.getColor());
+    return oval;
+  }
+
+  /**
+   * Creates {@link LayerText} from {@link Label}.
+   * 
+   * @param label
+   *          object from which result will be created
+   * @return {@link LayerText} from {@link Label}
+   */
+  public LayerText createText(Label label) {
+    Rectangle2D rec = label.getRectangle();
+
+    LayerText text = new LayerText();
+    text.setX(rec.getX());
+    text.setY(rec.getY());
+    text.setHeight(rec.getHeight());
+    text.setWidth(rec.getWidth());
+    text.setColor(label.getColor());
+    if (text.getColor().equals(Color.WHITE)) {
+      text.setColor(Color.BLACK);
+    }
+    text.setNotes(label.getName());
+    return text;
+  }
+
+  /**
+   * Creates alias for {@link GraphicalPathwayElement}. Type of the alias is
+   * defined by the parameter {@link Species}
+   * 
+   * @param gpmlElement
+   *          object from which alias will be create
+   * @param alias
+   *          specie for which alias will be created
+   * @return {@link Species} created from input {@link Label}
+   */
+  public Element updateAlias(GraphicalPathwayElement gpmlElement, Element alias) {
+    if (alias instanceof Compartment) {
+      if (((Shape) gpmlElement).getShape().equalsIgnoreCase("oval")) {
+        alias = new OvalCompartment((Compartment) alias);
+      } else {
+        alias = new SquareCompartment((Compartment) alias);
+      }
+      String name = ((Shape) gpmlElement).getTextLabel();
+      if (name == null) {
+        name = "";
+      }
+      alias.setName(name);
+    }
+
+    Rectangle2D rec = gpmlElement.getRectangle();
+    alias.setX(rec.getX());
+    alias.setY(rec.getY());
+    alias.setWidth((int) rec.getWidth());
+    alias.setHeight((int) rec.getHeight());
+    alias.setColor(gpmlElement.getFillColor());
+    return alias;
+  }
+
+  /**
+   * Creates {@link Unknown species} from {@link Label}.
+   * 
+   * @param label
+   *          original label from which output should be created
+   * @return {@link Unknown} object created from input {@link Label}
+   */
+  private Species createSpecies(Label label) {
+    logger.warn(label.getWarningPrefix() + " Label cannot be part of reaction. Tranforming to Unknown");
+
+    Species res = new Unknown(label.getGraphId());
+    res.setName(label.getName());
+    return res;
+  }
+
+  /**
+   * Creates {@link Unknown species} from {@link Shape}.
+   * 
+   * @param shape
+   *          original label from which output should be created
+   * @return {@link Unknown} object created from input {@link Label}
+   */
+  private Species createSpecies(Shape shape) {
+    logger.warn(shape.getWarningPrefix() + " Shape can not be part of reaction. Tranforming to Unknown");
+
+    Species res = new Unknown(shape.getGraphId());
+    res.setName(shape.getName());
+    return res;
+  }
+
+  /**
+   * This function add Species to right Complexes.
+   * 
+   * @param graph
+   *          gpml data model
+   * @param data
+   *          ...
+   * @throws UnknownChildClassException
+   *           thrown when complex contain invalid child
+   */
+  protected void putSpeciesIntoComplexes(Graph graph, Data data) throws UnknownChildClassException {
+    for (Group group : graph.getGroups()) {
+
+      Complex complexSpecies = (Complex) data.id2alias.get(group.getGraphId());
+      for (PathwayElement pe : group.getNodes()) {
+        Element species = data.id2alias.get(pe.getGraphId());
+        if (species != null) {
+          if (species instanceof Species) {
+
+            Species speciesAlias = (Species) species;
+            speciesAlias.setComplex(complexSpecies);
+            complexSpecies.addSpecies(speciesAlias);
+          }
+          // we have label
+        } else if (graph.getLabelByGraphId(pe.getGraphId()) != null) {
+          Label label = graph.getLabelByGraphId(pe.getGraphId());
+          // if complex has generic name then change it into label
+          if (complexSpecies.getName().equals(group.getGraphId())) {
+            complexSpecies.setName(label.getTextLabel());
+          } else {
+            // if there are more labels than one then merge labels
+            complexSpecies.setName(complexSpecies.getName() + "\n" + label.getTextLabel());
+          }
+        } else if (graph.getShapeByGraphId(pe.getGraphId()) != null) {
+          Shape shape = graph.getShapeByGraphId(pe.getGraphId());
+          if (INALID_COMPLEX_SHAPE_CHILDREN.contains(shape.getShape())) {
+            logger.warn(shape.getWarningPrefix() + shape.getShape() + " cannot be part of a complex. Skipping.");
+          } else {
+            throw new UnknownChildClassException("Unknown class type with id \"" + pe.getGraphId() + "\": "
+                + shape.getShape() + ". Group id: " + group.getGraphId());
+          }
+        } else {
+          throw new UnknownChildClassException(
+              "Cannot find child with id: " + pe.getGraphId() + ". Group id: " + group.getGraphId());
+        }
+      }
+    }
+  }
+
+  /**
+   * This function creates {@link Reaction} from {@link Interaction} from graph.
+   * 
+   * @param interaction
+   *          gpml interaction
+   * @param graph
+   *          gpml data model
+   * @param data
+   *          ...
+   * @return reaction created from gpml {@link Interaction}
+   */
+  protected Reaction createReactionFromInteraction(Interaction interaction, Graph graph, Data data) {
+    InteractionMapping mapping = InteractionMapping.getInteractionMapping(interaction.getType(),
+        interaction.getLine().getType());
+    if (mapping == null) {
+      throw new InvalidArgumentException("Unknown interaction type: " + interaction.getType());
+    }
+    Reaction reaction = createReactionByType(mapping.getModelReactionType());
+    reaction.setIdReaction(interaction.getGraphId());
+    reaction.setReversible(mapping.isReversible());
+
+    reaction.addMiriamData(interaction.getReferences());
+    for (String ref : interaction.getBiopaxReferences()) {
+      BiopaxPublication publication = graph.getBiopaxData().getPublicationByReference(ref);
+      MiriamData md = biopaxParser.createMiriamData(publication);
+      if (md != null) {
+        reaction.addMiriamData(md);
+      }
+    }
+
+    PolylineData pd = interaction.getLine();
+
+    Pair<PolylineData, PolylineData> pair = splitPolyline(pd);
+    PolylineData pdfirstpart = pair.getLeft();
+    PolylineData pdsecondpart = pair.getRight();
+
+    Reactant reactant = new Reactant();
+    reactant.setElement(data.id2alias.get(interaction.getStart()));
+    reactant.setLine(pdfirstpart);
+    reaction.addReactant(reactant);
+
+    Product product = new Product();
+    product.setElement(data.id2alias.get(interaction.getEnd()));
+    product.setLine(pdsecondpart);
+    reaction.addProduct(product);
+
+    for (Edge e : interaction.getReactants()) {
+      Reactant reac = createReactantFromEdge(data, e);
+      reaction.addReactant(reac);
+    }
+
+    for (Edge e : interaction.getProducts()) {
+      Product pro = createProductFromEdge(data, e);
+      reaction.addProduct(pro);
+    }
+
+    double centralLength = pdfirstpart.getPoints().get(pdfirstpart.getPoints().size() - 2)
+        .distance(pdfirstpart.getEndPoint()) * 2;
+
+    if (reaction.getReactants().size() > 1) {
+      PolylineData operatorLine = new PolylineData();
+      operatorLine.setColor(pdfirstpart.getColor());
+      operatorLine.addPoint((Point2D) pdfirstpart.getEndPoint().clone());
+      operatorLine.addPoint((Point2D) pdfirstpart.getEndPoint().clone());
+      pdfirstpart.trimEnd(centralLength / AND_OPERATOR_CENTRAL_LINE_RATIO);
+      operatorLine.setStartPoint((Point2D) pdfirstpart.getEndPoint().clone());
+      NodeOperator andOperator;
+      // heterodimer association use association operator
+      if (reaction instanceof HeterodimerAssociationReaction) {
+        andOperator = new AssociationOperator();
+        // all other reaction just force and operator between inputs
+      } else {
+        andOperator = new AndOperator();
+      }
+      andOperator.addInput(reactant);
+      andOperator.setLine(operatorLine);
+      for (int i = 1; i < reaction.getReactants().size(); i++) {
+        Reactant r = reaction.getReactants().get(i);
+        r.getLine().addPoint((Point2D) pdfirstpart.getEndPoint().clone());
+        andOperator.addInput(r);
+      }
+      reaction.addNode(andOperator);
+    }
+
+    if (reaction.getProducts().size() > 1) {
+      PolylineData operatorLine = new PolylineData();
+      operatorLine.setColor(pdsecondpart.getColor());
+
+      operatorLine.addPoint((Point2D) pdsecondpart.getBeginPoint().clone());
+      pdsecondpart.trimBegin(centralLength / SPLIT_OPERATOR_CENTRAL_LINE_RATIO);
+      operatorLine.addPoint((Point2D) pdsecondpart.getBeginPoint().clone());
+      SplitOperator splitOperator = new SplitOperator();
+      splitOperator.addOutput(product);
+      splitOperator.setLine(operatorLine);
+      for (int i = 1; i < reaction.getProducts().size(); i++) {
+        Product r = reaction.getProducts().get(i);
+        r.getLine().addPoint(0, (Point2D) pdsecondpart.getBeginPoint().clone());
+        splitOperator.addOutput(r);
+      }
+      reaction.addNode(splitOperator);
+    }
+
+    for (Edge e : interaction.getModifiers()) {
+      Modifier mod = createModifierFromEdge(data, e);
+      reaction.addModifier(mod);
+    }
+    if (reaction instanceof TwoReactantReactionInterface && reaction.getReactants().size() < 2) {
+      logger.warn("Reaction should contain at least 2 reactants. GraphId: " + interaction.getGraphId());
+      reaction = new UnknownTransitionReaction(reaction);
+    }
+    if (reaction instanceof ReducedNotation && ((reaction.getReactants().size() > 1)
+        || reaction.getProducts().size() > 1 || reaction.getModifiers().size() > 0)) {
+      logger.warn("Reaction should contain only one reactant and one product. GraphId: " + interaction.getGraphId());
+      reaction = new UnknownTransitionReaction(reaction);
+    }
+    ReactionLineData rld = ReactionLineData.getByReactionType(reaction.getClass());
+    if (rld == null) {
+      throw new InvalidArgumentException("Don't know how to process reaction type: " + reaction.getClass());
+    }
+    for (AbstractNode node : reaction.getNodes()) {
+      if (!(node instanceof Modifier)) {
+        node.getLine().setType(rld.getLineType());
+      }
+    }
+    for (Product p : reaction.getProducts()) {
+      p.getLine().getEndAtd().setArrowType(rld.getProductArrowType());
+      if (rld.getProductLineTrim() > 0) {
+        p.getLine().trimEnd(rld.getProductLineTrim());
+      }
+
+    }
+    if (reaction.isReversible()) {
+      for (Reactant r : reaction.getReactants()) {
+        r.getLine().getBeginAtd().setArrowType(rld.getProductArrowType());
+        if (rld.getProductLineTrim() > 0) {
+          r.getLine().trimBegin(rld.getProductLineTrim());
+        }
+      }
+    }
+
+    ModifierTypeUtils mtu = new ModifierTypeUtils();
+    for (Modifier m : reaction.getModifiers()) {
+      m.getLine().setEndPoint(m.getLine().getPoints().get(m.getLine().getPoints().size() - 2));
+      m.getLine().setEndPoint(mtu.getAnchorPointOnReactionRect(reaction, mtu.getTargetLineIndexByModifier(m)));
+    }
+
+    return reaction;
+  }
+
+  /**
+   * Creates {@link Reactant} from gpml edge.
+   * 
+   * @param data
+   *          ...
+   * @param e
+   *          edge
+   * @return {@link Reactant} from gpml edge
+   */
+  protected Reactant createReactantFromEdge(Data data, Edge e) {
+    String id = null;
+    if (data.id2alias.containsKey(e.getStart())) {
+      id = e.getStart();
+    } else if (data.id2alias.containsKey(e.getEnd())) {
+      id = e.getEnd();
+    }
+    if (id == null) {
+      throw new InvalidStateException("This reactant is invalid");
+    }
+
+    Reactant reac = new Reactant();
+    reac.setElement(data.id2alias.get(id));
+    reac.setLine(e.getLine());
+
+    // if somebody drew the reaction in reverse order (starting from reaction
+    // and going to the product) then reverse the order of points: order should
+    // be from reactant to the product
+    if (id.equals(e.getEnd())) {
+      reac.setLine(reac.getLine().reverse());
+    }
+    return reac;
+  }
+
+  /**
+   * Creates {@link Product} from gpml edge.
+   * 
+   * @param data
+   *          ...
+   * @param e
+   *          edge
+   * @return {@link Product} from gpml edge
+   */
+  protected Product createProductFromEdge(Data data, Edge e) {
+    String id = null;
+    if (data.id2alias.containsKey(e.getStart())) {
+      id = e.getStart();
+    } else if (data.id2alias.containsKey(e.getEnd())) {
+      id = e.getEnd();
+    }
+    if (id == null) {
+      throw new InvalidStateException("This product is invalid");
+    }
+    Product pro = new Product();
+    pro.setElement(data.id2alias.get(id));
+    pro.setLine(e.getLine());
+    // if somebody drew the reaction in reverse order (starting from reaction
+    // and going to the product) then reverse the order of points: order should
+    // be from reactant to the product
+    if (id.equals(e.getStart())) {
+      pro.setLine(pro.getLine().reverse());
+    }
+    return pro;
+  }
+
+  /**
+   * Creates {@link Modifier} from gpml edge.
+   * 
+   * @param data
+   *          ...
+   * @param e
+   *          edge
+   * @return {@link Modifier} from gpml edge
+   */
+  protected Modifier createModifierFromEdge(Data data, Edge e) {
+    InteractionMapping modifierMapping = InteractionMapping.getInteractionMapping(e.getType(), e.getLine().getType());
+    if (modifierMapping == null) {
+      throw new InvalidArgumentException("Unknown interaction type: " + e.getType());
+    }
+
+    Class<? extends ReactionNode> modifierType = null;
+    String id = null;
+    if (data.id2alias.containsKey(e.getStart())) {
+      modifierType = modifierMapping.getModelInputReactionNodeType();
+      id = e.getStart();
+    } else if (data.id2alias.containsKey(e.getEnd())) {
+      modifierType = modifierMapping.getModelOutputReactionNodeType();
+      id = e.getEnd();
+    }
+    if (id == null) {
+      throw new InvalidStateException("This modifier is invalid");
+    }
+
+    Modifier mod = createModifierByType(modifierType, (Species) data.id2alias.get(id));
+
+    ModifierType mt = mtu.getModifierTypeForClazz(mod.getClass());
+
+    e.getLine().setEndAtd(mt.getAtd());
+    e.getLine().setType(mt.getLineType());
+    mod.setLine(e.getLine());
+    return mod;
+  }
+
+  /**
+   * Creates {@link Reaction} for a given class type.
+   * 
+   * @param reactionType
+   *          type of reaction to create
+   * @return new instance of the reactionType
+   */
+  private Reaction createReactionByType(Class<? extends Reaction> reactionType) {
+    try {
+      Reaction result = reactionType.getConstructor().newInstance();
+      return result;
+    } catch (Exception e) {
+      throw new InvalidArgumentException("Cannot create reaction.", e);
+    }
+  }
+
+  /**
+   * Creates {@link Modifier} for a given class type.
+   * 
+   * @param modifierType
+   *          type of modifier in reaction to create
+   * @param alias
+   *          {@link Species alias } to which modifier is attached
+   * @return new instance of the modifierType
+   */
+  private Modifier createModifierByType(Class<? extends ReactionNode> modifierType, Species alias) {
+    try {
+      Modifier result = (Modifier) modifierType.getConstructor(Element.class).newInstance(alias);
+      return result;
+    } catch (Exception e) {
+      throw new InvalidArgumentException("Cannot create modifier.", e);
+    }
+  }
+
+  /**
+   * This function creates {@link Model} from {@link Graph}.
+   * 
+   * @param graph
+   *          object with data obtained from gpml
+   * @return {@link Model} object representing gpml
+   * @throws ConverterException
+   *           exception thrown when conversion from graph couldn't be performed
+   * 
+   */
+  public Model getModel(Graph graph) throws ConverterException {
+    try {
+      Data data = new Data();
+      Model model = new ModelFullIndexed(null);
+      model.setWidth(graph.getBoardWidth());
+      model.setHeight(graph.getBoardHeight());
+
+      model.setIdModel("1");
+      model.getLayers().add(data.layer);
+
+      addComplexSpecies(model, graph, data);
+      addElement(model, graph, data);
+      putSpeciesIntoComplexes(graph, data);
+
+      for (Interaction interaction : graph.getInteractions()) {
+        Reaction reaction = createReactionFromInteraction(interaction, graph, data);
+        model.addReaction(reaction);
+      }
+
+      removeEmptyComplexes(model);
+
+      fixCompartmentAliases(model);
+
+      StringBuilder tmp = new StringBuilder();
+      for (String string : graph.getComments()) {
+        tmp.append(string + "\n");
+      }
+      String notes = tmp.toString();
+      boolean different = false;
+      do {
+        String newNotes = StringEscapeUtils.unescapeHtml4(notes);
+        different = newNotes.compareTo(notes) != 0;
+        notes = newNotes;
+      } while (different);
+      if (notes != null) {
+        notes = StringEscapeUtils.unescapeHtml4(notes);
+      }
+      model.setNotes(notes);
+      StringBuilder references = new StringBuilder("");
+      for (String string : graph.getBiopaxReferences()) {
+        references.append(string + ", ");
+      }
+      if (references.length() > 0) {
+        logger.warn("[Biopax, " + references.toString() + "]\tModel annotations are not supported.");
+      }
+
+      assignNamesToComplexes(model);
+      assignNamesToCompartments(model);
+
+      data.layer.addLayerLines(createLines(graph));
+
+      putAliasesIntoCompartments(model);
+
+      return model;
+    } catch (UnknownChildClassException e) {
+      throw new ConverterException(e);
+    }
+  }
+
+  /**
+   * Method that put {@link Species aliases} that are not assigned into any
+   * {@link Compartment} into a proper compartment.
+   * 
+   * @param model
+   *          model where aliases will be modifed
+   */
+  private void putAliasesIntoCompartments(Model model) {
+    for (Element alias : model.getElements()) {
+      if (alias.getCompartment() == null) {
+        if (alias instanceof Species) {
+          Compartment selectedAlias = null;
+          for (Compartment cAlias : model.getCompartments()) {
+            if (cAlias.cross(alias)) {
+              if (selectedAlias == null) {
+                selectedAlias = cAlias;
+              } else if (selectedAlias.getSize() > cAlias.getSize()) {
+                selectedAlias = cAlias;
+              }
+            }
+          }
+          if (selectedAlias != null) {
+            selectedAlias.addElement(alias);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Removes empty complexes (with size 0) from model.
+   * 
+   * @param model
+   *          model where operation is performed
+   */
+  private void removeEmptyComplexes(Model model) {
+    Set<Element> aliasesInReaction = new HashSet<>();
+    for (Reaction reaction : model.getReactions()) {
+      for (ReactionNode node : reaction.getReactionNodes()) {
+        aliasesInReaction.add(node.getElement());
+      }
+    }
+    List<Element> toRemove = new ArrayList<>();
+    ElementUtils eu = new ElementUtils();
+    for (Element alias : model.getElements()) {
+      if (alias instanceof Complex) {
+        Complex cAlias = (Complex) alias;
+        if (cAlias.getSize() <= EPSILON && cAlias.getAllChildren().size() == 0) {
+          if (aliasesInReaction.contains(alias)) {
+            logger.warn(eu.getElementTag(alias) + "Empty element is invalid, but it's a part of reaction.");
+          } else {
+            toRemove.add(alias);
+            logger.warn(eu.getElementTag(alias) + "Empty element is invalid");
+          }
+        }
+      }
+    }
+    for (Element alias : toRemove) {
+      model.removeElement(alias);
+    }
+  }
+
+  /**
+   * Tries to find a name to assign to complexes if complexes don't contain them.
+   * 
+   * @param model
+   *          model where complexes are placed
+   */
+  private void assignNamesToComplexes(Model model) {
+    for (Element alias : model.getElements()) {
+      if (alias instanceof Complex) {
+        if (alias.getName() == null || (alias.getName().isEmpty())) {
+          for (Layer layer : model.getLayers()) {
+            LayerText toRemove = null;
+            for (LayerText lt : layer.getTexts()) {
+              if (alias.contains(lt)) {
+                alias.setName(lt.getNotes());
+                toRemove = lt;
+                break;
+              }
+            }
+            if (toRemove != null) {
+              layer.removeLayerText(toRemove);
+              break;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Tries to find a name to assign to compartments if comparments don't contain
+   * them.
+   * 
+   * @param model
+   *          model where compartments are placed
+   */
+  private void assignNamesToCompartments(Model model) {
+    for (Element alias : model.getElements()) {
+      if (alias instanceof Compartment) {
+        if (alias.getName() == null || alias.getName().isEmpty()) {
+          for (Layer layer : model.getLayers()) {
+            LayerText toRemove = null;
+            for (LayerText lt : layer.getTexts()) {
+              if (alias.contains(lt)) {
+                alias.setName(lt.getNotes());
+                toRemove = lt;
+                break;
+              }
+            }
+            if (toRemove != null) {
+              layer.removeLayerText(toRemove);
+              break;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Creates list of {@link LayerLine} in the model from gpml model.
+   * 
+   * @param graph
+   *          gpml model
+   * @return list of {@link LayerLine}
+   */
+  private Collection<PolylineData> createLines(Graph graph) {
+    List<PolylineData> result = new ArrayList<PolylineData>();
+    for (PolylineData pd : graph.getLines()) {
+      result.add(pd);
+    }
+    return result;
+  }
+
+  /**
+   * By default gpml doesn't offer information about compartments structure. This
+   * function fixes assignments to compartment and compartment aliases.
+   * 
+   * @param model
+   *          model where assignments are fixed.
+   */
+  private void fixCompartmentAliases(Model model) {
+    List<Compartment> aliases = model.getCompartments();
+    // clear all assignments
+    for (Compartment compartmentAlias : aliases) {
+      compartmentAlias.getElements().clear();
+    }
+
+    for (Element alias : model.getElements()) {
+      // elements inside complexes shouldn't be considered
+      if (alias instanceof Species) {
+        if (((Species) alias).getComplex() != null) {
+          continue;
+        }
+      }
+      Compartment parentAlias = null;
+      for (Compartment compartmentAlias : aliases) {
+        if (compartmentAlias.contains(alias)) {
+          if (parentAlias == null) {
+            parentAlias = compartmentAlias;
+          } else if (parentAlias.getSize() > compartmentAlias.getSize()) {
+            parentAlias = compartmentAlias;
+          }
+        }
+      }
+      if (parentAlias != null) {
+        parentAlias.addElement(alias);
+        alias.setCompartment(parentAlias);
+      }
+    }
+  }
 }
diff --git a/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java b/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java
index 63d7d4c0cc8cb5b99e9ade47cf4025e4d11a4000..4a32fc7fb2b20eb25f0d94eead4982f921e54edd 100644
--- a/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java
+++ b/pathvisio/src/test/java/lcsb/mapviewer/wikipathway/GPMLToModelTest.java
@@ -30,662 +30,664 @@ import lcsb.mapviewer.model.map.species.Protein;
 import lcsb.mapviewer.wikipathway.XML.GPMLToModel;
 
 public class GPMLToModelTest extends WikipathwaysTestFunctions {
-	/**
-	 * Default class logger.
-	 */
-	static Logger						logger = Logger.getLogger(GPMLToModelTest.class);
+  /**
+   * Default class logger.
+   */
+  static Logger logger = Logger.getLogger(GPMLToModelTest.class);
 
-	private ModelComparator	mc		 = new ModelComparator(1.0);
+  private ModelComparator mc = new ModelComparator(1.0);
 
-	@Test
-	public void DopamineTest() throws Exception {
-		try {
-			String pathToFile = "testFiles/wikipathways/";
-			String fileName = "Dopamine.gpml";
+  @Test
+  public void DopamineTest() throws Exception {
+    try {
+      String pathToFile = "testFiles/wikipathways/";
+      String fileName = "Dopamine.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
+      Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
 
-			assertEquals(22, getWarnings().size());
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      assertEquals(22, getWarnings().size());
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void WP1403_75220Test() throws Exception {
-		try {
-			String pathToFile = "testFiles/wikipathways/";
-			String fileName = "WP1403_75220.gpml";
+  @Test
+  public void WP1403_75220Test() throws Exception {
+    try {
+      String pathToFile = "testFiles/wikipathways/";
+      String fileName = "WP1403_75220.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
+      Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
 
-			assertEquals(22, getWarnings().size());
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      assertEquals(22, getWarnings().size());
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void WP528_76269Test() throws Exception {
-		try {
+  @Test
+  public void WP528_76269Test() throws Exception {
+    try {
 
-			String pathToFile = "testFiles/wikipathways/";
-			String fileName = "WP528_76269.gpml";
+      String pathToFile = "testFiles/wikipathways/";
+      String fileName = "WP528_76269.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
+      Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
 
-			assertEquals(15, getWarnings().size());
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      assertEquals(15, getWarnings().size());
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void WP550_73391Test() throws Exception {
-		try {
-			String pathToFile = "testFiles/wikipathways/";
-			String fileName = "WP550_73391.gpml";
+  @Test
+  public void WP550_73391Test() throws Exception {
+    try {
+      String pathToFile = "testFiles/wikipathways/";
+      String fileName = "WP550_73391.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
+      Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
 
-			assertEquals(16, getWarnings().size());
+      assertEquals(16, getWarnings().size());
 
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void WP197_69902Test() throws Exception {
-		try {
-			String pathToFile = "testFiles/wikipathways/";
-			String fileName = "WP197_69902.gpml";
+  @Test
+  public void WP197_69902Test() throws Exception {
+    try {
+      String pathToFile = "testFiles/wikipathways/";
+      String fileName = "WP197_69902.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
+      Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
 
-			assertEquals(3, getWarnings().size());
+      assertEquals(3, getWarnings().size());
 
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void WP179_70629Test() throws Exception {
-		try {
-			String pathToFile = "testFiles/wikipathways/";
-			String fileName = "WP179_70629.gpml";
+  @Test
+  public void WP179_70629Test() throws Exception {
+    try {
+      String pathToFile = "testFiles/wikipathways/";
+      String fileName = "WP179_70629.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
+      Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
 
-			assertEquals(38, getWarnings().size());
+      assertEquals(38, getWarnings().size());
 
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void WP306_71714Test() throws Exception {
-		try {
+  @Test
+  public void WP306_71714Test() throws Exception {
+    try {
 
-			String pathToFile = "testFiles/wikipathways/";
-			String fileName = "WP306_71714.gpml";
+      String pathToFile = "testFiles/wikipathways/";
+      String fileName = "WP306_71714.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
+      Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
 
-			assertEquals(41, getWarnings().size());
+      assertEquals(41, getWarnings().size());
 
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void WP481_72080Test() throws Exception {
-		try {
+  @Test
+  public void WP481_72080Test() throws Exception {
+    try {
 
-			String pathToFile = "testFiles/wikipathways/";
-			String fileName = "WP481_72080.gpml";
+      String pathToFile = "testFiles/wikipathways/";
+      String fileName = "WP481_72080.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
+      Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
 
-			assertEquals(22, getWarnings().size());
+      assertEquals(22, getWarnings().size());
 
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void testTwoReactants() throws Exception {
-		try {
+  @Test
+  public void testTwoReactants() throws Exception {
+    try {
 
-			String pathToFile = "testFiles/small/";
-			String fileName = "two_reactant.gpml";
+      String pathToFile = "testFiles/small/";
+      String fileName = "two_reactant.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
+      Model model1 = new GPMLToModel().getModel(pathToFile + fileName);
 
-			assertEquals(0, getWarnings().size());
+      assertEquals(0, getWarnings().size());
 
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
 
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void testTwoPubmeds() throws Exception {
-		try {
+  @Test
+  public void testTwoPubmeds() throws Exception {
+    try {
 
-			String pathToFile = "testFiles/small/reaction_with_two_pubmeds.gpml";
+      String pathToFile = "testFiles/small/reaction_with_two_pubmeds.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile);
-			assertEquals(2, model1.getReactions().iterator().next().getMiriamData().size());
+      Model model1 = new GPMLToModel().getModel(pathToFile);
+      assertEquals(2, model1.getReactions().iterator().next().getMiriamData().size());
 
-			assertEquals(0, getWarnings().size());
+      assertEquals(0, getWarnings().size());
 
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
 
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void testComment() throws Exception {
-		try {
+  @Test
+  public void testComment() throws Exception {
+    try {
 
-			String pathToFile = "testFiles/small/comment.gpml";
+      String pathToFile = "testFiles/small/comment.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile);
-			assertTrue(model1.getNotes().contains("Metabolic Process"));
+      Model model1 = new GPMLToModel().getModel(pathToFile);
+      assertTrue(model1.getNotes().contains("Metabolic Process"));
 
-			assertEquals(0, getWarnings().size());
+      assertEquals(0, getWarnings().size());
 
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
 
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void testGstp() throws Exception {
-		try {
+  @Test
+  public void testGstp() throws Exception {
+    try {
 
-			String pathToFile = "testFiles/wikipathways/gstp.gpml";
+      String pathToFile = "testFiles/wikipathways/gstp.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile);
+      Model model1 = new GPMLToModel().getModel(pathToFile);
 
-			assertEquals(3, getWarnings().size());
+      assertEquals(3, getWarnings().size());
 
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
 
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-	@Test
-	public void testMissingAliasesInCompartment() throws Exception {
-		try {
+  @Test
+  public void testMissingAliasesInCompartment() throws Exception {
+    try {
 
-			String pathToFile = "testFiles/small/missing_aliases_in_compartment.gpml";
+      String pathToFile = "testFiles/small/missing_aliases_in_compartment.gpml";
 
-			Model model1 = new GPMLToModel().getModel(pathToFile);
+      Model model1 = new GPMLToModel().getModel(pathToFile);
 
-			assertEquals(3, getWarnings().size());
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testModelLines() throws Exception {
-		try {
-
-			String fileName = "testFiles/small/model_with_line.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-
-			assertEquals(0, getWarnings().size());
-
-			assertEquals(1, model1.getLayers().iterator().next().getLines().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testModelShapes() throws Exception {
-		try {
-			String fileName = "testFiles/small/shapes.gpml";
-			new GPMLToModel().getModel(fileName);
-
-			assertEquals(11, getWarnings().size());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testHypotheticlaComplex() throws Exception {
-		try {
-			String fileName = "testFiles/complex/hypothetical_complex.gpml";
-			Model model = new GPMLToModel().getModel(fileName);
-			for (Complex species : model.getComplexList()) {
-				assertTrue("Complex parsed from gpml should be hypothetical", species.isHypothetical());
-			}
-
-			assertEquals(0, getWarnings().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testNonHypotheticlaComplex() throws Exception {
-		try {
-			String fileName = "testFiles/complex/nonhypothetical_complex.gpml";
-			Model model = new GPMLToModel().getModel(fileName);
-			for (Complex species : model.getComplexList()) {
-				assertFalse("Complex parsed from gpml should be hypothetical", species.isHypothetical());
-			}
-			assertEquals(0, getWarnings().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testComplexName() throws Exception {
-		try {
-			String fileName = "testFiles/complex/complex_with_name.gpml";
-			Model model = new GPMLToModel().getModel(fileName);
-			boolean nameFound = false;
-			for (Complex species : model.getComplexList()) {
-				if ("p70 S6 Kinases".equals(species.getName())) {
-					nameFound = true;
-				}
-			}
-			assertTrue("Complex parsed from gpml should have a valid name", nameFound);
-			assertEquals(1, getWarnings().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testCompartmentName() throws Exception {
-		try {
-			String fileName = "testFiles/compartment/compartment_name.gpml";
-			Model model = new GPMLToModel().getModel(fileName);
-			for (Compartment compartment : model.getCompartments()) {
-				assertEquals("Compartment parsed from gpml should have a valid name", "Label", compartment.getName());
-			}
-			assertEquals(0, getWarnings().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test(timeout = 30000)
-	@Ignore
-	public void test() throws Exception {
-		try {
-			String fileName = "D:/WP3408_81714.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			AbstractImageGenerator.Params params = new AbstractImageGenerator.Params().model(model1).width(model1.getWidth()).height(model1.getHeight());
-			PngImageGenerator pig = new PngImageGenerator(params);
-			pig.saveToFile("D:/tes1.png");
-
-			Desktop.getDesktop().open(new File("D:/tes1.png"));
-
-			params = new AbstractImageGenerator.Params().model(model2).width(model2.getWidth()).height(model2.getHeight());
-			pig = new PngImageGenerator(params);
-			pig.saveToFile("D:/tes2.png");
-
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testComplexInCompartment() throws Exception {
-		try {
-			String fileName = "testFiles/compartment/complex_in_compartment.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			assertEquals(0, mc.compare(model1, model2));
-
-			assertEquals(2, getWarnings().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testReactionToComplex() throws Exception {
-		try {
-			String fileName = "testFiles/small/reaction_to_complex.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			assertEquals(0, mc.compare(model1, model2));
-
-			assertEquals(54, getWarnings().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testColorfullComplexReaction() throws Exception {
-		try {
-			String fileName = "testFiles/reactions/complex_color_reaction.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testColorfullComplexReaction2() throws Exception {
-		try {
-			String fileName = "testFiles/reactions/complex_color_reaction2.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testProteinWithModification() throws Exception {
-		try {
-			String fileName = "testFiles/small/protein_with_modification.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-			assertEquals(0, getWarnings().size());
-
-			Gene protein = (Gene) model1.getElementByElementId("be3de");
-			assertNotNull(protein);
-			assertEquals(2, protein.getModificationResidues().size());
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			assertEquals(0, mc.compare(model1, model2));
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testProteinWithModification2() throws Exception {
-		try {
-			String fileName = "testFiles/small/protein_with_modification_2.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-			assertEquals(0, getWarnings().size());
-
-			Gene protein = (Gene) model1.getElementByElementId("be3de");
-			assertNotNull(protein);
-			assertEquals(2, protein.getModificationResidues().size());
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			assertEquals(0, mc.compare(model1, model2));
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testModifierPosition() throws Exception {
-		try {
-			String fileName = "testFiles/small/modifier_misaligned.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-
-			Reaction reaction = model1.getReactions().iterator().next();
-
-			double distance = reaction.getCenterPoint().distance(reaction.getModifiers().get(0).getLine().getEndPoint());
-			assertTrue("Modifier is too far from center point: " + distance, distance < ReactionCellDesignerConverter.RECT_SIZE);
-
-			assertEquals(1, getWarnings().size());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testReactionToLabel() throws Exception {
-		try {
-			String fileName = "testFiles/small/reaction_to_label.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-
-			assertEquals(1, getWarnings().size());
-
-			assertEquals(1, model1.getReactions().size());
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
-
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testModifierAsLabel() throws Exception {
-		try {
-			String fileName = "testFiles/small/modifier_to_label.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-
-			assertEquals(1, model1.getReactions().size());
-			assertEquals(3, model1.getReactions().iterator().next().getNodes().size());
-
-			assertEquals(1, getWarnings().size());
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      assertEquals(3, getWarnings().size());
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testModelLines() throws Exception {
+    try {
+
+      String fileName = "testFiles/small/model_with_line.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+
+      assertEquals(0, getWarnings().size());
+
+      assertEquals(1, model1.getLayers().iterator().next().getLines().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testModelShapes() throws Exception {
+    try {
+      String fileName = "testFiles/small/shapes.gpml";
+      new GPMLToModel().getModel(fileName);
+
+      assertEquals(11, getWarnings().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testHypotheticlaComplex() throws Exception {
+    try {
+      String fileName = "testFiles/complex/hypothetical_complex.gpml";
+      Model model = new GPMLToModel().getModel(fileName);
+      for (Complex species : model.getComplexList()) {
+        assertTrue("Complex parsed from gpml should be hypothetical", species.isHypothetical());
+      }
+
+      assertEquals(0, getWarnings().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testNonHypotheticlaComplex() throws Exception {
+    try {
+      String fileName = "testFiles/complex/nonhypothetical_complex.gpml";
+      Model model = new GPMLToModel().getModel(fileName);
+      for (Complex species : model.getComplexList()) {
+        assertFalse("Complex parsed from gpml should be hypothetical", species.isHypothetical());
+      }
+      assertEquals(0, getWarnings().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testComplexName() throws Exception {
+    try {
+      String fileName = "testFiles/complex/complex_with_name.gpml";
+      Model model = new GPMLToModel().getModel(fileName);
+      boolean nameFound = false;
+      for (Complex species : model.getComplexList()) {
+        if ("p70 S6 Kinases".equals(species.getName())) {
+          nameFound = true;
+        }
+      }
+      assertTrue("Complex parsed from gpml should have a valid name", nameFound);
+      assertEquals(1, getWarnings().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testCompartmentName() throws Exception {
+    try {
+      String fileName = "testFiles/compartment/compartment_name.gpml";
+      Model model = new GPMLToModel().getModel(fileName);
+      for (Compartment compartment : model.getCompartments()) {
+        assertEquals("Compartment parsed from gpml should have a valid name", "Label", compartment.getName());
+      }
+      assertEquals(0, getWarnings().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test(timeout = 30000)
+  @Ignore
+  public void test() throws Exception {
+    try {
+      String fileName = "D:/WP3408_81714.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+      AbstractImageGenerator.Params params = new AbstractImageGenerator.Params().model(model1).width(model1.getWidth())
+          .height(model1.getHeight());
+      PngImageGenerator pig = new PngImageGenerator(params);
+      pig.saveToFile("D:/tes1.png");
+
+      Desktop.getDesktop().open(new File("D:/tes1.png"));
+
+      params = new AbstractImageGenerator.Params().model(model2).width(model2.getWidth()).height(model2.getHeight());
+      pig = new PngImageGenerator(params);
+      pig.saveToFile("D:/tes2.png");
+
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testComplexInCompartment() throws Exception {
+    try {
+      String fileName = "testFiles/compartment/complex_in_compartment.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+      assertEquals(0, mc.compare(model1, model2));
+
+      assertEquals(2, getWarnings().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testReactionToComplex() throws Exception {
+    try {
+      String fileName = "testFiles/small/reaction_to_complex.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+      assertEquals(0, mc.compare(model1, model2));
+
+      assertEquals(54, getWarnings().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testColorfullComplexReaction() throws Exception {
+    try {
+      String fileName = "testFiles/reactions/complex_color_reaction.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testColorfullComplexReaction2() throws Exception {
+    try {
+      String fileName = "testFiles/reactions/complex_color_reaction2.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testProteinWithModification() throws Exception {
+    try {
+      String fileName = "testFiles/small/protein_with_modification.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+      assertEquals(0, getWarnings().size());
+
+      Gene protein = (Gene) model1.getElementByElementId("be3de");
+      assertNotNull(protein);
+      assertEquals(2, protein.getModificationResidues().size());
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+      assertEquals(0, mc.compare(model1, model2));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testProteinWithModification2() throws Exception {
+    try {
+      String fileName = "testFiles/small/protein_with_modification_2.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+      assertEquals(0, getWarnings().size());
+
+      Gene protein = (Gene) model1.getElementByElementId("be3de");
+      assertNotNull(protein);
+      assertEquals(2, protein.getModificationResidues().size());
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+      assertEquals(0, mc.compare(model1, model2));
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testModifierPosition() throws Exception {
+    try {
+      String fileName = "testFiles/small/modifier_misaligned.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+
+      Reaction reaction = model1.getReactions().iterator().next();
+
+      double distance = reaction.getCenterPoint().distance(reaction.getModifiers().get(0).getLine().getEndPoint());
+      assertTrue("Modifier is too far from center point: " + distance,
+          distance < ReactionCellDesignerConverter.RECT_SIZE);
+
+      assertEquals(1, getWarnings().size());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testReactionToLabel() throws Exception {
+    try {
+      String fileName = "testFiles/small/reaction_to_label.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+
+      assertEquals(1, getWarnings().size());
+
+      assertEquals(1, model1.getReactions().size());
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testModifierAsLabel() throws Exception {
+    try {
+      String fileName = "testFiles/small/modifier_to_label.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+
+      assertEquals(1, model1.getReactions().size());
+      assertEquals(3, model1.getReactions().iterator().next().getNodes().size());
+
+      assertEquals(1, getWarnings().size());
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+  @Test
+  public void testModifierAdsLabel() throws Exception {
+    try {
+      String fileName = "testFiles/small/protein_with_state.gpml";
+      Model model1 = new GPMLToModel().getModel(fileName);
+
+      Protein protein = (Protein) model1.getElementsByName("Protein").get(0);
+      assertEquals(0, protein.getModificationResidues().size());
+      assertEquals("GTP", protein.getStructuralState());
+
+      CellDesignerXmlParser parser = new CellDesignerXmlParser();
+      String xml = parser.toXml(model1);
+      InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
 
-	@Test
-	public void testModifierAdsLabel() throws Exception {
-		try {
-			String fileName = "testFiles/small/protein_with_state.gpml";
-			Model model1 = new GPMLToModel().getModel(fileName);
-
-			Protein protein = (Protein) model1.getElementsByName("Protein").get(0);
-			assertEquals(0, protein.getModificationResidues().size());
-			assertEquals("GTP", protein.getStructuralState());
-
-			CellDesignerXmlParser parser = new CellDesignerXmlParser();
-			String xml = parser.toXml(model1);
-			InputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+      Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
 
-			Model model2 = parser.createModel(new ConverterParams().inputStream(is).sizeAutoAdjust(false));
-
-			assertEquals(0, mc.compare(model1, model2));
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+      assertEquals(0, mc.compare(model1, model2));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
 }
diff --git a/persist/src/db/12.1.0~alpha.0/fix_db_20180705.sql b/persist/src/db/12.1.0~alpha.0/fix_db_20180705.sql
new file mode 100644
index 0000000000000000000000000000000000000000..d7bfbb3822d9b7af353d10b4e91556e39c903273
--- /dev/null
+++ b/persist/src/db/12.1.0~alpha.0/fix_db_20180705.sql
@@ -0,0 +1,7 @@
+-- coordinates for antisense rna changed into absolute x,y
+
+alter table antisense_rna_region_table add column position varchar(255);
+update antisense_rna_region_table set position=concat(element_table.x+(element_table.width*3/4*antisense_rna_region_table.pos),',',element_table.y) from  element_table where element_table.iddb = antisense_rna_region_table.idspeciesdb and not pos is null;
+update antisense_rna_region_table set position=concat(element_table.x,',',element_table.y) from  element_table where element_table.iddb = antisense_rna_region_table.idspeciesdb and pos is null;
+alter table antisense_rna_region_table drop column pos;
+
diff --git a/persist/src/db/12.1.0~alpha.0/fix_db_20180709.sql b/persist/src/db/12.1.0~alpha.0/fix_db_20180709.sql
new file mode 100644
index 0000000000000000000000000000000000000000..00778adbbc79f3ee1601e6f1605fdd700251dc31
--- /dev/null
+++ b/persist/src/db/12.1.0~alpha.0/fix_db_20180709.sql
@@ -0,0 +1,55 @@
+-- antisense rna uses string type
+
+alter table antisense_rna_region_table add column type_string varchar(255);
+update antisense_rna_region_table set type_string ='MODIFICATION_SITE' where type =0;
+update antisense_rna_region_table set type_string ='CODING_REGION' where type =1;
+update antisense_rna_region_table set type_string ='PROTEIN_BINDING_DOMAIN' where type =2;
+alter table antisense_rna_region_table drop column type;
+alter table antisense_rna_region_table rename COLUMN type_string to type;
+
+-- antisense region doesn't have state
+alter table antisense_rna_region_table drop column state;
+
+--size is changed to width for antisense rna region
+alter table antisense_rna_region_table add column width numeric(6,2);
+update antisense_rna_region_table set width=element_table.width*antisense_rna_region_table.size from  element_table where element_table.iddb = antisense_rna_region_table.idspeciesdb and not size is null;
+alter table antisense_rna_region_table drop column size;
+
+-- unused CellDesigner 'side' parameter removed
+alter table modification_residue_table drop column side;
+
+-- unused CellDesigner 'size' parameter removed
+alter table modification_residue_table drop column size;
+
+-- changing modification residue angle into x,y coordinates
+update modification_residue_table set angle=0 where angle>=2*pi();
+alter table modification_residue_table add column position varchar(255);
+--GENE
+update modification_residue_table set position=concat(element_table.x+modification_residue_table.angle/(2*pi())*element_table.width,',',element_table.y) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='GENE_ALIAS';
+
+--GENERIC PROTEIN
+update modification_residue_table set position=concat(element_table.x+element_table.width,',',element_table.y+element_table.height/2-modification_residue_table.angle/(pi()/4)*element_table.height/2) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='GENERIC_PROTEIN_ALIAS' and angle<=pi()/4;
+update modification_residue_table set position=concat(element_table.x+element_table.width-(modification_residue_table.angle-pi()/4)/(pi()/2)*element_table.width,',',element_table.y) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='GENERIC_PROTEIN_ALIAS' and angle>pi()/4 and angle<=3*pi()/4;
+update modification_residue_table set position=concat(element_table.x,',',element_table.y+((modification_residue_table.angle-3*pi()/4)/(pi()/2)*element_table.height)) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='GENERIC_PROTEIN_ALIAS' and angle>3*pi()/4 and angle<=5*pi()/4;
+update modification_residue_table set position=concat(element_table.x+((modification_residue_table.angle-5*pi()/4)/(pi()/2)*element_table.width),',',element_table.y+element_table.height) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='GENERIC_PROTEIN_ALIAS' and angle>5*pi()/4 and angle<=7*pi()/4;
+update modification_residue_table set position=concat(element_table.x+element_table.width,',',element_table.y+element_table.height-((modification_residue_table.angle-7*pi()/4)/(pi()/2)*element_table.height)) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='GENERIC_PROTEIN_ALIAS' and angle>7*pi()/4;
+--ION CHANNEL (it's the same as in generic protein - bug in old version)
+update modification_residue_table set position=concat(element_table.x+element_table.width,',',element_table.y+element_table.height/2-modification_residue_table.angle/(pi()/4)*element_table.height/2) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='ION_CHANNEL_PROTEIN_ALIAS' and angle<=pi()/4;
+update modification_residue_table set position=concat(element_table.x+element_table.width-(modification_residue_table.angle-pi()/4)/(pi()/2)*element_table.width,',',element_table.y) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='ION_CHANNEL_PROTEIN_ALIAS' and angle>pi()/4 and angle<=3*pi()/4;
+update modification_residue_table set position=concat(element_table.x,',',element_table.y+((modification_residue_table.angle-3*pi()/4)/(pi()/2)*element_table.height)) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='ION_CHANNEL_PROTEIN_ALIAS' and angle>3*pi()/4 and angle<=5*pi()/4;
+update modification_residue_table set position=concat(element_table.x+((modification_residue_table.angle-5*pi()/4)/(pi()/2)*element_table.width),',',element_table.y+element_table.height) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='ION_CHANNEL_PROTEIN_ALIAS' and angle>5*pi()/4 and angle<=7*pi()/4;
+update modification_residue_table set position=concat(element_table.x+element_table.width,',',element_table.y+element_table.height-((modification_residue_table.angle-7*pi()/4)/(pi()/2)*element_table.height)) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='ION_CHANNEL_PROTEIN_ALIAS' and angle>7*pi()/4;
+--RECEPTOR PROTEIN
+update modification_residue_table set position=concat(element_table.x+element_table.width,',',element_table.y+(1-modification_residue_table.angle/(pi()/4))*2.0/5.0*element_table.height) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='RECEPTOR_PROTEIN_ALIAS' and angle<=pi()/4;
+update modification_residue_table set position=concat(element_table.x+element_table.width-(modification_residue_table.angle-pi()/4)/(pi()/4)*element_table.width/2,',',element_table.y+(modification_residue_table.angle-pi()/4)/(pi()/4)*1.0/5.0*element_table.height) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='RECEPTOR_PROTEIN_ALIAS' and angle>pi()/4 and angle<=2*pi()/4;
+update modification_residue_table set position=concat(element_table.x+element_table.width/2-(modification_residue_table.angle-pi()/2)/(pi()/4)*element_table.width/2,',',element_table.y+1.0/5.0*element_table.height-(modification_residue_table.angle-pi()/2)/(pi()/4)*1.0/5.0*element_table.height) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='RECEPTOR_PROTEIN_ALIAS' and angle>2*pi()/4 and angle<=3*pi()/4;
+update modification_residue_table set position=concat(element_table.x,',',element_table.y+((modification_residue_table.angle-3*pi()/4)/(pi()/2)*4.0/5.0*element_table.height)) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='RECEPTOR_PROTEIN_ALIAS' and angle>3*pi()/4 and angle<=5*pi()/4;
+update modification_residue_table set position=concat(element_table.x+(modification_residue_table.angle-5*pi()/4)/(pi()/4)*element_table.width/2,',',element_table.y+4.0/5.0*element_table.height+(modification_residue_table.angle-5*pi()/4)/(pi()/4)*1.0/5.0*element_table.height) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='RECEPTOR_PROTEIN_ALIAS' and angle>5*pi()/4 and angle<=6*pi()/4;
+update modification_residue_table set position=concat(element_table.x+element_table.width/2+(modification_residue_table.angle-6*pi()/4)/(pi()/4)*element_table.width/2,',',element_table.y+element_table.height-(modification_residue_table.angle-6*pi()/4)/(pi()/4)*1.0/5.0*element_table.height) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='RECEPTOR_PROTEIN_ALIAS' and angle>6*pi()/4 and angle<=7*pi()/4;
+update modification_residue_table set position=concat(element_table.x+element_table.width,',',element_table.y+4.0/5.0*element_table.height-(modification_residue_table.angle-7*pi()/4)/(pi()/4)*2.0/5.0*element_table.height) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='RECEPTOR_PROTEIN_ALIAS' and angle>7*pi()/4;
+--TRUNCATED PROTEIN ALIAS
+update modification_residue_table set position=concat(element_table.x+element_table.width,',',element_table.y+element_table.height/2-modification_residue_table.angle/(pi()/4)*element_table.height/2) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='TRUNCATED_PROTEIN_ALIAS' and angle<=pi()/4;
+update modification_residue_table set position=concat(element_table.x+element_table.width-(modification_residue_table.angle-pi()/4)/(pi()/2)*element_table.width,',',element_table.y) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='TRUNCATED_PROTEIN_ALIAS' and angle>pi()/4 and angle<=3*pi()/4;
+update modification_residue_table set position=concat(element_table.x,',',element_table.y+((modification_residue_table.angle-3*pi()/4)/(pi()/2)*element_table.height)) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='TRUNCATED_PROTEIN_ALIAS' and angle>3*pi()/4 and angle<=5*pi()/4;
+update modification_residue_table set position=concat(element_table.x+((modification_residue_table.angle-5*pi()/4)/(pi()/2)*4.0/5.0*element_table.width),',',element_table.y+element_table.height) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='TRUNCATED_PROTEIN_ALIAS' and angle>5*pi()/4 and angle<=7*pi()/4;
+update modification_residue_table set position=concat(element_table.x+4.0/5.0*element_table.width,',',element_table.y+element_table.height-((modification_residue_table.angle-7*pi()/4)/(pi()/2)*element_table.height)) from element_table where element_table.iddb = modification_residue_table.idspeciesdb and element_type_db='TRUNCATED_PROTEIN_ALIAS' and angle>7*pi()/4;
diff --git a/persist/src/db/12.1.0~alpha.0/fix_db_20180710.sql b/persist/src/db/12.1.0~alpha.0/fix_db_20180710.sql
new file mode 100644
index 0000000000000000000000000000000000000000..c391524b79276d2df05443cda3f190fafd25ae18
--- /dev/null
+++ b/persist/src/db/12.1.0~alpha.0/fix_db_20180710.sql
@@ -0,0 +1,27 @@
+-- state of modification_residue is mapped via string
+
+alter table modification_residue_table add column state_string varchar(255);
+update modification_residue_table set state_string='PHOSPHORYLATED' where state=0;
+update modification_residue_table set state_string='ACETYLATED' where state=1;
+update modification_residue_table set state_string='UBIQUITINATED' where state=2;
+update modification_residue_table set state_string='METHYLATED' where state=3;
+update modification_residue_table set state_string='HYDROXYLATED' where state=4;
+update modification_residue_table set state_string='MYRISTOYLATED' where state=5;
+update modification_residue_table set state_string='SULFATED' where state=6;
+update modification_residue_table set state_string='PRENYLATED' where state=7;
+update modification_residue_table set state_string='GLYCOSYLATED' where state=8;
+update modification_residue_table set state_string='PALMYTOYLATED' where state=9;
+update modification_residue_table set state_string='UNKNOWN' where state=10;
+update modification_residue_table set state_string='EMPTY' where state=11;
+update modification_residue_table set state_string='PROTONATED' where state=12;
+update modification_residue_table set state_string='DONT_CARE' where state=13;
+alter table modification_residue_table drop column state;
+alter table modification_residue_table rename column state_string to state;
+
+-- coordinates for rna region changed into absolute x,y
+
+alter table rna_region_table add column position varchar(255);
+update rna_region_table set position=concat(element_table.x+element_table.width/4 +(element_table.width*3/4*rna_region_table.pos),',',element_table.y) from  element_table where element_table.iddb = rna_region_table.idspeciesdb and not pos is null;
+update rna_region_table set position=concat(element_table.x,',',element_table.y) from  element_table where element_table.iddb = rna_region_table.idspeciesdb and pos is null;
+alter table rna_region_table drop column pos;
+
diff --git a/persist/src/db/12.1.0~alpha.0/fix_db_20180711.sql b/persist/src/db/12.1.0~alpha.0/fix_db_20180711.sql
new file mode 100644
index 0000000000000000000000000000000000000000..f6867729b929fa57ebb957f66fe64bd21f3b7cc7
--- /dev/null
+++ b/persist/src/db/12.1.0~alpha.0/fix_db_20180711.sql
@@ -0,0 +1,21 @@
+--size is changed to width for rna region
+alter table rna_region_table add column width numeric(6,2);
+update rna_region_table set width=element_table.width*rna_region_table.size from  element_table where element_table.iddb = rna_region_table.idspeciesdb and not size is null;
+alter table rna_region_table drop column size;
+
+--modifications includes different type of modification (that will be resolved to different classes)
+alter table modification_residue_table add column modification_type varchar(255);
+update modification_residue_table set modification_type='MODIFICATION_SITE' from element_table where modification_residue_table.idspeciesdb=element_table.iddb and element_type_db='GENE_ALIAS';
+update modification_residue_table set modification_type='RESIDUE' from element_table where modification_residue_table.idspeciesdb=element_table.iddb and modification_type is null;
+
+-- move antisense rna regions into modification table
+alter table modification_residue_table add column width numeric(6,2);
+insert into modification_residue_table (idmodificationresidue, name, idspeciesdb, position, state, modification_type, width) select idantisensernaregion, name, idspeciesdb, position, null, type, width from antisense_rna_region_table;
+drop table antisense_rna_region_table;
+
+-- move rna regions into modification table
+insert into modification_residue_table (idmodificationresidue, name, idspeciesdb, position, state, modification_type, width) select idrnaregion, name, idspeciesdb, position, state, type, width from rna_region_table;
+update modification_residue_table set modification_type='MODIFICATION_SITE' where modification_type='Modification Site';
+update modification_residue_table set modification_type='PROTEIN_BINDING_DOMAIN' where modification_type='proteinBindingDomain';
+update modification_residue_table set modification_type='CODING_REGION' where modification_type='CodingRegion';
+drop table rna_region_table;
diff --git a/persist/src/db/12.1.0~alpha.0/fix_db_20180712.sql b/persist/src/db/12.1.0~alpha.0/fix_db_20180712.sql
new file mode 100644
index 0000000000000000000000000000000000000000..1383f8dffb33214795aaeaaf49f861afaafddfd5
--- /dev/null
+++ b/persist/src/db/12.1.0~alpha.0/fix_db_20180712.sql
@@ -0,0 +1,6 @@
+-- modification residue should have height 
+alter table modification_residue_table add column height numeric(6,2);
+update modification_residue_table set height = 10.0;
+
+-- transcription site activity and direction
+alter table modification_residue_table add column direction varchar(255);
diff --git a/persist/src/db/12.1.0~alpha.0/fix_db_20180718.sql b/persist/src/db/12.1.0~alpha.0/fix_db_20180718.sql
new file mode 100644
index 0000000000000000000000000000000000000000..6872876ec79cbd77890de8f7bacdad58780af5eb
--- /dev/null
+++ b/persist/src/db/12.1.0~alpha.0/fix_db_20180718.sql
@@ -0,0 +1,2 @@
+-- user account can be connected to LDAP directory 
+alter table user_table add column connectedtoldap boolean default false;
diff --git a/persist/src/main/java/lcsb/mapviewer/persist/dao/user/UserDao.java b/persist/src/main/java/lcsb/mapviewer/persist/dao/user/UserDao.java
index 84af311b9bf9fdcf675954b54995d6a3e257e203..b40e97920c451c461c04ec04326a38f3d6fb2fc4 100644
--- a/persist/src/main/java/lcsb/mapviewer/persist/dao/user/UserDao.java
+++ b/persist/src/main/java/lcsb/mapviewer/persist/dao/user/UserDao.java
@@ -2,9 +2,6 @@ package lcsb.mapviewer.persist.dao.user;
 
 import java.util.List;
 
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.crypto.password.PasswordEncoder;
-
 import lcsb.mapviewer.model.user.User;
 import lcsb.mapviewer.persist.dao.BaseDao;
 
@@ -16,102 +13,60 @@ import lcsb.mapviewer.persist.dao.BaseDao;
  */
 public class UserDao extends BaseDao<User> {
 
-	/**
-	 * Service that provides password encoding.
-	 */
-	@Autowired
-	private PasswordEncoder passwordEncoder;
-
-	/**
-	 * Default constructor.
-	 */
-	public UserDao() {
-		super(User.class, "removed");
-	}
-
-	/**
-	 * Returns user with a given login and password.
-	 * 
-	 * @param login
-	 *          user login
-	 * @param password
-	 *          - user password (plain text)
-	 * @return user for given login and password
-	 */
-	public User getUserByLoginAndPassword(String login, String password) {
-		if (password == null) {
-			return getUserByLoginAndCryptedPassword(login, null);
-		}
-		return getUserByLoginAndCryptedPassword(login, passwordEncoder.encode(password));
-	}
-
-	/**
-	 * Returns user with a given login and password.
-	 * 
-	 * @param login
-	 *          user login
-	 * @param password
-	 *          - user password (encrypted)
-	 * @return user for given login and password
-	 */
-	public User getUserByLoginAndCryptedPassword(String login, String password) {
-		List<?> list = getSession()
-				.createQuery(" from User where login=:login and cryptedPassword =:passwd " + removableAndStatemant()).setParameter("login", login)
-				.setParameter("passwd", password).list();
-		if (list.size() == 0) {
-			return null;
-		} else {
-			User user = (User) list.get(0);
-			return user;
-		}
-	}
-
-	/**
-	 * Returns user with a given login.
-	 * 
-	 * @param login
-	 *          user login
-	 * @return user for a given login
-	 */
-	public User getUserByLogin(String login) {
-		return getByParameter("login", login);
-	}
+  /**
+   * Default constructor.
+   */
+  public UserDao() {
+    super(User.class, "removed");
+  }
 
-	/**
-	 * Returns user with a given email.
-	 * 
-	 * @param email
-	 *          user email
-	 * @return user for a given email
-	 */
-	public User getUserByEmail(String email) {
-		return getByParameter("email", email);
-	}
+  /**
+   * Returns user with a given login and password.
+   * 
+   * @param login
+   *          user login
+   * @param password
+   *          - user password (encrypted)
+   * @return user for given login and password
+   */
+  public User getUserByLoginAndCryptedPassword(String login, String password) {
+    List<?> list = getSession()
+        .createQuery(" from User where login=:login and cryptedPassword =:passwd " + removableAndStatemant())
+        .setParameter("login", login).setParameter("passwd", password).list();
+    if (list.size() == 0) {
+      return null;
+    } else {
+      User user = (User) list.get(0);
+      return user;
+    }
+  }
 
-	@Override
-	public void delete(User object) {
-		object.setRemoved(true);
-		object.setLogin("[REMOVED]_" + object.getId() + "_" + object.getLogin());
-		update(object);
-	}
+  /**
+   * Returns user with a given login.
+   * 
+   * @param login
+   *          user login
+   * @return user for a given login
+   */
+  public User getUserByLogin(String login) {
+    return getByParameter("login", login);
+  }
 
-	/**
-	 * Returns {@link User} for given "name surname" string.
-	 * 
-	 * @param nameSurnameString
-	 *          string identifing user with name and surname separated by single
-	 *          space
-	 * @return {@link User} for given "name surname" string
-	 */
-	public User getUserByNameSurname(String nameSurnameString) {
-		List<?> list = getSession()
-				.createQuery(" from " + this.getClazz().getSimpleName() + " where  concat(name, ' ', surname) " + " = :param_val " + removableAndStatemant())
-				.setParameter("param_val", nameSurnameString).list();
-		if (list.size() == 0) {
-			return null;
-		} else {
-			return (User) list.get(0);
-		}
-	}
+  /**
+   * Returns user with a given email.
+   * 
+   * @param email
+   *          user email
+   * @return user for a given email
+   */
+  public User getUserByEmail(String email) {
+    return getByParameter("email", email);
+  }
 
+  @Override
+  public void delete(User object) {
+    object.setRemoved(true);
+    object.setLogin("[REMOVED]_" + object.getId() + "_" + object.getLogin());
+    update(object);
+  }
 }
diff --git a/persist/src/main/resources/applicationContext-persist.xml b/persist/src/main/resources/applicationContext-persist.xml
index 94e3760435c033093c2fed4f762ceb4c0d5490b3..104c0fb09f89b0e439566319960bf65309fed9ef 100644
--- a/persist/src/main/resources/applicationContext-persist.xml
+++ b/persist/src/main/resources/applicationContext-persist.xml
@@ -176,9 +176,13 @@
 				<value>lcsb.mapviewer.model.map.species.TruncatedProtein</value>
 				<value>lcsb.mapviewer.model.map.species.Unknown</value>
 
-				<value>lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion</value>
-				<value>lcsb.mapviewer.model.map.species.field.ModificationResidue</value>
-				<value>lcsb.mapviewer.model.map.species.field.RnaRegion</value>
+				<value>lcsb.mapviewer.model.map.species.field.BindingRegion</value>
+				<value>lcsb.mapviewer.model.map.species.field.CodingRegion</value>
+				<value>lcsb.mapviewer.model.map.species.field.ModificationSite</value>
+				<value>lcsb.mapviewer.model.map.species.field.ProteinBindingDomain</value>
+				<value>lcsb.mapviewer.model.map.species.field.RegulatoryRegion</value>				
+				<value>lcsb.mapviewer.model.map.species.field.Residue</value>
+				<value>lcsb.mapviewer.model.map.species.field.TranscriptionSite</value>				
 				<value>lcsb.mapviewer.model.map.species.field.UniprotRecord</value>
 				<value>lcsb.mapviewer.model.map.species.field.Structure</value>
 				
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/PersistTestFunctions.java b/persist/src/test/java/lcsb/mapviewer/persist/PersistTestFunctions.java
index 03b6cad1942c420382e0e165f6ef8e59029c6a58..80cdbd417b4393348102b0e4826b9af81e0e1814 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/PersistTestFunctions.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/PersistTestFunctions.java
@@ -56,241 +56,241 @@ import lcsb.mapviewer.persist.dao.user.UserDao;
 
 @Transactional(value = "txManager")
 @Rollback(true)
-@ContextConfiguration(locations = { "/applicationContext-persist.xml", // 
-		"/test-applicationContext.xml", // 
-		"/dataSource.xml"  //
-		})
+@ContextConfiguration(locations = { "/applicationContext-persist.xml", //
+    "/test-applicationContext.xml", //
+    "/dataSource.xml" //
+})
 @RunWith(SpringJUnit4ClassRunner.class)
 public abstract class PersistTestFunctions {
-	private Logger						 logger	 = Logger.getLogger(PersistTestFunctions.class);
-
-	public double							 EPSILON = 1e-6;
-
-	@Autowired
-	protected LogDao					 logDao;
-
-	@Autowired
-	protected SearchHistoryDao searchHistoryDao;
-
-	@Autowired
-	private PasswordEncoder		 passwordEncoder;
-
-	@Autowired
-	protected ProjectDao			 projectDao;
-
-	@Autowired
-	protected CacheQueryDao		 cacheQueryDao;
-
-	@Autowired
-	protected PolylineDao			 polylineDao;
-
-	@Autowired
-	protected ModelDao				 modelDao;
-
-	@Autowired
-	protected UserDao					 userDao;
-
-	@Autowired
-	protected PrivilegeDao		 privilegeDao;
-
-	@Autowired
-	protected CommentDao			 commentDao;
-
-	@Autowired
-	protected DbUtils					 dbUtils;
-
-	@Autowired
-	protected ReactionDao			 reactionDao;
-
-	@Autowired
-	protected ElementDao				 aliasDao;
-
-	protected User						 user;
-
-	@Autowired
-	protected CacheTypeDao		 cacheTypeDao;
-
-	protected String readFile(String file) throws IOException {
-		StringBuilder stringBuilder = new StringBuilder();
-		BufferedReader reader = new BufferedReader(new FileReader(file));
-		try {
-			String line = null;
-			String ls = System.getProperty("line.separator");
-
-			while ((line = reader.readLine()) != null) {
-				stringBuilder.append(line);
-				stringBuilder.append(ls);
-			}
-		} finally {
-			reader.close();
-		}
-
-		return stringBuilder.toString();
-	}
-
-	protected Node getNodeFromXmlString(String text) throws InvalidXmlSchemaException {
-		InputSource is = new InputSource();
-		is.setCharacterStream(new StringReader(text));
-		return getXmlDocumentFromInputSource(is).getChildNodes().item(0);
-	}
-
-	protected Document getXmlDocumentFromFile(String fileName) throws InvalidXmlSchemaException, IOException {
-		File file = new File(fileName);
-		InputStream inputStream = new FileInputStream(file);
-		Reader reader = null;
-		try {
-			reader = new InputStreamReader(inputStream, "UTF-8");
-			InputSource is = new InputSource(reader);
-
-			Document result = getXmlDocumentFromInputSource(is);
-			inputStream.close();
-			return result;
-		} catch (UnsupportedEncodingException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-		return null;
-	}
-
-	protected Document getXmlDocumentFromInputSource(InputSource stream) throws InvalidXmlSchemaException {
-		DocumentBuilder db;
-		try {
-			db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
-		} catch (ParserConfigurationException e) {
-			throw new InvalidXmlSchemaException("Problem with xml parser");
-		}
-		Document doc = null;
-		try {
-			doc = db.parse(stream);
-		} catch (SAXException e) {
-			logger.error(e);
-		} catch (IOException e) {
-			logger.error(e);
-		}
-		return doc;
-	}
-
-	/**
-	 * This method remove model with all connections from db (used only when the
-	 * db must be handled manually)
-	 * 
-	 * @param id
-	 */
-	protected void removeModelById(int id) {
-		modelDao.delete(modelDao.getById(id));
-	}
-
-	protected void createUser() {
-		user = new User();
-		user.setName("John");
-		user.setSurname("Doe");
-		user.setEmail("john.doe@uni.lu");
-		user.setLogin("john.doe");
-		user.setCryptedPassword(passwordEncoder.encode("passwd"));
-		userDao.add(user);
-	}
-
-	protected String createTmpFileName() {
-		try {
-			File f = File.createTempFile("prefix", ".txt");
-			String filename = f.getName();
-			f.delete();
-			return filename;
-		} catch (IOException e) {
-			e.printStackTrace();
-			return null;
-		}
-	}
-
-	protected String nodeToString(Node node) {
-		return nodeToString(node, false);
-	}
-
-	protected String nodeToString(Node node, boolean includeHeadNode) {
-		if (node == null)
-			return null;
-		StringWriter sw = new StringWriter();
-		try {
-			Transformer t = TransformerFactory.newInstance().newTransformer();
-			t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
-			t.setOutputProperty(OutputKeys.INDENT, "yes");
-			t.setOutputProperty(OutputKeys.METHOD, "xml");
-
-			NodeList list = node.getChildNodes();
-			for (int i = 0; i < list.getLength(); i++) {
-				Node element = list.item(i);
-				t.transform(new DOMSource(element), new StreamResult(sw));
-			}
-		} catch (TransformerException te) {
-			logger.debug("nodeToString Transformer Exception");
-		}
-		if (includeHeadNode) {
-			return "<" + node.getNodeName() + ">" + sw.toString() + "</" + node.getNodeName() + ">";
-		}
-		return sw.toString();
-	}
-
-	protected boolean equalFiles(String fileA, String fileB) throws IOException {
-		int BLOCK_SIZE = 65536;
-		FileInputStream inputStreamA = new FileInputStream(fileA);
-		FileInputStream inputStreamB = new FileInputStream(fileB);
-		// vary BLOCK_SIZE to suit yourself.
-		// it should probably a factor or multiple of the size of a disk
-		// sector/cluster.
-		// Note that your max heap size may need to be adjused
-		// if you have a very big block size or lots of these comparators.
-
-		// assume inputStreamA and inputStreamB are streams from your two files.
-		byte[] streamABlock = new byte[BLOCK_SIZE];
-		byte[] streamBBlock = new byte[BLOCK_SIZE];
-		boolean match = true;
-		int bytesReadA = 0;
-		int bytesReadB = 0;
-		do {
-			bytesReadA = inputStreamA.read(streamABlock);
-			bytesReadB = inputStreamB.read(streamBBlock);
-			match = ((bytesReadA == bytesReadB) && Arrays.equals(streamABlock, streamBBlock));
-		} while (match && (bytesReadA > -1));
-		inputStreamA.close();
-		inputStreamB.close();
-		return match;
-	}
-
-	public PrivilegeDao getPrivilegeDao() {
-		return privilegeDao;
-	}
-
-	public void setPrivilegeDao(PrivilegeDao privilegeDao) {
-		this.privilegeDao = privilegeDao;
-	}
-
-	public File createTempDirectory() throws IOException {
-		final File temp;
-
-		temp = File.createTempFile("temp", Long.toString(System.nanoTime()));
-
-		if (!(temp.delete())) {
-			throw new IOException("Could not delete temp file: " + temp.getAbsolutePath());
-		}
-
-		if (!(temp.mkdir())) {
-			throw new IOException("Could not create temp directory: " + temp.getAbsolutePath());
-		}
-
-		return (temp);
-	}
-
-	protected String getWebpage(String accessUrl) throws IOException {
-		String inputLine;
-		StringBuilder tmp = new StringBuilder();
-		URL url = new URL(accessUrl);
-		URLConnection urlConn = url.openConnection();
-		BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
-
-		while ((inputLine = in.readLine()) != null) {
-			tmp.append(inputLine);
-		}
-		in.close();
-		return tmp.toString();
-	}
+  private Logger logger = Logger.getLogger(PersistTestFunctions.class);
+
+  public double EPSILON = 1e-6;
+
+  @Autowired
+  protected LogDao logDao;
+
+  @Autowired
+  protected SearchHistoryDao searchHistoryDao;
+
+  @Autowired
+  private PasswordEncoder passwordEncoder;
+
+  @Autowired
+  protected ProjectDao projectDao;
+
+  @Autowired
+  protected CacheQueryDao cacheQueryDao;
+
+  @Autowired
+  protected PolylineDao polylineDao;
+
+  @Autowired
+  protected ModelDao modelDao;
+
+  @Autowired
+  protected UserDao userDao;
+
+  @Autowired
+  protected PrivilegeDao privilegeDao;
+
+  @Autowired
+  protected CommentDao commentDao;
+
+  @Autowired
+  protected DbUtils dbUtils;
+
+  @Autowired
+  protected ReactionDao reactionDao;
+
+  @Autowired
+  protected ElementDao elementDao;
+
+  protected User user;
+
+  @Autowired
+  protected CacheTypeDao cacheTypeDao;
+
+  protected String readFile(String file) throws IOException {
+    StringBuilder stringBuilder = new StringBuilder();
+    BufferedReader reader = new BufferedReader(new FileReader(file));
+    try {
+      String line = null;
+      String ls = System.getProperty("line.separator");
+
+      while ((line = reader.readLine()) != null) {
+        stringBuilder.append(line);
+        stringBuilder.append(ls);
+      }
+    } finally {
+      reader.close();
+    }
+
+    return stringBuilder.toString();
+  }
+
+  protected Node getNodeFromXmlString(String text) throws InvalidXmlSchemaException {
+    InputSource is = new InputSource();
+    is.setCharacterStream(new StringReader(text));
+    return getXmlDocumentFromInputSource(is).getChildNodes().item(0);
+  }
+
+  protected Document getXmlDocumentFromFile(String fileName) throws InvalidXmlSchemaException, IOException {
+    File file = new File(fileName);
+    InputStream inputStream = new FileInputStream(file);
+    Reader reader = null;
+    try {
+      reader = new InputStreamReader(inputStream, "UTF-8");
+      InputSource is = new InputSource(reader);
+
+      Document result = getXmlDocumentFromInputSource(is);
+      inputStream.close();
+      return result;
+    } catch (UnsupportedEncodingException e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+    }
+    return null;
+  }
+
+  protected Document getXmlDocumentFromInputSource(InputSource stream) throws InvalidXmlSchemaException {
+    DocumentBuilder db;
+    try {
+      db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+    } catch (ParserConfigurationException e) {
+      throw new InvalidXmlSchemaException("Problem with xml parser");
+    }
+    Document doc = null;
+    try {
+      doc = db.parse(stream);
+    } catch (SAXException e) {
+      logger.error(e);
+    } catch (IOException e) {
+      logger.error(e);
+    }
+    return doc;
+  }
+
+  /**
+   * This method remove model with all connections from db (used only when the db
+   * must be handled manually)
+   * 
+   * @param id
+   */
+  protected void removeModelById(int id) {
+    modelDao.delete(modelDao.getById(id));
+  }
+
+  protected void createUser() {
+    user = new User();
+    user.setName("John");
+    user.setSurname("Doe");
+    user.setEmail("john.doe@uni.lu");
+    user.setLogin("john.doe");
+    user.setCryptedPassword(passwordEncoder.encode("passwd"));
+    userDao.add(user);
+  }
+
+  protected String createTmpFileName() {
+    try {
+      File f = File.createTempFile("prefix", ".txt");
+      String filename = f.getName();
+      f.delete();
+      return filename;
+    } catch (IOException e) {
+      e.printStackTrace();
+      return null;
+    }
+  }
+
+  protected String nodeToString(Node node) {
+    return nodeToString(node, false);
+  }
+
+  protected String nodeToString(Node node, boolean includeHeadNode) {
+    if (node == null)
+      return null;
+    StringWriter sw = new StringWriter();
+    try {
+      Transformer t = TransformerFactory.newInstance().newTransformer();
+      t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+      t.setOutputProperty(OutputKeys.INDENT, "yes");
+      t.setOutputProperty(OutputKeys.METHOD, "xml");
+
+      NodeList list = node.getChildNodes();
+      for (int i = 0; i < list.getLength(); i++) {
+        Node element = list.item(i);
+        t.transform(new DOMSource(element), new StreamResult(sw));
+      }
+    } catch (TransformerException te) {
+      logger.debug("nodeToString Transformer Exception");
+    }
+    if (includeHeadNode) {
+      return "<" + node.getNodeName() + ">" + sw.toString() + "</" + node.getNodeName() + ">";
+    }
+    return sw.toString();
+  }
+
+  protected boolean equalFiles(String fileA, String fileB) throws IOException {
+    int BLOCK_SIZE = 65536;
+    FileInputStream inputStreamA = new FileInputStream(fileA);
+    FileInputStream inputStreamB = new FileInputStream(fileB);
+    // vary BLOCK_SIZE to suit yourself.
+    // it should probably a factor or multiple of the size of a disk
+    // sector/cluster.
+    // Note that your max heap size may need to be adjused
+    // if you have a very big block size or lots of these comparators.
+
+    // assume inputStreamA and inputStreamB are streams from your two files.
+    byte[] streamABlock = new byte[BLOCK_SIZE];
+    byte[] streamBBlock = new byte[BLOCK_SIZE];
+    boolean match = true;
+    int bytesReadA = 0;
+    int bytesReadB = 0;
+    do {
+      bytesReadA = inputStreamA.read(streamABlock);
+      bytesReadB = inputStreamB.read(streamBBlock);
+      match = ((bytesReadA == bytesReadB) && Arrays.equals(streamABlock, streamBBlock));
+    } while (match && (bytesReadA > -1));
+    inputStreamA.close();
+    inputStreamB.close();
+    return match;
+  }
+
+  public PrivilegeDao getPrivilegeDao() {
+    return privilegeDao;
+  }
+
+  public void setPrivilegeDao(PrivilegeDao privilegeDao) {
+    this.privilegeDao = privilegeDao;
+  }
+
+  public File createTempDirectory() throws IOException {
+    final File temp;
+
+    temp = File.createTempFile("temp", Long.toString(System.nanoTime()));
+
+    if (!(temp.delete())) {
+      throw new IOException("Could not delete temp file: " + temp.getAbsolutePath());
+    }
+
+    if (!(temp.mkdir())) {
+      throw new IOException("Could not create temp directory: " + temp.getAbsolutePath());
+    }
+
+    return (temp);
+  }
+
+  protected String getWebpage(String accessUrl) throws IOException {
+    String inputLine;
+    StringBuilder tmp = new StringBuilder();
+    URL url = new URL(accessUrl);
+    URLConnection urlConn = url.openConnection();
+    BufferedReader in = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));
+
+    while ((inputLine = in.readLine()) != null) {
+      tmp.append(inputLine);
+    }
+    in.close();
+    return tmp.toString();
+  }
 }
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/cache/BigFileEntryDaoTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/cache/BigFileEntryDaoTest.java
index e7bbd2c94aa9f69577d1c092ac2630fbf086291b..39aad751d664333c46ddc40602814da613db67fd 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/cache/BigFileEntryDaoTest.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/cache/BigFileEntryDaoTest.java
@@ -1,80 +1,80 @@
-package lcsb.mapviewer.persist.dao.cache;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-
-import lcsb.mapviewer.model.cache.BigFileEntry;
-import lcsb.mapviewer.persist.DbUtils;
-import lcsb.mapviewer.persist.PersistTestFunctions;
-
-public class BigFileEntryDaoTest extends PersistTestFunctions {
-
-	@Autowired
-	BigFileEntryDao	bigFileEntryDao;
-
-	@Autowired
-	DbUtils					dbUtils;
-
-	boolean					flush;
-
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
-
-	@Before
-	public void setUp() throws Exception {
-		flush = dbUtils.isAutoFlush();
-		dbUtils.setAutoFlush(true);
-	}
-
-	@After
-	public void tearDown() throws Exception {
-		dbUtils.setAutoFlush(flush);
-	}
-
-	@Test
-	public void testAdd() {
-		try {
-			BigFileEntry entry = new BigFileEntry();
-			long count = bigFileEntryDao.getCount();
-			bigFileEntryDao.add(entry);
-			long count2 = bigFileEntryDao.getCount();
-			bigFileEntryDao.delete(entry);
-			long count3 = bigFileEntryDao.getCount();
-
-			assertEquals(count + 1, count2);
-			assertEquals(count2 - 1, count3);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetByUrl() {
-		try {
-			String url = "xxx.yyy";
-			BigFileEntry entry = new BigFileEntry();
-			entry.setUrl(url);
-
-			BigFileEntry result = bigFileEntryDao.getByUrl(url);
-			assertNull(result);
-			bigFileEntryDao.add(entry);
-
-			result = bigFileEntryDao.getByUrl(url);
-			assertEquals(entry, result);
-
-			bigFileEntryDao.delete(entry);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.persist.dao.cache;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import lcsb.mapviewer.model.cache.BigFileEntry;
+import lcsb.mapviewer.persist.DbUtils;
+import lcsb.mapviewer.persist.PersistTestFunctions;
+
+public class BigFileEntryDaoTest extends PersistTestFunctions {
+
+  @Autowired
+  BigFileEntryDao bigFileEntryDao;
+
+  @Autowired
+  DbUtils dbUtils;
+
+  boolean flush;
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    flush = dbUtils.isAutoFlush();
+    dbUtils.setAutoFlush(true);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    dbUtils.setAutoFlush(flush);
+  }
+
+  @Test
+  public void testAdd() {
+    try {
+      BigFileEntry entry = new BigFileEntry();
+      long count = bigFileEntryDao.getCount();
+      bigFileEntryDao.add(entry);
+      long count2 = bigFileEntryDao.getCount();
+      bigFileEntryDao.delete(entry);
+      long count3 = bigFileEntryDao.getCount();
+
+      assertEquals(count + 1, count2);
+      assertEquals(count2 - 1, count3);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetByUrl() {
+    try {
+      String url = "xxx.yyy";
+      BigFileEntry entry = new BigFileEntry();
+      entry.setUrl(url);
+
+      BigFileEntry result = bigFileEntryDao.getByUrl(url);
+      assertNull(result);
+      bigFileEntryDao.add(entry);
+
+      result = bigFileEntryDao.getByUrl(url);
+      assertEquals(entry, result);
+
+      bigFileEntryDao.delete(entry);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/CommentDaoTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/CommentDaoTest.java
index b18a7cba2a305f7f2885bef08bdb49817ef45c37..e00f0b9d3a59dd54fd112a61054a5dc23879a434 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/CommentDaoTest.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/CommentDaoTest.java
@@ -1,185 +1,186 @@
-package lcsb.mapviewer.persist.dao.map;
-
-import static org.junit.Assert.assertEquals;
-
-import java.awt.Color;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.map.Comment;
-import lcsb.mapviewer.model.map.MiriamData;
-import lcsb.mapviewer.model.map.MiriamRelationType;
-import lcsb.mapviewer.model.map.MiriamType;
-import lcsb.mapviewer.model.map.compartment.Compartment;
-import lcsb.mapviewer.model.map.layout.graphics.Layer;
-import lcsb.mapviewer.model.map.layout.graphics.LayerRect;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelFullIndexed;
-import lcsb.mapviewer.model.map.reaction.Product;
-import lcsb.mapviewer.model.map.reaction.Reactant;
-import lcsb.mapviewer.model.map.reaction.Reaction;
-import lcsb.mapviewer.model.map.reaction.type.TransportReaction;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.GenericProtein;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.persist.PersistTestFunctions;
-
-public class CommentDaoTest extends PersistTestFunctions {
-	int							identifierCounter	= 1;
-
-	private Project	project;
-	String					projectId					= "Some_id";
-
-	@Before
-	public void setUp() throws Exception {
-		project = projectDao.getProjectByProjectId(projectId);
-		if (project != null) {
-			projectDao.delete(project);
-		}
-		project = new Project();
-		project.setProjectId(projectId);
-		projectDao.add(project);
-	}
-
-	@After
-	public void tearDown() throws Exception {
-		projectDao.delete(project);
-	}
-
-	@Test
-	public void testGetComments() {
-		try {
-			Model model = createModel();
-			project.addModel(model);
-			modelDao.add(model);
-			projectDao.update(project);
-
-			Comment comment = new Comment();
-			comment.setDeleted(true);
-			comment.setModel(model);
-			commentDao.add(comment);
-
-			Comment comment2 = new Comment();
-			comment2.setPinned(true);
-			comment2.setModel(model);
-			commentDao.add(comment2);
-
-			assertEquals(0, commentDao.getCommentByModel(model, true, true).size());
-			assertEquals(1, commentDao.getCommentByModel(model, false, true).size());
-			assertEquals(1, commentDao.getCommentByModel(model, null, true).size());
-			assertEquals(1, commentDao.getCommentByModel(model, true, false).size());
-			assertEquals(0, commentDao.getCommentByModel(model, false, false).size());
-			assertEquals(1, commentDao.getCommentByModel(model, null, false).size());
-			assertEquals(1, commentDao.getCommentByModel(model, true, null).size());
-			assertEquals(1, commentDao.getCommentByModel(model, false, null).size());
-			assertEquals(2, commentDao.getCommentByModel(model, null, null).size());
-
-			assertEquals(0, commentDao.getCommentByModel(model.getModelData(), true, true).size());
-			assertEquals(1, commentDao.getCommentByModel(model.getModelData(), false, true).size());
-			assertEquals(1, commentDao.getCommentByModel(model.getModelData(), null, true).size());
-			assertEquals(1, commentDao.getCommentByModel(model.getModelData(), true, false).size());
-			assertEquals(0, commentDao.getCommentByModel(model.getModelData(), false, false).size());
-			assertEquals(1, commentDao.getCommentByModel(model.getModelData(), null, false).size());
-			assertEquals(1, commentDao.getCommentByModel(model.getModelData(), true, null).size());
-			assertEquals(1, commentDao.getCommentByModel(model.getModelData(), false, null).size());
-			assertEquals(2, commentDao.getCommentByModel(model.getModelData(), null, null).size());
-
-			commentDao.delete(comment);
-			commentDao.delete(comment2);
-			modelDao.delete(model);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-
-	}
-
-	private Model createModel() {
-		Model model = new ModelFullIndexed(null);
-
-		GenericProtein alias = createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "sa2");
-		model.addElement(alias);
-		alias = createSpeciesAlias(267.6666666666665, 438.75, 80.0, 40.0, "sa1117");
-		model.addElement(alias);
-		alias = createSpeciesAlias(261.6666666666665, 600.75, 92.0, 52.0, "sa1119");
-		model.addElement(alias);
-		alias = createSpeciesAlias(203.666666666667, 687.75, 98.0, 58.0, "sa1121");
-		model.addElement(alias);
-
-		alias = createSpeciesAlias(817.714285714286, 287.642857142859, 80.0, 40.0, "sa1422");
-		Species alias2 = createSpeciesAlias(224.964285714286, 241.392857142859, 80.0, 40.0, "sa1419");
-		Complex alias3 = createComplexAlias(804.714285714286, 182.642857142859, 112.0, 172.0, "csa152");
-		alias3.addSpecies(alias);
-		alias3.addSpecies(alias2);
-		alias.setComplex(alias3);
-		alias2.setComplex(alias3);
-
-		model.addElement(alias);
-		model.addElement(alias2);
-		model.addElement(alias3);
-
-		Compartment cAlias = createCompartmentAlias(380.0, 416.0, 1893.0, 1866.0, "ca1");
-		model.addElement(cAlias);
-		model.setWidth(2000);
-		model.setHeight(2000);
-
-		Layer layer = new Layer();
-		model.addLayer(layer);
-
-		LayerRect lr = new LayerRect();
-		lr.setColor(Color.YELLOW);
-		layer.addLayerRect(lr);
-
-		Reaction reaction = new TransportReaction();
-		reaction.addProduct(new Product(alias));
-		reaction.addReactant(new Reactant(alias2));
-		reaction.setIdReaction("re" + identifierCounter++);
-		model.addReaction(reaction);
-
-		alias = createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "pr1");
-		model.addElement(alias);
-
-		ModificationResidue mr = new ModificationResidue();
-		mr.setName("mr");
-		alias.addModificationResidue(mr);
-
-		alias.addMiriamData(new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.CHEBI, "c"));
-		return model;
-	}
-
-	private Compartment createCompartmentAlias(double x, double y, double width, double height, String aliasId) {
-		Compartment alias = new Compartment(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-	private GenericProtein createSpeciesAlias(double x, double y, double width, double height, String aliasId) {
-		GenericProtein alias = new GenericProtein(aliasId);
-		alias.setName("SNCA");
-		alias.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA"));
-		alias.addMiriamData(new MiriamData(MiriamType.HGNC, "11138"));
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-	private Complex createComplexAlias(double x, double y, double width, double height, String aliasId) {
-		Complex alias = new Complex(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-}
+package lcsb.mapviewer.persist.dao.map;
+
+import static org.junit.Assert.assertEquals;
+
+import java.awt.Color;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.map.Comment;
+import lcsb.mapviewer.model.map.MiriamData;
+import lcsb.mapviewer.model.map.MiriamRelationType;
+import lcsb.mapviewer.model.map.MiriamType;
+import lcsb.mapviewer.model.map.compartment.Compartment;
+import lcsb.mapviewer.model.map.layout.graphics.Layer;
+import lcsb.mapviewer.model.map.layout.graphics.LayerRect;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.model.map.reaction.Product;
+import lcsb.mapviewer.model.map.reaction.Reactant;
+import lcsb.mapviewer.model.map.reaction.Reaction;
+import lcsb.mapviewer.model.map.reaction.type.TransportReaction;
+import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.Residue;
+import lcsb.mapviewer.persist.PersistTestFunctions;
+
+public class CommentDaoTest extends PersistTestFunctions {
+  int identifierCounter = 1;
+
+  private Project project;
+  String projectId = "Some_id";
+
+  @Before
+  public void setUp() throws Exception {
+    project = projectDao.getProjectByProjectId(projectId);
+    if (project != null) {
+      projectDao.delete(project);
+    }
+    project = new Project();
+    project.setProjectId(projectId);
+    projectDao.add(project);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    projectDao.delete(project);
+  }
+
+  @Test
+  public void testGetComments() {
+    try {
+      Model model = createModel();
+      project.addModel(model);
+      modelDao.add(model);
+      projectDao.update(project);
+
+      Comment comment = new Comment();
+      comment.setDeleted(true);
+      comment.setModel(model);
+      commentDao.add(comment);
+
+      Comment comment2 = new Comment();
+      comment2.setPinned(true);
+      comment2.setModel(model);
+      commentDao.add(comment2);
+
+      assertEquals(0, commentDao.getCommentByModel(model, true, true).size());
+      assertEquals(1, commentDao.getCommentByModel(model, false, true).size());
+      assertEquals(1, commentDao.getCommentByModel(model, null, true).size());
+      assertEquals(1, commentDao.getCommentByModel(model, true, false).size());
+      assertEquals(0, commentDao.getCommentByModel(model, false, false).size());
+      assertEquals(1, commentDao.getCommentByModel(model, null, false).size());
+      assertEquals(1, commentDao.getCommentByModel(model, true, null).size());
+      assertEquals(1, commentDao.getCommentByModel(model, false, null).size());
+      assertEquals(2, commentDao.getCommentByModel(model, null, null).size());
+
+      assertEquals(0, commentDao.getCommentByModel(model.getModelData(), true, true).size());
+      assertEquals(1, commentDao.getCommentByModel(model.getModelData(), false, true).size());
+      assertEquals(1, commentDao.getCommentByModel(model.getModelData(), null, true).size());
+      assertEquals(1, commentDao.getCommentByModel(model.getModelData(), true, false).size());
+      assertEquals(0, commentDao.getCommentByModel(model.getModelData(), false, false).size());
+      assertEquals(1, commentDao.getCommentByModel(model.getModelData(), null, false).size());
+      assertEquals(1, commentDao.getCommentByModel(model.getModelData(), true, null).size());
+      assertEquals(1, commentDao.getCommentByModel(model.getModelData(), false, null).size());
+      assertEquals(2, commentDao.getCommentByModel(model.getModelData(), null, null).size());
+
+      commentDao.delete(comment);
+      commentDao.delete(comment2);
+      modelDao.delete(model);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+
+  }
+
+  private Model createModel() {
+    Model model = new ModelFullIndexed(null);
+
+    GenericProtein alias = createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "sa2");
+    model.addElement(alias);
+    alias = createSpeciesAlias(267.6666666666665, 438.75, 80.0, 40.0, "sa1117");
+    model.addElement(alias);
+    alias = createSpeciesAlias(261.6666666666665, 600.75, 92.0, 52.0, "sa1119");
+    model.addElement(alias);
+    alias = createSpeciesAlias(203.666666666667, 687.75, 98.0, 58.0, "sa1121");
+    model.addElement(alias);
+
+    alias = createSpeciesAlias(817.714285714286, 287.642857142859, 80.0, 40.0, "sa1422");
+    Species alias2 = createSpeciesAlias(224.964285714286, 241.392857142859, 80.0, 40.0, "sa1419");
+    Complex alias3 = createComplexAlias(804.714285714286, 182.642857142859, 112.0, 172.0, "csa152");
+    alias3.addSpecies(alias);
+    alias3.addSpecies(alias2);
+    alias.setComplex(alias3);
+    alias2.setComplex(alias3);
+
+    model.addElement(alias);
+    model.addElement(alias2);
+    model.addElement(alias3);
+
+    Compartment cAlias = createCompartmentAlias(380.0, 416.0, 1893.0, 1866.0, "ca1");
+    model.addElement(cAlias);
+    model.setWidth(2000);
+    model.setHeight(2000);
+
+    Layer layer = new Layer();
+    model.addLayer(layer);
+
+    LayerRect lr = new LayerRect();
+    lr.setColor(Color.YELLOW);
+    layer.addLayerRect(lr);
+
+    Reaction reaction = new TransportReaction();
+    reaction.addProduct(new Product(alias));
+    reaction.addReactant(new Reactant(alias2));
+    reaction.setIdReaction("re" + identifierCounter++);
+    model.addReaction(reaction);
+
+    alias = createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "pr1");
+    model.addElement(alias);
+
+    ModificationResidue mr = new Residue();
+    mr.setName("mr");
+    alias.addModificationResidue(mr);
+
+    alias.addMiriamData(new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.CHEBI, "c"));
+    return model;
+  }
+
+  private Compartment createCompartmentAlias(double x, double y, double width, double height, String aliasId) {
+    Compartment alias = new Compartment(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  private GenericProtein createSpeciesAlias(double x, double y, double width, double height, String aliasId) {
+    GenericProtein alias = new GenericProtein(aliasId);
+    alias.setName("SNCA");
+    alias.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA"));
+    alias.addMiriamData(new MiriamData(MiriamType.HGNC, "11138"));
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  private Complex createComplexAlias(double x, double y, double width, double height, String aliasId) {
+    Complex alias = new Complex(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+}
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/LayoutDaoTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/LayoutDaoTest.java
index 8b67d43aa92791640ad6fe43c9f55f89f9545ae9..83572545fdaf861ba0299e25b96d7880550b44f6 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/LayoutDaoTest.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/LayoutDaoTest.java
@@ -1,230 +1,230 @@
-package lcsb.mapviewer.persist.dao.map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import java.awt.Color;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-
-import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.cache.UploadedFileEntry;
-import lcsb.mapviewer.model.map.MiriamData;
-import lcsb.mapviewer.model.map.MiriamRelationType;
-import lcsb.mapviewer.model.map.MiriamType;
-import lcsb.mapviewer.model.map.compartment.Compartment;
-import lcsb.mapviewer.model.map.layout.Layout;
-import lcsb.mapviewer.model.map.layout.graphics.Layer;
-import lcsb.mapviewer.model.map.layout.graphics.LayerRect;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelFullIndexed;
-import lcsb.mapviewer.model.map.reaction.Product;
-import lcsb.mapviewer.model.map.reaction.Reactant;
-import lcsb.mapviewer.model.map.reaction.Reaction;
-import lcsb.mapviewer.model.map.reaction.type.TransportReaction;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.GenericProtein;
-import lcsb.mapviewer.model.map.species.Protein;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.persist.PersistTestFunctions;
-
-public class LayoutDaoTest extends PersistTestFunctions {
-
-	@Autowired
-	private LayoutDao		layoutDao;
-
-	final static Logger	logger						= Logger.getLogger(LayoutDaoTest.class);
-
-	int									identifierCounter	= 0;
-
-	@Before
-	public void setUp() throws Exception {
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	/**
-	 * After adding layouts to model.
-	 * 
-	 * @throws Exception
-	 */
-	@Test
-	public void testLayoutsWithData() throws Exception {
-		try {
-			Model model = createModel();
-
-			Project project = new Project();
-			project.addModel(model);
-			projectDao.add(project);
-
-			modelDao.evict(model);
-			projectDao.evict(project);
-
-			Layout layout = new Layout();
-			layout.setDirectory("tmp");
-			layout.setTitle("temporary name");
-
-			byte[] data = "test".getBytes();
-			UploadedFileEntry fileEntry = new UploadedFileEntry();
-			fileEntry.setFileContent(data);
-
-			layout.setInputData(fileEntry);
-			model.addLayout(layout);
-			layoutDao.add(layout);
-
-			layoutDao.evict(layout);
-
-			layout = layoutDao.getById(layout.getId());
-
-			assertEquals("test", new String(layout.getInputData().getFileContent(), StandardCharsets.UTF_8));
-
-			project = projectDao.getById(project.getId());
-			projectDao.delete(project);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	/**
-	 * After adding layouts to model.
-	 * 
-	 * @throws Exception
-	 */
-	@Test
-	public void testLayoutsWithoutData() throws Exception {
-		try {
-			Model model = createModel();
-			String tempName = "temporary name";
-
-			createUser();
-
-			Project project = new Project();
-			project.addModel(model);
-			projectDao.add(project);
-
-			modelDao.evict(model);
-			projectDao.evict(project);
-
-			assertEquals(0, layoutDao.getCountByUser(user));
-			assertEquals(0, layoutDao.getLayoutsByModel(model).size());
-			assertNull(layoutDao.getLayoutByName(model, tempName));
-
-			Layout layout = new Layout();
-			layout.setDirectory("tmp");
-			layout.setTitle(tempName);
-			layout.setCreator(user);
-			model.addLayout(layout);
-			layoutDao.add(layout);
-
-			layoutDao.evict(layout);
-
-			layout = layoutDao.getById(layout.getId());
-
-			assertEquals(1, layoutDao.getLayoutsByModel(model).size());
-			assertNotNull(layoutDao.getLayoutByName(model, tempName));
-			assertEquals(1, layoutDao.getCountByUser(user));
-
-			assertNull(layout.getInputData());
-
-			project = projectDao.getById(project.getId());
-			projectDao.delete(project);
-
-			userDao.delete(user);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	private Model createModel() {
-		Model model = new ModelFullIndexed(null);
-
-		Species alias = createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "sa2");
-		model.addElement(alias);
-		alias = createSpeciesAlias(267.6666666666665, 438.75, 80.0, 40.0, "sa1117");
-		model.addElement(alias);
-		alias = createSpeciesAlias(261.6666666666665, 600.75, 92.0, 52.0, "sa1119");
-		model.addElement(alias);
-		alias = createSpeciesAlias(203.666666666667, 687.75, 98.0, 58.0, "sa1121");
-		model.addElement(alias);
-
-		alias = createSpeciesAlias(817.714285714286, 287.642857142859, 80.0, 40.0, "sa1422");
-		Species alias2 = createSpeciesAlias(224.964285714286, 241.392857142859, 80.0, 40.0, "sa1419");
-		Complex alias3 = createComplexAlias(804.714285714286, 182.642857142859, 112.0, 172.0, "csa152");
-		alias3.addSpecies(alias);
-		alias3.addSpecies(alias2);
-		alias.setComplex(alias3);
-		alias2.setComplex(alias3);
-
-		model.addElement(alias);
-		model.addElement(alias2);
-		model.addElement(alias3);
-
-		Compartment cAlias = createCompartmentAlias(380.0, 416.0, 1893.0, 1866.0, "ca1");
-		model.addElement(cAlias);
-		model.setWidth(2000);
-		model.setHeight(2000);
-
-		Layer layer = new Layer();
-		model.addLayer(layer);
-
-		LayerRect lr = new LayerRect();
-		lr.setColor(Color.YELLOW);
-		layer.addLayerRect(lr);
-
-		Reaction reaction = new TransportReaction();
-		reaction.addProduct(new Product(alias));
-		reaction.addReactant(new Reactant(alias2));
-		reaction.setIdReaction("re" + identifierCounter++);
-		model.addReaction(reaction);
-
-		Protein protein = createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "pr1");
-		model.addElement(protein);
-
-		ModificationResidue mr = new ModificationResidue();
-		mr.setName("mr");
-		protein.addModificationResidue(mr);
-
-		protein.addMiriamData(new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.CHEBI, "c"));
-		return model;
-	}
-
-	private Compartment createCompartmentAlias(double x, double y, double width, double height, String aliasId) {
-		Compartment alias = new Compartment(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-	private Protein createSpeciesAlias(double x, double y, double width, double height, String aliasId) {
-		GenericProtein alias = new GenericProtein("s" + identifierCounter++);
-		alias.setElementId(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-	private Complex createComplexAlias(double x, double y, double width, double height, String aliasId) {
-		Complex alias = new Complex(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-}
+package lcsb.mapviewer.persist.dao.map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.awt.Color;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.cache.UploadedFileEntry;
+import lcsb.mapviewer.model.map.MiriamData;
+import lcsb.mapviewer.model.map.MiriamRelationType;
+import lcsb.mapviewer.model.map.MiriamType;
+import lcsb.mapviewer.model.map.compartment.Compartment;
+import lcsb.mapviewer.model.map.layout.Layout;
+import lcsb.mapviewer.model.map.layout.graphics.Layer;
+import lcsb.mapviewer.model.map.layout.graphics.LayerRect;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.model.map.reaction.Product;
+import lcsb.mapviewer.model.map.reaction.Reactant;
+import lcsb.mapviewer.model.map.reaction.Reaction;
+import lcsb.mapviewer.model.map.reaction.type.TransportReaction;
+import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.Residue;
+import lcsb.mapviewer.persist.PersistTestFunctions;
+
+public class LayoutDaoTest extends PersistTestFunctions {
+
+  @Autowired
+  private LayoutDao layoutDao;
+
+  final static Logger logger = Logger.getLogger(LayoutDaoTest.class);
+
+  int identifierCounter = 0;
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  /**
+   * After adding layouts to model.
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testLayoutsWithData() throws Exception {
+    try {
+      Model model = createModel();
+
+      Project project = new Project();
+      project.addModel(model);
+      projectDao.add(project);
+
+      modelDao.evict(model);
+      projectDao.evict(project);
+
+      Layout layout = new Layout();
+      layout.setDirectory("tmp");
+      layout.setTitle("temporary name");
+
+      byte[] data = "test".getBytes();
+      UploadedFileEntry fileEntry = new UploadedFileEntry();
+      fileEntry.setFileContent(data);
+
+      layout.setInputData(fileEntry);
+      model.addLayout(layout);
+      layoutDao.add(layout);
+
+      layoutDao.evict(layout);
+
+      layout = layoutDao.getById(layout.getId());
+
+      assertEquals("test", new String(layout.getInputData().getFileContent(), StandardCharsets.UTF_8));
+
+      project = projectDao.getById(project.getId());
+      projectDao.delete(project);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  /**
+   * After adding layouts to model.
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testLayoutsWithoutData() throws Exception {
+    try {
+      Model model = createModel();
+      String tempName = "temporary name";
+
+      createUser();
+
+      Project project = new Project();
+      project.addModel(model);
+      projectDao.add(project);
+
+      modelDao.evict(model);
+      projectDao.evict(project);
+
+      assertEquals(0, layoutDao.getCountByUser(user));
+      assertEquals(0, layoutDao.getLayoutsByModel(model).size());
+      assertNull(layoutDao.getLayoutByName(model, tempName));
+
+      Layout layout = new Layout();
+      layout.setDirectory("tmp");
+      layout.setTitle(tempName);
+      layout.setCreator(user);
+      model.addLayout(layout);
+      layoutDao.add(layout);
+
+      layoutDao.evict(layout);
+
+      layout = layoutDao.getById(layout.getId());
+
+      assertEquals(1, layoutDao.getLayoutsByModel(model).size());
+      assertNotNull(layoutDao.getLayoutByName(model, tempName));
+      assertEquals(1, layoutDao.getCountByUser(user));
+
+      assertNull(layout.getInputData());
+
+      project = projectDao.getById(project.getId());
+      projectDao.delete(project);
+
+      userDao.delete(user);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private Model createModel() {
+    Model model = new ModelFullIndexed(null);
+
+    Species alias = createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "sa2");
+    model.addElement(alias);
+    alias = createSpeciesAlias(267.6666666666665, 438.75, 80.0, 40.0, "sa1117");
+    model.addElement(alias);
+    alias = createSpeciesAlias(261.6666666666665, 600.75, 92.0, 52.0, "sa1119");
+    model.addElement(alias);
+    alias = createSpeciesAlias(203.666666666667, 687.75, 98.0, 58.0, "sa1121");
+    model.addElement(alias);
+
+    alias = createSpeciesAlias(817.714285714286, 287.642857142859, 80.0, 40.0, "sa1422");
+    Species alias2 = createSpeciesAlias(224.964285714286, 241.392857142859, 80.0, 40.0, "sa1419");
+    Complex alias3 = createComplexAlias(804.714285714286, 182.642857142859, 112.0, 172.0, "csa152");
+    alias3.addSpecies(alias);
+    alias3.addSpecies(alias2);
+    alias.setComplex(alias3);
+    alias2.setComplex(alias3);
+
+    model.addElement(alias);
+    model.addElement(alias2);
+    model.addElement(alias3);
+
+    Compartment cAlias = createCompartmentAlias(380.0, 416.0, 1893.0, 1866.0, "ca1");
+    model.addElement(cAlias);
+    model.setWidth(2000);
+    model.setHeight(2000);
+
+    Layer layer = new Layer();
+    model.addLayer(layer);
+
+    LayerRect lr = new LayerRect();
+    lr.setColor(Color.YELLOW);
+    layer.addLayerRect(lr);
+
+    Reaction reaction = new TransportReaction();
+    reaction.addProduct(new Product(alias));
+    reaction.addReactant(new Reactant(alias2));
+    reaction.setIdReaction("re" + identifierCounter++);
+    model.addReaction(reaction);
+
+    Protein protein = createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "pr1");
+    model.addElement(protein);
+
+    Residue mr = new Residue();
+    mr.setName("mr");
+    protein.addModificationResidue(mr);
+
+    protein.addMiriamData(new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.CHEBI, "c"));
+    return model;
+  }
+
+  private Compartment createCompartmentAlias(double x, double y, double width, double height, String aliasId) {
+    Compartment alias = new Compartment(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  private Protein createSpeciesAlias(double x, double y, double width, double height, String aliasId) {
+    GenericProtein alias = new GenericProtein("s" + identifierCounter++);
+    alias.setElementId(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  private Complex createComplexAlias(double x, double y, double width, double height, String aliasId) {
+    Complex alias = new Complex(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+}
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/ModelDaoTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/ModelDaoTest.java
index 3a211e414adc17f9c450e630f7377714bac0ec4f..02bf55c42b3c0adef12ae00f1fb6a1cc8e479e70 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/ModelDaoTest.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/ModelDaoTest.java
@@ -1,465 +1,470 @@
-package lcsb.mapviewer.persist.dao.map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.awt.Color;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.map.MiriamData;
-import lcsb.mapviewer.model.map.MiriamRelationType;
-import lcsb.mapviewer.model.map.MiriamType;
-import lcsb.mapviewer.model.map.compartment.Compartment;
-import lcsb.mapviewer.model.map.kinetics.SbmlFunction;
-import lcsb.mapviewer.model.map.kinetics.SbmlKinetics;
-import lcsb.mapviewer.model.map.kinetics.SbmlParameter;
-import lcsb.mapviewer.model.map.kinetics.SbmlUnit;
-import lcsb.mapviewer.model.map.kinetics.SbmlUnitType;
-import lcsb.mapviewer.model.map.kinetics.SbmlUnitTypeFactor;
-import lcsb.mapviewer.model.map.layout.Layout;
-import lcsb.mapviewer.model.map.layout.graphics.Layer;
-import lcsb.mapviewer.model.map.layout.graphics.LayerRect;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelComparator;
-import lcsb.mapviewer.model.map.model.ModelData;
-import lcsb.mapviewer.model.map.model.ModelFullIndexed;
-import lcsb.mapviewer.model.map.reaction.Product;
-import lcsb.mapviewer.model.map.reaction.Reactant;
-import lcsb.mapviewer.model.map.reaction.Reaction;
-import lcsb.mapviewer.model.map.reaction.type.TransportReaction;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.GenericProtein;
-import lcsb.mapviewer.model.map.species.Protein;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.persist.PersistTestFunctions;
-
-public class ModelDaoTest extends PersistTestFunctions {
-  ModelComparator modelComparator = new ModelComparator();
-
-  Logger logger = Logger.getLogger(ModelDaoTest.class);
-  private Project project;
-  String projectId = "Some_id";
-  int identifierCounter = 0;
-
-  @Before
-  public void setUp() throws Exception {
-    project = projectDao.getProjectByProjectId(projectId);
-    if (project != null) {
-      projectDao.delete(project);
-    }
-    project = new Project();
-    project.setProjectId(projectId);
-    projectDao.add(project);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    projectDao.delete(project);
-  }
-
-  @Test
-  public void testLoadFromDb() throws Exception {
-    try {
-      Model model = createModel();
-      project.addModel(model);
-      modelDao.add(model);
-      projectDao.update(project);
-      projectDao.evict(project);
-
-      modelDao.evict(model);
-      ModelData model2 = modelDao.getById(model.getId());
-      assertNotNull(model2);
-      assertFalse(model2 == model);
-
-      assertEquals(model.getElements().size(), model2.getElements().size());
-      assertEquals(model.getLayers().size(), model2.getLayers().size());
-      assertEquals(model.getReactions().size(), model2.getReactions().size());
-
-      modelDao.delete(model2);
-      model2 = modelDao.getById(model.getId());
-      assertNull(model2);
-      project = projectDao.getById(project.getId());
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testIndexesReload() throws Exception {
-    try {
-      Model model = createModel();
-      project.addModel(model);
-      modelDao.add(model);
-      modelDao.evict(model);
-      ModelData model2 = modelDao.getById(model.getId());
-      Model fullModel = new ModelFullIndexed(model2);
-      assertNotNull(model2);
-
-      assertEquals(model.getElements().size(), model2.getElements().size());
-      assertEquals(model.getLayers().size(), model2.getLayers().size());
-      assertEquals(model.getReactions().size(), model2.getReactions().size());
-
-      // check if we really performed a test
-      boolean test = false;
-
-      for (Element alias : model.getElements()) {
-        assertNotNull(fullModel.getElementByElementId(alias.getElementId()));
-        test = true;
-      }
-      assertTrue(test);
-
-      test = false;
-      for (Element alias : model.getElements()) {
-        if (alias instanceof Compartment) {
-          assertNotNull(fullModel.getElementByElementId(alias.getElementId()));
-          test = true;
-        }
-      }
-      assertTrue(test);
-
-      model2.setHeight(32);
-      modelDao.update(model2.getModel());
-
-      modelDao.delete(model2);
-      model2 = modelDao.getById(model.getId());
-      assertNull(model2);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testReactionInModelAfterReload() throws Exception {
-    try {
-      Model model = createModel();
-      Reaction reaction = model.getReactions().iterator().next();
-      project.addModel(model);
-      modelDao.add(model);
-      projectDao.update(project);
-      projectDao.evict(project);
-      modelDao.evict(model);
-      ModelData model2 = modelDao.getById(model.getId());
-
-      Reaction reaction2 = null;
-      for (Reaction r : model2.getReactions()) {
-        if (r.getIdReaction().equals(reaction.getIdReaction())) {
-          reaction2 = r;
-        }
-      }
-      assertNotNull(reaction2);
-      assertFalse(reaction.equals(reaction2));
-
-      assertEquals(reaction.getNodes().size(), reaction2.getNodes().size());
-
-      modelDao.delete(model2);
-      model2 = modelDao.getById(model.getId());
-      assertNull(model2);
-      project = projectDao.getById(project.getId());
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testReactionInWithKinetics() throws Exception {
-    try {
-      Model model = createModel();
-      Reaction reaction = model.getReactions().iterator().next();
-      SbmlKinetics kinetics = new SbmlKinetics();
-      kinetics.addElement(reaction.getReactants().get(0).getElement());
-      kinetics.addFunction(createFunction());
-      model.addFunctions(kinetics.getFunctions());
-      kinetics.addParameter(createParameter());
-      model.addUnit(kinetics.getParameters().iterator().next().getUnits());
-      reaction.setKinetics(kinetics);
-      project.addModel(model);
-      modelDao.add(model);
-      projectDao.update(project);
-      projectDao.evict(project);
-      modelDao.evict(model);
-      ModelData model2 = modelDao.getById(model.getId());
-
-      assertEquals(0, modelComparator.compare(model, new ModelFullIndexed(model2)));
-
-      project = projectDao.getById(project.getId());
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testModelWithParameters() throws Exception {
-    try {
-      Model model = createModel();
-      model.addParameter(createParameter());
-      model.addUnit(model.getParameters().iterator().next().getUnits());
-      project.addModel(model);
-      modelDao.add(model);
-      projectDao.update(project);
-      projectDao.evict(project);
-      modelDao.evict(model);
-      ModelData model2 = modelDao.getById(model.getId());
-
-      assertEquals(0, modelComparator.compare(model, new ModelFullIndexed(model2)));
-
-      project = projectDao.getById(project.getId());
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  private SbmlParameter createParameter() {
-    SbmlParameter parameter = new SbmlParameter("param_id");
-    parameter.setName("X");
-    parameter.setValue(4.7);
-    parameter.setUnits(createUnits());
-    return parameter;
-  }
-
-  private SbmlUnit createUnits() {
-    SbmlUnit unit = new SbmlUnit("unit_id");
-    unit.setName("u name");
-    unit.addUnitTypeFactor(new SbmlUnitTypeFactor(SbmlUnitType.AMPERE, 1, 2, 3));
-    return unit;
-  }
-
-  private SbmlFunction createFunction() {
-    SbmlFunction result = new SbmlFunction("fun_id");
-    result.setDefinition("def(k1)");
-    result.addArgument("k1");
-    result.setName("fun name");
-    return result;
-  }
-
-  @Test
-  public void testGetLastModelForProjectName() throws Exception {
-    try {
-      ModelData model3 = modelDao.getLastModelForProjectIdentifier(projectId, false);
-      assertNull(model3);
-
-      Model model = createModel();
-      project.addModel(model);
-      modelDao.add(model);
-
-      ModelData newModel = modelDao.getLastModelForProjectIdentifier(projectId, false);
-      assertNotNull(newModel);
-      assertEquals(model.getId(), newModel.getId());
-
-      Model model2 = createModel();
-      project.addModel(model2);
-      modelDao.add(model2);
-
-      newModel = modelDao.getLastModelForProjectIdentifier(projectId, false);
-      assertNotNull(newModel);
-      assertEquals(model2.getId(), newModel.getId());
-
-      modelDao.delete(model2);
-      modelDao.delete(model);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  /**
-   * After adding model to db, modification residues disappear from the model...
-   * 
-   * @throws Exception
-   */
-  @Test
-  public void testModificationsInProteins() throws Exception {
-    try {
-      Model model = createModel();
-      Project project = new Project();
-      project.addModel(model);
-      projectDao.add(project);
-
-      modelDao.evict(model);
-      projectDao.evict(project);
-      Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
-
-      Protein originalSpecies = (Protein) model.getElementByElementId("pr1");
-      Protein fromDbSpecies = (Protein) model2.getElementByElementId("pr1");
-
-      assertFalse(originalSpecies.equals(fromDbSpecies));
-      assertEquals(originalSpecies.getModificationResidues().size(), fromDbSpecies.getModificationResidues().size());
-
-      project = projectDao.getById(project.getId());
-      projectDao.delete(project);
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  /**
-   * After adding model to db, miriam annotations disappear...
-   * 
-   * @throws Exception
-   */
-  @Test
-  public void testMiriamInSpecies() throws Exception {
-    try {
-      Model model = createModel();
-      Project project = new Project();
-      project.addModel(model);
-      projectDao.add(project);
-
-      modelDao.evict(model);
-      projectDao.evict(project);
-      Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
-
-      Protein originalSpecies = (Protein) model.getElementByElementId("pr1");
-      Protein fromDbSpecies = (Protein) model2.getElementByElementId("pr1");
-
-      assertFalse(originalSpecies.equals(fromDbSpecies));
-      assertEquals(originalSpecies.getMiriamData().size(), fromDbSpecies.getMiriamData().size());
-
-      project = projectDao.getById(project.getId());
-      projectDao.delete(project);
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  /**
-   * After adding layouts to model.
-   * 
-   * @throws Exception
-   */
-  @Test
-  public void testLayoutsInModel() throws Exception {
-    try {
-      Model model = createModel();
-
-      Layout layout = new Layout();
-      layout.setDirectory("tmp");
-      layout.setTitle("temporary name");
-      model.addLayout(layout);
-      Project project = new Project();
-      project.addModel(model);
-      projectDao.add(project);
-
-      modelDao.evict(model);
-      projectDao.evict(project);
-      ModelData model2 = modelDao.getById(model.getId());
-
-      assertEquals(1, model2.getLayouts().size());
-      assertEquals("tmp", model2.getLayouts().get(0).getDirectory());
-      assertEquals("temporary name", model2.getLayouts().get(0).getTitle());
-
-      project = projectDao.getById(project.getId());
-      projectDao.delete(project);
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  private Model createModel() {
-    Model model = new ModelFullIndexed(null);
-
-    GenericProtein alias = createSpecies(264.8333333333335, 517.75, 86.0, 46.0, "sa2");
-    model.addElement(alias);
-    alias = createSpecies(267.6666666666665, 438.75, 80.0, 40.0, "sa1117");
-    model.addElement(alias);
-    alias = createSpecies(261.6666666666665, 600.75, 92.0, 52.0, "sa1119");
-    model.addElement(alias);
-    alias = createSpecies(203.666666666667, 687.75, 98.0, 58.0, "sa1121");
-    model.addElement(alias);
-
-    alias = createSpecies(817.714285714286, 287.642857142859, 80.0, 40.0, "sa1422");
-    Species alias2 = createSpecies(224.964285714286, 241.392857142859, 80.0, 40.0, "sa1419");
-    Complex alias3 = createComplex(804.714285714286, 182.642857142859, 112.0, 172.0, "csa152");
-    alias3.addSpecies(alias);
-    alias3.addSpecies(alias2);
-    alias.setComplex(alias3);
-    alias2.setComplex(alias3);
-
-    model.addElement(alias);
-    model.addElement(alias2);
-    model.addElement(alias3);
-
-    Compartment cAlias = createCompartment(380.0, 416.0, 1893.0, 1866.0, "ca1");
-    model.addElement(cAlias);
-    model.setWidth(2000);
-    model.setHeight(2000);
-
-    Layer layer = new Layer();
-    model.addLayer(layer);
-
-    LayerRect lr = new LayerRect();
-    lr.setColor(Color.YELLOW);
-    layer.addLayerRect(lr);
-
-    Reaction reaction = new TransportReaction();
-    reaction.addProduct(new Product(alias));
-    reaction.addReactant(new Reactant(alias2));
-    reaction.setIdReaction("re" + identifierCounter++);
-    model.addReaction(reaction);
-
-    alias = createSpecies(264.8333333333335, 517.75, 86.0, 46.0, "pr1");
-    model.addElement(alias);
-
-    ModificationResidue mr = new ModificationResidue();
-    mr.setName("mr");
-    alias.addModificationResidue(mr);
-
-    alias.addMiriamData(new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.CHEBI, "c"));
-    return model;
-  }
-
-  private Compartment createCompartment(double x, double y, double width, double height, String aliasId) {
-    Compartment alias = new Compartment(aliasId);
-    alias.setX(x);
-    alias.setY(y);
-    alias.setWidth(width);
-    alias.setHeight(height);
-    return alias;
-  }
-
-  private GenericProtein createSpecies(double x, double y, double width, double height, String aliasId) {
-    GenericProtein alias = new GenericProtein(aliasId);
-    alias.setName("SNCA");
-    alias.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA"));
-    alias.addMiriamData(new MiriamData(MiriamType.HGNC, "11138"));
-    alias.setElementId(aliasId);
-    alias.setX(x);
-    alias.setY(y);
-    alias.setWidth(width);
-    alias.setHeight(height);
-    return alias;
-  }
-
-  private Complex createComplex(double x, double y, double width, double height, String aliasId) {
-    Complex alias = new Complex(aliasId);
-    alias.setX(x);
-    alias.setY(y);
-    alias.setWidth(width);
-    alias.setHeight(height);
-    return alias;
-  }
-
-}
+package lcsb.mapviewer.persist.dao.map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.map.MiriamData;
+import lcsb.mapviewer.model.map.MiriamRelationType;
+import lcsb.mapviewer.model.map.MiriamType;
+import lcsb.mapviewer.model.map.compartment.Compartment;
+import lcsb.mapviewer.model.map.kinetics.SbmlFunction;
+import lcsb.mapviewer.model.map.kinetics.SbmlKinetics;
+import lcsb.mapviewer.model.map.kinetics.SbmlParameter;
+import lcsb.mapviewer.model.map.kinetics.SbmlUnit;
+import lcsb.mapviewer.model.map.kinetics.SbmlUnitType;
+import lcsb.mapviewer.model.map.kinetics.SbmlUnitTypeFactor;
+import lcsb.mapviewer.model.map.layout.Layout;
+import lcsb.mapviewer.model.map.layout.graphics.Layer;
+import lcsb.mapviewer.model.map.layout.graphics.LayerRect;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelComparator;
+import lcsb.mapviewer.model.map.model.ModelData;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.model.map.reaction.Product;
+import lcsb.mapviewer.model.map.reaction.Reactant;
+import lcsb.mapviewer.model.map.reaction.Reaction;
+import lcsb.mapviewer.model.map.reaction.type.TransportReaction;
+import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.Residue;
+import lcsb.mapviewer.persist.PersistTestFunctions;
+
+public class ModelDaoTest extends PersistTestFunctions {
+  ModelComparator modelComparator = new ModelComparator();
+
+  Logger logger = Logger.getLogger(ModelDaoTest.class);
+  private Project project;
+  String projectId = "Some_id";
+  int identifierCounter = 0;
+
+  @Before
+  public void setUp() throws Exception {
+    project = projectDao.getProjectByProjectId(projectId);
+    if (project != null) {
+      projectDao.delete(project);
+    }
+    project = new Project();
+    project.setProjectId(projectId);
+    projectDao.add(project);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    projectDao.delete(project);
+  }
+
+  @Test
+  public void testLoadFromDb() throws Exception {
+    try {
+      Model model = createModel();
+      project.addModel(model);
+      modelDao.add(model);
+      projectDao.update(project);
+      projectDao.evict(project);
+
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+      assertNotNull(model2);
+      assertFalse(model2 == model);
+
+      assertEquals(model.getElements().size(), model2.getElements().size());
+      assertEquals(model.getLayers().size(), model2.getLayers().size());
+      assertEquals(model.getReactions().size(), model2.getReactions().size());
+
+      ModelComparator comparator = new ModelComparator();
+      assertEquals(0, comparator.compare(model, new ModelFullIndexed(model2)));
+
+      modelDao.delete(model2);
+      model2 = modelDao.getById(model.getId());
+      assertNull(model2);
+      project = projectDao.getById(project.getId());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testIndexesReload() throws Exception {
+    try {
+      Model model = createModel();
+      project.addModel(model);
+      modelDao.add(model);
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+      Model fullModel = new ModelFullIndexed(model2);
+      assertNotNull(model2);
+
+      assertEquals(model.getElements().size(), model2.getElements().size());
+      assertEquals(model.getLayers().size(), model2.getLayers().size());
+      assertEquals(model.getReactions().size(), model2.getReactions().size());
+
+      // check if we really performed a test
+      boolean test = false;
+
+      for (Element alias : model.getElements()) {
+        assertNotNull(fullModel.getElementByElementId(alias.getElementId()));
+        test = true;
+      }
+      assertTrue(test);
+
+      test = false;
+      for (Element alias : model.getElements()) {
+        if (alias instanceof Compartment) {
+          assertNotNull(fullModel.getElementByElementId(alias.getElementId()));
+          test = true;
+        }
+      }
+      assertTrue(test);
+
+      model2.setHeight(32);
+      modelDao.update(model2.getModel());
+
+      modelDao.delete(model2);
+      model2 = modelDao.getById(model.getId());
+      assertNull(model2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testReactionInModelAfterReload() throws Exception {
+    try {
+      Model model = createModel();
+      Reaction reaction = model.getReactions().iterator().next();
+      project.addModel(model);
+      modelDao.add(model);
+      projectDao.update(project);
+      projectDao.evict(project);
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+
+      Reaction reaction2 = null;
+      for (Reaction r : model2.getReactions()) {
+        if (r.getIdReaction().equals(reaction.getIdReaction())) {
+          reaction2 = r;
+        }
+      }
+      assertNotNull(reaction2);
+      assertFalse(reaction.equals(reaction2));
+
+      assertEquals(reaction.getNodes().size(), reaction2.getNodes().size());
+
+      modelDao.delete(model2);
+      model2 = modelDao.getById(model.getId());
+      assertNull(model2);
+      project = projectDao.getById(project.getId());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testReactionInWithKinetics() throws Exception {
+    try {
+      Model model = createModel();
+      Reaction reaction = model.getReactions().iterator().next();
+      SbmlKinetics kinetics = new SbmlKinetics();
+      kinetics.addElement(reaction.getReactants().get(0).getElement());
+      kinetics.addFunction(createFunction());
+      model.addFunctions(kinetics.getFunctions());
+      kinetics.addParameter(createParameter());
+      model.addUnit(kinetics.getParameters().iterator().next().getUnits());
+      reaction.setKinetics(kinetics);
+      project.addModel(model);
+      modelDao.add(model);
+      projectDao.update(project);
+      projectDao.evict(project);
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+
+      assertEquals(0, modelComparator.compare(model, new ModelFullIndexed(model2)));
+
+      project = projectDao.getById(project.getId());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testModelWithParameters() throws Exception {
+    try {
+      Model model = createModel();
+      model.addParameter(createParameter());
+      model.addUnit(model.getParameters().iterator().next().getUnits());
+      project.addModel(model);
+      modelDao.add(model);
+      projectDao.update(project);
+      projectDao.evict(project);
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+
+      assertEquals(0, modelComparator.compare(model, new ModelFullIndexed(model2)));
+
+      project = projectDao.getById(project.getId());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private SbmlParameter createParameter() {
+    SbmlParameter parameter = new SbmlParameter("param_id");
+    parameter.setName("X");
+    parameter.setValue(4.7);
+    parameter.setUnits(createUnits());
+    return parameter;
+  }
+
+  private SbmlUnit createUnits() {
+    SbmlUnit unit = new SbmlUnit("unit_id");
+    unit.setName("u name");
+    unit.addUnitTypeFactor(new SbmlUnitTypeFactor(SbmlUnitType.AMPERE, 1, 2, 3));
+    return unit;
+  }
+
+  private SbmlFunction createFunction() {
+    SbmlFunction result = new SbmlFunction("fun_id");
+    result.setDefinition("def(k1)");
+    result.addArgument("k1");
+    result.setName("fun name");
+    return result;
+  }
+
+  @Test
+  public void testGetLastModelForProjectName() throws Exception {
+    try {
+      ModelData model3 = modelDao.getLastModelForProjectIdentifier(projectId, false);
+      assertNull(model3);
+
+      Model model = createModel();
+      project.addModel(model);
+      modelDao.add(model);
+
+      ModelData newModel = modelDao.getLastModelForProjectIdentifier(projectId, false);
+      assertNotNull(newModel);
+      assertEquals(model.getId(), newModel.getId());
+
+      Model model2 = createModel();
+      project.addModel(model2);
+      modelDao.add(model2);
+
+      newModel = modelDao.getLastModelForProjectIdentifier(projectId, false);
+      assertNotNull(newModel);
+      assertEquals(model2.getId(), newModel.getId());
+
+      modelDao.delete(model2);
+      modelDao.delete(model);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  /**
+   * After adding model to db, modification residues disappear from the model...
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testModificationsInProteins() throws Exception {
+    try {
+      Model model = createModel();
+      Project project = new Project();
+      project.addModel(model);
+      projectDao.add(project);
+
+      modelDao.evict(model);
+      projectDao.evict(project);
+      Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
+
+      Protein originalSpecies = (Protein) model.getElementByElementId("pr1");
+      Protein fromDbSpecies = (Protein) model2.getElementByElementId("pr1");
+
+      assertFalse(originalSpecies.equals(fromDbSpecies));
+      assertEquals(originalSpecies.getModificationResidues().size(), fromDbSpecies.getModificationResidues().size());
+
+      project = projectDao.getById(project.getId());
+      projectDao.delete(project);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  /**
+   * After adding model to db, miriam annotations disappear...
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testMiriamInSpecies() throws Exception {
+    try {
+      Model model = createModel();
+      Project project = new Project();
+      project.addModel(model);
+      projectDao.add(project);
+
+      modelDao.evict(model);
+      projectDao.evict(project);
+      Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
+
+      Protein originalSpecies = (Protein) model.getElementByElementId("pr1");
+      Protein fromDbSpecies = (Protein) model2.getElementByElementId("pr1");
+
+      assertFalse(originalSpecies.equals(fromDbSpecies));
+      assertEquals(originalSpecies.getMiriamData().size(), fromDbSpecies.getMiriamData().size());
+
+      project = projectDao.getById(project.getId());
+      projectDao.delete(project);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  /**
+   * After adding layouts to model.
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testLayoutsInModel() throws Exception {
+    try {
+      Model model = createModel();
+
+      Layout layout = new Layout();
+      layout.setDirectory("tmp");
+      layout.setTitle("temporary name");
+      model.addLayout(layout);
+      Project project = new Project();
+      project.addModel(model);
+      projectDao.add(project);
+
+      modelDao.evict(model);
+      projectDao.evict(project);
+      ModelData model2 = modelDao.getById(model.getId());
+
+      assertEquals(1, model2.getLayouts().size());
+      assertEquals("tmp", model2.getLayouts().get(0).getDirectory());
+      assertEquals("temporary name", model2.getLayouts().get(0).getTitle());
+
+      project = projectDao.getById(project.getId());
+      projectDao.delete(project);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private Model createModel() {
+    Model model = new ModelFullIndexed(null);
+
+    GenericProtein alias = createSpecies(264.8333333333335, 517.75, 86.0, 46.0, "sa2");
+    model.addElement(alias);
+    alias = createSpecies(267.6666666666665, 438.75, 80.0, 40.0, "sa1117");
+    model.addElement(alias);
+    alias = createSpecies(261.6666666666665, 600.75, 92.0, 52.0, "sa1119");
+    model.addElement(alias);
+    alias = createSpecies(203.666666666667, 687.75, 98.0, 58.0, "sa1121");
+    model.addElement(alias);
+
+    alias = createSpecies(817.714285714286, 287.642857142859, 80.0, 40.0, "sa1422");
+    Species alias2 = createSpecies(224.964285714286, 241.392857142859, 80.0, 40.0, "sa1419");
+    Complex alias3 = createComplex(804.714285714286, 182.642857142859, 112.0, 172.0, "csa152");
+    alias3.addSpecies(alias);
+    alias3.addSpecies(alias2);
+    alias.setComplex(alias3);
+    alias2.setComplex(alias3);
+
+    model.addElement(alias);
+    model.addElement(alias2);
+    model.addElement(alias3);
+
+    Compartment cAlias = createCompartment(380.0, 416.0, 1893.0, 1866.0, "ca1");
+    model.addElement(cAlias);
+    model.setWidth(2000);
+    model.setHeight(2000);
+
+    Layer layer = new Layer();
+    model.addLayer(layer);
+
+    LayerRect lr = new LayerRect();
+    lr.setColor(Color.YELLOW);
+    layer.addLayerRect(lr);
+
+    Reaction reaction = new TransportReaction();
+    reaction.addProduct(new Product(alias));
+    reaction.addReactant(new Reactant(alias2));
+    reaction.setIdReaction("re" + identifierCounter++);
+    model.addReaction(reaction);
+
+    alias = createSpecies(264.8333333333335, 517.75, 86.0, 46.0, "pr1");
+    model.addElement(alias);
+
+    Residue mr = new Residue();
+    mr.setName("mr");
+    mr.setPosition(new Point2D.Double(10, 20));
+    alias.addModificationResidue(mr);
+
+    alias.addMiriamData(new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.CHEBI, "c"));
+    return model;
+  }
+
+  private Compartment createCompartment(double x, double y, double width, double height, String aliasId) {
+    Compartment alias = new Compartment(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  private GenericProtein createSpecies(double x, double y, double width, double height, String aliasId) {
+    GenericProtein alias = new GenericProtein(aliasId);
+    alias.setName("SNCA");
+    alias.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA"));
+    alias.addMiriamData(new MiriamData(MiriamType.HGNC, "11138"));
+    alias.setElementId(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  private Complex createComplex(double x, double y, double width, double height, String aliasId) {
+    Complex alias = new Complex(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+}
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AliasDaoTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AliasDaoTest.java
index 3bab7806b996767c2978bb1438fbff6ecd9b17a8..2d02a5e4e6ae6f125b019a2cb3e9a3235e777da0 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AliasDaoTest.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AliasDaoTest.java
@@ -1,146 +1,146 @@
-package lcsb.mapviewer.persist.dao.map.layout.alias;
-
-import static org.junit.Assert.assertEquals;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.map.SearchIndex;
-import lcsb.mapviewer.model.map.compartment.Compartment;
-import lcsb.mapviewer.model.map.model.ElementSubmodelConnection;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelFullIndexed;
-import lcsb.mapviewer.model.map.model.SubmodelType;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.SimpleMolecule;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.persist.PersistTestFunctions;
-
-public class AliasDaoTest extends PersistTestFunctions {
-	Logger					logger						= Logger.getLogger(AliasDaoTest.class);
-
-	private Project	project;
-	String					projectId				= "Some_id";
-
-	int							identifierCounter	= 0;
-
-	@Before
-	public void setUp() throws Exception {
-		project = projectDao.getProjectByProjectId(projectId);
-		if (project!=null) {
-			projectDao.delete(project);
-		}
-		project = new Project();
-		project.setProjectId(projectId);
-		projectDao.add(project);
-	}
-
-	@After
-	public void tearDown() throws Exception {
-		projectDao.delete(project);
-	}
-
-	@Test
-	public void anotherSaveDaoTest() throws Exception {
-		try {
-			Model model = createModel();
-			project.addModel(model);
-
-			Species alias = (Species) model.getElementByElementId("sa2");
-
-			alias.getSearchIndexes().add(new SearchIndex("blabla"));
-
-			modelDao.add(model);
-
-			Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
-
-			Species alias2 = (Species) aliasDao.getById(model2.getElementByElementId("sa2").getId());
-
-			assertEquals(1, alias2.getSearchIndexes().size());
-
-			modelDao.delete(model);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	private Model createModel() {
-		Model model = new ModelFullIndexed(null);
-		model.addElement(createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "sa2"));
-		model.addElement(createSpeciesAlias(267.6666666666665, 438.75, 80.0, 40.0, "sa1117"));
-		model.addElement(createSpeciesAlias(261.6666666666665, 600.75, 92.0, 52.0, "sa1119"));
-		model.addElement(createSpeciesAlias(203.666666666667, 687.75, 98.0, 58.0, "sa1121"));
-
-		Species alias = createSpeciesAlias(817.714285714286, 287.642857142859, 80.0, 40.0, "sa1422");
-		Species alias2 = createSpeciesAlias(224.964285714286, 241.392857142859, 80.0, 40.0, "sa1419");
-		Complex alias3 = createComplexAlias(804.714285714286, 182.642857142859, 112.0, 172.0, "csa152");
-		alias3.addSpecies(alias);
-		alias3.addSpecies(alias2);
-		alias.setComplex(alias3);
-		alias2.setComplex(alias3);
-
-		model.addElement(alias);
-		model.addElement(alias2);
-		model.addElement(alias3);
-
-		model.addElement(createCompartmentAlias(380.0, 416.0, 1893.0, 1866.0, "ca1"));
-		model.setWidth(2000);
-		model.setHeight(2000);
-		return model;
-	}
-
-	private Compartment createCompartmentAlias(double x, double y, double width, double height, String aliasId) {
-		Compartment alias = new Compartment(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-	private Species createSpeciesAlias(double x, double y, double width, double height, String aliasId) {
-		SimpleMolecule alias = new SimpleMolecule(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-	private Complex createComplexAlias(double x, double y, double width, double height, String aliasId) {
-		Complex alias = new Complex(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-	@Test
-	public void saveAliasWithSubmodelTest() throws Exception {
-		try {
-			long count = modelDao.getCount();
-			Model model = createModel();
-			Model model1 = createModel();
-			Element alias = model.getElementByElementId("sa2");
-			ElementSubmodelConnection submodel = new ElementSubmodelConnection(model1, SubmodelType.UNKNOWN);
-			alias.setSubmodel(submodel);
-			project.addModel(model);
-
-			projectDao.add(project);
-			projectDao.flush();
-
-			long count2 = modelDao.getCount();
-			assertEquals(count + 2, count2);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-}
+package lcsb.mapviewer.persist.dao.map.layout.alias;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.map.SearchIndex;
+import lcsb.mapviewer.model.map.compartment.Compartment;
+import lcsb.mapviewer.model.map.model.ElementSubmodelConnection;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.model.map.model.SubmodelType;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Complex;
+import lcsb.mapviewer.model.map.species.SimpleMolecule;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.persist.PersistTestFunctions;
+
+public class AliasDaoTest extends PersistTestFunctions {
+  Logger logger = Logger.getLogger(AliasDaoTest.class);
+
+  private Project project;
+  String projectId = "Some_id";
+
+  int identifierCounter = 0;
+
+  @Before
+  public void setUp() throws Exception {
+    project = projectDao.getProjectByProjectId(projectId);
+    if (project != null) {
+      projectDao.delete(project);
+    }
+    project = new Project();
+    project.setProjectId(projectId);
+    projectDao.add(project);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    projectDao.delete(project);
+  }
+
+  @Test
+  public void anotherSaveDaoTest() throws Exception {
+    try {
+      Model model = createModel();
+      project.addModel(model);
+
+      Species alias = (Species) model.getElementByElementId("sa2");
+
+      alias.getSearchIndexes().add(new SearchIndex("blabla"));
+
+      modelDao.add(model);
+
+      Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
+
+      Species alias2 = (Species) elementDao.getById(model2.getElementByElementId("sa2").getId());
+
+      assertEquals(1, alias2.getSearchIndexes().size());
+
+      modelDao.delete(model);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private Model createModel() {
+    Model model = new ModelFullIndexed(null);
+    model.addElement(createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "sa2"));
+    model.addElement(createSpeciesAlias(267.6666666666665, 438.75, 80.0, 40.0, "sa1117"));
+    model.addElement(createSpeciesAlias(261.6666666666665, 600.75, 92.0, 52.0, "sa1119"));
+    model.addElement(createSpeciesAlias(203.666666666667, 687.75, 98.0, 58.0, "sa1121"));
+
+    Species alias = createSpeciesAlias(817.714285714286, 287.642857142859, 80.0, 40.0, "sa1422");
+    Species alias2 = createSpeciesAlias(224.964285714286, 241.392857142859, 80.0, 40.0, "sa1419");
+    Complex alias3 = createComplexAlias(804.714285714286, 182.642857142859, 112.0, 172.0, "csa152");
+    alias3.addSpecies(alias);
+    alias3.addSpecies(alias2);
+    alias.setComplex(alias3);
+    alias2.setComplex(alias3);
+
+    model.addElement(alias);
+    model.addElement(alias2);
+    model.addElement(alias3);
+
+    model.addElement(createCompartmentAlias(380.0, 416.0, 1893.0, 1866.0, "ca1"));
+    model.setWidth(2000);
+    model.setHeight(2000);
+    return model;
+  }
+
+  private Compartment createCompartmentAlias(double x, double y, double width, double height, String aliasId) {
+    Compartment alias = new Compartment(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  private Species createSpeciesAlias(double x, double y, double width, double height, String aliasId) {
+    SimpleMolecule alias = new SimpleMolecule(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  private Complex createComplexAlias(double x, double y, double width, double height, String aliasId) {
+    Complex alias = new Complex(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  @Test
+  public void saveAliasWithSubmodelTest() throws Exception {
+    try {
+      long count = modelDao.getCount();
+      Model model = createModel();
+      Model model1 = createModel();
+      Element alias = model.getElementByElementId("sa2");
+      ElementSubmodelConnection submodel = new ElementSubmodelConnection(model1, SubmodelType.UNKNOWN);
+      alias.setSubmodel(submodel);
+      project.addModel(model);
+
+      projectDao.add(project);
+      projectDao.flush();
+
+      long count2 = modelDao.getCount();
+      assertEquals(count + 2, count2);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AliasDaoTest2.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AliasDaoTest2.java
index 1aefeefe0383b3e6b860bbe77ab348f73461bc50..abab8f1ff18ba61d06e5297769f517dd076474b0 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AliasDaoTest2.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AliasDaoTest2.java
@@ -1,311 +1,301 @@
-package lcsb.mapviewer.persist.dao.map.layout.alias;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.model.map.MiriamData;
-import lcsb.mapviewer.model.map.MiriamRelationType;
-import lcsb.mapviewer.model.map.MiriamType;
-import lcsb.mapviewer.model.map.compartment.Compartment;
-import lcsb.mapviewer.model.map.species.AntisenseRna;
-import lcsb.mapviewer.model.map.species.Chemical;
-import lcsb.mapviewer.model.map.species.GenericProtein;
-import lcsb.mapviewer.model.map.species.Ion;
-import lcsb.mapviewer.model.map.species.Phenotype;
-import lcsb.mapviewer.model.map.species.Protein;
-import lcsb.mapviewer.model.map.species.Rna;
-import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegionType;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
-import lcsb.mapviewer.model.map.species.field.ModificationState;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
-import lcsb.mapviewer.persist.PersistTestFunctions;
-
-public class AliasDaoTest2 extends PersistTestFunctions {
-  static Logger logger = Logger.getLogger(AliasDaoTest.class);
-
-  private Integer testChargeVal = 1;
-  private String testIdAlias = "a";
-  private Double testInitialAmount = 2.0;
-  private Double testInitialConcentration = 3.0;
-  private String testName = "d";
-  private String testNotes = "e";
-  private Boolean testOnlySubstanceunits = true;
-
-  @Before
-  public void setUp() throws Exception {
-  }
-
-  @After
-  public void tearDown() throws Exception {
-  }
-
-  @Test
-  public void testAdd() throws Exception {
-    try {
-
-      GenericProtein sp = new GenericProtein(testIdAlias);
-      sp.setCharge(testChargeVal);
-      sp.setInitialAmount(testInitialAmount);
-      sp.setInitialConcentration(testInitialConcentration);
-      sp.setName(testName);
-      sp.setNotes(testNotes);
-      sp.setOnlySubstanceUnits(testOnlySubstanceunits);
-
-      Compartment parent = new Compartment("comp id");
-      sp.setCompartment(parent);
-
-      MiriamData md = new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.UNKNOWN, "c");
-      sp.addMiriamData(md);
-
-      aliasDao.add(sp);
-
-      Species sp2 = (Species) aliasDao.getById(sp.getId());
-      assertNotNull(sp2);
-      assertEquals(sp.getCharge(), sp2.getCharge());
-      assertEquals(sp.getElementId(), sp2.getElementId());
-      assertEquals(sp.getInitialAmount(), sp2.getInitialAmount());
-      assertEquals(sp.getInitialConcentration(), sp2.getInitialConcentration());
-      assertEquals(sp.getName(), sp2.getName());
-      assertEquals(sp.getNotes(), sp2.getNotes());
-      assertEquals(sp.hasOnlySubstanceUnits(), sp2.hasOnlySubstanceUnits());
-
-      Compartment parent2 = sp2.getCompartment();
-      assertNotNull(parent2);
-      assertEquals("comp id", parent2.getElementId());
-
-      assertNotNull(sp2.getMiriamData());
-
-      MiriamData md2 = sp2.getMiriamData().iterator().next();
-      assertNotNull(md2);
-      assertEquals(md.getDataType(), md2.getDataType());
-      assertEquals(md.getRelationType(), md2.getRelationType());
-      assertEquals(md.getResource(), md2.getResource());
-
-      aliasDao.delete(sp);
-      sp2 = (Species) aliasDao.getById(sp.getId());
-      assertNull(sp2);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testProtein() throws Exception {
-    try {
-
-      Protein protein = new GenericProtein(testIdAlias);
-      ModificationResidue mr = new ModificationResidue();
-      mr.setAngle(2.0);
-      mr.setName("name");
-      mr.setSide("side");
-      mr.setSize(3.0);
-      mr.setState(ModificationState.GLYCOSYLATED);
-      protein.addModificationResidue(mr);
-
-      aliasDao.add(protein);
-
-      Protein sp2 = (Protein) aliasDao.getById(protein.getId());
-      assertNotNull(sp2);
-      assertEquals(protein.getElementId(), sp2.getElementId());
-
-      assertNotNull(sp2.getModificationResidues());
-      assertEquals(1, sp2.getModificationResidues().size());
-
-      assertEquals(sp2.getModificationResidues().get(0).getAngle(), mr.getAngle());
-      assertEquals(sp2.getModificationResidues().get(0).getIdModificationResidue(), mr.getIdModificationResidue());
-      assertEquals(sp2.getModificationResidues().get(0).getName(), mr.getName());
-      assertEquals(sp2.getModificationResidues().get(0).getSide(), mr.getSide());
-      assertEquals(sp2.getModificationResidues().get(0).getSize(), mr.getSize());
-      assertEquals(sp2.getModificationResidues().get(0).getState(), mr.getState());
-
-      aliasDao.delete(sp2);
-      sp2 = (Protein) aliasDao.getById(protein.getId());
-      assertNull(sp2);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testRna() throws Exception {
-    try {
-
-      Rna sp = new Rna(testIdAlias);
-      RnaRegion mr = new RnaRegion();
-      mr.setName("name");
-      mr.setSize(3.0);
-      mr.setState(ModificationState.DONT_CARE);
-      sp.addRegion(mr);
-
-      aliasDao.add(sp);
-      aliasDao.evict(sp);
-
-      Rna sp2 = (Rna) aliasDao.getById(sp.getId());
-      assertNotNull(sp2);
-      assertEquals(sp.getElementId(), sp2.getElementId());
-
-      assertNotNull(sp2.getRegions());
-      assertEquals(1, sp2.getRegions().size());
-
-      assertEquals(sp2.getRegions().get(0).getId(), mr.getId());
-      assertEquals(sp2.getRegions().get(0).getName(), mr.getName());
-      assertEquals(sp2.getRegions().get(0).getSize(), mr.getSize(), EPSILON);
-      assertEquals(sp2.getRegions().get(0).getState(), mr.getState());
-
-      aliasDao.delete(sp2);
-      sp2 = (Rna) aliasDao.getById(sp.getId());
-      assertNull(sp2);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testAntisenseRna() throws Exception {
-    try {
-
-      AntisenseRna sp = new AntisenseRna(testIdAlias);
-      AntisenseRnaRegion mr = new AntisenseRnaRegion();
-      mr.setName("name");
-      mr.setSize(3.0);
-      mr.setType(AntisenseRnaRegionType.MODIFICATION_SITE);
-      mr.setState(ModificationState.UNKNOWN);
-      sp.addRegion(mr);
-
-      aliasDao.add(sp);
-      aliasDao.evict(sp);
-
-      AntisenseRna sp2 = (AntisenseRna) aliasDao.getById(sp.getId());
-      assertNotNull(sp2);
-      assertEquals(sp.getElementId(), sp2.getElementId());
-
-      assertNotNull(sp2.getRegions());
-      assertEquals(1, sp2.getRegions().size());
-
-      assertEquals(sp2.getRegions().get(0).getIdAntisenseRnaRegion(), mr.getIdAntisenseRnaRegion());
-      assertEquals(sp2.getRegions().get(0).getName(), mr.getName());
-      assertEquals(sp2.getRegions().get(0).getSize(), mr.getSize(), EPSILON);
-      assertEquals(sp2.getRegions().get(0).getState(), mr.getState());
-      assertEquals(sp2.getRegions().get(0).getType(), mr.getType());
-
-      aliasDao.delete(sp2);
-      sp2 = (AntisenseRna) aliasDao.getById(sp.getId());
-      assertNull(sp2);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testSynonymsInAlias() throws Exception {
-    try {
-      Protein protein = new GenericProtein(testIdAlias);
-      protein.addSynonym("Synonym");
-      protein.addSynonym("Synonym A");
-      protein.addSynonym("A");
-
-      protein.addFormerSymbol("Sym");
-      protein.addFormerSymbol("Sym A");
-      protein.addFormerSymbol("DD");
-
-      aliasDao.add(protein);
-      aliasDao.flush();
-
-      aliasDao.evict(protein);
-      Protein sp2 = (Protein) aliasDao.getById(protein.getId());
-
-      assertNotNull(sp2.getSynonyms());
-      assertEquals(protein.getSynonyms().size(), sp2.getSynonyms().size());
-
-      for (int i = 0; i < protein.getSynonyms().size(); i++) {
-        assertEquals(protein.getSynonyms().get(i), sp2.getSynonyms().get(i));
-      }
-
-      assertNotNull(sp2.getFormerSymbols());
-      assertEquals(protein.getFormerSymbols().size(), sp2.getFormerSymbols().size());
-
-      for (int i = 0; i < protein.getFormerSymbols().size(); i++) {
-        assertEquals(protein.getFormerSymbols().get(i), sp2.getFormerSymbols().get(i));
-      }
-
-      aliasDao.delete(sp2);
-      sp2 = (Protein) aliasDao.getById(protein.getId());
-      assertNull(sp2);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testChemicals() throws Exception {
-    try {
-      Chemical ion = new Ion(testIdAlias);
-      ion.setInChI("come inchi");
-      ion.setInChIKey("keyyy");
-      ion.setSmiles("smile");
-
-      aliasDao.add(ion);
-      aliasDao.flush();
-
-      aliasDao.evict(ion);
-      Ion sp2 = (Ion) aliasDao.getById(ion.getId());
-
-      assertNotNull(sp2.getSynonyms());
-      assertEquals(ion.getSynonyms().size(), sp2.getSynonyms().size());
-
-      assertEquals(ion.getSmiles(), sp2.getSmiles());
-      assertEquals(ion.getInChIKey(), sp2.getInChIKey());
-      assertEquals(ion.getInChI(), sp2.getInChI());
-
-      aliasDao.delete(sp2);
-      sp2 = (Ion) aliasDao.getById(ion.getId());
-      assertNull(sp2);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testPhenotype() throws Exception {
-    try {
-      Phenotype phenotype = new Phenotype(testIdAlias);
-
-      aliasDao.add(phenotype);
-      aliasDao.flush();
-
-      aliasDao.evict(phenotype);
-      Phenotype sp2 = (Phenotype) aliasDao.getById(phenotype.getId());
-
-      assertNotNull(sp2.getSynonyms());
-      assertEquals(phenotype.getSynonyms().size(), phenotype.getSynonyms().size());
-
-      aliasDao.delete(sp2);
-      sp2 = (Phenotype) aliasDao.getById(phenotype.getId());
-      assertNull(sp2);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-}
+package lcsb.mapviewer.persist.dao.map.layout.alias;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.awt.geom.Point2D;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.model.map.MiriamData;
+import lcsb.mapviewer.model.map.MiriamRelationType;
+import lcsb.mapviewer.model.map.MiriamType;
+import lcsb.mapviewer.model.map.compartment.Compartment;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Chemical;
+import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.Ion;
+import lcsb.mapviewer.model.map.species.Phenotype;
+import lcsb.mapviewer.model.map.species.Protein;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.Species;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.ModificationState;
+import lcsb.mapviewer.model.map.species.field.Residue;
+import lcsb.mapviewer.persist.PersistTestFunctions;
+
+public class AliasDaoTest2 extends PersistTestFunctions {
+  static Logger logger = Logger.getLogger(AliasDaoTest.class);
+
+  private Integer testChargeVal = 1;
+  private String testIdAlias = "a";
+  private Double testInitialAmount = 2.0;
+  private Double testInitialConcentration = 3.0;
+  private String testName = "d";
+  private String testNotes = "e";
+  private Boolean testOnlySubstanceunits = true;
+
+  @Before
+  public void setUp() throws Exception {
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testAdd() throws Exception {
+    try {
+
+      GenericProtein sp = new GenericProtein(testIdAlias);
+      sp.setCharge(testChargeVal);
+      sp.setInitialAmount(testInitialAmount);
+      sp.setInitialConcentration(testInitialConcentration);
+      sp.setName(testName);
+      sp.setNotes(testNotes);
+      sp.setOnlySubstanceUnits(testOnlySubstanceunits);
+
+      Compartment parent = new Compartment("comp id");
+      sp.setCompartment(parent);
+
+      MiriamData md = new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.UNKNOWN, "c");
+      sp.addMiriamData(md);
+
+      elementDao.add(sp);
+
+      Species sp2 = (Species) elementDao.getById(sp.getId());
+      assertNotNull(sp2);
+      assertEquals(sp.getCharge(), sp2.getCharge());
+      assertEquals(sp.getElementId(), sp2.getElementId());
+      assertEquals(sp.getInitialAmount(), sp2.getInitialAmount());
+      assertEquals(sp.getInitialConcentration(), sp2.getInitialConcentration());
+      assertEquals(sp.getName(), sp2.getName());
+      assertEquals(sp.getNotes(), sp2.getNotes());
+      assertEquals(sp.hasOnlySubstanceUnits(), sp2.hasOnlySubstanceUnits());
+
+      Compartment parent2 = sp2.getCompartment();
+      assertNotNull(parent2);
+      assertEquals("comp id", parent2.getElementId());
+
+      assertNotNull(sp2.getMiriamData());
+
+      MiriamData md2 = sp2.getMiriamData().iterator().next();
+      assertNotNull(md2);
+      assertEquals(md.getDataType(), md2.getDataType());
+      assertEquals(md.getRelationType(), md2.getRelationType());
+      assertEquals(md.getResource(), md2.getResource());
+
+      elementDao.delete(sp);
+      sp2 = (Species) elementDao.getById(sp.getId());
+      assertNull(sp2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testProtein() throws Exception {
+    try {
+
+      Protein protein = new GenericProtein(testIdAlias);
+      Residue mr = new Residue();
+      mr.setPosition(new Point2D.Double(10, 20));
+      mr.setName("name");
+      mr.setState(ModificationState.GLYCOSYLATED);
+      protein.addModificationResidue(mr);
+
+      elementDao.add(protein);
+
+      Protein sp2 = (Protein) elementDao.getById(protein.getId());
+      assertNotNull(sp2);
+      assertEquals(protein.getElementId(), sp2.getElementId());
+
+      assertNotNull(sp2.getModificationResidues());
+      assertEquals(1, sp2.getModificationResidues().size());
+
+      Residue copy = (Residue) sp2.getModificationResidues().get(0);
+      assertEquals(copy.getPosition(), mr.getPosition());
+      assertEquals(copy.getIdModificationResidue(), mr.getIdModificationResidue());
+      assertEquals(copy.getName(), mr.getName());
+      assertEquals(copy.getState(), mr.getState());
+
+      elementDao.delete(sp2);
+      sp2 = (Protein) elementDao.getById(protein.getId());
+      assertNull(sp2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testRna() throws Exception {
+    try {
+
+      Rna sp = new Rna(testIdAlias);
+      ModificationSite mr = new ModificationSite();
+      mr.setName("name");
+      mr.setState(ModificationState.DONT_CARE);
+      sp.addRegion(mr);
+
+      elementDao.add(sp);
+      elementDao.evict(sp);
+
+      Rna sp2 = (Rna) elementDao.getById(sp.getId());
+      assertNotNull(sp2);
+      assertEquals(sp.getElementId(), sp2.getElementId());
+
+      assertNotNull(sp2.getRegions());
+      assertEquals(1, sp2.getRegions().size());
+
+      ModificationSite copy = (ModificationSite) sp2.getRegions().get(0);
+      assertEquals(copy.getId(), mr.getId());
+      assertEquals(copy.getName(), mr.getName());
+      assertEquals(copy.getState(), mr.getState());
+
+      elementDao.delete(sp2);
+      sp2 = (Rna) elementDao.getById(sp.getId());
+      assertNull(sp2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testAntisenseRna() throws Exception {
+    try {
+
+      AntisenseRna sp = new AntisenseRna(testIdAlias);
+      ModificationSite mr = new ModificationSite();
+      mr.setName("name");
+      sp.addRegion(mr);
+
+      elementDao.add(sp);
+      elementDao.evict(sp);
+
+      AntisenseRna sp2 = (AntisenseRna) elementDao.getById(sp.getId());
+      assertNotNull(sp2);
+      assertEquals(sp.getElementId(), sp2.getElementId());
+
+      assertNotNull(sp2.getRegions());
+      assertEquals(1, sp2.getRegions().size());
+
+      assertEquals(sp2.getRegions().get(0).getIdModificationResidue(), mr.getIdModificationResidue());
+      assertEquals(sp2.getRegions().get(0).getName(), mr.getName());
+
+      elementDao.delete(sp2);
+      sp2 = (AntisenseRna) elementDao.getById(sp.getId());
+      assertNull(sp2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testSynonymsInAlias() throws Exception {
+    try {
+      Protein protein = new GenericProtein(testIdAlias);
+      protein.addSynonym("Synonym");
+      protein.addSynonym("Synonym A");
+      protein.addSynonym("A");
+
+      protein.addFormerSymbol("Sym");
+      protein.addFormerSymbol("Sym A");
+      protein.addFormerSymbol("DD");
+
+      elementDao.add(protein);
+      elementDao.flush();
+
+      elementDao.evict(protein);
+      Protein sp2 = (Protein) elementDao.getById(protein.getId());
+
+      assertNotNull(sp2.getSynonyms());
+      assertEquals(protein.getSynonyms().size(), sp2.getSynonyms().size());
+
+      for (int i = 0; i < protein.getSynonyms().size(); i++) {
+        assertEquals(protein.getSynonyms().get(i), sp2.getSynonyms().get(i));
+      }
+
+      assertNotNull(sp2.getFormerSymbols());
+      assertEquals(protein.getFormerSymbols().size(), sp2.getFormerSymbols().size());
+
+      for (int i = 0; i < protein.getFormerSymbols().size(); i++) {
+        assertEquals(protein.getFormerSymbols().get(i), sp2.getFormerSymbols().get(i));
+      }
+
+      elementDao.delete(sp2);
+      sp2 = (Protein) elementDao.getById(protein.getId());
+      assertNull(sp2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testChemicals() throws Exception {
+    try {
+      Chemical ion = new Ion(testIdAlias);
+      ion.setInChI("come inchi");
+      ion.setInChIKey("keyyy");
+      ion.setSmiles("smile");
+
+      elementDao.add(ion);
+      elementDao.flush();
+
+      elementDao.evict(ion);
+      Ion sp2 = (Ion) elementDao.getById(ion.getId());
+
+      assertNotNull(sp2.getSynonyms());
+      assertEquals(ion.getSynonyms().size(), sp2.getSynonyms().size());
+
+      assertEquals(ion.getSmiles(), sp2.getSmiles());
+      assertEquals(ion.getInChIKey(), sp2.getInChIKey());
+      assertEquals(ion.getInChI(), sp2.getInChI());
+
+      elementDao.delete(sp2);
+      sp2 = (Ion) elementDao.getById(ion.getId());
+      assertNull(sp2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testPhenotype() throws Exception {
+    try {
+      Phenotype phenotype = new Phenotype(testIdAlias);
+
+      elementDao.add(phenotype);
+      elementDao.flush();
+
+      elementDao.evict(phenotype);
+      Phenotype sp2 = (Phenotype) elementDao.getById(phenotype.getId());
+
+      assertNotNull(sp2.getSynonyms());
+      assertEquals(phenotype.getSynonyms().size(), phenotype.getSynonyms().size());
+
+      elementDao.delete(sp2);
+      sp2 = (Phenotype) elementDao.getById(phenotype.getId());
+      assertNull(sp2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+}
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AntisenseRnaTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AntisenseRnaTest.java
index 02c33a2fc3ba37e16ada8225dd09f7ed302b1507..44bb7dcec7e4cc03078389b86f2b6fcf2e4c5373 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AntisenseRnaTest.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/AntisenseRnaTest.java
@@ -1,88 +1,88 @@
-package lcsb.mapviewer.persist.dao.map.layout.alias;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.springframework.test.annotation.Rollback;
-
-import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelFullIndexed;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.AntisenseRna;
-import lcsb.mapviewer.persist.PersistTestFunctions;
-
-@Rollback(true)
-public class AntisenseRnaTest extends PersistTestFunctions {
-	Logger logger						 = Logger.getLogger(AntisenseRnaTest.class);
-
-	int		 identifierCounter = 0;
-	String projectId				 = "Some_id";
-
-	@Before
-	public void setUp() throws Exception {
-		Project project = projectDao.getProjectByProjectId(projectId);
-		if (project != null) {
-			projectDao.delete(project);
-		}
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testAntisenseRnaRegionInDb() throws Exception {
-		try {
-			Project project = new Project();
-			project.setProjectId(projectId);
-
-			Model model = createModel();
-
-			project.addModel(model);
-			projectDao.add(project);
-			projectDao.evict(project);
-
-			Project project2 = projectDao.getProjectByProjectId(projectId);
-			assertNotNull(project2);
-			assertFalse(project2.equals(project));
-			assertEquals(project.getId(), project2.getId());
-
-			Model model2 = new ModelFullIndexed(project2.getModels().iterator().next());
-
-			Element sp = model.getElements().iterator().next();
-			AntisenseRna ar = (AntisenseRna) sp;
-
-			Element sp2 = model2.getElements().iterator().next();
-			AntisenseRna ar2 = (AntisenseRna) sp2;
-
-			projectDao.delete(project2);
-
-			assertEquals(ar.getRegions().size(), ar2.getRegions().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	private Model createModel() {
-		Model model = new ModelFullIndexed(null);
-
-		AntisenseRna alias = new AntisenseRna("As");
-		alias.addRegion(new AntisenseRnaRegion());
-		alias.setX(1);
-		alias.setY(2);
-		alias.setWidth(10);
-		alias.setHeight(20);
-		model.addElement(alias);
-
-		return model;
-	}
-
-}
+package lcsb.mapviewer.persist.dao.map.layout.alias;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.test.annotation.Rollback;
+
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.model.map.species.AntisenseRna;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.persist.PersistTestFunctions;
+
+@Rollback(true)
+public class AntisenseRnaTest extends PersistTestFunctions {
+  Logger logger = Logger.getLogger(AntisenseRnaTest.class);
+
+  int identifierCounter = 0;
+  String projectId = "Some_id";
+
+  @Before
+  public void setUp() throws Exception {
+    Project project = projectDao.getProjectByProjectId(projectId);
+    if (project != null) {
+      projectDao.delete(project);
+    }
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testAntisenseRnaRegionInDb() throws Exception {
+    try {
+      Project project = new Project();
+      project.setProjectId(projectId);
+
+      Model model = createModel();
+
+      project.addModel(model);
+      projectDao.add(project);
+      projectDao.evict(project);
+
+      Project project2 = projectDao.getProjectByProjectId(projectId);
+      assertNotNull(project2);
+      assertFalse(project2.equals(project));
+      assertEquals(project.getId(), project2.getId());
+
+      Model model2 = new ModelFullIndexed(project2.getModels().iterator().next());
+
+      Element sp = model.getElements().iterator().next();
+      AntisenseRna ar = (AntisenseRna) sp;
+
+      Element sp2 = model2.getElements().iterator().next();
+      AntisenseRna ar2 = (AntisenseRna) sp2;
+
+      projectDao.delete(project2);
+
+      assertEquals(ar.getRegions().size(), ar2.getRegions().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private Model createModel() {
+    Model model = new ModelFullIndexed(null);
+
+    AntisenseRna alias = new AntisenseRna("As");
+    alias.addRegion(new CodingRegion());
+    alias.setX(1);
+    alias.setY(2);
+    alias.setWidth(10);
+    alias.setHeight(20);
+    model.addElement(alias);
+
+    return model;
+  }
+
+}
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/RnaTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/RnaTest.java
index 04da77ac6f445aa3dea8f1755afa915499f53e8e..4eea1e67a969bfceb63b199381fe79e7d95e4464 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/RnaTest.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/layout/alias/RnaTest.java
@@ -1,87 +1,87 @@
-package lcsb.mapviewer.persist.dao.map.layout.alias;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-
-import org.apache.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.map.model.Model;
-import lcsb.mapviewer.model.map.model.ModelFullIndexed;
-import lcsb.mapviewer.model.map.species.Element;
-import lcsb.mapviewer.model.map.species.Rna;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
-import lcsb.mapviewer.persist.PersistTestFunctions;
-
-public class RnaTest extends PersistTestFunctions {
-	Logger logger						 = Logger.getLogger(RnaTest.class);
-
-	int		 identifierCounter = 0;
-
-	String projectId				 = "Some_id";
-
-	@Before
-	public void setUp() throws Exception {
-		Project project = projectDao.getProjectByProjectId(projectId);
-		if (project != null) {
-			projectDao.delete(project);
-		}
-	}
-
-	@After
-	public void tearDown() throws Exception {
-	}
-
-	@Test
-	public void testRnaRegionInDb() throws Exception {
-		try {
-			Project project = new Project();
-			project.setProjectId(projectId);
-
-			Model model = createModel();
-
-			project.addModel(model);
-			projectDao.add(project);
-			projectDao.evict(project);
-
-			Project project2 = projectDao.getProjectByProjectId(projectId);
-			assertNotNull(project2);
-			assertFalse(project2.equals(project));
-			assertEquals(project.getId(), project2.getId());
-
-			Model model2 = new ModelFullIndexed(project2.getModels().iterator().next());
-
-			Element sp = model.getElements().iterator().next();
-			Rna ar = (Rna) sp;
-
-			Element sp2 = model2.getElements().iterator().next();
-			Rna ar2 = (Rna) sp2;
-
-			projectDao.delete(project2);
-
-			assertEquals(ar.getRegions().size(), ar2.getRegions().size());
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	private Model createModel() {
-		Model model = new ModelFullIndexed(null);
-
-		Rna alias = new Rna("As");
-		alias.addRegion(new RnaRegion());
-		alias.setX(1);
-		alias.setY(2);
-		alias.setWidth(10);
-		alias.setHeight(20);
-		model.addElement(alias);
-
-		return model;
-	}
-
-}
+package lcsb.mapviewer.persist.dao.map.layout.alias;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelFullIndexed;
+import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Rna;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.persist.PersistTestFunctions;
+
+public class RnaTest extends PersistTestFunctions {
+  Logger logger = Logger.getLogger(RnaTest.class);
+
+  int identifierCounter = 0;
+
+  String projectId = "Some_id";
+
+  @Before
+  public void setUp() throws Exception {
+    Project project = projectDao.getProjectByProjectId(projectId);
+    if (project != null) {
+      projectDao.delete(project);
+    }
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testRnaRegionInDb() throws Exception {
+    try {
+      Project project = new Project();
+      project.setProjectId(projectId);
+
+      Model model = createModel();
+
+      project.addModel(model);
+      projectDao.add(project);
+      projectDao.evict(project);
+
+      Project project2 = projectDao.getProjectByProjectId(projectId);
+      assertNotNull(project2);
+      assertFalse(project2.equals(project));
+      assertEquals(project.getId(), project2.getId());
+
+      Model model2 = new ModelFullIndexed(project2.getModels().iterator().next());
+
+      Element sp = model.getElements().iterator().next();
+      Rna ar = (Rna) sp;
+
+      Element sp2 = model2.getElements().iterator().next();
+      Rna ar2 = (Rna) sp2;
+
+      projectDao.delete(project2);
+
+      assertEquals(ar.getRegions().size(), ar2.getRegions().size());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private Model createModel() {
+    Model model = new ModelFullIndexed(null);
+
+    Rna alias = new Rna("As");
+    alias.addRegion(new CodingRegion());
+    alias.setX(1);
+    alias.setY(2);
+    alias.setWidth(10);
+    alias.setHeight(20);
+    model.addElement(alias);
+
+    return model;
+  }
+
+}
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/user/UserDaoTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/user/UserDaoTest.java
index 0192989f6d3471a9bd30b06f1a97ed4c8332223e..aad6f041c4ff8015282de4d5152c84becfa82f44 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/user/UserDaoTest.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/user/UserDaoTest.java
@@ -122,49 +122,6 @@ public class UserDaoTest extends PersistTestFunctions {
     }
   }
 
-  @Test
-  public void testGetUserByLoginAndPassword() throws Exception {
-    try {
-      User user = new User();
-      user.setCryptedPassword(passwordEncoder.encode(testPasswd));
-      user.setLogin(testLogin);
-      userDao.add(user);
-      User user2 = userDao.getUserByLoginAndPassword(testLogin, testPasswd);
-      assertNotNull(user2);
-      assertEquals(user2.getId(), user.getId());
-      assertEquals(user2.getLogin(), user.getLogin());
-      assertEquals(user2.getCryptedPassword(), user.getCryptedPassword());
-      userDao.delete(user);
-      // after we remove it we shouldn't be able to get it
-      User user3 = userDao.getUserByLoginAndPassword(testLogin, testPasswd);
-      assertNull(user3);
-
-      // after we remove it we shouldn't be able to get the removed and modified
-      // object
-      User user4 = userDao.getUserByLoginAndPassword(user2.getLogin(), testPasswd);
-      assertNull(user4);
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
-  @Test
-  public void testGetUserByLoginAndEmptyPassword() throws Exception {
-    try {
-      User user = new User();
-      user.setCryptedPassword(passwordEncoder.encode(testPasswd));
-      user.setLogin(testLogin);
-      userDao.add(user);
-      User user2 = userDao.getUserByLoginAndPassword(testLogin, null);
-      assertNull(user2);
-      userDao.delete(user);
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
   @Test
   public void testGetUserByLogin() throws Exception {
     try {
@@ -208,27 +165,6 @@ public class UserDaoTest extends PersistTestFunctions {
     }
   }
 
-  @Test
-  public void testGetUserByNameSurname() throws Exception {
-    try {
-      User user = new User();
-      user.setCryptedPassword(passwordEncoder.encode(testPasswd));
-      user.setLogin(testLogin);
-      user.setEmail(testEmail);
-      user.setName(testName);
-      user.setSurname(testSurname);
-      userDao.add(user);
-      User user2 = userDao.getUserByNameSurname(testName + " " + testSurname);
-      assertNotNull(user2);
-      user2 = userDao.getUserByNameSurname(testName + "  " + testSurname);
-      assertNull(user2);
-      userDao.delete(user);
-    } catch (Exception e) {
-      e.printStackTrace();
-      throw e;
-    }
-  }
-
   @Test
   public void testGetAll() throws Exception {
     try {
diff --git a/pom.xml b/pom.xml
index be583c05b21d751798a01048bf847c29d2a6e06f..d5d32a9cadb483204b206b47cce6112ac4f49447 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,6 +82,8 @@
 		
 		<cglib.version>2.2.2</cglib.version>
 		
+
+    <unboundid-ldapsdk.version>4.0.6</unboundid-ldapsdk.version>
 		<mockito.version>1.10.19</mockito.version>
 	</properties>
 
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeController.java b/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeController.java
index 67b4a370f098d4b3c23627b47751a9a158c6386a..cbcb47bcad6476b71d847b34013efab9a2cf3f3e 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeController.java
@@ -1,16 +1,21 @@
 package lcsb.mapviewer.api.genomics;
 
+import java.io.IOException;
+import java.util.List;
 import java.util.Map;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
+import org.springframework.util.MultiValueMap;
 import org.springframework.web.bind.annotation.CookieValue;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
 import javassist.tools.rmi.ObjectNotFoundException;
+import lcsb.mapviewer.annotation.services.genome.ReferenceGenomeConnectorException;
 import lcsb.mapviewer.api.BaseController;
 import lcsb.mapviewer.api.QueryException;
 import lcsb.mapviewer.common.Configuration;
@@ -32,4 +37,88 @@ public class ReferenceGenomeController extends BaseController {
   ) throws SecurityException, QueryException, ObjectNotFoundException {
     return referenceGenomeController.getReferenceGenome(token, organism, type, version);
   }
+
+  @RequestMapping(value = "/genomics/taxonomies/{organismId}/genomeTypes/{type}/versions/{version}:getAvailableRemoteUrls", method = {
+      RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public List<Map<String, Object>> getRemoteUrls(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "organismId") String organism, //
+      @PathVariable(value = "type") String type, //
+      @PathVariable(value = "version") String version//
+  ) throws SecurityException, QueryException, ObjectNotFoundException {
+    return referenceGenomeController.getRemoteUrls(token, organism, type, version);
+  }
+
+  @RequestMapping(value = "/genomics/taxonomies/", method = { RequestMethod.GET }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public List<Map<String, Object>> getGenomeTaxonomies(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, QueryException, ObjectNotFoundException {
+    return referenceGenomeController.getReferenceGenomeTaxonomies(token);
+  }
+
+  @RequestMapping(value = "/genomics/", method = { RequestMethod.POST }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object> addGenome(//
+      @RequestBody MultiValueMap<String, Object> formData, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, QueryException, IOException, ReferenceGenomeConnectorException  {
+    return referenceGenomeController.addReferenceGenome(formData, token);
+  }
+
+  @RequestMapping(value = "/genomics/taxonomies/{organismId}/genomeTypes/", method = { RequestMethod.GET }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public List<Map<String, Object>> getGenomeTaxonomyTypes(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "organismId") String organism //
+  ) throws SecurityException, QueryException, ObjectNotFoundException {
+    return referenceGenomeController.getReferenceGenomeTypes(token, organism);
+  }
+
+  @RequestMapping(value = "/genomics/taxonomies/{organismId}/genomeTypes/{type}/versions/", method = {
+      RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public List<Map<String, Object>> getGenomeVersion(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token, //
+      @PathVariable(value = "organismId") String organism, //
+      @PathVariable(value = "type") String type //
+  ) throws SecurityException, QueryException, ObjectNotFoundException {
+    return referenceGenomeController.getReferenceGenomeVersions(token, organism, type);
+  }
+
+  @RequestMapping(value = "/genomics/", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON_VALUE })
+  public List<Map<String, Object>> getDownloaded(//
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, QueryException, ObjectNotFoundException {
+    return referenceGenomeController.getReferenceGenomes(token);
+  }
+
+  @RequestMapping(value = "/genomics/{genomeId}/", method = { RequestMethod.DELETE }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object> removeGenome(//
+      @PathVariable(value = "genomeId") String genomeId, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, IOException {
+    return referenceGenomeController.removeGenome(genomeId, token);
+  }
+
+  @RequestMapping(value = "/genomics/{genomeId}/geneMapping/{mappingId}/", method = { RequestMethod.DELETE }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object> removeGeneMapping(//
+      @PathVariable(value = "genomeId") String genomeId, //
+      @PathVariable(value = "mappingId") String mappingId, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, IOException, lcsb.mapviewer.api.ObjectNotFoundException {
+    return referenceGenomeController.removeGeneMapping(genomeId,mappingId, token);
+  }
+
+  @RequestMapping(value = "/genomics/{genomeId}/geneMapping/", method = { RequestMethod.POST }, produces = {
+      MediaType.APPLICATION_JSON_VALUE })
+  public Map<String, Object> addGeneMapping(//
+      @PathVariable(value = "genomeId") String genomeId, //
+      @RequestBody MultiValueMap<String, Object> formData, //
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token //
+  ) throws SecurityException, QueryException, IOException, ReferenceGenomeConnectorException  {
+    return referenceGenomeController.addGeneMapping(formData, genomeId, token);
+  }
+
 }
\ No newline at end of file
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeRestImpl.java
index 9c1f782af4c1debc383b2bc0aeeb405a29e93959..b47cf24709cfd7ac17eb4937aa75b761904fca9f 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/genomics/ReferenceGenomeRestImpl.java
@@ -1,16 +1,23 @@
 package lcsb.mapviewer.api.genomics;
 
 import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.TreeMap;
 
 import org.apache.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.MultiValueMap;
 
 import lcsb.mapviewer.annotation.cache.BigFileCache;
+import lcsb.mapviewer.annotation.services.genome.ReferenceGenomeConnectorException;
 import lcsb.mapviewer.api.BaseRestImpl;
 import lcsb.mapviewer.api.ObjectNotFoundException;
 import lcsb.mapviewer.api.QueryException;
@@ -19,6 +26,7 @@ import lcsb.mapviewer.model.map.MiriamType;
 import lcsb.mapviewer.model.map.layout.ReferenceGenome;
 import lcsb.mapviewer.model.map.layout.ReferenceGenomeGeneMapping;
 import lcsb.mapviewer.model.map.layout.ReferenceGenomeType;
+import lcsb.mapviewer.model.user.PrivilegeType;
 import lcsb.mapviewer.services.SecurityException;
 import lcsb.mapviewer.services.interfaces.IReferenceGenomeService;
 
@@ -62,16 +70,42 @@ public class ReferenceGenomeRestImpl extends BaseRestImpl {
     }
   }
 
+  public List<Map<String, Object>> getRemoteUrls(String token, String organismId, String type, String version)
+      throws SecurityException, QueryException, ObjectNotFoundException {
+    MiriamData organism = null;
+    if (organismId != null && !organismId.isEmpty()) {
+      organism = new MiriamData(MiriamType.TAXONOMY, organismId);
+    } else {
+      throw new QueryException("Unknown taxonomy organism: " + organismId);
+    }
+    try {
+      ReferenceGenomeType genomeType = ReferenceGenomeType.valueOf(type);
+      String url = referenceGenomeService.getUrlForGenomeVersion(genomeType, organism, version);
+
+      List<Map<String, Object>> result = new ArrayList<>();
+      if (url != null) {
+        Map<String, Object> row = new TreeMap<>();
+        row.put("url", url);
+        result.add(row);
+      }
+      return result;
+    } catch (IllegalArgumentException e) {
+      throw new QueryException("Cannot find type: " + type);
+    }
+  }
+
   private Map<String, Object> genomeToMap(ReferenceGenome genome) {
     Map<String, Object> result = new TreeMap<>();
     result.put("organism", super.createAnnotation(genome.getOrganism()));
     result.put("version", genome.getVersion());
+    result.put("type", genome.getType());
     result.put("downloadProgress", genome.getDownloadProgress());
     result.put("sourceUrl", genome.getSourceUrl());
     result.put("localUrl", getLocalUrl(genome.getSourceUrl()));
+    result.put("idObject", genome.getId());
     result.put("geneMapping", geneMappingToMaps(genome.getGeneMapping()));
 
-    return null;
+    return result;
   }
 
   private String getLocalUrl(String sourceUrl) {
@@ -99,7 +133,153 @@ public class ReferenceGenomeRestImpl extends BaseRestImpl {
     result.put("localUrl", getLocalUrl(mapping.getSourceUrl()));
     result.put("sourceUrl", mapping.getSourceUrl());
     result.put("name", mapping.getName());
+    result.put("idObject", mapping.getId());
     return result;
   }
 
+  public List<Map<String, Object>> getReferenceGenomeTaxonomies(String token) throws QueryException {
+    try {
+      Set<MiriamData> organisms = new HashSet<>();
+      for (ReferenceGenomeType type : ReferenceGenomeType.values()) {
+        organisms.addAll(referenceGenomeService.getOrganismsByReferenceGenomeType(type));
+      }
+      List<Map<String, Object>> result = new ArrayList<>();
+      for (MiriamData miriamData : organisms) {
+        result.add(createAnnotation(miriamData));
+      }
+      return result;
+    } catch (ReferenceGenomeConnectorException e) {
+      throw new QueryException("Problem with obtaining organism list", e);
+    }
+  }
+
+  public List<Map<String, Object>> getReferenceGenomeTypes(String token, String organismId) throws QueryException {
+    try {
+      Set<MiriamData> organisms = new HashSet<>();
+      for (ReferenceGenomeType type : ReferenceGenomeType.values()) {
+        organisms.addAll(referenceGenomeService.getOrganismsByReferenceGenomeType(type));
+      }
+      List<Map<String, Object>> result = new ArrayList<>();
+      for (MiriamData miriamData : organisms) {
+        if (miriamData.getResource().equals(organismId)) {
+          Map<String, Object> entry = new HashMap<>();
+          entry.put("type", ReferenceGenomeType.UCSC.toString());
+          result.add(entry);
+        }
+      }
+      return result;
+    } catch (ReferenceGenomeConnectorException e) {
+      throw new QueryException("Problem with obtaining organism list", e);
+    }
+  }
+
+  public List<Map<String, Object>> getReferenceGenomeVersions(String token, String organismId, String type)
+      throws QueryException {
+    ReferenceGenomeType genomeType = ReferenceGenomeType.valueOf(type);
+    MiriamData organism = null;
+    if (organismId != null && !organismId.isEmpty()) {
+      organism = new MiriamData(MiriamType.TAXONOMY, organismId);
+    } else {
+      throw new QueryException("Unknown taxonomy organism: " + organismId);
+    }
+    List<String> versions;
+    try {
+      versions = referenceGenomeService.getAvailableGenomeVersions(genomeType, organism);
+    } catch (ReferenceGenomeConnectorException e) {
+      throw new QueryException("Problem with obtaining version list", e);
+    }
+
+    List<Map<String, Object>> result = new ArrayList<>();
+    for (String string : versions) {
+      Map<String, Object> entry = new HashMap<>();
+      entry.put("version", string);
+      result.add(entry);
+    }
+    return result;
+  }
+
+  public List<Map<String, Object>> getReferenceGenomes(String token)
+      throws SecurityException, QueryException, ObjectNotFoundException {
+    List<Map<String, Object>> result = new ArrayList<>();
+    for (ReferenceGenome genome : referenceGenomeService.getDownloadedGenomes()) {
+      result.add(genomeToMap(genome));
+    }
+    return result;
+  }
+
+  public Map<String, Object> removeGenome(String genomeId, String token) throws SecurityException, IOException {
+    if (!getUserService().userHasPrivilege(token, PrivilegeType.MANAGE_GENOMES)) {
+      throw new SecurityException("Access denied");
+    }
+    ReferenceGenome genome = referenceGenomeService.getReferenceGenomeById(Integer.parseInt(genomeId), token);
+    referenceGenomeService.removeGenome(genome);
+    return okStatus();
+  }
+
+  public Map<String, Object> addReferenceGenome(MultiValueMap<String, Object> formData, String token)
+      throws SecurityException, QueryException, IOException, ReferenceGenomeConnectorException {
+    if (!getUserService().userHasPrivilege(token, PrivilegeType.MANAGE_GENOMES)) {
+      throw new SecurityException("Access denied");
+    }
+
+    String organismId = getFirstValue(formData.get("organismId"));
+    String type = getFirstValue(formData.get("type"));
+    String version = getFirstValue(formData.get("version"));
+    String url = getFirstValue(formData.get("sourceUrl"));
+    MiriamData organism = null;
+    if (organismId != null && !organismId.isEmpty()) {
+      organism = new MiriamData(MiriamType.TAXONOMY, organismId);
+    } else {
+      throw new QueryException("Unknown taxonomy organism: " + organismId);
+    }
+    ReferenceGenomeType genomeType = ReferenceGenomeType.valueOf(type);
+    try {
+      referenceGenomeService.addReferenceGenome(genomeType, organism, version, url);
+      return okStatus();
+    } catch (URISyntaxException e) {
+      throw new QueryException("Problem wih given uri", e);
+    }
+  }
+
+  public Map<String, Object> addGeneMapping(MultiValueMap<String, Object> formData, String genomeId, String token)
+      throws SecurityException, QueryException, IOException, ReferenceGenomeConnectorException {
+    if (!getUserService().userHasPrivilege(token, PrivilegeType.MANAGE_GENOMES)) {
+      throw new SecurityException("Access denied");
+    }
+
+    int id = Integer.parseInt(genomeId);
+    try {
+      ReferenceGenome genome = referenceGenomeService.getReferenceGenomeById(id, token);
+      String name = getFirstValue(formData.get("name"));
+      String url = getFirstValue(formData.get("url"));
+      referenceGenomeService.addReferenceGenomeGeneMapping(genome, name, url);
+      return okStatus();
+    } catch (URISyntaxException e) {
+      throw new QueryException("Problem wih given uri", e);
+    }
+  }
+
+  public Map<String, Object> removeGeneMapping(String genomeId, String mappingId, String token)
+      throws SecurityException, IOException, ObjectNotFoundException {
+    if (!getUserService().userHasPrivilege(token, PrivilegeType.MANAGE_GENOMES)) {
+      throw new SecurityException("Access denied");
+    }
+    ReferenceGenome genome = referenceGenomeService.getReferenceGenomeById(Integer.parseInt(genomeId), token);
+    if (genome == null) {
+      throw new ObjectNotFoundException("Genome doesn't exist");
+    }
+    int id = Integer.parseInt(mappingId);
+    ReferenceGenomeGeneMapping geneMapping = null;
+    for (ReferenceGenomeGeneMapping mapping : genome.getGeneMapping()) {
+      if (mapping.getId() == id) {
+        geneMapping = mapping;
+      }
+    }
+    if (geneMapping == null) {
+      throw new ObjectNotFoundException("Gene mapping doesn't exist");
+    }
+    referenceGenomeService.removeReferenceGenomeGeneMapping(geneMapping);
+    return okStatus();
+  }
+
 }
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/drugs/DrugRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/drugs/DrugRestImpl.java
index f34f2cbe61f28de4981c333b9405a4e0847fde11..785e3def809ca0460680c859f2f966e91fbdb0b9 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/drugs/DrugRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/drugs/DrugRestImpl.java
@@ -39,15 +39,12 @@ public class DrugRestImpl extends BaseRestImpl {
   @Autowired
   private IDrugService drugService;
 
-  @Autowired
-  private IModelService modelService;
-
   @Autowired
   private IUserService userService;
 
   public List<Map<String, Object>> getDrugsByQuery(String token, String projectId, String columns, String query)
       throws SecurityException, QueryException {
-    Model model = modelService.getLastModelByProjectId(projectId, token);
+    Model model = getModelService().getLastModelByProjectId(projectId, token);
     if (model == null) {
       throw new QueryException("Project with given id doesn't exist");
     }
@@ -87,23 +84,6 @@ public class DrugRestImpl extends BaseRestImpl {
     this.userService = userService;
   }
 
-  /**
-   * @return the modelService
-   * @see #modelService
-   */
-  public IModelService getModelService() {
-    return modelService;
-  }
-
-  /**
-   * @param modelService
-   *          the modelService to set
-   * @see #modelService
-   */
-  public void setModelService(IModelService modelService) {
-    this.modelService = modelService;
-  }
-
   private Map<String, Object> prepareDrug(Drug drug, Set<String> columnsSet, List<Model> models) {
     Map<String, Object> result = new TreeMap<>();
     for (String string : columnsSet) {
@@ -171,7 +151,7 @@ public class DrugRestImpl extends BaseRestImpl {
 
   public List<Map<String, Object>> getDrugsByTarget(String token, String projectId, String targetType, String targetId,
       String columns) throws SecurityException, QueryException {
-    Model model = modelService.getLastModelByProjectId(projectId, token);
+    Model model = getModelService().getLastModelByProjectId(projectId, token);
     if (model == null) {
       throw new QueryException("Project with given id doesn't exist");
     }
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementsRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementsRestImpl.java
index 5aac8ca42447821d037d06e2573fef3d6ed764c9..d2f3739d5417c2ec12897b5c1e5e299a34f6e148 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementsRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementsRestImpl.java
@@ -12,16 +12,27 @@ import org.springframework.transaction.annotation.Transactional;
 
 import lcsb.mapviewer.api.BaseRestImpl;
 import lcsb.mapviewer.api.QueryException;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.converter.model.celldesigner.structure.fields.ModificationType;
 import lcsb.mapviewer.model.map.BioEntity;
 import lcsb.mapviewer.model.map.compartment.Compartment;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.species.AntisenseRna;
 import lcsb.mapviewer.model.map.species.Element;
+import lcsb.mapviewer.model.map.species.Gene;
 import lcsb.mapviewer.model.map.species.Protein;
 import lcsb.mapviewer.model.map.species.Rna;
 import lcsb.mapviewer.model.map.species.Species;
-import lcsb.mapviewer.model.map.species.field.ElementModification;
+import lcsb.mapviewer.model.map.species.field.AbstractSiteModification;
+import lcsb.mapviewer.model.map.species.field.BindingRegion;
+import lcsb.mapviewer.model.map.species.field.CodingRegion;
+import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
+import lcsb.mapviewer.model.map.species.field.ProteinBindingDomain;
+import lcsb.mapviewer.model.map.species.field.RegulatoryRegion;
+import lcsb.mapviewer.model.map.species.field.Residue;
 import lcsb.mapviewer.model.map.species.field.Structure;
+import lcsb.mapviewer.model.map.species.field.TranscriptionSite;
 import lcsb.mapviewer.model.map.species.field.UniprotRecord;
 import lcsb.mapviewer.services.SecurityException;
 
@@ -213,12 +224,16 @@ public class ElementsRestImpl extends BaseRestImpl {
       structuralState = protein.getStructuralState();
     } else if (element instanceof Rna) {
       Rna rna = ((Rna) element);
-      modifications = getModifications(((Rna) element).getRegions());
+      modifications = getModifications(rna.getRegions());
       structuralState = rna.getState();
     } else if (element instanceof AntisenseRna) {
       AntisenseRna antisenseRna = ((AntisenseRna) element);
-      modifications = getModifications(((AntisenseRna) element).getRegions());
+      modifications = getModifications(antisenseRna.getRegions());
       structuralState = antisenseRna.getState();
+    } else if (element instanceof Gene) {
+      Gene gene = ((Gene) element);
+      modifications = getModifications(gene.getModificationResidues());
+      structuralState = gene.getState();
     }
     if (element instanceof Species) {
       structures = getStructures(((Species) element).getUniprots());
@@ -230,16 +245,42 @@ public class ElementsRestImpl extends BaseRestImpl {
     return result;
   }
 
-  private List<Map<String, Object>> getModifications(List<? extends ElementModification> elements) {
+  private List<Map<String, Object>> getModifications(List<? extends ModificationResidue> elements) {
     List<Map<String, Object>> result = new ArrayList<>();
-    for (ElementModification region : elements) {
-      if (region.getState() != null) {
-        Map<String, Object> row = new TreeMap<>();
-        row.put("name", region.getName());
-        String state = region.getState().name();
-        row.put("state", state);
-        result.add(row);
+    for (ModificationResidue region : elements) {
+      Map<String, Object> row = new TreeMap<>();
+      row.put("name", region.getName());
+      row.put("modificationId", region.getIdModificationResidue());
+      if (region instanceof AbstractSiteModification) {
+        AbstractSiteModification siteModification = ((AbstractSiteModification) region);
+        if (siteModification.getState() != null) {
+          row.put("state", siteModification.getState().name());
+        }
+      }
+      String type = null;
+      if (region instanceof Residue) {
+        type = ModificationType.RESIDUE.name();
+      } else if (region instanceof BindingRegion) {
+        type = ModificationType.BINDING_REGION.name();
+      } else if (region instanceof CodingRegion) {
+        type = ModificationType.CODING_REGION.name();
+      } else if (region instanceof ProteinBindingDomain) {
+        type = ModificationType.PROTEIN_BINDING_DOMAIN.name();
+      } else if (region instanceof RegulatoryRegion) {
+        type = ModificationType.REGULATORY_REGION.name();
+      } else if (region instanceof TranscriptionSite) {
+        if (((TranscriptionSite) region).getDirection().equals("LEFT")) {
+          type = ModificationType.TRANSCRIPTION_SITE_LEFT.name();
+        } else {
+          type = ModificationType.TRANSCRIPTION_SITE_RIGHT.name();
+        }
+      } else if (region instanceof ModificationSite) {
+        type = ModificationType.MODIFICATION_SITE.name();
+      } else {
+        throw new InvalidArgumentException("Unknown class: " + region.getClass());
       }
+      row.put("type", type);
+      result.add(row);
     }
     return result;
   }
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java
index de838df959d2569ba49fe26d57fc0f12c666c7fd..4753bfa1e50f66992d8eec1b52614698b46c57b4 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/users/UserRestImpl.java
@@ -1,609 +1,628 @@
-package lcsb.mapviewer.api.users;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-import org.apache.log4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.MultiValueMap;
-
-import lcsb.mapviewer.api.BaseRestImpl;
-import lcsb.mapviewer.api.ObjectNotFoundException;
-import lcsb.mapviewer.api.QueryException;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.map.MiriamType;
-import lcsb.mapviewer.model.user.BasicPrivilege;
-import lcsb.mapviewer.model.user.ConfigurationOption;
-import lcsb.mapviewer.model.user.ObjectPrivilege;
-import lcsb.mapviewer.model.user.PrivilegeType;
-import lcsb.mapviewer.model.user.User;
-import lcsb.mapviewer.model.user.UserAnnotationSchema;
-import lcsb.mapviewer.model.user.UserAnnotatorsParam;
-import lcsb.mapviewer.model.user.UserClassAnnotators;
-import lcsb.mapviewer.model.user.UserClassRequiredAnnotations;
-import lcsb.mapviewer.model.user.UserClassValidAnnotations;
-import lcsb.mapviewer.model.user.UserGuiPreference;
-import lcsb.mapviewer.services.SecurityException;
-import lcsb.mapviewer.services.interfaces.IConfigurationService;
-import lcsb.mapviewer.services.interfaces.ILayoutService;
-
-@Transactional(value = "txManager")
-public class UserRestImpl extends BaseRestImpl {
-
-  /**
-   * Default class logger.
-   */
-  @SuppressWarnings("unused")
-  private Logger logger = Logger.getLogger(UserRestImpl.class);
-
-  @Autowired
-  private ILayoutService layoutService;
-
-  @Autowired
-  private IConfigurationService configurationService;
-
-  public Map<String, Object> getUser(String token, String login, String columns)
-      throws SecurityException, ObjectNotFoundException {
-    User ownUserData = getUserService().getUserByToken(token);
-
-    Set<String> columnSet = createUserColumnSet(columns);
-
-    boolean isAdmin = getUserService().userHasPrivilege(ownUserData, PrivilegeType.USER_MANAGEMENT);
-
-    if (ownUserData.getLogin().equals(login) || isAdmin) {
-      User user = getUserService().getUserByLogin(login);
-      if (user == null) {
-        throw new ObjectNotFoundException("User doesn't exist");
-      }
-      return prepareUse(user, columnSet, isAdmin);
-    } else {
-      throw new SecurityException("You cannot access data of the user with given id");
-    }
-  }
-
-  private Set<String> createUserColumnSet(String columns) {
-    Set<String> columnsSet = new HashSet<>();
-    if (columns.equals("")) {
-      columnsSet.add("id");
-      columnsSet.add("login");
-      columnsSet.add("name");
-      columnsSet.add("surname");
-      columnsSet.add("email");
-      columnsSet.add("minColor");
-      columnsSet.add("maxColor");
-      columnsSet.add("neutralColor");
-      columnsSet.add("simpleColor");
-      columnsSet.add("removed");
-      columnsSet.add("privileges");
-      columnsSet.add("termsOfUseConsent");
-    } else {
-      for (String str : columns.split(",")) {
-        columnsSet.add(str);
-      }
-    }
-    return columnsSet;
-  }
-
-  private Map<String, Object> prepareUse(User user, Set<String> columnsSet, boolean admin) {
-    Map<String, Object> result = new TreeMap<>();
-    for (String string : columnsSet) {
-      String column = string.toLowerCase();
-      Object value = null;
-      if (column.equals("id") || column.equals("idobject")) {
-        value = user.getId();
-      } else if (column.equals("name")) {
-        value = user.getName();
-      } else if (column.equals("surname")) {
-        value = user.getSurname();
-      } else if (column.equals("login")) {
-        value = user.getLogin();
-      } else if (column.equals("email")) {
-        value = user.getEmail();
-      } else if (column.equals("mincolor")) {
-        value = user.getMinColor();
-      } else if (column.equals("maxcolor")) {
-        value = user.getMaxColor();
-      } else if (column.equals("neutralcolor")) {
-        value = user.getNeutralColor();
-      } else if (column.equals("simplecolor")) {
-        value = user.getSimpleColor();
-      } else if (column.equals("removed")) {
-        value = user.isRemoved();
-      } else if (column.equals("termsofuseconsent")) {
-        value = user.isTermsOfUseConsent();
-      } else if (column.equals("privileges") && admin) {
-        value = preparePrivileges(user);
-      } else if (column.equals("preferences")) {
-        value = preparePreferences(user);
-      } else {
-        value = "Unknown column";
-      }
-      result.put(string, value);
-    }
-    return result;
-  }
-
-  private Map<String, Object> preparePreferences(User user) {
-    Map<String, Object> result = new TreeMap<>();
-    UserAnnotationSchema schema = getProjectService().prepareUserAnnotationSchema(user);
-    result.put("project-upload", prepareProjectUploadPreferences(schema));
-    result.put("element-annotators", prepareElementAnnotators(schema.getClassAnnotators()));
-    result.put("element-required-annotations", prepareRequiredAnnotations(schema.getClassRequiredAnnotators()));
-    result.put("element-valid-annotations", prepareValidAnnotations(schema.getClassValidAnnotators()));
-    result.put("annotators-parameters", prepareAnnotatorsParams(schema.getAnnotatorsParams()));
-    result.put("gui-preferences", prepareGuiPreferences(schema.getGuiPreferences()));
-    return result;
-  }
-
-  Map<String, Object> prepareGuiPreferences(Set<UserGuiPreference> guiPreferences) {
-    Map<String, Object> result = new TreeMap<>();
-    for (UserGuiPreference userGuiPreference : guiPreferences) {
-      result.put(userGuiPreference.getKey(), userGuiPreference.getValue());
-    }
-    return result;
-  }
-
-  /**
-   * Prepares annotator parameters in the form of a map having annotators class
-   * names as keys and map of name:value pairs of given annotator as values.
-   *
-   * @param annotatorsParams
-   * @return
-   */
-  private Map<String, Object> prepareAnnotatorsParams(List<UserAnnotatorsParam> annotatorsParams) {
-    Map<String, Object> result = new TreeMap<>();
-    for (UserAnnotatorsParam param : annotatorsParams) {
-      String className = param.getAnnotatorClassName().getName();
-      Map<String, String> annotatorParams = (Map<String, String>) result.get(className);
-      if (annotatorParams == null) {
-        annotatorParams = new TreeMap<>();
-        result.put(className, annotatorParams);
-      }
-      annotatorParams.put(param.getParamName(), param.getParamValue());
-    }
-    return result;
-  }
-
-  private Map<String, Object> prepareValidAnnotations(List<UserClassValidAnnotations> classValidAnnotators) {
-    Map<String, Object> result = new TreeMap<>();
-    for (UserClassValidAnnotations userClassAnnotators : classValidAnnotators) {
-      result.put(userClassAnnotators.getClassName(), new ArrayList<>(userClassAnnotators.getValidMiriamTypes()));
-    }
-    return result;
-  }
-
-  private void updateValidAnnotations(UserAnnotationSchema schema, Map<String, Object> data) {
-    for (String key : data.keySet()) {
-      UserClassValidAnnotations annotator = null;
-      for (UserClassValidAnnotations userClassAnnotators : schema.getClassValidAnnotators()) {
-        if (userClassAnnotators.getClassName().equals(key)) {
-          annotator = userClassAnnotators;
-        }
-      }
-      if (annotator == null) {
-        annotator = new UserClassValidAnnotations();
-        annotator.setClassName(key);
-        schema.addClassValidAnnotations(annotator);
-      }
-      annotator.getValidMiriamTypes().clear();
-      for (Object row : (List<?>) data.get(key)) {
-        annotator.getValidMiriamTypes().add(MiriamType.valueOf((String) row));
-      }
-    }
-  }
-
-  private void updateAnnotatorsParams(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
-    for (String annotatorClassname : data.keySet()) {
-      Map<String, Object> nameValueS = (Map<String, Object>) data.get(annotatorClassname);
-      for (String name : nameValueS.keySet()) {
-        String value = (String) nameValueS.get(name);
-        try {
-          UserAnnotatorsParam param = new UserAnnotatorsParam(Class.forName(annotatorClassname), name, value);
-          schema.addAnnotatorParam(param);
-        } catch (ClassNotFoundException e) {
-          throw new QueryException("Unknown annotator class name: " + annotatorClassname);
-        }
-      }
-    }
-  }
-
-  private void updateGuiPreferences(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
-    for (String key : data.keySet()) {
-      Object object = data.get(key);
-      String value = "";
-      if (object instanceof Integer) {
-        value = object + "";
-      } else if (object instanceof String) {
-        value = (String) data.get(key);
-      } else {
-        throw new InvalidArgumentException("Invalid value class: " + value);
-      }
-      schema.setGuiPreference(key, value);
-    }
-  }
-
-  private Map<String, Object> prepareRequiredAnnotations(List<UserClassRequiredAnnotations> classRequiredAnnotators) {
-    Map<String, Object> result = new TreeMap<>();
-    for (UserClassRequiredAnnotations requiredAnnotations : classRequiredAnnotators) {
-      Map<String, Object> row = new TreeMap<>();
-      row.put("require-at-least-one", requiredAnnotations.getRequireAtLeastOneAnnotation());
-      List<String> miriamTypes = new ArrayList<>();
-
-      for (MiriamType mt : requiredAnnotations.getRequiredMiriamTypes()) {
-        miriamTypes.add(mt.name());
-      }
-      row.put("annotation-list", miriamTypes);
-      result.put(requiredAnnotations.getClassName(), row);
-    }
-    return result;
-  }
-
-  private void updateRequiredAnnotations(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
-    for (String key : data.keySet()) {
-      UserClassRequiredAnnotations annotator = null;
-      for (UserClassRequiredAnnotations userClassAnnotators : schema.getClassRequiredAnnotators()) {
-        if (userClassAnnotators.getClassName().equals(key)) {
-          annotator = userClassAnnotators;
-        }
-      }
-      if (annotator == null) {
-        annotator = new UserClassRequiredAnnotations();
-        annotator.setClassName(key);
-        schema.addClassRequiredAnnotations(annotator);
-      }
-      updateAnnotator(annotator, (Map<String, Object>) data.get(key));
-    }
-  }
-
-  private void updateAnnotator(UserClassRequiredAnnotations annotator, Map<String, Object> data) throws QueryException {
-    for (String key : data.keySet()) {
-      if (key.equals("require-at-least-one")) {
-        annotator.setRequireAtLeastOneAnnotation((Boolean) data.get("require-at-least-one"));
-      } else if (key.equals("annotation-list")) {
-        annotator.getRequiredMiriamTypes().clear();
-        for (Object row : (List<?>) data.get(key)) {
-          annotator.getRequiredMiriamTypes().add(MiriamType.valueOf((String) row));
-        }
-      } else {
-        throw new QueryException("Unknown field: " + key);
-      }
-    }
-
-  }
-
-  private Map<String, Object> prepareElementAnnotators(List<UserClassAnnotators> classAnnotators) {
-    Map<String, Object> result = new TreeMap<>();
-    for (UserClassAnnotators userClassAnnotators : classAnnotators) {
-      result.put(userClassAnnotators.getClassName(), new ArrayList<>(userClassAnnotators.getAnnotators()));
-    }
-    return result;
-  }
-
-  private void updateElementAnnotators(UserAnnotationSchema schema, Map<String, Object> data) {
-    for (String key : data.keySet()) {
-      UserClassAnnotators annotator = null;
-      for (UserClassAnnotators userClassAnnotators : schema.getClassAnnotators()) {
-        if (userClassAnnotators.getClassName().equals(key)) {
-          annotator = userClassAnnotators;
-        }
-      }
-      if (annotator == null) {
-        annotator = new UserClassAnnotators();
-        annotator.setClassName(key);
-        schema.addClassAnnotator(annotator);
-      }
-      annotator.getAnnotators().clear();
-      annotator.getAnnotators().addAll((List<String>) data.get(key));
-    }
-  }
-
-  private Map<String, Object> prepareProjectUploadPreferences(UserAnnotationSchema schema) {
-    Map<String, Object> result = new TreeMap<>();
-    result.put("validate-miriam", schema.getValidateMiriamTypes());
-    result.put("annotate-model", schema.getAnnotateModel());
-    result.put("cache-data", schema.getCacheData());
-    result.put("auto-resize", schema.getAutoResizeMap());
-    result.put("semantic-zooming", schema.getSemanticZooming());
-    result.put("sbgn", schema.getSbgnFormat());
-    return result;
-  }
-
-  private List<Map<String, Object>> preparePrivileges(User user) {
-    List<Map<String, Object>> result = new ArrayList<>();
-    Set<PrivilegeType> definedDefaultProjectPrivilegeTypes = new HashSet<>();
-    List<BasicPrivilege> privileges = new ArrayList<>();
-    privileges.addAll(user.getPrivileges());
-    privileges.sort(BasicPrivilege.ID_COMPARATOR);
-    for (BasicPrivilege privilege : privileges) {
-      if (privilege instanceof ObjectPrivilege) {
-        if (Project.class.equals(privilege.getType().getPrivilegeObjectType())
-            && ((ObjectPrivilege) privilege).getIdObject() == null) {
-          definedDefaultProjectPrivilegeTypes.add(privilege.getType());
-        }
-        result.add(prepareObjectPrivilege((ObjectPrivilege) privilege));
-      } else {
-        result.add(prepareBasicPrivilege(privilege));
-      }
-    }
-    for (PrivilegeType privilegeType : PrivilegeType.values()) {
-      if (Project.class.equals(privilegeType.getPrivilegeObjectType())
-          && !definedDefaultProjectPrivilegeTypes.contains(privilegeType)) {
-        result.add(prepareDefaultObjectPrivilege(privilegeType));
-      }
-    }
-    Map<String, Object> customLayouts = new TreeMap<>();
-    customLayouts.put("type", "CUSTOM_LAYOUTS_AVAILABLE");
-    customLayouts.put("value", layoutService.getAvailableCustomLayoutsNumber(user));
-    result.add(customLayouts);
-    return result;
-  }
-
-  private Map<String, Object> prepareDefaultObjectPrivilege(PrivilegeType privilegeType) {
-    Map<String, Object> result = new TreeMap<>();
-    result.put("type", privilegeType);
-    ConfigurationOption value = configurationService.getValue(privilegeType);
-    if (value == null) {
-      result.put("value", 0);
-    } else if (value.getValue().equalsIgnoreCase("true")) {
-      result.put("value", 1);
-    } else if (value.getValue().equalsIgnoreCase("false")) {
-      result.put("value", 0);
-    } else {
-      result.put("value", value.getValue());
-    }
-    result.put("objectId", null);
-    return result;
-  }
-
-  private Map<String, Object> prepareObjectPrivilege(ObjectPrivilege privilege) {
-    Map<String, Object> result = new TreeMap<>();
-    result.put("type", privilege.getType());
-    result.put("value", privilege.getLevel());
-    result.put("objectId", privilege.getIdObject());
-    return result;
-  }
-
-  private Map<String, Object> prepareBasicPrivilege(BasicPrivilege privilege) {
-    Map<String, Object> result = new TreeMap<>();
-    if (privilege.getClass().equals(BasicPrivilege.class)) {
-      result.put("type", privilege.getType());
-      result.put("value", privilege.getLevel());
-      return result;
-    } else {
-      throw new InvalidArgumentException("Don't know how to handle class: " + privilege.getClass());
-    }
-  }
-
-  /**
-   * @return the layoutService
-   * @see #layoutService
-   */
-  public ILayoutService getLayoutService() {
-    return layoutService;
-  }
-
-  /**
-   * @param layoutService
-   *          the layoutService to set
-   * @see #layoutService
-   */
-  public void setLayoutService(ILayoutService layoutService) {
-    this.layoutService = layoutService;
-  }
-
-  public List<Map<String, Object>> getUsers(String token, String columns) throws SecurityException {
-    User ownUserData = getUserService().getUserByToken(token);
-    boolean isAdmin = getUserService().userHasPrivilege(ownUserData, PrivilegeType.USER_MANAGEMENT);
-
-    Set<String> columnSet = createUserColumnSet(columns);
-
-    List<Map<String, Object>> result = new ArrayList<>();
-    List<User> users = getUserService().getUsers(token);
-    users.sort(User.LOGIN_COMPARATOR);
-    for (User user : users) {
-      result.add(prepareUse(user, columnSet, isAdmin));
-    }
-    return result;
-  }
-
-  public Map<String, Object> updatePrivileges(String token, String login, Map<String, Object> privilegesData)
-      throws SecurityException, QueryException {
-    if (privilegesData == null) {
-      throw new QueryException("Privileges not defined");
-    }
-    try {
-      User modifiedUser = getUserService().getUserByLogin(login);
-
-      for (String key : privilegesData.keySet()) {
-        Object value = privilegesData.get(key);
-
-        PrivilegeType type = PrivilegeType.valueOf(key);
-
-        if (type.getPrivilegeClassType().equals(BasicPrivilege.class)) {
-          getUserService().setUserPrivilege(modifiedUser, type, value, token);
-        } else if (type.getPrivilegeClassType().equals(ObjectPrivilege.class)) {
-          if (value instanceof Map) {
-            Map<?, ?> objects = (Map<?, ?>) value;
-            for (Object objectId : objects.keySet()) {
-              Integer objectIdAsInteger = null;
-              if (!objectId.equals("null")) {
-                objectIdAsInteger = Integer.valueOf((String) objectId);
-              }
-              getUserService().setUserPrivilege(modifiedUser, type, objects.get(objectId), objectIdAsInteger, token);
-            }
-          } else {
-            throw new QueryException("Invalid value for privilege: " + key);
-          }
-        } else {
-          throw new QueryException("Unknown privilege type: " + key);
-        }
-
-      }
-      return getUser(token, login, "");
-    } catch (IllegalArgumentException e) {
-      throw new QueryException("Invalid input", e);
-    }
-  }
-
-  public Map<String, Object> updatePreferences(String token, String login, Map<String, Object> preferencesData)
-      throws SecurityException, QueryException {
-    if (preferencesData == null) {
-      throw new QueryException("Preferences not defined");
-    }
-    try {
-      User modifiedUser = getUserService().getUserByLogin(login);
-      if (modifiedUser == null) {
-        throw new ObjectNotFoundException("User doesn't exist");
-      }
-
-      UserAnnotationSchema schema = getProjectService().prepareUserAnnotationSchema(modifiedUser);
-
-      for (String key : preferencesData.keySet()) {
-        Map<String, Object> value = (Map<String, Object>) preferencesData.get(key);
-
-        if (key.equals("project-upload")) {
-          updateUploadPreferences(schema, value);
-        } else if (key.equals("element-annotators")) {
-          updateElementAnnotators(schema, value);
-        } else if (key.equals("element-required-annotations")) {
-          updateRequiredAnnotations(schema, value);
-        } else if (key.equals("element-valid-annotations")) {
-          updateValidAnnotations(schema, value);
-        } else if (key.equals("annotators-parameters")) {
-          updateAnnotatorsParams(schema, value);
-        } else if (key.equals("gui-preferences")) {
-          updateGuiPreferences(schema, value);
-        } else {
-          throw new QueryException("Unknown preferences field: " + key);
-        }
-      }
-      modifiedUser.setAnnotationSchema(schema);
-      getUserService().updateUser(modifiedUser, token);
-      return getUser(token, login, "preferences");
-    } catch (IllegalArgumentException e) {
-      throw new QueryException("Invalid input", e);
-    }
-  }
-
-  private void updateUploadPreferences(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
-    for (String key : data.keySet()) {
-      Boolean value = (Boolean) data.get(key);
-      if (value != null) {
-        if (key.equals("validate-miriam")) {
-          schema.setValidateMiriamTypes(value);
-        } else if (key.equals("annotate-model")) {
-          schema.setAnnotateModel(value);
-        } else if (key.equals("cache-data")) {
-          schema.setCacheData(value);
-        } else if (key.equals("auto-resize")) {
-          schema.setAutoResizeMap(value);
-        } else if (key.equals("semantic-zooming")) {
-          schema.setSemanticZooming(value);
-        } else if (key.equals("sbgn")) {
-          schema.setSbgnFormat(value);
-        } else {
-          throw new QueryException("Unknown upload preference field: " + key);
-        }
-      }
-    }
-
-  }
-
-  public Map<String, Object> updateUser(String token, String login, Map<String, Object> userData)
-      throws QueryException, SecurityException {
-    if (userData == null) {
-      throw new QueryException("user field cannot be undefined");
-    }
-    User user = getUserService().getUserByLogin(login);
-    if (user == null) {
-      throw new ObjectNotFoundException("user doesn't exist");
-    }
-    boolean isAdmin = getUserService().userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT);
-    if (!isAdmin && !login.equalsIgnoreCase(getUserService().getUserByToken(token).getLogin())) {
-      throw new SecurityException("Access denied");
-    }
-    for (String key : userData.keySet()) {
-      Object value = userData.get(key);
-      String stringValue = null;
-      if (value instanceof String) {
-        stringValue = (String) value;
-      }
-      if (key.equalsIgnoreCase("name")) {
-        user.setName(stringValue);
-      } else if (key.equalsIgnoreCase("surname")) {
-        user.setSurname(stringValue);
-      } else if (key.equalsIgnoreCase("email")) {
-        user.setEmail(stringValue);
-      } else if (key.equalsIgnoreCase("termsofuseconsent")) {
-        user.setTermsOfUseConsent((Boolean) value);
-      } else if (key.equalsIgnoreCase("password")) {
-        if (stringValue != null && !stringValue.trim().isEmpty()) {
-          user.setCryptedPassword(getUserService().encodePassword(stringValue));
-        }
-      } else if (key.equalsIgnoreCase("login")) {
-        if (!user.getLogin().equals((String) value)) {
-          throw new QueryException("login cannot be modified");
-        }
-      } else {
-        throw new QueryException("Unknown parameter: " + key);
-      }
-    }
-    getUserService().updateUser(user);
-    return getUser(token, login, "");
-  }
-
-  public Map<String, Object> addProject(String token, String login, MultiValueMap<String, Object> userData)
-      throws QueryException, SecurityException {
-    if (!getUserService().userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
-      throw new SecurityException("Access denied");
-    }
-
-    User user = getUserService().getUserByLogin(login);
-    if (user != null) {
-      throw new QueryException("user exists");
-    }
-    user = new User();
-    user.setLogin(login);
-    for (String key : userData.keySet()) {
-      String stringValue = getFirstValue((List<Object>) userData.get(key));
-      if (key.equalsIgnoreCase("name")) {
-        user.setName(stringValue);
-      } else if (key.equalsIgnoreCase("surname")) {
-        user.setSurname(stringValue);
-      } else if (key.equalsIgnoreCase("email")) {
-        user.setEmail(stringValue);
-      } else if (key.equalsIgnoreCase("password")) {
-        if (stringValue != null && !stringValue.trim().isEmpty()) {
-          user.setCryptedPassword(getUserService().encodePassword(stringValue));
-        }
-      } else if (key.equalsIgnoreCase("login")) {
-        if (!user.getLogin().equals(stringValue)) {
-          throw new QueryException("login must match url");
-        }
-      } else {
-        throw new QueryException("Unknown parameter: " + key);
-      }
-    }
-    getUserService().addUser(user);
-    return getUser(token, login, "");
-  }
-
-  public Map<String, Object> removeUser(String token, String login) throws SecurityException, QueryException {
-    User user = getUserService().getUserByLogin(login);
-    if (!getUserService().userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
-      throw new SecurityException("Access denied");
-    }
-    if (user == null) {
-      throw new QueryException("user doesn't exists");
-    }
-    getUserService().deleteUser(user);
-    return okStatus();
-  }
-
-}
+package lcsb.mapviewer.api.users;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.MultiValueMap;
+
+import lcsb.mapviewer.api.BaseRestImpl;
+import lcsb.mapviewer.api.ObjectNotFoundException;
+import lcsb.mapviewer.api.QueryException;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.map.MiriamType;
+import lcsb.mapviewer.model.user.BasicPrivilege;
+import lcsb.mapviewer.model.user.ConfigurationOption;
+import lcsb.mapviewer.model.user.ObjectPrivilege;
+import lcsb.mapviewer.model.user.PrivilegeType;
+import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.model.user.UserAnnotationSchema;
+import lcsb.mapviewer.model.user.UserAnnotatorsParam;
+import lcsb.mapviewer.model.user.UserClassAnnotators;
+import lcsb.mapviewer.model.user.UserClassRequiredAnnotations;
+import lcsb.mapviewer.model.user.UserClassValidAnnotations;
+import lcsb.mapviewer.model.user.UserGuiPreference;
+import lcsb.mapviewer.services.SecurityException;
+import lcsb.mapviewer.services.interfaces.IConfigurationService;
+import lcsb.mapviewer.services.interfaces.ILayoutService;
+
+@Transactional(value = "txManager")
+public class UserRestImpl extends BaseRestImpl {
+
+  /**
+   * Default class logger.
+   */
+  @SuppressWarnings("unused")
+  private Logger logger = Logger.getLogger(UserRestImpl.class);
+
+  @Autowired
+  private ILayoutService layoutService;
+
+  @Autowired
+  private IConfigurationService configurationService;
+
+  public Map<String, Object> getUser(String token, String login, String columns)
+      throws SecurityException, ObjectNotFoundException {
+    User ownUserData = getUserService().getUserByToken(token);
+
+    Set<String> columnSet = createUserColumnSet(columns);
+
+    boolean isAdmin = getUserService().userHasPrivilege(ownUserData, PrivilegeType.USER_MANAGEMENT);
+
+    if (ownUserData.getLogin().equals(login) || isAdmin) {
+      User user = getUserService().getUserByLogin(login);
+      if (user == null) {
+        throw new ObjectNotFoundException("User doesn't exist");
+      }
+      Boolean ldapAvailable = false;
+      if (columnSet.contains("ldapAccountAvailable")) {
+        List<User> userList = new ArrayList<>();
+        userList.add(ownUserData);
+        ldapAvailable = getUserService().ldapAccountExistsForLogin(userList).get(login);
+      }
+      return prepareUse(user, columnSet, isAdmin, ldapAvailable);
+    } else {
+      throw new SecurityException("You cannot access data of the user with given id");
+    }
+  }
+
+  private Set<String> createUserColumnSet(String columns) {
+    Set<String> columnsSet = new HashSet<>();
+    if (columns.equals("")) {
+      columnsSet.add("id");
+      columnsSet.add("login");
+      columnsSet.add("name");
+      columnsSet.add("surname");
+      columnsSet.add("email");
+      columnsSet.add("minColor");
+      columnsSet.add("maxColor");
+      columnsSet.add("neutralColor");
+      columnsSet.add("simpleColor");
+      columnsSet.add("removed");
+      columnsSet.add("privileges");
+      columnsSet.add("termsOfUseConsent");
+      columnsSet.add("connectedToLdap");
+      columnsSet.add("ldapAccountAvailable");
+    } else {
+      for (String str : columns.split(",")) {
+        columnsSet.add(str);
+      }
+    }
+    return columnsSet;
+  }
+
+  private Map<String, Object> prepareUse(User user, Set<String> columnsSet, boolean admin, Boolean ldapAvailable) {
+    Map<String, Object> result = new TreeMap<>();
+    for (String string : columnsSet) {
+      String column = string.toLowerCase();
+      Object value = null;
+      if (column.equals("id") || column.equals("idobject")) {
+        value = user.getId();
+      } else if (column.equals("name")) {
+        value = user.getName();
+      } else if (column.equals("surname")) {
+        value = user.getSurname();
+      } else if (column.equals("login")) {
+        value = user.getLogin();
+      } else if (column.equals("email")) {
+        value = user.getEmail();
+      } else if (column.equals("mincolor")) {
+        value = user.getMinColor();
+      } else if (column.equals("maxcolor")) {
+        value = user.getMaxColor();
+      } else if (column.equals("neutralcolor")) {
+        value = user.getNeutralColor();
+      } else if (column.equals("simplecolor")) {
+        value = user.getSimpleColor();
+      } else if (column.equals("removed")) {
+        value = user.isRemoved();
+      } else if (column.equals("termsofuseconsent")) {
+        value = user.isTermsOfUseConsent();
+      } else if (column.equals("connectedtoldap") && admin) {
+        value = user.isConnectedToLdap();
+      } else if (column.equals("ldapaccountavailable") && admin) {
+        if (ldapAvailable == null) {
+          ldapAvailable = false;
+        }
+        value = ldapAvailable;
+      } else if (column.equals("privileges") && admin) {
+        value = preparePrivileges(user);
+      } else if (column.equals("preferences")) {
+        value = preparePreferences(user);
+      } else {
+        value = "Unknown column";
+      }
+      result.put(string, value);
+    }
+    return result;
+  }
+
+  private Map<String, Object> preparePreferences(User user) {
+    Map<String, Object> result = new TreeMap<>();
+    UserAnnotationSchema schema = getProjectService().prepareUserAnnotationSchema(user);
+    result.put("project-upload", prepareProjectUploadPreferences(schema));
+    result.put("element-annotators", prepareElementAnnotators(schema.getClassAnnotators()));
+    result.put("element-required-annotations", prepareRequiredAnnotations(schema.getClassRequiredAnnotators()));
+    result.put("element-valid-annotations", prepareValidAnnotations(schema.getClassValidAnnotators()));
+    result.put("annotators-parameters", prepareAnnotatorsParams(schema.getAnnotatorsParams()));
+    result.put("gui-preferences", prepareGuiPreferences(schema.getGuiPreferences()));
+    return result;
+  }
+
+  Map<String, Object> prepareGuiPreferences(Set<UserGuiPreference> guiPreferences) {
+    Map<String, Object> result = new TreeMap<>();
+    for (UserGuiPreference userGuiPreference : guiPreferences) {
+      result.put(userGuiPreference.getKey(), userGuiPreference.getValue());
+    }
+    return result;
+  }
+
+  /**
+   * Prepares annotator parameters in the form of a map having annotators class
+   * names as keys and map of name:value pairs of given annotator as values.
+   *
+   * @param annotatorsParams
+   * @return
+   */
+  private Map<String, Object> prepareAnnotatorsParams(List<UserAnnotatorsParam> annotatorsParams) {
+    Map<String, Object> result = new TreeMap<>();
+    for (UserAnnotatorsParam param : annotatorsParams) {
+      String className = param.getAnnotatorClassName().getName();
+      Map<String, String> annotatorParams = (Map<String, String>) result.get(className);
+      if (annotatorParams == null) {
+        annotatorParams = new TreeMap<>();
+        result.put(className, annotatorParams);
+      }
+      annotatorParams.put(param.getParamName(), param.getParamValue());
+    }
+    return result;
+  }
+
+  private Map<String, Object> prepareValidAnnotations(List<UserClassValidAnnotations> classValidAnnotators) {
+    Map<String, Object> result = new TreeMap<>();
+    for (UserClassValidAnnotations userClassAnnotators : classValidAnnotators) {
+      result.put(userClassAnnotators.getClassName(), new ArrayList<>(userClassAnnotators.getValidMiriamTypes()));
+    }
+    return result;
+  }
+
+  private void updateValidAnnotations(UserAnnotationSchema schema, Map<String, Object> data) {
+    for (String key : data.keySet()) {
+      UserClassValidAnnotations annotator = null;
+      for (UserClassValidAnnotations userClassAnnotators : schema.getClassValidAnnotators()) {
+        if (userClassAnnotators.getClassName().equals(key)) {
+          annotator = userClassAnnotators;
+        }
+      }
+      if (annotator == null) {
+        annotator = new UserClassValidAnnotations();
+        annotator.setClassName(key);
+        schema.addClassValidAnnotations(annotator);
+      }
+      annotator.getValidMiriamTypes().clear();
+      for (Object row : (List<?>) data.get(key)) {
+        annotator.getValidMiriamTypes().add(MiriamType.valueOf((String) row));
+      }
+    }
+  }
+
+  private void updateAnnotatorsParams(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
+    for (String annotatorClassname : data.keySet()) {
+      Map<String, Object> nameValueS = (Map<String, Object>) data.get(annotatorClassname);
+      for (String name : nameValueS.keySet()) {
+        String value = (String) nameValueS.get(name);
+        try {
+          UserAnnotatorsParam param = new UserAnnotatorsParam(Class.forName(annotatorClassname), name, value);
+          schema.addAnnotatorParam(param);
+        } catch (ClassNotFoundException e) {
+          throw new QueryException("Unknown annotator class name: " + annotatorClassname);
+        }
+      }
+    }
+  }
+
+  private void updateGuiPreferences(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
+    for (String key : data.keySet()) {
+      Object object = data.get(key);
+      String value = "";
+      if (object instanceof Integer) {
+        value = object + "";
+      } else if (object instanceof String) {
+        value = (String) data.get(key);
+      } else {
+        throw new InvalidArgumentException("Invalid value class: " + value);
+      }
+      schema.setGuiPreference(key, value);
+    }
+  }
+
+  private Map<String, Object> prepareRequiredAnnotations(List<UserClassRequiredAnnotations> classRequiredAnnotators) {
+    Map<String, Object> result = new TreeMap<>();
+    for (UserClassRequiredAnnotations requiredAnnotations : classRequiredAnnotators) {
+      Map<String, Object> row = new TreeMap<>();
+      row.put("require-at-least-one", requiredAnnotations.getRequireAtLeastOneAnnotation());
+      List<String> miriamTypes = new ArrayList<>();
+
+      for (MiriamType mt : requiredAnnotations.getRequiredMiriamTypes()) {
+        miriamTypes.add(mt.name());
+      }
+      row.put("annotation-list", miriamTypes);
+      result.put(requiredAnnotations.getClassName(), row);
+    }
+    return result;
+  }
+
+  private void updateRequiredAnnotations(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
+    for (String key : data.keySet()) {
+      UserClassRequiredAnnotations annotator = null;
+      for (UserClassRequiredAnnotations userClassAnnotators : schema.getClassRequiredAnnotators()) {
+        if (userClassAnnotators.getClassName().equals(key)) {
+          annotator = userClassAnnotators;
+        }
+      }
+      if (annotator == null) {
+        annotator = new UserClassRequiredAnnotations();
+        annotator.setClassName(key);
+        schema.addClassRequiredAnnotations(annotator);
+      }
+      updateAnnotator(annotator, (Map<String, Object>) data.get(key));
+    }
+  }
+
+  private void updateAnnotator(UserClassRequiredAnnotations annotator, Map<String, Object> data) throws QueryException {
+    for (String key : data.keySet()) {
+      if (key.equals("require-at-least-one")) {
+        annotator.setRequireAtLeastOneAnnotation((Boolean) data.get("require-at-least-one"));
+      } else if (key.equals("annotation-list")) {
+        annotator.getRequiredMiriamTypes().clear();
+        for (Object row : (List<?>) data.get(key)) {
+          annotator.getRequiredMiriamTypes().add(MiriamType.valueOf((String) row));
+        }
+      } else {
+        throw new QueryException("Unknown field: " + key);
+      }
+    }
+
+  }
+
+  private Map<String, Object> prepareElementAnnotators(List<UserClassAnnotators> classAnnotators) {
+    Map<String, Object> result = new TreeMap<>();
+    for (UserClassAnnotators userClassAnnotators : classAnnotators) {
+      result.put(userClassAnnotators.getClassName(), new ArrayList<>(userClassAnnotators.getAnnotators()));
+    }
+    return result;
+  }
+
+  private void updateElementAnnotators(UserAnnotationSchema schema, Map<String, Object> data) {
+    for (String key : data.keySet()) {
+      UserClassAnnotators annotator = null;
+      for (UserClassAnnotators userClassAnnotators : schema.getClassAnnotators()) {
+        if (userClassAnnotators.getClassName().equals(key)) {
+          annotator = userClassAnnotators;
+        }
+      }
+      if (annotator == null) {
+        annotator = new UserClassAnnotators();
+        annotator.setClassName(key);
+        schema.addClassAnnotator(annotator);
+      }
+      annotator.getAnnotators().clear();
+      annotator.getAnnotators().addAll((List<String>) data.get(key));
+    }
+  }
+
+  private Map<String, Object> prepareProjectUploadPreferences(UserAnnotationSchema schema) {
+    Map<String, Object> result = new TreeMap<>();
+    result.put("validate-miriam", schema.getValidateMiriamTypes());
+    result.put("annotate-model", schema.getAnnotateModel());
+    result.put("cache-data", schema.getCacheData());
+    result.put("auto-resize", schema.getAutoResizeMap());
+    result.put("semantic-zooming", schema.getSemanticZooming());
+    result.put("sbgn", schema.getSbgnFormat());
+    return result;
+  }
+
+  private List<Map<String, Object>> preparePrivileges(User user) {
+    List<Map<String, Object>> result = new ArrayList<>();
+    Set<PrivilegeType> definedDefaultProjectPrivilegeTypes = new HashSet<>();
+    List<BasicPrivilege> privileges = new ArrayList<>();
+    privileges.addAll(user.getPrivileges());
+    privileges.sort(BasicPrivilege.ID_COMPARATOR);
+    for (BasicPrivilege privilege : privileges) {
+      if (privilege instanceof ObjectPrivilege) {
+        if (Project.class.equals(privilege.getType().getPrivilegeObjectType())
+            && ((ObjectPrivilege) privilege).getIdObject() == null) {
+          definedDefaultProjectPrivilegeTypes.add(privilege.getType());
+        }
+        result.add(prepareObjectPrivilege((ObjectPrivilege) privilege));
+      } else {
+        result.add(prepareBasicPrivilege(privilege));
+      }
+    }
+    for (PrivilegeType privilegeType : PrivilegeType.values()) {
+      if (Project.class.equals(privilegeType.getPrivilegeObjectType())
+          && !definedDefaultProjectPrivilegeTypes.contains(privilegeType)) {
+        result.add(prepareDefaultObjectPrivilege(privilegeType));
+      }
+    }
+    Map<String, Object> customLayouts = new TreeMap<>();
+    customLayouts.put("type", "CUSTOM_LAYOUTS_AVAILABLE");
+    customLayouts.put("value", layoutService.getAvailableCustomLayoutsNumber(user));
+    result.add(customLayouts);
+    return result;
+  }
+
+  private Map<String, Object> prepareDefaultObjectPrivilege(PrivilegeType privilegeType) {
+    Map<String, Object> result = new TreeMap<>();
+    result.put("type", privilegeType);
+    ConfigurationOption value = configurationService.getValue(privilegeType);
+    if (value == null) {
+      result.put("value", 0);
+    } else if (value.getValue().equalsIgnoreCase("true")) {
+      result.put("value", 1);
+    } else if (value.getValue().equalsIgnoreCase("false")) {
+      result.put("value", 0);
+    } else {
+      result.put("value", value.getValue());
+    }
+    result.put("objectId", null);
+    return result;
+  }
+
+  private Map<String, Object> prepareObjectPrivilege(ObjectPrivilege privilege) {
+    Map<String, Object> result = new TreeMap<>();
+    result.put("type", privilege.getType());
+    result.put("value", privilege.getLevel());
+    result.put("objectId", privilege.getIdObject());
+    return result;
+  }
+
+  private Map<String, Object> prepareBasicPrivilege(BasicPrivilege privilege) {
+    Map<String, Object> result = new TreeMap<>();
+    if (privilege.getClass().equals(BasicPrivilege.class)) {
+      result.put("type", privilege.getType());
+      result.put("value", privilege.getLevel());
+      return result;
+    } else {
+      throw new InvalidArgumentException("Don't know how to handle class: " + privilege.getClass());
+    }
+  }
+
+  /**
+   * @return the layoutService
+   * @see #layoutService
+   */
+  public ILayoutService getLayoutService() {
+    return layoutService;
+  }
+
+  /**
+   * @param layoutService
+   *          the layoutService to set
+   * @see #layoutService
+   */
+  public void setLayoutService(ILayoutService layoutService) {
+    this.layoutService = layoutService;
+  }
+
+  public List<Map<String, Object>> getUsers(String token, String columns) throws SecurityException {
+    User ownUserData = getUserService().getUserByToken(token);
+    boolean isAdmin = getUserService().userHasPrivilege(ownUserData, PrivilegeType.USER_MANAGEMENT);
+
+    Set<String> columnSet = createUserColumnSet(columns);
+
+    List<Map<String, Object>> result = new ArrayList<>();
+    List<User> users = getUserService().getUsers(token);
+    users.sort(User.LOGIN_COMPARATOR);
+    Map<String, Boolean> ldapAvailability = getUserService().ldapAccountExistsForLogin(users);
+
+    for (User user : users) {
+      result.add(prepareUse(user, columnSet, isAdmin, ldapAvailability.get(user.getLogin())));
+    }
+    return result;
+  }
+
+  public Map<String, Object> updatePrivileges(String token, String login, Map<String, Object> privilegesData)
+      throws SecurityException, QueryException {
+    if (privilegesData == null) {
+      throw new QueryException("Privileges not defined");
+    }
+    try {
+      User modifiedUser = getUserService().getUserByLogin(login);
+
+      for (String key : privilegesData.keySet()) {
+        Object value = privilegesData.get(key);
+
+        PrivilegeType type = PrivilegeType.valueOf(key);
+
+        if (type.getPrivilegeClassType().equals(BasicPrivilege.class)) {
+          getUserService().setUserPrivilege(modifiedUser, type, value, token);
+        } else if (type.getPrivilegeClassType().equals(ObjectPrivilege.class)) {
+          if (value instanceof Map) {
+            Map<?, ?> objects = (Map<?, ?>) value;
+            for (Object objectId : objects.keySet()) {
+              Integer objectIdAsInteger = null;
+              if (!objectId.equals("null")) {
+                objectIdAsInteger = Integer.valueOf((String) objectId);
+              }
+              getUserService().setUserPrivilege(modifiedUser, type, objects.get(objectId), objectIdAsInteger, token);
+            }
+          } else {
+            throw new QueryException("Invalid value for privilege: " + key);
+          }
+        } else {
+          throw new QueryException("Unknown privilege type: " + key);
+        }
+
+      }
+      return getUser(token, login, "");
+    } catch (IllegalArgumentException e) {
+      throw new QueryException("Invalid input", e);
+    }
+  }
+
+  public Map<String, Object> updatePreferences(String token, String login, Map<String, Object> preferencesData)
+      throws SecurityException, QueryException {
+    if (preferencesData == null) {
+      throw new QueryException("Preferences not defined");
+    }
+    try {
+      User modifiedUser = getUserService().getUserByLogin(login);
+      if (modifiedUser == null) {
+        throw new ObjectNotFoundException("User doesn't exist");
+      }
+
+      UserAnnotationSchema schema = getProjectService().prepareUserAnnotationSchema(modifiedUser);
+
+      for (String key : preferencesData.keySet()) {
+        Map<String, Object> value = (Map<String, Object>) preferencesData.get(key);
+
+        if (key.equals("project-upload")) {
+          updateUploadPreferences(schema, value);
+        } else if (key.equals("element-annotators")) {
+          updateElementAnnotators(schema, value);
+        } else if (key.equals("element-required-annotations")) {
+          updateRequiredAnnotations(schema, value);
+        } else if (key.equals("element-valid-annotations")) {
+          updateValidAnnotations(schema, value);
+        } else if (key.equals("annotators-parameters")) {
+          updateAnnotatorsParams(schema, value);
+        } else if (key.equals("gui-preferences")) {
+          updateGuiPreferences(schema, value);
+        } else {
+          throw new QueryException("Unknown preferences field: " + key);
+        }
+      }
+      modifiedUser.setAnnotationSchema(schema);
+      getUserService().updateUser(modifiedUser, token);
+      return getUser(token, login, "preferences");
+    } catch (IllegalArgumentException e) {
+      throw new QueryException("Invalid input", e);
+    }
+  }
+
+  private void updateUploadPreferences(UserAnnotationSchema schema, Map<String, Object> data) throws QueryException {
+    for (String key : data.keySet()) {
+      Boolean value = (Boolean) data.get(key);
+      if (value != null) {
+        if (key.equals("validate-miriam")) {
+          schema.setValidateMiriamTypes(value);
+        } else if (key.equals("annotate-model")) {
+          schema.setAnnotateModel(value);
+        } else if (key.equals("cache-data")) {
+          schema.setCacheData(value);
+        } else if (key.equals("auto-resize")) {
+          schema.setAutoResizeMap(value);
+        } else if (key.equals("semantic-zooming")) {
+          schema.setSemanticZooming(value);
+        } else if (key.equals("sbgn")) {
+          schema.setSbgnFormat(value);
+        } else {
+          throw new QueryException("Unknown upload preference field: " + key);
+        }
+      }
+    }
+
+  }
+
+  public Map<String, Object> updateUser(String token, String login, Map<String, Object> userData)
+      throws QueryException, SecurityException {
+    if (userData == null) {
+      throw new QueryException("user field cannot be undefined");
+    }
+    User user = getUserService().getUserByLogin(login);
+    if (user == null) {
+      throw new ObjectNotFoundException("user doesn't exist");
+    }
+    boolean isAdmin = getUserService().userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT);
+    if (!isAdmin && !login.equalsIgnoreCase(getUserService().getUserByToken(token).getLogin())) {
+      throw new SecurityException("Access denied");
+    }
+    for (String key : userData.keySet()) {
+      Object value = userData.get(key);
+      String stringValue = null;
+      if (value instanceof String) {
+        stringValue = (String) value;
+      }
+      if (key.equalsIgnoreCase("name")) {
+        user.setName(stringValue);
+      } else if (key.equalsIgnoreCase("surname")) {
+        user.setSurname(stringValue);
+      } else if (key.equalsIgnoreCase("email")) {
+        user.setEmail(stringValue);
+      } else if (key.equalsIgnoreCase("termsofuseconsent")) {
+        user.setTermsOfUseConsent((Boolean) value);
+      } else if (key.equalsIgnoreCase("connectedtoldap")) {
+        user.setConnectedToLdap((Boolean) value);
+      } else if (key.equalsIgnoreCase("password")) {
+        if (stringValue != null && !stringValue.trim().isEmpty()) {
+          user.setCryptedPassword(getUserService().encodePassword(stringValue));
+        }
+      } else if (key.equalsIgnoreCase("login")) {
+        if (!user.getLogin().equals((String) value)) {
+          throw new QueryException("login cannot be modified");
+        }
+      } else {
+        throw new QueryException("Unknown parameter: " + key);
+      }
+    }
+    getUserService().updateUser(user);
+    return getUser(token, login, "");
+  }
+
+  public Map<String, Object> addProject(String token, String login, MultiValueMap<String, Object> userData)
+      throws QueryException, SecurityException {
+    if (!getUserService().userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
+      throw new SecurityException("Access denied");
+    }
+
+    User user = getUserService().getUserByLogin(login);
+    if (user != null) {
+      throw new QueryException("user exists");
+    }
+    user = new User();
+    user.setLogin(login);
+    for (String key : userData.keySet()) {
+      String stringValue = getFirstValue((List<Object>) userData.get(key));
+      if (key.equalsIgnoreCase("name")) {
+        user.setName(stringValue);
+      } else if (key.equalsIgnoreCase("surname")) {
+        user.setSurname(stringValue);
+      } else if (key.equalsIgnoreCase("email")) {
+        user.setEmail(stringValue);
+      } else if (key.equalsIgnoreCase("password")) {
+        if (stringValue != null && !stringValue.trim().isEmpty()) {
+          user.setCryptedPassword(getUserService().encodePassword(stringValue));
+        }
+      } else if (key.equalsIgnoreCase("login")) {
+        if (!user.getLogin().equals(stringValue)) {
+          throw new QueryException("login must match url");
+        }
+      } else {
+        throw new QueryException("Unknown parameter: " + key);
+      }
+    }
+    getUserService().addUser(user);
+    return getUser(token, login, "");
+  }
+
+  public Map<String, Object> removeUser(String token, String login) throws SecurityException, QueryException {
+    User user = getUserService().getUserByLogin(login);
+    if (!getUserService().userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
+      throw new SecurityException("Access denied");
+    }
+    if (user == null) {
+      throw new QueryException("user doesn't exists");
+    }
+    getUserService().deleteUser(user);
+    return okStatus();
+  }
+
+}
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/genomics/ReferenceGenomeControllerTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/genomics/ReferenceGenomeControllerTest.java
index 4d9929a940e2786a6e3e77ab936d070cacc055e1..35e85fa7db3d56036ca1bc37cea10ccde548ced3 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/genomics/ReferenceGenomeControllerTest.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/genomics/ReferenceGenomeControllerTest.java
@@ -1,8 +1,12 @@
 package lcsb.mapviewer.api.genomics;
 
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.util.List;
+import java.util.Map;
+
 import org.apache.log4j.Logger;
 import org.junit.After;
 import org.junit.AfterClass;
@@ -58,4 +62,65 @@ public class ReferenceGenomeControllerTest extends RestTestFunctions {
     }
   }
 
+  @Test
+  public void testGetReferenceGenomeTaxonomies() throws Exception {
+    try {
+      List<Map<String, Object>> result = referenceGenomeRestImpl.getReferenceGenomeTaxonomies(token);
+      assertNotNull(result);
+      assertTrue(result.size() > 0);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetReferenceGenomeTypes() throws Exception {
+    try {
+      List<Map<String, Object>> result = referenceGenomeRestImpl.getReferenceGenomeTypes(token,"9606");
+      assertNotNull(result);
+      assertTrue(result.size() > 0);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetReferenceGenomeVersions() throws Exception {
+    try {
+      List<Map<String, Object>> result = referenceGenomeRestImpl.getReferenceGenomeVersions(token,"9606","UCSC");
+      assertNotNull(result);
+      assertTrue(result.size() > 0);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetRemoteUrls() throws Exception {
+    try {
+      List<Map<String, Object>> result = referenceGenomeRestImpl.getRemoteUrls(adminToken, "9606", "UCSC", "hg18");
+      assertNotNull(result);
+      assertTrue(result.size() > 0);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetAllDowloadedReferenceGenomes() throws Exception {
+    try {
+      List<?> result = referenceGenomeRestImpl.getReferenceGenomes(token);
+      assertNotNull(result);
+      assertTrue(result.size() > 0);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+
 }
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/projects/chemicals/ChemicalRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/projects/chemicals/ChemicalRestImplTest.java
index 5608bc531c31ad1ef4998628f6440d62ffbd7b43..f93f3239832b58f798d2afd4e98f697c384cacf4 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/projects/chemicals/ChemicalRestImplTest.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/projects/chemicals/ChemicalRestImplTest.java
@@ -25,58 +25,61 @@ import lcsb.mapviewer.services.search.DbSearchCriteria;
 import lcsb.mapviewer.services.search.chemical.IChemicalService;
 
 public class ChemicalRestImplTest extends RestTestFunctions {
-	Logger									 logger	= Logger.getLogger(ChemicalRestImplTest.class);
+  Logger logger = Logger.getLogger(ChemicalRestImplTest.class);
 
-    @Autowired
+  @Autowired
 
-    private ChemicalRestImpl _drugRestImpl;
-    
-    @Autowired
-    private IChemicalService chemicalService;
+  private ChemicalRestImpl _drugRestImpl;
 
-	@AfterClass
-	public static void tearDownAfterClass() throws Exception {
-	}
+  @Autowired
+  private IChemicalService chemicalService;
 
-	@Before
-	public void setUp() throws Exception {
-	}
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+  }
 
-	@After
-	public void tearDown() throws Exception {
-	}
+  @Before
+  public void setUp() throws Exception {
+  }
 
-    @Test
-    public void testPrepareChemical() throws Exception {
-        try {
-            Chemical chemical = new Chemical();
-            chemical.setChemicalId(new MiriamData(MiriamType.MESH_2012, "D010300"));
-            Map<String, Object> result = _drugRestImpl.prepareChemical(chemical, _drugRestImpl.createChemicalColumnSet(""), new ArrayList<>());
-            assertNotNull(result);
-        } catch (Exception e) {
-            e.printStackTrace();
-            throw e;
-        }
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testPrepareChemical() throws Exception {
+    try {
+      Chemical chemical = new Chemical();
+      chemical.setChemicalId(new MiriamData(MiriamType.MESH_2012, "D010300"));
+      Map<String, Object> result = _drugRestImpl.prepareChemical(chemical, _drugRestImpl.createChemicalColumnSet(""),
+          new ArrayList<>());
+      assertNotNull(result);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
     }
+  }
 
-    @Test
-    public void testPrepareChemicalWithProblematicMesh() throws Exception {
-        try {
-            Chemical chemical = chemicalService.getByName("Tetrachlorodibenzodioxin", new DbSearchCriteria().disease(new MiriamData(MiriamType.MESH_2012, "D010300")));
-            Map<String, Object> result = _drugRestImpl.prepareChemical(chemical, _drugRestImpl.createChemicalColumnSet(""), new ArrayList<>());
-            assertNotNull(result);
-        } catch (Exception e) {
-            e.printStackTrace();
-            throw e;
-        }
+  @Test
+  public void testPrepareChemicalWithProblematicMesh() throws Exception {
+    try {
+      Chemical chemical = chemicalService.getByName("Tetrachlorodibenzodioxin",
+          new DbSearchCriteria().disease(new MiriamData(MiriamType.MESH_2012, "D010300")));
+      Map<String, Object> result = _drugRestImpl.prepareChemical(chemical, _drugRestImpl.createChemicalColumnSet(""),
+          new ArrayList<>());
+      assertNotNull(result);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
     }
+  }
 
-	protected ChemicalRestImpl createMockChemicalRest(String string) throws Exception {
-		Model model = super.getModelForFile(string, true);
-		IModelService mockModelService = Mockito.mock(IModelService.class);
-		Mockito.when(mockModelService.getLastModelByProjectId(anyString(), any())).thenReturn(model);
-		_drugRestImpl.setModelService(mockModelService);
-		return _drugRestImpl;
-	}
+  protected ChemicalRestImpl createMockChemicalRest(String string) throws Exception {
+    Model model = super.getModelForFile(string, true);
+    IModelService mockModelService = Mockito.mock(IModelService.class);
+    Mockito.when(mockModelService.getLastModelByProjectId(anyString(), any())).thenReturn(model);
+    _drugRestImpl.setModelService(mockModelService);
+    return _drugRestImpl;
+  }
 
 }
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementRestImplTest.java
index a5a06edbcebc117f303da8876033620b17043439..24b414c4f298d61a854932c6f9e9af93bee71ca3 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementRestImplTest.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/projects/models/bioEntities/elements/ElementRestImplTest.java
@@ -27,10 +27,9 @@ import lcsb.mapviewer.model.map.species.AntisenseRna;
 import lcsb.mapviewer.model.map.species.GenericProtein;
 import lcsb.mapviewer.model.map.species.Protein;
 import lcsb.mapviewer.model.map.species.Rna;
-import lcsb.mapviewer.model.map.species.field.AntisenseRnaRegion;
-import lcsb.mapviewer.model.map.species.field.ModificationResidue;
+import lcsb.mapviewer.model.map.species.field.ModificationSite;
 import lcsb.mapviewer.model.map.species.field.ModificationState;
-import lcsb.mapviewer.model.map.species.field.RnaRegion;
+import lcsb.mapviewer.model.map.species.field.Residue;
 import lcsb.mapviewer.services.interfaces.IModelService;
 
 public class ElementRestImplTest extends RestTestFunctions {
@@ -115,7 +114,7 @@ public class ElementRestImplTest extends RestTestFunctions {
     try {
       String state = "asd";
       GenericProtein protein = new GenericProtein("s1");
-      ModificationResidue mr = new ModificationResidue();
+      Residue mr = new Residue();
       mr.setState(ModificationState.ACETYLATED);
       mr.setName("S250");
       protein.addModificationResidue(mr);
@@ -137,7 +136,7 @@ public class ElementRestImplTest extends RestTestFunctions {
     try {
       String state = "asd";
       Rna rna = new Rna("s1");
-      RnaRegion mr = new RnaRegion();
+      ModificationSite mr = new ModificationSite();
       mr.setState(ModificationState.ACETYLATED);
       mr.setName("S250");
       rna.addRegion(mr);
@@ -159,12 +158,12 @@ public class ElementRestImplTest extends RestTestFunctions {
     try {
       String state = "asd";
       AntisenseRna antisenseRna = new AntisenseRna("s1");
-      AntisenseRnaRegion mr = new AntisenseRnaRegion();
-      mr.setState(ModificationState.ACETYLATED);
+      ModificationSite mr = new ModificationSite();
       mr.setName("S250");
       antisenseRna.addRegion(mr);
       antisenseRna.setState(state);
       Map<String, Object> result = _elementsRestImpl.getOthersForElement(antisenseRna);
+      logger.debug(result);
       assertNotNull(result.get("modifications"));
       assertEquals(state, result.get("structuralState"));
       List<Map<String, Object>> modifications = (List<Map<String, Object>>) result.get("modifications");
diff --git a/service/pom.xml b/service/pom.xml
index 683846f0af0938281b311caf2ece1656b55c0516..f80ec93ad194b0539355a3b82708891388aabd25 100644
--- a/service/pom.xml
+++ b/service/pom.xml
@@ -118,6 +118,13 @@
 			<version>3.12</version>
 		</dependency>
 
+		<!-- https://mvnrepository.com/artifact/com.unboundid/unboundid-ldapsdk -->
+		<dependency>
+		    <groupId>com.unboundid</groupId>
+		    <artifactId>unboundid-ldapsdk</artifactId>
+		    <version>${unboundid-ldapsdk.version}</version>
+		</dependency>
+
 <!-- mockito used for testing -->
 		<dependency>
 			<groupId>org.mockito</groupId>
diff --git a/service/src/main/java/lcsb/mapviewer/services/UserDTO.java b/service/src/main/java/lcsb/mapviewer/services/UserDTO.java
new file mode 100644
index 0000000000000000000000000000000000000000..d84f9836e4a3719b44bd37c95b75faeb2465ada4
--- /dev/null
+++ b/service/src/main/java/lcsb/mapviewer/services/UserDTO.java
@@ -0,0 +1,49 @@
+package lcsb.mapviewer.services;
+
+public class UserDTO {
+  private String login;
+  private String firstName;
+  private String lastName;
+  private String email;
+  private String bindDn;
+
+  public String getLogin() {
+    return login;
+  }
+
+  public void setLogin(String login) {
+    this.login = login;
+  }
+
+  public String getFirstName() {
+    return firstName;
+  }
+
+  public void setFirstName(String firstName) {
+    this.firstName = firstName;
+  }
+
+  public String getLastName() {
+    return lastName;
+  }
+
+  public void setLastName(String lastName) {
+    this.lastName = lastName;
+  }
+
+  public String getEmail() {
+    return email;
+  }
+
+  public void setEmail(String email) {
+    this.email = email;
+  }
+
+  public String getBindDn() {
+    return bindDn;
+  }
+
+  public void setBindDn(String bindDn) {
+    this.bindDn = bindDn;
+  }
+}
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/LdapService.java b/service/src/main/java/lcsb/mapviewer/services/impl/LdapService.java
new file mode 100644
index 0000000000000000000000000000000000000000..8e40c11e36f30899f3a7fcadc16fd2f6742d3d15
--- /dev/null
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/LdapService.java
@@ -0,0 +1,240 @@
+package lcsb.mapviewer.services.impl;
+
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.unboundid.ldap.sdk.Attribute;
+import com.unboundid.ldap.sdk.BindResult;
+import com.unboundid.ldap.sdk.Filter;
+import com.unboundid.ldap.sdk.LDAPConnection;
+import com.unboundid.ldap.sdk.LDAPException;
+import com.unboundid.ldap.sdk.ResultCode;
+import com.unboundid.ldap.sdk.SearchResult;
+import com.unboundid.ldap.sdk.SearchResultEntry;
+import com.unboundid.ldap.sdk.SearchScope;
+import com.unboundid.ldap.sdk.SimpleBindRequest;
+import com.unboundid.util.ssl.SSLUtil;
+import com.unboundid.util.ssl.TrustAllTrustManager;
+
+import lcsb.mapviewer.common.exception.InvalidStateException;
+import lcsb.mapviewer.model.user.ConfigurationElementType;
+import lcsb.mapviewer.services.UserDTO;
+import lcsb.mapviewer.services.interfaces.IConfigurationService;
+import lcsb.mapviewer.services.interfaces.ILdapService;
+
+@Transactional(value = "txManager")
+public class LdapService implements ILdapService {
+  Logger logger = Logger.getLogger(LdapService.class);
+
+  @Autowired
+  private IConfigurationService configurationService;
+
+  protected LDAPConnection getConnection() throws LDAPException {
+    String address = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_ADDRESS);
+    if (address == null || address.trim().isEmpty()) {
+      return null;
+    }
+    boolean ssl = "true"
+        .equalsIgnoreCase(configurationService.getConfigurationValue(ConfigurationElementType.LDAP_SSL));
+
+    String portString = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_PORT);
+    if (portString == null || address.trim().isEmpty()) {
+      if (ssl) {
+        portString = "636";
+      } else {
+        portString = "389";
+      }
+    }
+    int port = Integer.parseInt(portString);
+    LDAPConnection connection;
+    if (ssl) {
+      SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
+      try {
+        connection = new LDAPConnection(sslUtil.createSSLSocketFactory());
+      } catch (GeneralSecurityException e) {
+        throw new InvalidStateException(e);
+      }
+    } else {
+      connection = new LDAPConnection();
+    }
+    connection.connect(address, port);
+
+    String bindDn = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_BIND_DN);
+    String password = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_PASSWORD);
+
+    if (bindDn == null || bindDn.trim().isEmpty()) {
+      connection.bind(new SimpleBindRequest());
+    } else {
+      connection.bind(bindDn, password);
+    }
+
+    return connection;
+  }
+
+  @Override
+  public boolean login(String login, String password) throws LDAPException {
+    if (!isValidConfiguration()) {
+      logger.warn("Invalid LDAP configuration");
+      return false;
+    }
+    LDAPConnection connection = getConnection();
+    UserDTO user = getUserByLogin(login);
+    if (user != null) {
+      try {
+        BindResult result = connection.bind(user.getBindDn(), password);
+        return result.getResultCode().equals(ResultCode.SUCCESS);
+      } catch (Exception e) {
+        return false;
+      }
+    }
+
+    return false;
+  }
+
+  @Override
+  public List<String> getUsernames() throws LDAPException {
+    if (!isValidConfiguration()) {
+      logger.warn("Invalid LDAP configuration");
+      return new ArrayList<>();
+    }
+    List<String> result = new ArrayList<>();
+    LDAPConnection connection = getConnection();
+
+    Filter f2 = createObjectClassFilter();
+    Filter f3 = createAttributeFilter();
+
+    Filter filter = Filter.createANDFilter(f2, f3);
+
+    String baseDn = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_BASE_DN);
+    SearchResult searchResult = connection.search(baseDn, SearchScope.SUB, filter);
+
+    for (SearchResultEntry entry : searchResult.getSearchEntries()) {
+      Attribute uid = entry.getAttribute("uid");
+      if (uid != null) {
+        result.add(uid.getValue());
+      } else {
+        logger.warn("Invalid ldap entry: " + entry);
+      }
+    }
+    connection.close();
+
+    return result;
+  }
+
+  @Override
+  public UserDTO getUserByLogin(String login) throws LDAPException {
+    if (!isValidConfiguration()) {
+      logger.warn("Invalid LDAP configuration");
+      return null;
+    }
+    LDAPConnection connection = getConnection();
+    try {
+      String baseDn = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_BASE_DN);
+      String firstNameAttribute = configurationService
+          .getConfigurationValue(ConfigurationElementType.LDAP_FIRST_NAME_ATTRIBUTE);
+      String lastNameAttribute = configurationService
+          .getConfigurationValue(ConfigurationElementType.LDAP_LAST_NAME_ATTRIBUTE);
+      String emailAttribute = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_EMAIL_ATTRIBUTE);
+
+      Filter f1 = createLoginFilter(login);
+      Filter f2 = createObjectClassFilter();
+      Filter f3 = createAttributeFilter();
+
+      Filter filter = Filter.createANDFilter(f1, f2, f3);
+      SearchResult searchResult = connection.search(baseDn, SearchScope.SUB, filter);
+
+      for (SearchResultEntry entry : searchResult.getSearchEntries()) {
+        UserDTO result = new UserDTO();
+        result.setBindDn(entry.getDN());
+
+        Attribute uidAttribute = entry.getAttribute("uid");
+        if (uidAttribute != null) {
+          result.setLogin(uidAttribute.getValue());
+        } else {
+          logger.warn("Invalid ldap entry: " + entry);
+        }
+        if (!firstNameAttribute.trim().isEmpty()) {
+          Attribute firstName = entry.getAttribute(firstNameAttribute);
+          if (firstName != null) {
+            result.setFirstName(firstName.getValue());
+          }
+        }
+
+        if (!lastNameAttribute.trim().isEmpty()) {
+          Attribute lastName = entry.getAttribute(lastNameAttribute);
+          if (lastName != null) {
+            result.setLastName(lastName.getValue());
+          }
+        }
+
+        if (!emailAttribute.trim().isEmpty()) {
+          Attribute emailName = entry.getAttribute(emailAttribute);
+          if (emailName != null) {
+            result.setEmail(emailName.getValue());
+          }
+        }
+
+        return result;
+      }
+      return null;
+    } finally {
+      connection.close();
+    }
+  }
+
+  private Filter createObjectClassFilter() throws LDAPException {
+    String objectClass = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_OBJECT_CLASS);
+
+    if (objectClass == null || objectClass.trim().isEmpty() || objectClass .equals( "*")) {
+      return Filter.create("objectClass=*");
+    }
+
+    return  Filter.createEqualityFilter("objectClass", objectClass);
+  }
+
+  private Filter createAttributeFilter() throws LDAPException {
+    String ldapStringFilter = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_FILTER);
+
+    if (ldapStringFilter == null || ldapStringFilter.trim().isEmpty()) {
+      return Filter.create("");
+    }
+
+    return Filter.create(ldapStringFilter);
+  }
+
+  private Filter createLoginFilter(String login) {
+    return  Filter.createEqualityFilter("uid", login);
+  }
+
+  public IConfigurationService getConfigurationService() {
+    return configurationService;
+  }
+
+  public void setConfigurationService(IConfigurationService configurationService) {
+    this.configurationService = configurationService;
+  }
+
+  @Override
+  public boolean isValidConfiguration() {
+    try {
+      String baseDn = configurationService.getConfigurationValue(ConfigurationElementType.LDAP_BASE_DN);
+      if (baseDn == null || baseDn.trim().isEmpty()) {
+        return false;
+      }
+      LDAPConnection connection = getConnection();
+      if (connection != null) {
+        connection.close();
+        return true;
+      }
+      return false;
+    } catch (Exception e) {
+      logger.error(e, e);
+      return false;
+    }
+  }
+}
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java
index b79e0ef37258f9217ede64927ce122ad8b7148a5..fe26c10cbfc2658004f24ad926a9648b971eaadc 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/ProjectService.java
@@ -5,7 +5,6 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -60,7 +59,6 @@ import lcsb.mapviewer.converter.zip.ZipEntryFile;
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.ProjectStatus;
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
-import lcsb.mapviewer.model.graphics.MapCanvasType;
 import lcsb.mapviewer.model.log.LogType;
 import lcsb.mapviewer.model.map.BioEntity;
 import lcsb.mapviewer.model.map.MiriamData;
@@ -477,20 +475,7 @@ public class ProjectService implements IProjectService {
     for (User user : userDao.getAll()) {
       if (!processedUser.contains(user)) {
         processedUser.add(user);
-        for (PrivilegeType type : PrivilegeType.values()) {
-          if (Project.class.equals(type.getPrivilegeObjectType())) {
-            int level = userService.getUserPrivilegeLevel(user, type, (Integer) null);
-            if (level < 0) {
-              if (configurationService.getValue(type).getValue().equalsIgnoreCase("true")) {
-                level = 1;
-              } else {
-                level = 0;
-              }
-            }
-            ObjectPrivilege privilege = new ObjectPrivilege(project, level, type, user);
-            userService.setUserPrivilege(user, privilege);
-          }
-        }
+        userService.createDefaultProjectPrivilegesForUser(project, user);
       }
     }
 
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/ReferenceGenomeService.java b/service/src/main/java/lcsb/mapviewer/services/impl/ReferenceGenomeService.java
index b3bc006549d1391246bc18d19aead5a5caeea55e..b7c1d54c7cf902a28928bacde42af146d56458ae 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/ReferenceGenomeService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/ReferenceGenomeService.java
@@ -143,4 +143,9 @@ public class ReferenceGenomeService implements IReferenceGenomeService {
     return null;
   }
 
+  @Override
+  public ReferenceGenome getReferenceGenomeById(int id, String authenticationToken) {
+    return referenceGenomeDao.getById(id);
+  }
+
 }
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java b/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
index 6eb486fdb5f1d404cb20b66d9fb9dded3d08ff1f..cfabf12b2a20ca1501772c3313a73557b6f643cd 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/UserService.java
@@ -1,530 +1,602 @@
-package lcsb.mapviewer.services.impl;
-
-import java.awt.Color;
-import java.math.BigInteger;
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-import org.apache.log4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.session.SessionInformation;
-import org.springframework.security.core.session.SessionRegistry;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.transaction.annotation.Transactional;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.common.ObjectUtils;
-import lcsb.mapviewer.common.comparator.IntegerComparator;
-import lcsb.mapviewer.common.exception.InvalidArgumentException;
-import lcsb.mapviewer.common.geometry.ColorParser;
-import lcsb.mapviewer.model.Project;
-import lcsb.mapviewer.model.log.LogType;
-import lcsb.mapviewer.model.user.BasicPrivilege;
-import lcsb.mapviewer.model.user.ConfigurationElementType;
-import lcsb.mapviewer.model.user.ObjectPrivilege;
-import lcsb.mapviewer.model.user.PrivilegeType;
-import lcsb.mapviewer.model.user.User;
-import lcsb.mapviewer.persist.dao.ProjectDao;
-import lcsb.mapviewer.persist.dao.user.PrivilegeDao;
-import lcsb.mapviewer.persist.dao.user.UserDao;
-import lcsb.mapviewer.services.SecurityException;
-import lcsb.mapviewer.services.interfaces.IConfigurationService;
-import lcsb.mapviewer.services.interfaces.ILogService;
-import lcsb.mapviewer.services.interfaces.ILogService.LogParams;
-import lcsb.mapviewer.services.interfaces.IUserService;
-
-/**
- * Implementation of the service that manages users.
- * 
- * @author Piotr Gawron
- * 
- */
-@Transactional(value = "txManager")
-public class UserService implements IUserService {
-
-  /**
-   * Default class logger.
-   */
-  private static Logger logger = Logger.getLogger(UserService.class);
-
-  /**
-   * Data access object for users.
-   */
-  @Autowired
-  private UserDao userDao;
-
-  /**
-   * Data access object for projects.
-   */
-  @Autowired
-  private ProjectDao projectDao;
-
-  /**
-   * Data access object for privileges.
-   */
-  @Autowired
-  private PrivilegeDao privilegeDao;
-
-  @Autowired
-  private SessionRegistry sessionRegistry;
-
-  /**
-   * Service that provides password encoding.
-   */
-  @Autowired
-  private PasswordEncoder passwordEncoder;
-
-  /**
-   * Service used for logging.
-   */
-  @Autowired
-  private ILogService logService;
-
-  /**
-   * Service used for accessing configuration parameters.
-   */
-  @Autowired
-  private IConfigurationService configurationService;
-
-  @Override
-  public String login(String login, String password) {
-    Random random = new SecureRandom();
-    String id = new BigInteger(130, random).toString(32);
-    return this.login(login, password, id);
-  }
-
-  @Override
-  public boolean userHasPrivilege(User user, PrivilegeType type) {
-    return getUserPrivilegeLevel(user, type) > 0;
-  }
-
-  @Override
-  public boolean userHasPrivilege(User user, PrivilegeType type, Object object) {
-    return getUserPrivilegeLevel(user, type, object) > 0;
-  }
-
-	@Override
-	public void setUserPrivilege(User user, BasicPrivilege privilege) {
-		updateUserPrivilegesWithoutDbModification(user, privilege);
-		updateUser(user);
-		userDao.flush();
-	}
-
-    private void updateUserPrivilegesWithoutDbModification(User user, BasicPrivilege privilege) {
-		BasicPrivilege oldPrivilege = null;
-		for (BasicPrivilege privilegeIter : user.getPrivileges()) {
-			if (privilegeIter.equalsPrivilege(privilege)) {
-				oldPrivilege = privilegeIter;
-			}
-		}
-		if (oldPrivilege != null) {
-		    privilege.setUser(null);
-		    oldPrivilege.setLevel(privilege.getLevel());
-		} else {
-		    privilege.setUser(user);
-		    user.getPrivileges().add(privilege);
-		}
-    }
-
-  @Override
-  public void addUser(User user) {
-    userDao.add(user);
-    LogParams params = new LogParams().description("User " + user.getLogin() + " created.").type(LogType.USER_CREATED)
-        .object(user);
-    logService.log(params);
-  }
-
-  @Override
-  public void updateUser(User user) {
-    userDao.update(user);
-  }
-
-  @Override
-  public void deleteUser(User user) {
-    userDao.delete(user);
-    LogParams params = new LogParams().description("User " + user.getLogin() + " removed.").type(LogType.USER_CREATED)
-        .object(user);
-    logService.log(params);
-  }
-
-  @Override
-  public User getUserById(int id) {
-    User result = userDao.getById(id);
-    if (result != null) {
-      userDao.refresh(result);
-    }
-    return result;
-  }
-
-  @Override
-  public User getUserByLogin(String login) {
-    User result = userDao.getUserByLogin(login);
-    if (result != null) {
-      userDao.refresh(result);
-    }
-    return result;
-  }
-
-  @Override
-  public void dropPrivilegesForObjectType(PrivilegeType type, int id) {
-    IntegerComparator integerComparator = new IntegerComparator();
-    // this will be slow when number of user will increase (we fetch all
-    // users and drop privileges one by one)
-    List<User> users = userDao.getAll();
-    for (User user : users) {
-      List<BasicPrivilege> toRemove = new ArrayList<BasicPrivilege>();
-      for (BasicPrivilege privilege : user.getPrivileges()) {
-        if (privilege.getType().equals(type) && privilege instanceof ObjectPrivilege
-            && integerComparator.compare(((ObjectPrivilege) privilege).getIdObject(), id) == 0) {
-          toRemove.add(privilege);
-        }
-      }
-      if (toRemove.size() > 0) {
-        user.getPrivileges().removeAll(toRemove);
-        userDao.update(user);
-      }
-    }
-  }
-
-  @Override
-  public int getUserPrivilegeLevel(User user, PrivilegeType type) {
-    if (type.getPrivilegeClassType() != BasicPrivilege.class) {
-      throw new InvalidArgumentException("This privilege requires additional information");
-    }
-    for (BasicPrivilege privilege : user.getPrivileges()) {
-      if (privilege.getType().equals(type)) {
-        return privilege.getLevel();
-      }
-    }
-    return 0;
-  }
-
-  @Override
-  public int getUserPrivilegeLevel(User user, PrivilegeType type, Object object) {
-    Integer id = null;
-    if (object != null) {
-      try {
-        id = ObjectUtils.getIdOfObject(object);
-      } catch (Exception e) {
-        logger.error(e.getMessage(), e);
-        throw new InvalidArgumentException("Internal server error. Problem with accessing id of the parameter object");
-      }
-      if (!type.getPrivilegeObjectType().isAssignableFrom(object.getClass())) {
-        throw new InvalidArgumentException("This privilege accept only " + type.getPrivilegeObjectType()
-            + " objects parameter, but " + object.getClass() + " class found.");
-      }
-    }
-    return getUserPrivilegeLevel(user, type, id);
-  }
-
-  private int getUserPrivilegeLevel(User user, PrivilegeType type, Integer id) {
-    if (type.getPrivilegeClassType() != ObjectPrivilege.class) {
-      throw new InvalidArgumentException("This privilege doesn't accept object parameter");
-    }
-    if (user == null) {
-      throw new InvalidArgumentException("User cannot be null");
-    }
-
-    // refresh user from db
-    if (user.getId() != null) {
-      user = userDao.getById(user.getId());
-    }
-    IntegerComparator integerComparator = new IntegerComparator();
-    for (BasicPrivilege privilege : user.getPrivileges()) {
-      if (privilege.getClass() == ObjectPrivilege.class) {
-        ObjectPrivilege oPrivilege = (ObjectPrivilege) privilege;
-        if (oPrivilege.getType().equals(type) && integerComparator.compare(oPrivilege.getIdObject(), id) == 0) {
-          return privilege.getLevel();
-        }
-      }
-    }
-    return -1;
-  }
-
-  @Override
-  public void setUserPrivilege(User user, PrivilegeType type, Integer value) {
-    BasicPrivilege privilege = new BasicPrivilege(value, type, user);
-
-    BasicPrivilege oldPrivilege = null;
-    for (BasicPrivilege privilegeIter : user.getPrivileges()) {
-      if (privilegeIter.getType().equals(type)) {
-        oldPrivilege = privilegeIter;
-      }
-    }
-    if (oldPrivilege != null) {
-      user.getPrivileges().remove(oldPrivilege);
-      oldPrivilege.setUser(null);
-    }
-    user.getPrivileges().add(privilege);
-    updateUser(user);
-    userDao.flush();
-
-  }
-
-  /**
-   * @return the userDao
-   * @see #userDao
-   */
-  public UserDao getUserDao() {
-    return userDao;
-  }
-
-  /**
-   * @param userDao
-   *          the userDao to set
-   * @see #userDao
-   */
-  public void setUserDao(UserDao userDao) {
-    this.userDao = userDao;
-  }
-
-  /**
-   * @return the projectDao
-   * @see #projectDao
-   */
-  public ProjectDao getProjectDao() {
-    return projectDao;
-  }
-
-  /**
-   * @param projectDao
-   *          the projectDao to set
-   * @see #projectDao
-   */
-  public void setProjectDao(ProjectDao projectDao) {
-    this.projectDao = projectDao;
-  }
-
-  /**
-   * @return the privilegeDao
-   * @see #privilegeDao
-   */
-  public PrivilegeDao getPrivilegeDao() {
-    return privilegeDao;
-  }
-
-  /**
-   * @param privilegeDao
-   *          the privilegeDao to set
-   * @see #privilegeDao
-   */
-  public void setPrivilegeDao(PrivilegeDao privilegeDao) {
-    this.privilegeDao = privilegeDao;
-  }
-
-  /**
-   * @return the passwordEncoder
-   * @see #passwordEncoder
-   */
-  public PasswordEncoder getPasswordEncoder() {
-    return passwordEncoder;
-  }
-
-  /**
-   * @param passwordEncoder
-   *          the passwordEncoder to set
-   * @see #passwordEncoder
-   */
-  public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
-    this.passwordEncoder = passwordEncoder;
-  }
-
-  /**
-   * @param password
-   *          input password
-   * @return encoded password
-   */
-  @Override
-  public String encodePassword(String password) {
-    return passwordEncoder.encode(password);
-  }
-
-  @Override
-  public User getUserByNameSurname(String nameSurnameString) {
-    return userDao.getUserByNameSurname(nameSurnameString);
-  }
-
-  @Override
-  public ColorExtractor getColorExtractorForUser(User loggedUser) {
-    Color colorMin = null;
-    Color colorMax = null;
-    Color colorSimple = null;
-    if (loggedUser != null) {
-      User dbUser = getUserById(loggedUser.getId());
-      if (dbUser != null) {
-        colorMin = dbUser.getMinColor();
-        colorMax = dbUser.getMaxColor();
-        colorSimple = dbUser.getSimpleColor();
-      }
-    }
-    ColorParser parser = new ColorParser();
-
-    if (colorMin == null) {
-      colorMin = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.MIN_COLOR_VAL));
-    }
-    if (colorMax == null) {
-      colorMax = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.MAX_COLOR_VAL));
-    }
-    if (colorSimple == null) {
-      colorSimple = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.SIMPLE_COLOR_VAL));
-    }
-    return new ColorExtractor(colorMin, colorMax, colorSimple);
-  }
-
-  /**
-   * @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;
-  }
-
-  @Override
-  public User getUserByToken(String token) throws SecurityException {
-    if (!isSessionExpired(token)) {
-      String login = ((org.springframework.security.core.userdetails.User) (sessionRegistry.getSessionInformation(token)
-          .getPrincipal())).getUsername();
-      return userDao.getUserByLogin(login);
-    } else {
-      throw new SecurityException("Invalid token");
-    }
-  }
-
-  private boolean isSessionExpired(String token) {
-    SessionInformation sessionData = sessionRegistry.getSessionInformation(token);
-    if (sessionData == null) {
-      logger.debug("No session data for token id: " + token);
-      return true;
-    }
-    return sessionData.isExpired();
-  }
-
-  @Override
-  public boolean userHasPrivilege(String token, PrivilegeType type, Object object) throws SecurityException {
-    return userHasPrivilege(getUserByToken(token), type, object);
-  }
-
-  @Override
-  public void logout(String tokenString) {
-    if (!isSessionExpired(tokenString)) {
-      sessionRegistry.removeSessionInformation(tokenString);
-    }
-  }
-
-  @Override
-  public User getUserById(String creatorId, String authenticationToken) throws SecurityException {
-    User user = getUserByToken(authenticationToken);
-    Integer id = Integer.parseInt(creatorId);
-    if (user.getId().equals(id)) {
-      return user;
-    } else if (userHasPrivilege(authenticationToken, PrivilegeType.USER_MANAGEMENT)) {
-      return getUserById(id);
-    } else {
-      throw new SecurityException("You cannot access data of other users");
-    }
-  }
-
-  @Override
-  public List<User> getUsers(String token) throws SecurityException {
-    if (userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
-      return userDao.getAll();
-    } else {
-      throw new SecurityException("You have no access to users data");
-    }
-  }
-
-  @Override
-  public void setUserPrivilege(User user, PrivilegeType type, Object value, String token) throws SecurityException {
-    if (!userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
-      throw new SecurityException("You cannot modify user privileges");
-    }
-    if (value instanceof Integer) {
-      setUserPrivilege(user, type, (Integer) value);
-    } else if (value instanceof Boolean) {
-      if ((Boolean) value) {
-        setUserPrivilege(user, type, 1);
-      } else {
-        setUserPrivilege(user, type, 0);
-      }
-    } else {
-      throw new InvalidArgumentException("Invalid privilege value: " + value);
-    }
-  }
-
-  @Override
-  public void setUserPrivilege(User user, PrivilegeType type, Object value, Integer objectId, String token)
-      throws SecurityException {
-    boolean canModify = userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT);
-    if (!canModify) {
-      if (type.getPrivilegeObjectType().isAssignableFrom(Project.class)) {
-        canModify = getUserPrivilegeLevel(getUserByToken(token), type, objectId) > 0;
-      }
-    }
-    if (!canModify) {
-      throw new SecurityException("You cannot modify user privileges");
-    }
-    Project projectIdWrapper = new Project();
-    if (objectId == null) {
-      projectIdWrapper = null;
-    } else {
-      projectIdWrapper.setId(objectId);
-    }
-    if (value instanceof Integer) {
-      setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, (Integer) value, type, user));
-    } else if (value instanceof Boolean) {
-      if ((Boolean) value) {
-        setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, 1, type, user));
-      } else {
-        setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, 0, type, user));
-      }
-    } else {
-      throw new InvalidArgumentException("Invalid privilege value: " + value);
-    }
-
-  }
-
-  @Override
-  public void updateUser(User modifiedUser, String token) throws SecurityException {
-    User user = getUserByToken(token);
-    if (user.getLogin().equals(modifiedUser.getLogin()) || userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
-      updateUser(modifiedUser);
-    } else {
-      throw new SecurityException("You cannot modify user");
-    }
-
-  }
-
-  @Override
-  public boolean userHasPrivilege(String token, PrivilegeType type) throws SecurityException {
-    return userHasPrivilege(getUserByToken(token), type);
-  }
-
-  @Override
-  public String login(String login, String password, String token) {
-    User user = userDao.getUserByLoginAndPassword(login, password);
-    if (user == null && Configuration.ANONYMOUS_LOGIN.equals(login) && "".equals(password)) {
-      user = getUserByLogin(Configuration.ANONYMOUS_LOGIN);
-    }
-    if (user != null) {
-      sessionRegistry.registerNewSession(token, new org.springframework.security.core.userdetails.User(login,
-          passwordEncoder.encode(password), AuthorityUtils.commaSeparatedStringToAuthorityList("")));
-      return token;
-    } else {
-      return null;
-    }
-  }
-
-}
+package lcsb.mapviewer.services.impl;
+
+import java.awt.Color;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.session.SessionInformation;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.unboundid.ldap.sdk.LDAPException;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.common.ObjectUtils;
+import lcsb.mapviewer.common.comparator.IntegerComparator;
+import lcsb.mapviewer.common.exception.InvalidArgumentException;
+import lcsb.mapviewer.common.geometry.ColorParser;
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.log.LogType;
+import lcsb.mapviewer.model.user.BasicPrivilege;
+import lcsb.mapviewer.model.user.ConfigurationElementType;
+import lcsb.mapviewer.model.user.ObjectPrivilege;
+import lcsb.mapviewer.model.user.PrivilegeType;
+import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.persist.dao.ProjectDao;
+import lcsb.mapviewer.persist.dao.user.PrivilegeDao;
+import lcsb.mapviewer.persist.dao.user.UserDao;
+import lcsb.mapviewer.services.SecurityException;
+import lcsb.mapviewer.services.UserDTO;
+import lcsb.mapviewer.services.interfaces.IConfigurationService;
+import lcsb.mapviewer.services.interfaces.ILdapService;
+import lcsb.mapviewer.services.interfaces.ILogService;
+import lcsb.mapviewer.services.interfaces.ILogService.LogParams;
+import lcsb.mapviewer.services.interfaces.IUserService;
+
+/**
+ * Implementation of the service that manages users.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+@Transactional(value = "txManager")
+public class UserService implements IUserService {
+
+  /**
+   * Default class logger.
+   */
+  private static Logger logger = Logger.getLogger(UserService.class);
+
+  /**
+   * Data access object for users.
+   */
+  @Autowired
+  private UserDao userDao;
+
+  /**
+   * Data access object for privileges.
+   */
+  @Autowired
+  private PrivilegeDao privilegeDao;
+
+  @Autowired
+  private SessionRegistry sessionRegistry;
+
+  /**
+   * Service that provides password encoding.
+   */
+  @Autowired
+  private PasswordEncoder passwordEncoder;
+
+  /**
+   * Service used for logging.
+   */
+  @Autowired
+  private ILogService logService;
+
+  @Autowired
+  private ILdapService ldapService;
+
+  @Autowired
+  private ProjectDao projectDao;
+
+  /**
+   * Service used for accessing configuration parameters.
+   */
+  @Autowired
+  private IConfigurationService configurationService;
+
+  @Override
+  public String login(String login, String password) {
+    Random random = new SecureRandom();
+    String id = new BigInteger(130, random).toString(32);
+    return this.login(login, password, id);
+  }
+
+  @Override
+  public boolean userHasPrivilege(User user, PrivilegeType type) {
+    return getUserPrivilegeLevel(user, type) > 0;
+  }
+
+  @Override
+  public boolean userHasPrivilege(User user, PrivilegeType type, Object object) {
+    return getUserPrivilegeLevel(user, type, object) > 0;
+  }
+
+  @Override
+  public void setUserPrivilege(User user, BasicPrivilege privilege) {
+    updateUserPrivilegesWithoutDbModification(user, privilege);
+    updateUser(user);
+    userDao.flush();
+  }
+
+  private void updateUserPrivilegesWithoutDbModification(User user, BasicPrivilege privilege) {
+    BasicPrivilege oldPrivilege = null;
+    for (BasicPrivilege privilegeIter : user.getPrivileges()) {
+      if (privilegeIter.equalsPrivilege(privilege)) {
+        oldPrivilege = privilegeIter;
+      }
+    }
+    if (oldPrivilege != null) {
+      privilege.setUser(null);
+      oldPrivilege.setLevel(privilege.getLevel());
+    } else {
+      privilege.setUser(user);
+      user.getPrivileges().add(privilege);
+    }
+  }
+
+  @Override
+  public void addUser(User user) {
+    userDao.add(user);
+    LogParams params = new LogParams().description("User " + user.getLogin() + " created.").type(LogType.USER_CREATED)
+        .object(user);
+    logService.log(params);
+  }
+
+  @Override
+  public void updateUser(User user) {
+    userDao.update(user);
+  }
+
+  @Override
+  public void deleteUser(User user) {
+    userDao.delete(user);
+    LogParams params = new LogParams().description("User " + user.getLogin() + " removed.").type(LogType.USER_CREATED)
+        .object(user);
+    logService.log(params);
+  }
+
+  @Override
+  public User getUserByLogin(String login) {
+    User result = userDao.getUserByLogin(login);
+    if (result != null) {
+      userDao.refresh(result);
+    }
+    return result;
+  }
+
+  @Override
+  public void dropPrivilegesForObjectType(PrivilegeType type, int id) {
+    IntegerComparator integerComparator = new IntegerComparator();
+    // this will be slow when number of user will increase (we fetch all
+    // users and drop privileges one by one)
+    List<User> users = userDao.getAll();
+    for (User user : users) {
+      List<BasicPrivilege> toRemove = new ArrayList<>();
+      for (BasicPrivilege privilege : user.getPrivileges()) {
+        if (privilege.getType().equals(type) && privilege instanceof ObjectPrivilege
+            && integerComparator.compare(((ObjectPrivilege) privilege).getIdObject(), id) == 0) {
+          toRemove.add(privilege);
+        }
+      }
+      if (toRemove.size() > 0) {
+        user.getPrivileges().removeAll(toRemove);
+        userDao.update(user);
+      }
+    }
+  }
+
+  @Override
+  public int getUserPrivilegeLevel(User user, PrivilegeType type) {
+    if (type.getPrivilegeClassType() != BasicPrivilege.class) {
+      throw new InvalidArgumentException("This privilege requires additional information");
+    }
+    for (BasicPrivilege privilege : user.getPrivileges()) {
+      if (privilege.getType().equals(type)) {
+        return privilege.getLevel();
+      }
+    }
+    return 0;
+  }
+
+  @Override
+  public int getUserPrivilegeLevel(User user, PrivilegeType type, Object object) {
+    Integer id = null;
+    if (object != null) {
+      try {
+        id = ObjectUtils.getIdOfObject(object);
+      } catch (Exception e) {
+        logger.error(e.getMessage(), e);
+        throw new InvalidArgumentException("Internal server error. Problem with accessing id of the parameter object");
+      }
+      if (!type.getPrivilegeObjectType().isAssignableFrom(object.getClass())) {
+        throw new InvalidArgumentException("This privilege accept only " + type.getPrivilegeObjectType()
+            + " objects parameter, but " + object.getClass() + " class found.");
+      }
+    }
+    return getUserPrivilegeLevel(user, type, id);
+  }
+
+  private int getUserPrivilegeLevel(User user, PrivilegeType type, Integer id) {
+    if (type.getPrivilegeClassType() != ObjectPrivilege.class) {
+      throw new InvalidArgumentException("This privilege doesn't accept object parameter");
+    }
+    if (user == null) {
+      throw new InvalidArgumentException("User cannot be null");
+    }
+
+    // refresh user from db
+    if (user.getId() != null) {
+      user = userDao.getById(user.getId());
+    }
+    IntegerComparator integerComparator = new IntegerComparator();
+    for (BasicPrivilege privilege : user.getPrivileges()) {
+      if (privilege.getClass() == ObjectPrivilege.class) {
+        ObjectPrivilege oPrivilege = (ObjectPrivilege) privilege;
+        if (oPrivilege.getType().equals(type) && integerComparator.compare(oPrivilege.getIdObject(), id) == 0) {
+          return privilege.getLevel();
+        }
+      }
+    }
+    return -1;
+  }
+
+  @Override
+  public void setUserPrivilege(User user, PrivilegeType type, Integer value) {
+    BasicPrivilege privilege = new BasicPrivilege(value, type, user);
+
+    BasicPrivilege oldPrivilege = null;
+    for (BasicPrivilege privilegeIter : user.getPrivileges()) {
+      if (privilegeIter.getType().equals(type)) {
+        oldPrivilege = privilegeIter;
+      }
+    }
+    if (oldPrivilege != null) {
+      user.getPrivileges().remove(oldPrivilege);
+      oldPrivilege.setUser(null);
+    }
+    user.getPrivileges().add(privilege);
+    updateUser(user);
+    userDao.flush();
+
+  }
+
+  /**
+   * @return the userDao
+   * @see #userDao
+   */
+  public UserDao getUserDao() {
+    return userDao;
+  }
+
+  /**
+   * @param userDao
+   *          the userDao to set
+   * @see #userDao
+   */
+  public void setUserDao(UserDao userDao) {
+    this.userDao = userDao;
+  }
+
+  /**
+   * @return the privilegeDao
+   * @see #privilegeDao
+   */
+  public PrivilegeDao getPrivilegeDao() {
+    return privilegeDao;
+  }
+
+  /**
+   * @param privilegeDao
+   *          the privilegeDao to set
+   * @see #privilegeDao
+   */
+  public void setPrivilegeDao(PrivilegeDao privilegeDao) {
+    this.privilegeDao = privilegeDao;
+  }
+
+  /**
+   * @return the passwordEncoder
+   * @see #passwordEncoder
+   */
+  public PasswordEncoder getPasswordEncoder() {
+    return passwordEncoder;
+  }
+
+  /**
+   * @param passwordEncoder
+   *          the passwordEncoder to set
+   * @see #passwordEncoder
+   */
+  public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
+    this.passwordEncoder = passwordEncoder;
+  }
+
+  /**
+   * @param password
+   *          input password
+   * @return encoded password
+   */
+  @Override
+  public String encodePassword(String password) {
+    return passwordEncoder.encode(password);
+  }
+
+  @Override
+  public ColorExtractor getColorExtractorForUser(User loggedUser) {
+    Color colorMin = null;
+    Color colorMax = null;
+    Color colorSimple = null;
+    if (loggedUser != null) {
+      User dbUser = getUserByLogin(loggedUser.getLogin());
+      if (dbUser != null) {
+        colorMin = dbUser.getMinColor();
+        colorMax = dbUser.getMaxColor();
+        colorSimple = dbUser.getSimpleColor();
+      }
+    }
+    ColorParser parser = new ColorParser();
+
+    if (colorMin == null) {
+      colorMin = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.MIN_COLOR_VAL));
+    }
+    if (colorMax == null) {
+      colorMax = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.MAX_COLOR_VAL));
+    }
+    if (colorSimple == null) {
+      colorSimple = parser.parse(configurationService.getConfigurationValue(ConfigurationElementType.SIMPLE_COLOR_VAL));
+    }
+    return new ColorExtractor(colorMin, colorMax, colorSimple);
+  }
+
+  /**
+   * @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;
+  }
+
+  @Override
+  public User getUserByToken(String token) throws SecurityException {
+    if (!isSessionExpired(token)) {
+      String login = ((org.springframework.security.core.userdetails.User) (sessionRegistry.getSessionInformation(token)
+          .getPrincipal())).getUsername();
+      return userDao.getUserByLogin(login);
+    } else {
+      throw new SecurityException("Invalid token");
+    }
+  }
+
+  private boolean isSessionExpired(String token) {
+    SessionInformation sessionData = sessionRegistry.getSessionInformation(token);
+    if (sessionData == null) {
+      logger.debug("No session data for token id: " + token);
+      return true;
+    }
+    return sessionData.isExpired();
+  }
+
+  @Override
+  public boolean userHasPrivilege(String token, PrivilegeType type, Object object) throws SecurityException {
+    return userHasPrivilege(getUserByToken(token), type, object);
+  }
+
+  @Override
+  public void logout(String tokenString) {
+    if (!isSessionExpired(tokenString)) {
+      sessionRegistry.removeSessionInformation(tokenString);
+    }
+  }
+
+  @Override
+  public List<User> getUsers(String token) throws SecurityException {
+    if (userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
+      return userDao.getAll();
+    } else {
+      throw new SecurityException("You have no access to users data");
+    }
+  }
+
+  @Override
+  public void setUserPrivilege(User user, PrivilegeType type, Object value, String token) throws SecurityException {
+    if (!userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
+      throw new SecurityException("You cannot modify user privileges");
+    }
+    if (value instanceof Integer) {
+      setUserPrivilege(user, type, (Integer) value);
+    } else if (value instanceof Boolean) {
+      if ((Boolean) value) {
+        setUserPrivilege(user, type, 1);
+      } else {
+        setUserPrivilege(user, type, 0);
+      }
+    } else {
+      throw new InvalidArgumentException("Invalid privilege value: " + value);
+    }
+  }
+
+  @Override
+  public void setUserPrivilege(User user, PrivilegeType type, Object value, Integer objectId, String token)
+      throws SecurityException {
+    boolean canModify = userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT);
+    if (!canModify) {
+      if (type.getPrivilegeObjectType().isAssignableFrom(Project.class)) {
+        canModify = getUserPrivilegeLevel(getUserByToken(token), type, objectId) > 0;
+      }
+    }
+    if (!canModify) {
+      throw new SecurityException("You cannot modify user privileges");
+    }
+    Project projectIdWrapper = new Project();
+    if (objectId == null) {
+      projectIdWrapper = null;
+    } else {
+      projectIdWrapper.setId(objectId);
+    }
+    if (value instanceof Integer) {
+      setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, (Integer) value, type, user));
+    } else if (value instanceof Boolean) {
+      if ((Boolean) value) {
+        setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, 1, type, user));
+      } else {
+        setUserPrivilege(user, new ObjectPrivilege(projectIdWrapper, 0, type, user));
+      }
+    } else {
+      throw new InvalidArgumentException("Invalid privilege value: " + value);
+    }
+
+  }
+
+  @Override
+  public void updateUser(User modifiedUser, String token) throws SecurityException {
+    User user = getUserByToken(token);
+    if (user.getLogin().equals(modifiedUser.getLogin()) || userHasPrivilege(token, PrivilegeType.USER_MANAGEMENT)) {
+      updateUser(modifiedUser);
+    } else {
+      throw new SecurityException("You cannot modify user");
+    }
+
+  }
+
+  @Override
+  public boolean userHasPrivilege(String token, PrivilegeType type) throws SecurityException {
+    return userHasPrivilege(getUserByToken(token), type);
+  }
+
+  @Override
+  public String login(String login, String password, String token) {
+    User user = userDao.getUserByLogin(login);
+    if (user == null) {
+      user = createUserFromLdap(login, password);
+    } else if (!user.isConnectedToLdap()) {
+      String cryptedPassword;
+      if (password != null) {
+        cryptedPassword = passwordEncoder.encode(password);
+      } else {
+        cryptedPassword = "";
+      }
+      user = userDao.getUserByLoginAndCryptedPassword(login, cryptedPassword);
+    } else {
+      if (!authenticateOverLdap(login, password)) {
+        user = null;
+      }
+    }
+
+    if (user == null && Configuration.ANONYMOUS_LOGIN.equals(login) && "".equals(password)) {
+      user = getUserByLogin(Configuration.ANONYMOUS_LOGIN);
+    }
+    if (user != null) {
+      sessionRegistry.registerNewSession(token, new org.springframework.security.core.userdetails.User(login,
+          passwordEncoder.encode(password), AuthorityUtils.commaSeparatedStringToAuthorityList("")));
+      return token;
+    } else {
+      return null;
+    }
+  }
+
+  private boolean authenticateOverLdap(String login, String password) {
+    if (!ldapService.isValidConfiguration()) {
+      return false;
+    }
+    try {
+      return ldapService.login(login, password);
+    } catch (LDAPException e) {
+      logger.warn("Problem with accessing LDAP directory", e);
+      return false;
+    }
+  }
+
+  private User createUserFromLdap(String login, String password) {
+    if (login == null || password == null) {
+      return null;
+    }
+    if (!ldapService.isValidConfiguration()) {
+      return null;
+    }
+    try {
+      User user = null;
+      boolean authenticatedOverLdap = ldapService.login(login, password);
+      if (authenticatedOverLdap) {
+        UserDTO ldapUserData = ldapService.getUserByLogin(login);
+        user = new User();
+        user.setLogin(login);
+        user.setCryptedPassword(passwordEncoder.encode(password));
+        user.setName(ldapUserData.getFirstName());
+        user.setSurname(ldapUserData.getLastName());
+        user.setEmail(ldapUserData.getEmail());
+        user.setConnectedToLdap(true);
+        addUser(user);
+        for (Project project : projectDao.getAll()) {
+          createDefaultProjectPrivilegesForUser(project, user);
+        }
+      }
+      return user;
+    } catch (LDAPException e) {
+      logger.warn("Problem with accessing LDAP directory", e);
+      return null;
+    }
+  }
+
+  @Override
+  public ILdapService getLdapService() {
+    return ldapService;
+  }
+
+  @Override
+  public void setLdapService(ILdapService ldapService) {
+    this.ldapService = ldapService;
+  }
+
+  @Override
+  public void createDefaultProjectPrivilegesForUser(Project project, User user) {
+    for (PrivilegeType type : PrivilegeType.values()) {
+      if (Project.class.equals(type.getPrivilegeObjectType())) {
+        int level = getUserPrivilegeLevel(user, type, (Integer) null);
+        if (level < 0) {
+          if (configurationService.getValue(type).getValue().equalsIgnoreCase("true")) {
+            level = 1;
+          } else {
+            level = 0;
+          }
+        }
+        ObjectPrivilege privilege = new ObjectPrivilege(project, level, type, user);
+        setUserPrivilege(user, privilege);
+      }
+    }
+  }
+
+  @Override
+  public Map<String, Boolean> ldapAccountExistsForLogin(Collection<User> logins) {
+    Map<String, Boolean> result = new HashMap<>();
+    for (User user : logins) {
+      result.put(user.getLogin(), false);
+    }
+
+    if (ldapService.isValidConfiguration()) {
+      try {
+        List<String> ldapUserNames = getLdapService().getUsernames();
+        for (String string : ldapUserNames) {
+          if (result.keySet().contains(string)) {
+            result.put(string, true);
+          }
+        }
+      } catch (LDAPException e) {
+        logger.error("Problem with accessing LDAP directory", e);
+      }
+    }
+    return result;
+  }
+
+}
diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/ILdapService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/ILdapService.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a56e5c37b2a3c3f68729b9a84c3406fb128d392
--- /dev/null
+++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/ILdapService.java
@@ -0,0 +1,61 @@
+package lcsb.mapviewer.services.interfaces;
+
+import java.util.List;
+
+import com.unboundid.ldap.sdk.LDAPException;
+
+import lcsb.mapviewer.model.user.ConfigurationElementTypeGroup;
+import lcsb.mapviewer.services.UserDTO;
+
+/**
+ * Connection service to LDAP server.
+ * 
+ * @author Piotr Gawron
+ *
+ */
+public interface ILdapService {
+
+  /**
+   * Checks if login and password match
+   * 
+   * @param login
+   *          user login
+   * @param password
+   *          password
+   * @return true if user login/password match
+   * @throws LDAPException
+   *           thrown when there is problem with LDAP connection
+   */
+  boolean login(String login, String password) throws LDAPException;
+
+  /**
+   * Returns list of user names available in the LDAP server.
+   * 
+   * @return list of user names
+   * @throws LDAPException
+   *           thrown when there is problem with LDAP connection
+   */
+  List<String> getUsernames() throws LDAPException;
+
+  /**
+   * Returns user data information from LDAP for given login.
+   * 
+   * @param login
+   *          user for which we obtain data
+   * @return user data information from LDAP for given login or null if such user
+   *         doesn't exist
+   * @throws LDAPException
+   *           thrown when there is problem with LDAP connection
+   */
+  UserDTO getUserByLogin(String login) throws LDAPException;
+
+  /**
+   * Checks if LDAP configuration
+   * ({@link ConfigurationElementTypeGroup#LDAP_CONFIGURATION}) is valid.
+   * 
+   * @return true if LDAP configuration
+   *         ({@link ConfigurationElementTypeGroup#LDAP_CONFIGURATION}) is valid
+   */
+  boolean isValidConfiguration();
+
+}
diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/IReferenceGenomeService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/IReferenceGenomeService.java
index 419116d1d747c16de154f38042f66797e009bf53..71af2fae75eedd66a5a6b5648d7d85eb0b1f0d73 100644
--- a/service/src/main/java/lcsb/mapviewer/services/interfaces/IReferenceGenomeService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/IReferenceGenomeService.java
@@ -11,7 +11,7 @@ import lcsb.mapviewer.model.map.layout.ReferenceGenomeGeneMapping;
 import lcsb.mapviewer.model.map.layout.ReferenceGenomeType;
 
 /**
- * Service used to maintain referemce genome data.
+ * Service used to maintain reference genome data.
  * 
  * @author Piotr Gawron
  *
@@ -24,7 +24,7 @@ public interface IReferenceGenomeService {
    * @param type
    *          {@link ReferenceGenomeType type} of reference genome
    * @param organism
-   *          organism for which renference genome is added
+   *          organism for which reference genome is added
    * @param version
    *          version of the reference genome
    * @param customUrl
@@ -35,7 +35,7 @@ public interface IReferenceGenomeService {
    *           thrown when url is invalid
    * @throws ReferenceGenomeConnectorException
    *           thrown when reference genome already exists or there is problem
-   *           wirh adding genome
+   *           with adding genome
    */
   void addReferenceGenome(ReferenceGenomeType type, MiriamData organism, String version, String customUrl)
       throws IOException, URISyntaxException, ReferenceGenomeConnectorException;
@@ -49,7 +49,7 @@ public interface IReferenceGenomeService {
    * @return list of available organisms
    * @throws ReferenceGenomeConnectorException
    *           thrown when there is a problem with accessing information about
-   *           reference genoems
+   *           reference genomes
    */
   List<MiriamData> getOrganismsByReferenceGenomeType(ReferenceGenomeType type) throws ReferenceGenomeConnectorException;
 
@@ -64,7 +64,7 @@ public interface IReferenceGenomeService {
    * @return list of available organisms
    * @throws ReferenceGenomeConnectorException
    *           thrown when there is a problem with accessing information about
-   *           reference genoems
+   *           reference genomes
    */
   List<String> getAvailableGenomeVersions(ReferenceGenomeType type, MiriamData organism)
       throws ReferenceGenomeConnectorException;
@@ -83,9 +83,9 @@ public interface IReferenceGenomeService {
   String getUrlForGenomeVersion(ReferenceGenomeType type, MiriamData organism, String version);
 
   /**
-   * Returns list of all downladed reference genomes.
+   * Returns list of all downloaded reference genomes.
    * 
-   * @return list of all downladed reference genomes
+   * @return list of all downloaded reference genomes
    */
   List<ReferenceGenome> getDownloadedGenomes();
 
@@ -100,7 +100,7 @@ public interface IReferenceGenomeService {
   void removeGenome(ReferenceGenome genome) throws IOException;
 
   /**
-   * Adds gene mapping to refernce genome.
+   * Adds gene mapping to reference genome.
    * 
    * @param referenceGenome
    *          reference genome where we add mapping
@@ -113,7 +113,7 @@ public interface IReferenceGenomeService {
    * @throws URISyntaxException
    *           thrown when url is invalid
    * @throws ReferenceGenomeConnectorException
-   *           thrown when there is a problem with manipulatinf information about
+   *           thrown when there is a problem with manipulating information about
    *           reference genome
    */
   void addReferenceGenomeGeneMapping(ReferenceGenome referenceGenome, String name, String url)
@@ -142,4 +142,6 @@ public interface IReferenceGenomeService {
    */
   ReferenceGenome getReferenceGenomeViewByParams(MiriamData organism, ReferenceGenomeType genomeType, String version,
       String authenticationToken);
+
+  ReferenceGenome getReferenceGenomeById(int id, String authenticationToken);
 }
diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java
index d11ffec752a33098732d22d9c279e1c51a085784..66bc88d3128ee4385f9d4241d364cba99cfa16e0 100644
--- a/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/IUserService.java
@@ -1,201 +1,189 @@
-package lcsb.mapviewer.services.interfaces;
-
-import java.util.List;
-
-import lcsb.mapviewer.commands.ColorExtractor;
-import lcsb.mapviewer.model.user.BasicPrivilege;
-import lcsb.mapviewer.model.user.PrivilegeType;
-import lcsb.mapviewer.model.user.User;
-import lcsb.mapviewer.services.SecurityException;
-
-/**
- * Service that manages users.
- * 
- * @author Piotr Gawron
- * 
- */
-public interface IUserService {
-  /**
-   * Check if its possible to login using given login and password.
-   * 
-   * @param login
-   *          user login
-   * @param password
-   *          plan password
-   * @return {@link String} containing session id if credentials are valid,
-   *         <code>null</code> otherwise
-   */
-  String login(String login, String password);
-
-  /**
-   * Returns user by login.
-   * 
-   * @param login
-   *          user login
-   * @return user if the login is valid, <code>null</code> otherwise
-   */
-  User getUserByLogin(String login);
-
-  /**
-   * Checks if user has a given privilege.
-   * 
-   * @param user
-   *          user for which the check is performed
-   * @param type
-   *          type of the privilege
-   * @return <code>true</code> if user has privilege, <code>false</code> otherwise
-   */
-  boolean userHasPrivilege(User user, PrivilegeType type);
-
-  /**
-   * Returns level of the user privilege.
-   * 
-   * @param user
-   *          user for which the check is performed
-   * @param type
-   *          type of the privilege
-   * @return level of the privilege
-   */
-  int getUserPrivilegeLevel(User user, PrivilegeType type);
-
-  /**
-   * Checks if user has a given privilege on the object.
-   * 
-   * @param user
-   *          user for which the check is performed
-   * @param type
-   *          type of the privilege
-   * @param object
-   *          object of the privilege
-   * @return <code>true</code> if user has privilege, <code>false</code> otherwise
-   */
-  boolean userHasPrivilege(User user, PrivilegeType type, Object object);
-
-  /**
-   * Returns level of the user privilege.
-   * 
-   * @param object
-   *          object of the privilege
-   * @param user
-   *          user for which the check is performed
-   * @param type
-   *          type of the privilege
-   * @return level of the privilege
-   */
-  int getUserPrivilegeLevel(User user, PrivilegeType type, Object object);
-
-  /**
-   * Sets the user privilege.
-   * 
-   * @param user
-   *          user for whom the privilege should be granted/dropped
-   * @param privilege
-   *          user privilege
-   */
-  void setUserPrivilege(User user, BasicPrivilege privilege);
-
-  /**
-   * Adds user to the system.
-   * 
-   * @param user
-   *          user to be added
-   */
-  void addUser(User user);
-
-  /**
-   * Updates user in the system.
-   * 
-   * @param user
-   *          user to be updated
-   */
-  void updateUser(User user);
-
-  /**
-   * Removes user from the system.
-   * 
-   * @param user
-   *          user to be removed
-   */
-  void deleteUser(User user);
-
-  /**
-   * Returns user by the database identifier.
-   * 
-   * @param id
-   *          database identifier
-   * @return user for the given identifier, null if user doesn't exist
-   * 
-   */
-  User getUserById(int id);
-
-  /**
-   * Drops privileges for every user on the given object and type.
-   * 
-   * @param type
-   *          type of privilege that should be dropped
-   * @param objectId
-   *          identifier of the object to which privileges should be dropped
-   */
-  void dropPrivilegesForObjectType(PrivilegeType type, int objectId);
-
-  /**
-   * Adds privilege to the user.
-   * 
-   * @param user
-   *          user to which privilege should be added
-   * @param type
-   *          type of the privilege
-   */
-  void setUserPrivilege(User user, PrivilegeType type, Integer value);
-
-  /**
-   * @param password
-   *          input password
-   * @return encoded password
-   */
-  String encodePassword(String password);
-
-  /**
-   * Returns {@link User} for given "name surname" string.
-   * 
-   * @param nameSurnameString
-   *          string identifying user with name and surname separated by single
-   *          space
-   * @return {@link User} for given "name surname" string
-   */
-  User getUserByNameSurname(String nameSurnameString);
-
-  /**
-   * Returns {@link ColorExtractor} that transform overlay values into colors for
-   * given user.
-   * 
-   * @param user
-   *          {@link User} for which {@link ColorExtractor} will be obtained
-   * @return {@link ColorExtractor} that transform overlay values into colors for
-   *         given user
-   */
-  ColorExtractor getColorExtractorForUser(User user);
-
-  User getUserByToken(String token) throws SecurityException;
-
-  boolean userHasPrivilege(String token, PrivilegeType type, Object object) throws SecurityException;
-
-  void logout(String tokenString) throws SecurityException;
-
-  boolean userHasPrivilege(String token, PrivilegeType addMap) throws SecurityException;
-
-  User getUserById(String creatorId, String token) throws SecurityException;
-
-  List<User> getUsers(String token) throws SecurityException;
-
-  void setUserPrivilege(User modifiedUser, PrivilegeType type, Object privilegeToSet, String authenticationToken)
-      throws SecurityException;
-
-  void setUserPrivilege(User modifiedUser, PrivilegeType type, Object privilegeToSet, Integer objectId,
-      String authenticationToken) throws SecurityException;
-
-  void updateUser(User modifiedUser, String authenticationToken) throws SecurityException;
-
-  String login(String login, String password, String id);
-
-}
+package lcsb.mapviewer.services.interfaces;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import lcsb.mapviewer.commands.ColorExtractor;
+import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.user.BasicPrivilege;
+import lcsb.mapviewer.model.user.PrivilegeType;
+import lcsb.mapviewer.model.user.User;
+import lcsb.mapviewer.services.SecurityException;
+
+/**
+ * Service that manages users.
+ * 
+ * @author Piotr Gawron
+ * 
+ */
+public interface IUserService {
+  /**
+   * Check if its possible to login using given login and password.
+   * 
+   * @param login
+   *          user login
+   * @param password
+   *          plan password
+   * @return {@link String} containing session id if credentials are valid,
+   *         <code>null</code> otherwise
+   */
+  String login(String login, String password);
+
+  /**
+   * Returns user by login.
+   * 
+   * @param login
+   *          user login
+   * @return user if the login is valid, <code>null</code> otherwise
+   */
+  User getUserByLogin(String login);
+
+  /**
+   * Checks if user has a given privilege.
+   * 
+   * @param user
+   *          user for which the check is performed
+   * @param type
+   *          type of the privilege
+   * @return <code>true</code> if user has privilege, <code>false</code> otherwise
+   */
+  boolean userHasPrivilege(User user, PrivilegeType type);
+
+  /**
+   * Returns level of the user privilege.
+   * 
+   * @param user
+   *          user for which the check is performed
+   * @param type
+   *          type of the privilege
+   * @return level of the privilege
+   */
+  int getUserPrivilegeLevel(User user, PrivilegeType type);
+
+  /**
+   * Checks if user has a given privilege on the object.
+   * 
+   * @param user
+   *          user for which the check is performed
+   * @param type
+   *          type of the privilege
+   * @param object
+   *          object of the privilege
+   * @return <code>true</code> if user has privilege, <code>false</code> otherwise
+   */
+  boolean userHasPrivilege(User user, PrivilegeType type, Object object);
+
+  /**
+   * Returns level of the user privilege.
+   * 
+   * @param object
+   *          object of the privilege
+   * @param user
+   *          user for which the check is performed
+   * @param type
+   *          type of the privilege
+   * @return level of the privilege
+   */
+  int getUserPrivilegeLevel(User user, PrivilegeType type, Object object);
+
+  /**
+   * Sets the user privilege.
+   * 
+   * @param user
+   *          user for whom the privilege should be granted/dropped
+   * @param privilege
+   *          user privilege
+   */
+  void setUserPrivilege(User user, BasicPrivilege privilege);
+
+  /**
+   * Adds user to the system.
+   * 
+   * @param user
+   *          user to be added
+   */
+  void addUser(User user);
+
+  /**
+   * Updates user in the system.
+   * 
+   * @param user
+   *          user to be updated
+   */
+  void updateUser(User user);
+
+  /**
+   * Removes user from the system.
+   * 
+   * @param user
+   *          user to be removed
+   */
+  void deleteUser(User user);
+
+  /**
+   * Drops privileges for every user on the given object and type.
+   * 
+   * @param type
+   *          type of privilege that should be dropped
+   * @param objectId
+   *          identifier of the object to which privileges should be dropped
+   */
+  void dropPrivilegesForObjectType(PrivilegeType type, int objectId);
+
+  /**
+   * Adds privilege to the user.
+   * 
+   * @param user
+   *          user to which privilege should be added
+   * @param type
+   *          type of the privilege
+   */
+  void setUserPrivilege(User user, PrivilegeType type, Integer value);
+
+  /**
+   * @param password
+   *          input password
+   * @return encoded password
+   */
+  String encodePassword(String password);
+
+  /**
+   * Returns {@link ColorExtractor} that transform overlay values into colors for
+   * given user.
+   * 
+   * @param user
+   *          {@link User} for which {@link ColorExtractor} will be obtained
+   * @return {@link ColorExtractor} that transform overlay values into colors for
+   *         given user
+   */
+  ColorExtractor getColorExtractorForUser(User user);
+
+  User getUserByToken(String token) throws SecurityException;
+
+  boolean userHasPrivilege(String token, PrivilegeType type, Object object) throws SecurityException;
+
+  void logout(String tokenString) throws SecurityException;
+
+  boolean userHasPrivilege(String token, PrivilegeType addMap) throws SecurityException;
+
+  List<User> getUsers(String token) throws SecurityException;
+
+  void setUserPrivilege(User modifiedUser, PrivilegeType type, Object privilegeToSet, String authenticationToken)
+      throws SecurityException;
+
+  void setUserPrivilege(User modifiedUser, PrivilegeType type, Object privilegeToSet, Integer objectId,
+      String authenticationToken) throws SecurityException;
+
+  void updateUser(User modifiedUser, String authenticationToken) throws SecurityException;
+
+  String login(String login, String password, String id);
+
+  ILdapService getLdapService();
+
+  void setLdapService(ILdapService ldapService);
+
+  void createDefaultProjectPrivilegesForUser(Project project, User user);
+
+  Map<String, Boolean> ldapAccountExistsForLogin(Collection<User> logins);
+}
diff --git a/service/src/main/resources/applicationContext-service.xml b/service/src/main/resources/applicationContext-service.xml
index 1cbe2873d141f3332a21faec68675b62e05613c0..961c5a7b037e3da2064d1f974c6e52805b6d93d4 100644
--- a/service/src/main/resources/applicationContext-service.xml
+++ b/service/src/main/resources/applicationContext-service.xml
@@ -23,6 +23,8 @@
 	
 	<bean id="LayoutService" class="lcsb.mapviewer.services.impl.LayoutService"/>
 
+	<bean id="LdapService" class="lcsb.mapviewer.services.impl.LdapService"/>
+
 	<bean id="LogService" class="lcsb.mapviewer.services.impl.LogService"/>
 
 	<bean id="MiriamService" class="lcsb.mapviewer.services.impl.MiriamService"/>
diff --git a/service/src/test/java/lcsb/mapviewer/services/impl/AllImplServiceTests.java b/service/src/test/java/lcsb/mapviewer/services/impl/AllImplServiceTests.java
index f08941eeb3d935f91970189f8a742698756cf173..3a5bb0badde51ea8b6998a5c597b4151bfa4340f 100644
--- a/service/src/test/java/lcsb/mapviewer/services/impl/AllImplServiceTests.java
+++ b/service/src/test/java/lcsb/mapviewer/services/impl/AllImplServiceTests.java
@@ -6,13 +6,14 @@ import org.junit.runners.Suite.SuiteClasses;
 
 @RunWith(Suite.class)
 @SuiteClasses({ CommentServiceTest.class, //
-		ConfigurationServiceTest.class, //
-		ExternalServicesServiceTest.class, //
-		LayoutServiceTest.class, //
-		Md5PasswordEncoderTest.class, //
-		ProjectServiceTest.class, //
-		SearchServiceTest.class, //
-		UserServiceTest.class,//
+    ConfigurationServiceTest.class, //
+    ExternalServicesServiceTest.class, //
+    LayoutServiceTest.class, //
+    LdapServiceTest.class, //
+    Md5PasswordEncoderTest.class, //
+    ProjectServiceTest.class, //
+    SearchServiceTest.class, //
+    UserServiceTest.class,//
 })
 public class AllImplServiceTests {
 
diff --git a/service/src/test/java/lcsb/mapviewer/services/impl/LdapServiceTest.java b/service/src/test/java/lcsb/mapviewer/services/impl/LdapServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..6e9446bb0c0107298cdfa8a6314f4555efa3aec8
--- /dev/null
+++ b/service/src/test/java/lcsb/mapviewer/services/impl/LdapServiceTest.java
@@ -0,0 +1,136 @@
+package lcsb.mapviewer.services.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.springframework.test.annotation.Rollback;
+
+import com.unboundid.ldap.listener.InMemoryDirectoryServer;
+import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
+import com.unboundid.ldap.sdk.LDAPConnection;
+
+import lcsb.mapviewer.model.user.ConfigurationElementType;
+import lcsb.mapviewer.services.ServiceTestFunctions;
+import lcsb.mapviewer.services.UserDTO;
+
+@Rollback(true)
+public class LdapServiceTest extends ServiceTestFunctions {
+  static Logger logger = Logger.getLogger(LdapServiceTest.class);
+
+  LdapService ldapService;
+
+  @Before
+  public void setUp() throws Exception {
+    try {
+      configurationService.setConfigurationValue(ConfigurationElementType.LDAP_BASE_DN, "dc=uni,dc=lu");
+      configurationService.setConfigurationValue(ConfigurationElementType.LDAP_OBJECT_CLASS, "person");
+      configurationService.setConfigurationValue(ConfigurationElementType.LDAP_FILTER, "memberof=cn=gitlab,cn=groups,cn=accounts,dc=uni,dc=lu");
+
+      ldapService = Mockito.spy(LdapService.class);
+      ldapService.setConfigurationService(configurationService);
+      Mockito.when(ldapService.getConnection()).thenAnswer(new Answer<LDAPConnection>() {
+
+        @Override
+        public LDAPConnection answer(InvocationOnMock invocation) throws Throwable {
+          // Create the configuration to use for the server.
+          InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=uni,dc=lu");
+          config.addAdditionalBindCredentials("uid=piotr.gawron,cn=users,cn=accounts,dc=uni,dc=lu", "test_passwd");
+          config.setSchema(null);
+
+          // Create the directory server instance, populate it with data from the
+          // "test-data.ldif" file, and start listening for client connections.
+          InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
+          ds.importFromLDIF(true, "testFiles/ldap/testdata.ldif");
+          ds.startListening();
+          return ds.getConnection();
+        }
+      });
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @After
+  public void tearDown() throws Exception {
+  }
+
+  @Test
+  public void testIsValidConfiguration() throws Exception {
+    try {
+      assertTrue(ldapService.isValidConfiguration());
+      configurationService.setConfigurationValue(ConfigurationElementType.LDAP_BASE_DN, "");
+      assertFalse(ldapService.isValidConfiguration());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testLogin() throws Exception {
+    try {
+      assertTrue(ldapService.login("piotr.gawron", "test_passwd"));
+      assertFalse(ldapService.login("piotr.gawron", "invalid_password"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetUsernames() throws Exception {
+    try {
+      List<String> list = ldapService.getUsernames();
+      assertEquals(2, list.size());
+      assertTrue(list.contains("piotr.gawron"));
+      assertFalse(list.contains("john.doe"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetUsernamesWithFiltering() throws Exception {
+    try {
+      configurationService.setConfigurationValue(ConfigurationElementType.LDAP_FILTER,
+          "(memberof=cn=owncloud,cn=groups,cn=accounts,dc=uni,dc=lu)");
+
+      List<String> list = ldapService.getUsernames();
+      assertEquals(1, list.size());
+      assertTrue(list.contains("piotr.gawron"));
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testGetUserByLogin() throws Exception {
+    try {
+      UserDTO user = ldapService.getUserByLogin("piotr.gawron");
+      assertEquals("Piotr", user.getFirstName());
+      assertEquals("Gawron", user.getLastName());
+      assertEquals("piotr.gawron", user.getLogin());
+      assertEquals("piotr.gawron@uni.lu", user.getEmail());
+      assertNotNull(user.getBindDn());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+}
diff --git a/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java b/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java
index 57ae4d75f0bd5a9f408471a92fcbf6d7449051f8..227edfbc2fb5efc5e3a3b3ba3c30b149b8cb1152 100644
--- a/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java
+++ b/service/src/test/java/lcsb/mapviewer/services/impl/UserServiceTest.java
@@ -11,14 +11,24 @@ import org.apache.log4j.Logger;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 import org.springframework.test.annotation.Rollback;
 
+import com.unboundid.ldap.listener.InMemoryDirectoryServer;
+import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
+import com.unboundid.ldap.sdk.LDAPConnection;
+import com.unboundid.ldap.sdk.LDAPException;
+
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.user.BasicPrivilege;
+import lcsb.mapviewer.model.user.ConfigurationElementType;
 import lcsb.mapviewer.model.user.ObjectPrivilege;
 import lcsb.mapviewer.model.user.PrivilegeType;
 import lcsb.mapviewer.model.user.User;
 import lcsb.mapviewer.services.ServiceTestFunctions;
+import lcsb.mapviewer.services.interfaces.ILdapService;
 
 @Rollback(true)
 public class UserServiceTest extends ServiceTestFunctions {
@@ -46,6 +56,59 @@ public class UserServiceTest extends ServiceTestFunctions {
     }
   }
 
+  @Test
+  public void testLoginFromLdap() throws Exception {
+    ILdapService originalLdapService = userService.getLdapService();
+    try {
+      String login = "john.doe.test";
+      String passwd = "test_passwd";
+
+      assertNull(userService.getUserByLogin(login));
+
+      LdapService ldapService = createMockLdapService("testFiles/ldap/john-doe-test-example.ldif", login, passwd);
+
+      userService.setLdapService(ldapService);
+      assertNull(userService.login(login, "incorrect password"));
+      assertNotNull("User from LDAP wasn't authenticated", userService.login(login, passwd));
+
+      User user = userService.getUserByLogin(login);
+      assertNotNull("After authentication from LDAP user is not present in the system", user);
+      assertTrue(user.isConnectedToLdap());
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    } finally {
+      userService.setLdapService(originalLdapService);
+    }
+  }
+
+  private LdapService createMockLdapService(String filename, String login, String passwd) throws LDAPException {
+    configurationService.setConfigurationValue(ConfigurationElementType.LDAP_BASE_DN, "dc=uni,dc=lu");
+    configurationService.setConfigurationValue(ConfigurationElementType.LDAP_OBJECT_CLASS, "person");
+    configurationService.setConfigurationValue(ConfigurationElementType.LDAP_FILTER, "memberof=cn=gitlab,cn=groups,cn=accounts,dc=uni,dc=lu");
+
+    LdapService ldapService = Mockito.spy(LdapService.class);
+    ldapService.setConfigurationService(configurationService);
+    Mockito.when(ldapService.getConnection()).thenAnswer(new Answer<LDAPConnection>() {
+
+      @Override
+      public LDAPConnection answer(InvocationOnMock invocation) throws Throwable {
+        // Create the configuration to use for the server.
+        InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=uni,dc=lu");
+        config.addAdditionalBindCredentials("uid=" + login + ",cn=users,cn=accounts,dc=uni,dc=lu", passwd);
+        config.setSchema(null);
+
+        // Create the directory server instance, populate it with data from the
+        // "test-data.ldif" file, and start listening for client connections.
+        InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
+        ds.importFromLDIF(true, filename);
+        ds.startListening();
+        return ds.getConnection();
+      }
+    });
+    return ldapService;
+  }
+
   @Test
   public void testLoginWithNull() {
     try {
@@ -149,10 +212,10 @@ public class UserServiceTest extends ServiceTestFunctions {
       long logCount2 = logDao.getCount();
       assertEquals("Log entry is missing for add user event", logCount + 1, logCount2);
       userDao.evict(user2);
-      User user3 = userService.getUserById(user2.getId());
+      User user3 = userService.getUserByLogin(user2.getLogin());
       assertNotNull(user3);
       userService.deleteUser(user3);
-      user3 = userService.getUserById(user2.getId());
+      user3 = userService.getUserByLogin(user2.getLogin());
       assertNull(user3);
 
       long logCount3 = logDao.getCount();
diff --git a/service/testFiles/ldap/john-doe-test-example.ldif b/service/testFiles/ldap/john-doe-test-example.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..4d89df27e370421ae78cf33fa0a4d891c9a954d2
--- /dev/null
+++ b/service/testFiles/ldap/john-doe-test-example.ldif
@@ -0,0 +1,92 @@
+version: 1
+
+dn: dc=uni,dc=lu
+objectClass: top
+objectClass: domain
+dc: uni
+
+dn: cn=accounts,dc=uni,dc=lu
+objectClass: extensibleObject
+cn: accounts
+
+dn: cn=users,cn=accounts,dc=uni,dc=lu
+objectClass: extensibleObject
+cn: users
+
+dn: uid=john.doe.test,cn=users,cn=accounts,dc=uni,dc=lu
+objectClass: mepOriginEntry
+objectClass: ipaSshGroupOfPubKeys
+objectClass: posixaccount
+objectClass: inetuser
+objectClass: krbprincipalaux
+objectClass: krbticketpolicyaux
+objectClass: organizationalperson
+objectClass: inetorgperson
+objectClass: ipasshuser
+objectClass: top
+objectClass: person
+objectClass: ipaobject
+cn: John Doe
+gidNumber: 369550501
+homeDirectory: /home/john.doe.test
+ipaUniqueID: adf723e6-20e4-11e5-8907-001a4ae51219
+sn: Doe
+uid: john.doe.test
+uidNumber: 369550501
+displayName: John Doe
+gecos: John Doe
+givenName: John
+initials: JD
+krbLastPwdChange: 20180608111630Z
+krbPasswordExpiration: 20190223111630Z
+krbPrincipalName: john.doe.test@UNI.LU
+loginShell: /bin/bash
+mail: john.doe.test@uni.lu
+memberOf: cn=lcsb,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: ipaUniqueID=d7549fa2-03a2-11e5-95f9-00163e0a4f7b,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=eff7677e-03a2-11e5-add5-00163e0a4f7b,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=f10ec0f6-7ef6-11e5-957b-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=2cf9b59e-7ef7-11e5-89c0-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=eeb5f68e-9775-11e5-81fb-00163e0a4f7b,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=176f7fb4-9776-11e5-a097-00163e0a4f7b,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=7dda82ae-99e1-11e5-834b-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=a44d842c-99e1-11e5-9c2f-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: cn=webdav-public-minerva,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: ipaUniqueID=1d1f58b8-a247-11e5-ac5d-00163e0a4f7b,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=41f879a8-a247-11e5-9d34-00163e0a4f7b,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=33e9e6a2-c8d1-11e5-b578-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=572fea30-c8d1-11e5-b770-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: cn=lcsb-biocore,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=gitlab,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=xwiki,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=owncloud,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=xwiki-biocore,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=webdav-public-biocore,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=grafana-biocore-gitlab-viewers,cn=groups,cn=accounts,dc=uni,dc=
+ lu
+memberOf: cn=grafana-biocore-icinga-viewers,cn=groups,cn=accounts,dc=uni,dc=
+ lu
+memberOf: ipaUniqueID=634b5286-3781-11e6-93c5-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=7fe6a210-3781-11e6-b515-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: cn=ncer-pd-ada,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=r3lab-docker,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: ipaUniqueID=390a3ce0-854b-11e6-85c3-001a4ae5127c,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=6d558608-854b-11e6-9aa7-001a4ae5127c,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+telephoneNumber: +3524666445526
+
diff --git a/service/testFiles/ldap/testdata.ldif b/service/testFiles/ldap/testdata.ldif
new file mode 100644
index 0000000000000000000000000000000000000000..b319630ec5a05a1e92daaa053d93344fed84c9e1
--- /dev/null
+++ b/service/testFiles/ldap/testdata.ldif
@@ -0,0 +1,128 @@
+version: 1
+
+dn: dc=uni,dc=lu
+objectClass: top
+objectClass: domain
+dc: uni
+
+dn: cn=accounts,dc=uni,dc=lu
+objectClass: extensibleObject
+cn: accounts
+
+dn: cn=users,cn=accounts,dc=uni,dc=lu
+objectClass: extensibleObject
+cn: users
+
+dn: uid=piotr.gawron,cn=users,cn=accounts,dc=uni,dc=lu
+objectClass: mepOriginEntry
+objectClass: ipaSshGroupOfPubKeys
+objectClass: posixaccount
+objectClass: inetuser
+objectClass: krbprincipalaux
+objectClass: krbticketpolicyaux
+objectClass: organizationalperson
+objectClass: inetorgperson
+objectClass: ipasshuser
+objectClass: top
+objectClass: person
+objectClass: ipaobject
+cn: Piotr Gawron
+gidNumber: 369550501
+homeDirectory: /home/piotr.gawron
+ipaUniqueID: adf723e6-20e4-11e5-8907-001a4ae51219
+sn: Gawron
+uid: piotr.gawron
+uidNumber: 369550501
+displayName: Piotr Gawron
+gecos: Piotr Gawron
+givenName: Piotr
+initials: PG
+krbLastPwdChange: 20180608111630Z
+krbPasswordExpiration: 20190223111630Z
+krbPrincipalName: piotr.gawron@UNI.LU
+loginShell: /bin/bash
+mail: piotr.gawron@uni.lu
+memberOf: cn=lcsb,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: ipaUniqueID=d7549fa2-03a2-11e5-95f9-00163e0a4f7b,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=eff7677e-03a2-11e5-add5-00163e0a4f7b,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=f10ec0f6-7ef6-11e5-957b-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=2cf9b59e-7ef7-11e5-89c0-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=eeb5f68e-9775-11e5-81fb-00163e0a4f7b,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=176f7fb4-9776-11e5-a097-00163e0a4f7b,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=7dda82ae-99e1-11e5-834b-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=a44d842c-99e1-11e5-9c2f-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: cn=webdav-public-minerva,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: ipaUniqueID=1d1f58b8-a247-11e5-ac5d-00163e0a4f7b,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=41f879a8-a247-11e5-9d34-00163e0a4f7b,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: ipaUniqueID=33e9e6a2-c8d1-11e5-b578-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=572fea30-c8d1-11e5-b770-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: cn=lcsb-biocore,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=gitlab,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=xwiki,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=owncloud,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=xwiki-biocore,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=webdav-public-biocore,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=grafana-biocore-gitlab-viewers,cn=groups,cn=accounts,dc=uni,dc=
+ lu
+memberOf: cn=grafana-biocore-icinga-viewers,cn=groups,cn=accounts,dc=uni,dc=
+ lu
+memberOf: ipaUniqueID=634b5286-3781-11e6-93c5-001a4ae5121e,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=7fe6a210-3781-11e6-b515-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+memberOf: cn=ncer-pd-ada,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=r3lab-docker,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: ipaUniqueID=390a3ce0-854b-11e6-85c3-001a4ae5127c,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=6d558608-854b-11e6-9aa7-001a4ae5127c,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
+telephoneNumber: +3524666445526
+
+dn: uid=piotr.atyjaszyk,cn=users,cn=accounts,dc=uni,dc=lu
+objectClass: mepOriginEntry
+objectClass: ipaSshGroupOfPubKeys
+objectClass: posixaccount
+objectClass: inetuser
+objectClass: krbprincipalaux
+objectClass: krbticketpolicyaux
+objectClass: organizationalperson
+objectClass: inetorgperson
+objectClass: ipasshuser
+objectClass: top
+objectClass: person
+objectClass: ipaobject
+cn: Piotr Matyjaszyk
+gidNumber: 369513507
+homeDirectory: /home/piotr.atyjaszyk
+ipaUniqueID: ab674608-854a-11e6-8b8d-001a4ae5127c
+sn: Matyjaszyk
+uid: piotr.atyjaszyk
+uidNumber: 369513507
+displayName: Piotr Matyjaszyk
+gecos: Piotr Matyjaszyk
+givenName: Piotr
+initials: PM
+krbLastPwdChange: 20161003204712Z
+krbPasswordExpiration: 20170531204712Z
+krbPrincipalName: piotr.atyjaszyk@UNI.LU
+loginShell: /bin/bash
+mail: piotrmk1@gmail.com
+manager: uid=piotr.gawron,cn=users,cn=accounts,dc=uni,dc=lu
+memberOf: cn=gitlab,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: cn=external,cn=groups,cn=accounts,dc=uni,dc=lu
+memberOf: ipaUniqueID=929b4e02-854b-11e6-b870-001a4ae5127c,cn=hbac,dc=uni,dc
+ =lu
+memberOf: ipaUniqueID=bf23444e-a1bf-11e6-bf86-001a4ae5121e,cn=sudorules,cn=s
+ udo,dc=uni,dc=lu
diff --git a/web/src/main/java/lcsb/mapviewer/security/CustomAuthenticationProvider.java b/web/src/main/java/lcsb/mapviewer/security/CustomAuthenticationProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..6346901dd29fd3454054a33fcea9902e5435bcd8
--- /dev/null
+++ b/web/src/main/java/lcsb/mapviewer/security/CustomAuthenticationProvider.java
@@ -0,0 +1,53 @@
+package lcsb.mapviewer.security;
+
+import java.util.ArrayList;
+
+import org.apache.log4j.Logger;
+import org.springframework.security.authentication.AuthenticationProvider;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.transaction.annotation.Transactional;
+
+import lcsb.mapviewer.services.interfaces.IUserService;
+
+@Transactional(readOnly = false)
+public class CustomAuthenticationProvider implements AuthenticationProvider {
+  Logger logger = Logger.getLogger(CustomAuthenticationProvider.class);
+
+  private IUserService userService;
+
+  @Override
+  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
+    // login
+    String name = authentication.getName();
+
+    // password
+    String password = null;
+    if (authentication.getCredentials() != null) {
+      password = authentication.getCredentials().toString();
+    }
+
+    // Your custom authentication logic here
+    if (userService.login(name, password) != null) {
+      Authentication auth = new UsernamePasswordAuthenticationToken(name, password, new ArrayList<>());
+      return auth;
+    }
+    throw new BadCredentialsException("Invalid credentials");
+  }
+
+  @Override
+  public boolean supports(Class<?> authentication) {
+    return authentication.equals(UsernamePasswordAuthenticationToken.class);
+  }
+
+  public IUserService getUserService() {
+    return userService;
+  }
+
+  public void setUserService(IUserService userService) {
+    this.userService = userService;
+  }
+
+}
diff --git a/web/src/main/java/lcsb/mapviewer/security/MvSecurityServiceImpl.java b/web/src/main/java/lcsb/mapviewer/security/MvSecurityServiceImpl.java
deleted file mode 100644
index 109a881dfa63c9e7796ecd1a5bd0365ee76834f7..0000000000000000000000000000000000000000
--- a/web/src/main/java/lcsb/mapviewer/security/MvSecurityServiceImpl.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package lcsb.mapviewer.security;
-
-import org.apache.log4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.core.authority.AuthorityUtils;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.security.crypto.password.PasswordEncoder;
-import org.springframework.transaction.annotation.Transactional;
-
-import lcsb.mapviewer.common.Configuration;
-import lcsb.mapviewer.services.interfaces.IUserService;
-
-/**
- * Spring implementation of class accessing user details.
- * 
- * @author Piotr Gawron
- * 
- */
-@Transactional(readOnly = false)
-public class MvSecurityServiceImpl implements UserDetailsService {
-  /**
-   * Default class logger.
-   */
-  @SuppressWarnings("unused")
-  private static Logger logger = Logger.getLogger(MvSecurityServiceImpl.class);
-
-  /**
-   * Service used for accessing user data.
-   */
-  @Autowired
-  private IUserService userService;
-
-  @Autowired
-  private PasswordEncoder passwordEncoder;
-
-  @Override
-  public UserDetails loadUserByUsername(String login) {
-    if (login == null || login.trim().isEmpty() || login.equals(Configuration.ANONYMOUS_LOGIN)) {
-      return new User(login, passwordEncoder.encode(""), AuthorityUtils.commaSeparatedStringToAuthorityList(""));
-    }
-
-    lcsb.mapviewer.model.user.User user = userService.getUserByLogin(login);
-    if (user == null) {
-      throw new UsernameNotFoundException("Invalid username or password.");
-    }
-    StringBuilder credentials = new StringBuilder();
-
-    return new User(user.getLogin(), user.getCryptedPassword(),
-        AuthorityUtils.commaSeparatedStringToAuthorityList(credentials.toString()));
-  }
-
-  /**
-   * @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;
-  }
-
-}
diff --git a/web/src/main/webapp/WEB-INF/security-context.xml b/web/src/main/webapp/WEB-INF/security-context.xml
index 41c1b8c8345460bcd9bdaa0ae1320bfb3f61de05..783c154e311a0d08767859e8dcbfe5c707d8f3a1 100644
--- a/web/src/main/webapp/WEB-INF/security-context.xml
+++ b/web/src/main/webapp/WEB-INF/security-context.xml
@@ -72,10 +72,6 @@
 		<constructor-arg value="/login.xhtml"></constructor-arg>
 	</bean>
 	
-	<bean id="userDetailsService" class="lcsb.mapviewer.security.MvSecurityServiceImpl">
-		<property name="userService" ref="UserService" />
-	</bean>
-
 	<bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
   	<constructor-arg>
     	<list>
@@ -98,9 +94,8 @@
 	
 	<bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository"/>
 	
-	<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
-		<property name="userDetailsService" ref="userDetailsService" />
-		<property name="passwordEncoder" ref="PasswordEncoder" />
+	<bean id="authenticationProvider" class="lcsb.mapviewer.security.CustomAuthenticationProvider">
+		<property name="userService" ref="UserService" />
 	</bean>
 		
 	<security:authentication-manager alias="authenticationManager">