From feb9892f1fed250c7d267a360c5dacae37ba6104 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Tue, 5 Nov 2019 11:41:47 +0100
Subject: [PATCH] import of structural state added

---
 CHANGELOG                                     |  2 +
 .../model/sbgnml/SbgnmlXmlParser.java         | 47 ++++++++++++++-----
 .../model/sbgnml/SbgnmlXmlParserTest2.java    | 14 +++++-
 .../stateVariable.sbgn                        | 13 +++++
 4 files changed, 62 insertions(+), 14 deletions(-)
 create mode 100644 converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/stateVariable.sbgn

diff --git a/CHANGELOG b/CHANGELOG
index 494b81d535..463eb98d64 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,8 @@
 minerva (15.0.0~alpha.1) stable; urgency=medium
   * Small improvement: sort order of tables in admin panel is preserved among
     sessions (#836)
+  * Bug fix: structural states of proteins are imported properly from SBGNML PD
+    (#995)
 
 minerva (15.0.0~alpha.0) stable; urgency=medium
   * Improvement: logs provided for validation data model are structurized (#325)
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 eb83df8f67..598553d58c 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
@@ -585,10 +585,20 @@ public class SbgnmlXmlParser {
     for (Glyph child : children) {
       if (GlyphClazz.fromClazz(child.getClazz()).equals(GlyphClazz.STATE_VARIABLE)) {
         if (child.getState() == null || child.getState().getVariable() != null) {
-          try {
-            parseStateVariable(child, newSpecies);
-          } catch (Exception ex) {
-            logger.warn(ex.getMessage());
+          Residue residue = stateVariableToResidue(child);
+          if (residue != null) {
+            if (newSpecies instanceof Protein) {
+              ((Protein) newSpecies).addResidue(residue);
+            } else {
+              logger.warn("Only macromolecule elements can have state variables.");
+            }
+          } else {
+            StructuralState state = stateVariableToStructuralState(child);
+            if (newSpecies instanceof Protein) {
+              ((Protein) newSpecies).setStructuralState(state);
+            } else {
+              logger.warn("Only macromolecule elements can have state.");
+            }
           }
         } else {
           if (newSpecies instanceof Protein) {
@@ -610,6 +620,20 @@ public class SbgnmlXmlParser {
 
   }
 
+  private StructuralState stateVariableToStructuralState(Glyph glyph) {
+    StructuralState state = new StructuralState();
+
+    state.setFontSize(10);
+    state.setPosition(new Point2D.Double(glyph.getBbox().getX(), glyph.getBbox().getY()));
+    state.setHeight((double) glyph.getBbox().getH());
+    state.setWidth((double) glyph.getBbox().getW());
+    if (glyph.getState() != null) {
+      state.setValue(glyph.getState().getValue());
+    }
+
+    return state;
+  }
+
   private StructuralState createStructuralState(Glyph glyph) {
     StructuralState structuralState = new StructuralState();
 
@@ -775,20 +799,19 @@ public class SbgnmlXmlParser {
    * 
    * @param unitOfInformationGlyph
    *          unit of information glyph from sbgn-ml file
-   * @param species
-   *          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, Species species) {
-    if (!(species instanceof Protein)) {
-      throw new InvalidArgumentException("Only macromolecule elements can have state variables.");
+  private Residue stateVariableToResidue(Glyph unitOfInformationGlyph) {
+    if (unitOfInformationGlyph.getState() != null && (unitOfInformationGlyph.getState().getVariable() == null
+        || unitOfInformationGlyph.getState().getVariable().trim().isEmpty())) {
+      return null;
+
     }
-    Protein protein = (Protein) species;
+
     Residue mr = new Residue();
 
-    mr.setSpecies(protein);
     mr.setIdModificationResidue(unitOfInformationGlyph.getId());
     if (unitOfInformationGlyph.getState() != null) {
       // If State variable consists of value and variable
@@ -806,7 +829,7 @@ public class SbgnmlXmlParser {
 
     mr.setPosition(new Point2D.Double(x, y));
 
-    protein.addResidue(mr);
+    return mr;
   }
 
   /**
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
index b0168dd398..2d0019add6 100644
--- 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
@@ -14,8 +14,7 @@ import lcsb.mapviewer.converter.ConverterParams;
 import lcsb.mapviewer.model.map.compartment.Compartment;
 import lcsb.mapviewer.model.map.model.Model;
 import lcsb.mapviewer.model.map.reaction.*;
-import lcsb.mapviewer.model.map.species.Complex;
-import lcsb.mapviewer.model.map.species.GenericProtein;
+import lcsb.mapviewer.model.map.species.*;
 import lcsb.mapviewer.model.map.species.field.Residue;
 
 public class SbgnmlXmlParserTest2 extends SbgnmlTestFunctions {
@@ -105,4 +104,15 @@ public class SbgnmlXmlParserTest2 extends SbgnmlTestFunctions {
     assertEquals(p2.getLine().getBeginPoint(), outputOperator.getLine().getBeginPoint());
   }
 
+  @Test
+  public void testProteinState() throws Exception {
+    Converter converter = new SbgnmlXmlConverter();
+    Model model = converter
+        .createModel(new ConverterParams().filename("testFiles/sbgnmlCellDesignerInompatible/stateVariable.sbgn"));
+    
+    Protein protein = model.getElementByElementId("glyph_n20");
+    assertEquals("inactive", protein.getStructuralState().getValue());
+    assertEquals(0, protein.getModificationResidues().size());
+  }
+
 }
diff --git a/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/stateVariable.sbgn b/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/stateVariable.sbgn
new file mode 100644
index 0000000000..c43a2b8f4e
--- /dev/null
+++ b/converter-SBGNML/testFiles/sbgnmlCellDesignerInompatible/stateVariable.sbgn
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<sbgn xmlns="http://sbgn.org/libsbgn/0.2">
+    <map language="process description">
+        <glyph class="macromolecule" id="glyph_n20">
+            <label text="PKA"/>
+            <bbox w="80.0" h="40.0" x="662.7319" y="21.57837"/>
+            <glyph class="state variable" id="glyph_n20_4">
+                <state value="inactive" variable=""/>
+                <bbox w="50.0" h="18.0" x="677.7319" y="51.86792"/>
+            </glyph>
+        </glyph>
+    </map>
+</sbgn>
\ No newline at end of file
-- 
GitLab