From d0e6a01dfd542c5e1f5bfe4870b96dbc8d54aebb Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Fri, 21 Dec 2018 09:32:25 +0100
Subject: [PATCH] data overlay upload process color schema type properly

---
 .../lcsb/mapviewer/common/TextFileUtils.java  |  84 ++++-----
 .../model/map/layout/ColorSchemaType.java     |  19 ++
 .../mapviewer/model/map/layout/Layout.java    |  15 ++
 ....20181221__overlay_type_property_added.sql |   1 +
 .../configuration/ConfigurationRestImpl.java  |   4 +-
 .../api/projects/models/ModelRestImpl.java    |   4 +-
 .../projects/overlays/OverlayController.java  |  33 ++--
 .../projects/overlays/OverlayRestImpl.java    |   2 +-
 .../overlays/OverlayRestImplTest.java         |   2 +-
 .../services/impl/LayoutService.java          | 173 +++++++++---------
 .../services/interfaces/ILayoutService.java   |   2 +-
 .../services/utils/ColorSchemaReader.java     |  31 +++-
 .../utils/data/ColorSchemaColumn.java         |   1 +
 .../services/utils/data/ColorSchemaType.java  |  21 ---
 .../services/impl/LayoutServiceTest.java      |  29 ++-
 .../coloring/gene_variants_without_type.txt   |   4 +
 16 files changed, 243 insertions(+), 182 deletions(-)
 create mode 100644 model/src/main/java/lcsb/mapviewer/model/map/layout/ColorSchemaType.java
 create mode 100644 persist/src/main/resources/db/migration/12.2.0~alpha.0/V12.2.0.20181221__overlay_type_property_added.sql
 delete mode 100644 service/src/main/java/lcsb/mapviewer/services/utils/data/ColorSchemaType.java
 create mode 100644 service/testFiles/coloring/gene_variants_without_type.txt

diff --git a/commons/src/main/java/lcsb/mapviewer/common/TextFileUtils.java b/commons/src/main/java/lcsb/mapviewer/common/TextFileUtils.java
index 824ae83c93..3f0b8226e2 100644
--- a/commons/src/main/java/lcsb/mapviewer/common/TextFileUtils.java
+++ b/commons/src/main/java/lcsb/mapviewer/common/TextFileUtils.java
@@ -15,50 +15,50 @@ import java.util.Map;
  */
 public final class TextFileUtils {
 
-	/**
-	 * Name of the param that contains number of columns.
-	 */
-	public static final String COLUMN_COUNT_PARAM = "__COLUMN_COUNT";
+  /**
+   * Name of the param that contains number of columns.
+   */
+  public static final String COLUMN_COUNT_PARAM = "__COLUMN_COUNT";
 
-	/**
-	 * Default constructor that prevents instatiation.
-	 */
-	private TextFileUtils() {
+  /**
+   * Default constructor that prevents instatiation.
+   */
+  private TextFileUtils() {
 
-	}
+  }
 
-	/**
-	 * Parses input stream to get parameters from header. {@link InputStream}
-	 * should be a text file. Header parameters are lines at the beginning of the
-	 * file starting with '#' character.
-	 * 
-	 * @param is
-	 *          input stream for a file to process
-	 * @return map with paramteres parsed from input stream
-	 * @throws IOException
-	 *           thrown when there is a problem with accessing input stream
-	 */
-	public static Map<String, String> getHeaderParametersFromFile(InputStream is) throws IOException {
-		Map<String, String> result = new HashMap<String, String>();
-		BufferedReader in = new BufferedReader(new InputStreamReader(is));
-		String line = null;
-		while ((line = in.readLine()) != null) {
-			if (line.startsWith("#")) {
-				String tmp = line.substring(1);
-				if (tmp.indexOf("=") > 0) {
-					String key = tmp.substring(0, tmp.indexOf("=")).trim();
-					String value = tmp.substring(tmp.indexOf("=") + 1).trim();
-					result.put(key, value);
-				}
-			} else {
-				String key = COLUMN_COUNT_PARAM;
-				String value = line.split("\t").length + "";
-				result.put(key, value);
-				break;
-			}
-		}
-		is.close();
-		return result;
-	}
+  /**
+   * Parses input stream to get parameters from header. {@link InputStream} should
+   * be a text file. Header parameters are lines at the beginning of the file
+   * starting with '#' character.
+   * 
+   * @param is
+   *          input stream for a file to process
+   * @return map with parameters parsed from input stream
+   * @throws IOException
+   *           thrown when there is a problem with accessing input stream
+   */
+  public static Map<String, String> getHeaderParametersFromFile(InputStream is) throws IOException {
+    Map<String, String> result = new HashMap<>();
+    BufferedReader in = new BufferedReader(new InputStreamReader(is));
+    String line = null;
+    while ((line = in.readLine()) != null) {
+      if (line.startsWith("#")) {
+        String tmp = line.substring(1);
+        if (tmp.indexOf("=") > 0) {
+          String key = tmp.substring(0, tmp.indexOf("=")).trim();
+          String value = tmp.substring(tmp.indexOf("=") + 1).trim();
+          result.put(key, value);
+        }
+      } else {
+        String key = COLUMN_COUNT_PARAM;
+        String value = line.split("\t").length + "";
+        result.put(key, value);
+        break;
+      }
+    }
+    is.close();
+    return result;
+  }
 
 }
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/layout/ColorSchemaType.java b/model/src/main/java/lcsb/mapviewer/model/map/layout/ColorSchemaType.java
new file mode 100644
index 0000000000..1c0072a4ed
--- /dev/null
+++ b/model/src/main/java/lcsb/mapviewer/model/map/layout/ColorSchemaType.java
@@ -0,0 +1,19 @@
+package lcsb.mapviewer.model.map.layout;
+
+/**
+ * Type of the {@link ColorSchema}.
+ * 
+ * @author Piotr Gawron
+ *
+ */
+public enum ColorSchemaType {
+  /**
+   * Generic color schema (used for expression levels, etc).
+   */
+  GENERIC,
+
+  /**
+   * Customized color schema used for highlighting genetic variants.
+   */
+  GENETIC_VARIANT
+}
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/layout/Layout.java b/model/src/main/java/lcsb/mapviewer/model/map/layout/Layout.java
index 6e51b69dc6..4e3537e542 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/layout/Layout.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/layout/Layout.java
@@ -91,6 +91,13 @@ public class Layout implements Serializable {
 
   private boolean googleLicenseConsent = false;
 
+  /**
+   * Data overlay type. It can be null in such case it should be obtained from
+   * {@link #inputData}.
+   */
+  @Enumerated(EnumType.STRING)
+  private ColorSchemaType colorSchemaType = null;
+
   /**
    * If overlay contain hierarchical view then it might be fixed on some specific
    * level. This parameter defines the level at which it's fixed or contains null
@@ -421,4 +428,12 @@ public class Layout implements Serializable {
     this.dataOverlayImageLayers = dataOverlayImageLayers;
   }
 
+  public ColorSchemaType getColorSchemaType() {
+    return colorSchemaType;
+  }
+
+  public void setColorSchemaType(ColorSchemaType colorSchemaType) {
+    this.colorSchemaType = colorSchemaType;
+  }
+
 }
diff --git a/persist/src/main/resources/db/migration/12.2.0~alpha.0/V12.2.0.20181221__overlay_type_property_added.sql b/persist/src/main/resources/db/migration/12.2.0~alpha.0/V12.2.0.20181221__overlay_type_property_added.sql
new file mode 100644
index 0000000000..dcf1b3feb5
--- /dev/null
+++ b/persist/src/main/resources/db/migration/12.2.0~alpha.0/V12.2.0.20181221__overlay_type_property_added.sql
@@ -0,0 +1 @@
+alter table layout_table add column color_schema_type character varying(255);
\ No newline at end of file
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationRestImpl.java
index ade1476684..3030964b4d 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/configuration/ConfigurationRestImpl.java
@@ -1,8 +1,6 @@
 package lcsb.mapviewer.api.configuration;
 
-import java.io.File;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -28,6 +26,7 @@ import lcsb.mapviewer.converter.graphics.ImageGenerators;
 import lcsb.mapviewer.model.graphics.MapCanvasType;
 import lcsb.mapviewer.model.map.MiriamType;
 import lcsb.mapviewer.model.map.kinetics.SbmlUnitType;
+import lcsb.mapviewer.model.map.layout.ColorSchemaType;
 import lcsb.mapviewer.model.map.model.SubmodelType;
 import lcsb.mapviewer.model.map.reaction.Reaction;
 import lcsb.mapviewer.model.map.species.Element;
@@ -39,7 +38,6 @@ import lcsb.mapviewer.modelutils.map.ClassTreeNode;
 import lcsb.mapviewer.modelutils.map.ElementUtils;
 import lcsb.mapviewer.services.SecurityException;
 import lcsb.mapviewer.services.interfaces.IConfigurationService;
-import lcsb.mapviewer.services.utils.data.ColorSchemaType;
 
 @Transactional
 @Service
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java
index e89cc3a92b..98534da8ff 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/models/ModelRestImpl.java
@@ -238,7 +238,7 @@ public class ModelRestImpl extends BaseRestImpl {
       Layout overlay = layoutService.getLayoutById(Integer.parseInt(overlayId.trim()), token);
 
       ColorSchemaReader reader = new ColorSchemaReader();
-      Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent());
+      Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent(), overlay.getColorSchemaType());
 
       new ColorModelCommand(part, schemas, getUserService().getColorExtractorForUser(user)).execute();
     }
@@ -328,7 +328,7 @@ public class ModelRestImpl extends BaseRestImpl {
     if (overlay != null) {
       if (overlay.getInputData() != null) {
         ColorSchemaReader reader = new ColorSchemaReader();
-        Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent());
+        Collection<ColorSchema> schemas = reader.readColorSchema(overlay.getInputData().getFileContent(), overlay.getColorSchemaType());
 
         new ColorModelCommand(colorModel, schemas, getUserService().getColorExtractorForUser(user)).execute();
       } else if (overlay.getTitle().equals(BuildInLayout.CLEAN.getTitle())) {
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayController.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayController.java
index 6fc3eeb591..39de15b080 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayController.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayController.java
@@ -43,8 +43,8 @@ public class OverlayController extends BaseController {
       @CookieValue(value = Configuration.AUTH_TOKEN) String token,
       @PathVariable(value = "projectId") String projectId,
       @RequestParam(value = "creator", defaultValue = "") String creator,
-      @RequestParam(value = "publicOverlay", defaultValue = "") String publicOverlay
-  ) throws SecurityException, QueryException {
+      @RequestParam(value = "publicOverlay", defaultValue = "") String publicOverlay)
+      throws SecurityException, QueryException {
     return overlayRestImp.getOverlayList(token, projectId, creator, publicOverlay);
   }
 
@@ -53,8 +53,7 @@ public class OverlayController extends BaseController {
   public Map<String, Object> getOverlayById(
       @CookieValue(value = Configuration.AUTH_TOKEN) String token,
       @PathVariable(value = "projectId") String projectId,
-      @PathVariable(value = "overlayId") String overlayId
-  ) throws SecurityException, QueryException {
+      @PathVariable(value = "overlayId") String overlayId) throws SecurityException, QueryException {
     return overlayRestImp.getOverlayById(token, projectId, overlayId);
   }
 
@@ -76,8 +75,7 @@ public class OverlayController extends BaseController {
       @PathVariable(value = "modelId") String modelId,
       @PathVariable(value = "overlayId") String overlayId,
       @PathVariable(value = "reactionId") String reactionId,
-      @RequestParam(value = "columns", defaultValue = "") String columns
-  ) throws SecurityException, QueryException {
+      @RequestParam(value = "columns", defaultValue = "") String columns) throws SecurityException, QueryException {
     return overlayRestImp.getOverlayElement(token, projectId, Integer.valueOf(modelId), Integer.valueOf(overlayId),
         Integer.valueOf(reactionId), "REACTION", columns);
   }
@@ -90,8 +88,7 @@ public class OverlayController extends BaseController {
       @PathVariable(value = "modelId") String modelId,
       @PathVariable(value = "overlayId") String overlayId,
       @PathVariable(value = "elementId") String reactionId,
-      @RequestParam(value = "columns", defaultValue = "") String columns
-  ) throws SecurityException, QueryException {
+      @RequestParam(value = "columns", defaultValue = "") String columns) throws SecurityException, QueryException {
     return overlayRestImp.getOverlayElement(token, projectId, Integer.valueOf(modelId), Integer.valueOf(overlayId),
         Integer.valueOf(reactionId), "ALIAS", columns);
   }
@@ -106,10 +103,11 @@ public class OverlayController extends BaseController {
       @RequestParam(value = "content", defaultValue = "") String content,
       @RequestParam(value = "fileId", defaultValue = "") String fileId,
       @RequestParam(value = "filename") String filename,
-            @RequestParam(value = "googleLicenseConsent") String googleLicenseConsent,
-      @RequestParam(value = "type", defaultValue = "") String type
-  ) throws SecurityException, QueryException, IOException {
-    return overlayRestImp.addOverlay(token, projectId, name, description, content, fileId, filename, type, googleLicenseConsent);
+      @RequestParam(value = "googleLicenseConsent") String googleLicenseConsent,
+      @RequestParam(value = "type", defaultValue = "") String type)
+      throws SecurityException, QueryException, IOException {
+    return overlayRestImp.addOverlay(token, projectId, name, description, content, fileId, filename, type,
+        googleLicenseConsent);
   }
 
   @RequestMapping(value = "/projects/{projectId}/overlays/{overlayId}", method = { RequestMethod.DELETE }, produces = {
@@ -117,8 +115,7 @@ public class OverlayController extends BaseController {
   public Map<String, Object> removeOverlay(
       @CookieValue(value = Configuration.AUTH_TOKEN) String token,
       @PathVariable(value = "projectId") String projectId,
-      @PathVariable(value = "overlayId") String overlayId
-  ) throws SecurityException, QueryException, IOException {
+      @PathVariable(value = "overlayId") String overlayId) throws SecurityException, QueryException, IOException {
     return overlayRestImp.removeOverlay(token, projectId, overlayId);
   }
 
@@ -128,8 +125,8 @@ public class OverlayController extends BaseController {
       @RequestBody String body,
       @PathVariable(value = "projectId") String projectId,
       @PathVariable(value = "overlayId") String overlayId,
-      @CookieValue(value = Configuration.AUTH_TOKEN) String token
-  ) throws SecurityException, QueryException, IOException {
+      @CookieValue(value = Configuration.AUTH_TOKEN) String token)
+      throws SecurityException, QueryException, IOException {
     Map<String, Object> node = parseBody(body);
     Map<String, Object> data = getData(node, "overlay");
     return overlayRestImp.updateOverlay(token, projectId, overlayId, data);
@@ -140,8 +137,8 @@ public class OverlayController extends BaseController {
   public ResponseEntity<byte[]> getOverlaySource(
       @CookieValue(value = Configuration.AUTH_TOKEN) String token,
       @PathVariable(value = "projectId") String projectId,
-      @PathVariable(value = "overlayId") String overlayId
-  ) throws SecurityException, QueryException, JsonParseException, JsonMappingException, IOException {
+      @PathVariable(value = "overlayId") String overlayId)
+      throws SecurityException, QueryException, JsonParseException, JsonMappingException, IOException {
 
     FileEntry file = overlayRestImp.getOverlaySource(token, projectId, overlayId);
     MediaType type = MediaType.TEXT_PLAIN;
diff --git a/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImpl.java b/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImpl.java
index 000bbc3e3f..88c1282aa5 100644
--- a/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImpl.java
+++ b/rest-api/src/main/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImpl.java
@@ -28,6 +28,7 @@ import lcsb.mapviewer.model.cache.FileEntry;
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
 import lcsb.mapviewer.model.map.BioEntity;
 import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.layout.ColorSchemaType;
 import lcsb.mapviewer.model.map.layout.DataOverlayImageLayer;
 import lcsb.mapviewer.model.map.layout.GeneVariationColorSchema;
 import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
@@ -42,7 +43,6 @@ import lcsb.mapviewer.persist.dao.map.LayoutDao;
 import lcsb.mapviewer.services.SecurityException;
 import lcsb.mapviewer.services.interfaces.ILayoutService;
 import lcsb.mapviewer.services.interfaces.ILayoutService.CreateLayoutParams;
-import lcsb.mapviewer.services.utils.data.ColorSchemaType;
 
 @Transactional
 @Service
diff --git a/rest-api/src/test/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImplTest.java b/rest-api/src/test/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImplTest.java
index 51eef85b9c..7c940c37e3 100644
--- a/rest-api/src/test/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImplTest.java
+++ b/rest-api/src/test/java/lcsb/mapviewer/api/projects/overlays/OverlayRestImplTest.java
@@ -11,10 +11,10 @@ import com.google.gson.Gson;
 
 import lcsb.mapviewer.api.RestTestFunctions;
 import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.map.layout.ColorSchemaType;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.persist.dao.ProjectDao;
 import lcsb.mapviewer.services.interfaces.IProjectService;
-import lcsb.mapviewer.services.utils.data.ColorSchemaType;
 
 public class OverlayRestImplTest extends RestTestFunctions {
 
diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java b/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java
index b2d15f2747..54713f147b 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/LayoutService.java
@@ -29,6 +29,7 @@ import lcsb.mapviewer.common.exception.InvalidArgumentException;
 import lcsb.mapviewer.common.exception.InvalidStateException;
 import lcsb.mapviewer.converter.graphics.MapGenerator;
 import lcsb.mapviewer.converter.graphics.MapGenerator.MapGeneratorParams;
+import lcsb.mapviewer.converter.zip.ZipEntryFileFactory;
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
 import lcsb.mapviewer.model.map.BioEntity;
@@ -392,11 +393,14 @@ public class LayoutService implements ILayoutService {
         return topLayout;
     }
 
-    @Override
-    public Layout createLayout(final CreateLayoutParams params) throws IOException, InvalidColorSchemaException {
-        ColorSchemaReader reader = new ColorSchemaReader();
-        final Collection<ColorSchema> schemas = reader.readColorSchema(params.getColorInputStream(),
-                TextFileUtils.getHeaderParametersFromFile(params.getColorInputStream()));
+  @Override
+  public Layout createLayout(final CreateLayoutParams params) throws IOException, InvalidColorSchemaException {
+    ColorSchemaReader reader = new ColorSchemaReader();
+    Map<String, String> parameters = TextFileUtils.getHeaderParametersFromFile(params.getColorInputStream());
+    if (params.getColorSchemaType() != null) {
+      parameters.put(ZipEntryFileFactory.LAYOUT_HEADER_PARAM_TYPE, params.getColorSchemaType().name());
+    }
+    final Collection<ColorSchema> schemas = reader.readColorSchema(params.getColorInputStream(), parameters);
 
     // check if we can color our model using this schema,
     // if not then exception will be thrown and passed up
@@ -411,6 +415,7 @@ public class LayoutService implements ILayoutService {
     layoutDao.flush();
 
     Layout topLayout = new Layout(params.getName(), false);
+    topLayout.setColorSchemaType(params.getColorSchemaType());
     if (params.getUser() == null) {
       topLayout.setPublicLayout(true);
     } else {
@@ -792,71 +797,76 @@ public class LayoutService implements ILayoutService {
         }
     }
 
-    @Override
-    public List<Pair<Element, ColorSchema>> getAliasesForLayout(Model model, int layoutId, String token)
-            throws SecurityException {
-        try {
-            ColorSchemaReader reader = new ColorSchemaReader();
-            Collection<ColorSchema> schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
-            // colors here are not important
-            ColorModelCommand command = new ColorModelCommand(model, schemas,
-                    new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
-            List<Pair<Element, ColorSchema>> result = new ArrayList<>();
-            for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
-                if (entry.getKey() instanceof Element) {
-                    result.add(new Pair<Element, ColorSchema>((Element) entry.getKey(), entry.getValue()));
-                }
-            }
-            result.sort(LayoutService.ELEMENT_PAIR_COMPARATOR);
-            return result;
-        } catch (InvalidColorSchemaException e) {
-            throw new InvalidStateException(e);
-        } catch (IOException e) {
-            throw new InvalidStateException(e);
+  @Override
+  public List<Pair<Element, ColorSchema>> getAliasesForLayout(Model model, int layoutId, String token)
+      throws SecurityException {
+    try {
+      Collection<ColorSchema> schemas = createColorSchemaCollection(layoutId, token);
+      // colors here are not important
+      ColorModelCommand command = new ColorModelCommand(model, schemas,
+          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
+      List<Pair<Element, ColorSchema>> result = new ArrayList<>();
+      for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
+        if (entry.getKey() instanceof Element) {
+          result.add(new Pair<Element, ColorSchema>((Element) entry.getKey(), entry.getValue()));
         }
+      }
+      result.sort(LayoutService.ELEMENT_PAIR_COMPARATOR);
+      return result;
+    } catch (InvalidColorSchemaException e) {
+      throw new InvalidStateException(e);
+    } catch (IOException e) {
+      throw new InvalidStateException(e);
     }
+  }
 
-    @Override
-    public List<Pair<Reaction, ColorSchema>> getReactionsForLayout(Model model, int layoutId, String token)
-            throws SecurityException {
-        try {
-            ColorSchemaReader reader = new ColorSchemaReader();
-            Collection<ColorSchema> schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
-            // colors here are not important
-            ColorModelCommand command = new ColorModelCommand(model, schemas,
-                    new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
-            List<Pair<Reaction, ColorSchema>> result = new ArrayList<>();
-            for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
-                if (entry.getKey() instanceof Reaction) {
-                    result.add(new Pair<Reaction, ColorSchema>((Reaction) entry.getKey(), entry.getValue()));
-                }
-            }
-            result.sort(LayoutService.ELEMENT_PAIR_COMPARATOR);
-            return result;
-        } catch (InvalidColorSchemaException e) {
-            throw new InvalidStateException(e);
-        } catch (IOException e) {
-            throw new InvalidStateException(e);
+  private Collection<ColorSchema> createColorSchemaCollection(int overlayId, String token)
+      throws IOException, InvalidColorSchemaException, SecurityException {
+    ColorSchemaReader reader = new ColorSchemaReader();
+    Layout overlay = getLayoutById(overlayId, token);
+    Collection<ColorSchema> schemas = reader.readColorSchema(getInputDataForLayout(overlayId, token),
+        overlay.getColorSchemaType());
+    return schemas;
+  }
+
+  @Override
+  public List<Pair<Reaction, ColorSchema>> getReactionsForLayout(Model model, int layoutId, String token)
+      throws SecurityException {
+    try {
+      Collection<ColorSchema> schemas = createColorSchemaCollection(layoutId, token);
+      // colors here are not important
+      ColorModelCommand command = new ColorModelCommand(model, schemas,
+          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
+      List<Pair<Reaction, ColorSchema>> result = new ArrayList<>();
+      for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
+        if (entry.getKey() instanceof Reaction) {
+          result.add(new Pair<Reaction, ColorSchema>((Reaction) entry.getKey(), entry.getValue()));
         }
+      }
+      result.sort(LayoutService.ELEMENT_PAIR_COMPARATOR);
+      return result;
+    } catch (InvalidColorSchemaException e) {
+      throw new InvalidStateException(e);
+    } catch (IOException e) {
+      throw new InvalidStateException(e);
     }
+  }
 
-    @Override
-    public Map<Object, ColorSchema> getElementsForLayout(Model model, Integer layoutId, String token)
-            throws SecurityException {
-        try {
-            ColorSchemaReader reader = new ColorSchemaReader();
-            Collection<ColorSchema> schemas;
-            schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
-            // colors here are not important
-            ColorModelCommand command = new ColorModelCommand(model, schemas,
-                    new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
-            return command.getModifiedElements();
-        } catch (InvalidColorSchemaException e) {
-            throw new InvalidStateException(e);
-        } catch (IOException e) {
-            throw new InvalidStateException(e);
-        }
+  @Override
+  public Map<Object, ColorSchema> getElementsForLayout(Model model, Integer layoutId, String token)
+      throws SecurityException {
+    try {
+      Collection<ColorSchema> schemas = createColorSchemaCollection(layoutId, token);
+      // colors here are not important
+      ColorModelCommand command = new ColorModelCommand(model, schemas,
+          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
+      return command.getModifiedElements();
+    } catch (InvalidColorSchemaException e) {
+      throw new InvalidStateException(e);
+    } catch (IOException e) {
+      throw new InvalidStateException(e);
     }
+  }
 
     @Override
     public EmailSender getEmailSender() {
@@ -902,16 +912,15 @@ public class LayoutService implements ILayoutService {
         return layout;
     }
 
-    @Override
-    public Pair<Element, ColorSchema> getFullAliasForLayout(Model model, Integer id, int layoutId, String token)
-            throws SecurityException {
-        try {
-            ColorSchemaReader reader = new ColorSchemaReader();
-            Collection<ColorSchema> schemas;
-            schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
-            // colors here are not important
-            ColorModelCommand command = new ColorModelCommand(model, schemas,
-                    new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
+  @Override
+  public Pair<Element, ColorSchema> getFullAliasForLayout(Model model, Integer id, int layoutId, String token)
+      throws SecurityException {
+    try {
+      ColorSchemaReader reader = new ColorSchemaReader();
+      Collection<ColorSchema> schemas = createColorSchemaCollection(layoutId, token);
+      // colors here are not important
+      ColorModelCommand command = new ColorModelCommand(model, schemas,
+          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
 
             for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
                 if (entry.getKey() instanceof Element) {
@@ -929,16 +938,14 @@ public class LayoutService implements ILayoutService {
         }
     }
 
-    @Override
-    public Pair<Reaction, ColorSchema> getFullReactionForLayout(Model model, Integer id, int layoutId, String token)
-            throws SecurityException {
-        try {
-            ColorSchemaReader reader = new ColorSchemaReader();
-            Collection<ColorSchema> schemas;
-            schemas = reader.readColorSchema(getInputDataForLayout(layoutId, token));
-            // colors here are not important
-            ColorModelCommand command = new ColorModelCommand(model, schemas,
-                    new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
+  @Override
+  public Pair<Reaction, ColorSchema> getFullReactionForLayout(Model model, Integer id, int layoutId, String token)
+      throws SecurityException {
+    try {
+      Collection<ColorSchema> schemas = createColorSchemaCollection(layoutId, token);
+      // colors here are not important
+      ColorModelCommand command = new ColorModelCommand(model, schemas,
+          new ColorExtractor(Color.BLACK, Color.BLACK, Color.BLACK));
 
             for (Map.Entry<Object, ColorSchema> entry : command.getModifiedElements().entrySet()) {
                 if (entry.getKey() instanceof Reaction) {
diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/ILayoutService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/ILayoutService.java
index 11f129385e..6901b0297a 100644
--- a/service/src/main/java/lcsb/mapviewer/services/interfaces/ILayoutService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/ILayoutService.java
@@ -11,6 +11,7 @@ import lcsb.mapviewer.commands.CommandExecutionException;
 import lcsb.mapviewer.common.Pair;
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.layout.ColorSchemaType;
 import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
 import lcsb.mapviewer.model.map.layout.Layout;
 import lcsb.mapviewer.model.map.model.Model;
@@ -20,7 +21,6 @@ import lcsb.mapviewer.model.user.User;
 import lcsb.mapviewer.persist.dao.map.LayoutDao;
 import lcsb.mapviewer.services.SecurityException;
 import lcsb.mapviewer.services.utils.EmailSender;
-import lcsb.mapviewer.services.utils.data.ColorSchemaType;
 
 /**
  * Service that manages layouts of the map.
diff --git a/service/src/main/java/lcsb/mapviewer/services/utils/ColorSchemaReader.java b/service/src/main/java/lcsb/mapviewer/services/utils/ColorSchemaReader.java
index 983d3f3b82..9b77d4d774 100644
--- a/service/src/main/java/lcsb/mapviewer/services/utils/ColorSchemaReader.java
+++ b/service/src/main/java/lcsb/mapviewer/services/utils/ColorSchemaReader.java
@@ -8,7 +8,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -31,6 +30,7 @@ import lcsb.mapviewer.converter.zip.ZipEntryFileFactory;
 import lcsb.mapviewer.model.map.MiriamData;
 import lcsb.mapviewer.model.map.MiriamType;
 import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.layout.ColorSchemaType;
 import lcsb.mapviewer.model.map.layout.GeneVariation;
 import lcsb.mapviewer.model.map.layout.GeneVariationColorSchema;
 import lcsb.mapviewer.model.map.layout.GenericColorSchema;
@@ -38,7 +38,6 @@ import lcsb.mapviewer.model.map.layout.InvalidColorSchemaException;
 import lcsb.mapviewer.model.map.layout.ReferenceGenomeType;
 import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.services.utils.data.ColorSchemaColumn;
-import lcsb.mapviewer.services.utils.data.ColorSchemaType;
 
 /**
  * Class that reads information about set of {@link ColorSchema color schemas}
@@ -726,9 +725,19 @@ public class ColorSchemaReader {
    * @throws InvalidColorSchemaException
    *           thrown when color schema is invalid
    */
-  public Collection<ColorSchema> readColorSchema(String filename) throws IOException, InvalidColorSchemaException {
-    return readColorSchema(new FileInputStream(filename),
-        TextFileUtils.getHeaderParametersFromFile(new FileInputStream(filename)));
+  public Collection<ColorSchema> readColorSchema(String filename, ColorSchemaType colorSchemaType)
+      throws IOException, InvalidColorSchemaException {
+    Map<String, String> params = TextFileUtils.getHeaderParametersFromFile(new FileInputStream(filename));
+    if (colorSchemaType != null) {
+      params.put(ZipEntryFileFactory.LAYOUT_HEADER_PARAM_TYPE, colorSchemaType.name());
+    }
+
+    return readColorSchema(new FileInputStream(filename), params);
+  }
+
+  Collection<ColorSchema> readColorSchema(String filename)
+      throws IOException, InvalidColorSchemaException {
+    return readColorSchema(filename, null);
   }
 
   /**
@@ -740,7 +749,7 @@ public class ColorSchemaReader {
    *         schemas)
    */
   public Collection<ColorSchemaColumn> getSetColorSchemaColumns(Collection<ColorSchema> schemas) {
-    Set<ColorSchemaColumn> result = new HashSet<ColorSchemaColumn>();
+    Set<ColorSchemaColumn> result = new HashSet<>();
     for (ColorSchema schema : schemas) {
       if (schema.getColor() != null) {
         result.add(ColorSchemaColumn.COLOR);
@@ -788,8 +797,12 @@ public class ColorSchemaReader {
    * @throws InvalidColorSchemaException
    *           thrown when color schema is invalid
    */
-  public Collection<ColorSchema> readColorSchema(byte[] inputData) throws IOException, InvalidColorSchemaException {
-    return readColorSchema(new ByteArrayInputStream(inputData),
-        TextFileUtils.getHeaderParametersFromFile(new ByteArrayInputStream(inputData)));
+  public Collection<ColorSchema> readColorSchema(byte[] inputData, ColorSchemaType colorSchemaType)
+      throws IOException, InvalidColorSchemaException {
+    Map<String, String> params = TextFileUtils.getHeaderParametersFromFile(new ByteArrayInputStream(inputData));
+    if (colorSchemaType != null) {
+      params.put(ZipEntryFileFactory.LAYOUT_HEADER_PARAM_TYPE, colorSchemaType.name());
+    }
+    return readColorSchema(new ByteArrayInputStream(inputData), params);
   }
 }
diff --git a/service/src/main/java/lcsb/mapviewer/services/utils/data/ColorSchemaColumn.java b/service/src/main/java/lcsb/mapviewer/services/utils/data/ColorSchemaColumn.java
index 6e593c9bf2..838eeda5fe 100644
--- a/service/src/main/java/lcsb/mapviewer/services/utils/data/ColorSchemaColumn.java
+++ b/service/src/main/java/lcsb/mapviewer/services/utils/data/ColorSchemaColumn.java
@@ -3,6 +3,7 @@ package lcsb.mapviewer.services.utils.data;
 import java.util.HashSet;
 import java.util.Set;
 
+import lcsb.mapviewer.model.map.layout.ColorSchemaType;
 import lcsb.mapviewer.model.map.layout.ReferenceGenome;
 import lcsb.mapviewer.model.map.layout.ReferenceGenomeType;
 
diff --git a/service/src/main/java/lcsb/mapviewer/services/utils/data/ColorSchemaType.java b/service/src/main/java/lcsb/mapviewer/services/utils/data/ColorSchemaType.java
deleted file mode 100644
index 108a4ce7b1..0000000000
--- a/service/src/main/java/lcsb/mapviewer/services/utils/data/ColorSchemaType.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package lcsb.mapviewer.services.utils.data;
-
-import lcsb.mapviewer.model.map.layout.ColorSchema;
-
-/**
- * Type of the {@link ColorSchema}.
- * 
- * @author Piotr Gawron
- *
- */
-public enum ColorSchemaType {
-	/**
-	 * Generic color schema (used for expression levels, etc).
-	 */
-	GENERIC,
-
-	/**
-	 * Customized color schema used for highlightig genetic variants.
-	 */
-	GENETIC_VARIANT
-}
diff --git a/service/src/test/java/lcsb/mapviewer/services/impl/LayoutServiceTest.java b/service/src/test/java/lcsb/mapviewer/services/impl/LayoutServiceTest.java
index 30aec7f828..9e2a8022b3 100644
--- a/service/src/test/java/lcsb/mapviewer/services/impl/LayoutServiceTest.java
+++ b/service/src/test/java/lcsb/mapviewer/services/impl/LayoutServiceTest.java
@@ -13,6 +13,7 @@ import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.log4j.Logger;
@@ -28,6 +29,8 @@ import lcsb.mapviewer.common.TextFileUtils;
 import lcsb.mapviewer.converter.ConverterParams;
 import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser;
 import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.map.layout.ColorSchema;
+import lcsb.mapviewer.model.map.layout.ColorSchemaType;
 import lcsb.mapviewer.model.map.layout.DataOverlayImageLayer;
 import lcsb.mapviewer.model.map.layout.ColorSchema;
 import lcsb.mapviewer.model.map.layout.GeneVariationColorSchema;
@@ -441,7 +444,7 @@ public class LayoutServiceTest extends ServiceTestFunctions {
 
       Model model = new CellDesignerXmlParser()
           .createModel(new ConverterParams().filename("testFiles/coloring/problematicModel2.xml"));
-      
+
       project.addModel(model);
       projectService.addProject(project);
 
@@ -497,4 +500,28 @@ public class LayoutServiceTest extends ServiceTestFunctions {
   }
 
 
+  @Test
+  public void testDataOverlayWithType() throws Exception {
+    try {
+      String layoutId = "Test";
+      userService.setUserPrivilege(user, new Privilege(1, PrivilegeType.CUSTOM_LAYOUTS, user));
+      CreateLayoutParams params = new CreateLayoutParams().name(layoutId).
+          directory("testDir").
+          project(project).
+          colorInputStream(new FileInputStream("testFiles/coloring/gene_variants_without_type.txt")).
+          user(user).colorSchemaType(ColorSchemaType.GENETIC_VARIANT);
+
+      Layout layout = layoutService.createLayout(params);
+      Map<Object, ColorSchema> result = layoutService.getElementsForLayout(model, layout.getId(), token);
+      assertNotNull(result);
+      layoutService.removeLayout(layout, null);
+
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+
 }
diff --git a/service/testFiles/coloring/gene_variants_without_type.txt b/service/testFiles/coloring/gene_variants_without_type.txt
new file mode 100644
index 0000000000..b58ad1bb26
--- /dev/null
+++ b/service/testFiles/coloring/gene_variants_without_type.txt
@@ -0,0 +1,4 @@
+#GENOME_TYPE=UCSC						
+#GENOME_VERSION=hg38						
+position	original_dna	alternative_dna	name	description	color	contig
+10146	AC	A	DDX11L1	upstream	#ff0000	chr1
-- 
GitLab