From c679cf77decd7a07fb0022ec63b41e0fd43c535c Mon Sep 17 00:00:00 2001
From: Piotr Gawron <p.gawron@atcomp.pl>
Date: Thu, 13 Mar 2025 15:10:48 +0100
Subject: [PATCH] export submodels

---
 .../lcsb/mapviewer/common/Comparator.java     |  2 +-
 .../common/comparator/SetComparator.java      | 16 +++----
 .../CellDesignerTestFunctions.java            | 16 +++++--
 .../model/celldesigner/ProjectExportTest.java | 43 ++++++++++++++++---
 .../mapviewer/converter/ProjectFactory.java   | 20 ++++++---
 .../mapviewer/model/ProjectComparator.java    |  5 ++-
 .../model/SubmodelConnectionComparator.java   | 19 ++++----
 7 files changed, 82 insertions(+), 39 deletions(-)

diff --git a/commons/src/main/java/lcsb/mapviewer/common/Comparator.java b/commons/src/main/java/lcsb/mapviewer/common/Comparator.java
index 772b161ba7..e908c2846b 100644
--- a/commons/src/main/java/lcsb/mapviewer/common/Comparator.java
+++ b/commons/src/main/java/lcsb/mapviewer/common/Comparator.java
@@ -9,7 +9,7 @@ import java.util.List;
 
 public abstract class Comparator<T extends Object> implements java.util.Comparator<T> {
   protected static Logger logger = LogManager.getLogger();
-  
+
   private final Class<T> comparatorClazz;
   private final boolean exactClassMatch;
   private final List<Comparator<? extends T>> subClassComparatorList = new ArrayList<>();
diff --git a/commons/src/main/java/lcsb/mapviewer/common/comparator/SetComparator.java b/commons/src/main/java/lcsb/mapviewer/common/comparator/SetComparator.java
index 1f178fbfcb..f237a1a15d 100644
--- a/commons/src/main/java/lcsb/mapviewer/common/comparator/SetComparator.java
+++ b/commons/src/main/java/lcsb/mapviewer/common/comparator/SetComparator.java
@@ -1,22 +1,21 @@
 package lcsb.mapviewer.common.comparator;
 
-import java.util.Comparator;
-import java.util.Set;
-
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import java.util.Comparator;
+import java.util.Set;
+
 /**
  * Comparator used for comparing sets of strings.
- * 
+ *
  * @author Piotr Gawron
- * 
  */
 public class SetComparator<T> implements Comparator<Set<T>> {
   /**
    * Default class logger.
    */
-  private Logger logger = LogManager.getLogger();
+  private final Logger logger = LogManager.getLogger();
 
   private Comparator<T> objectComparator;
 
@@ -41,6 +40,7 @@ public class SetComparator<T> implements Comparator<Set<T>> {
       for (final T objectInList0 : arg0) {
         if (objectComparator.compare(objectInList0, objectInList1) == 0) {
           found = true;
+          break;
         }
       }
       if (!found) {
@@ -54,11 +54,11 @@ public class SetComparator<T> implements Comparator<Set<T>> {
       for (final T objectInList1 : arg1) {
         if (objectComparator.compare(objectInList0, objectInList1) == 0) {
           found = true;
+          break;
         }
       }
       if (!found) {
-        new Exception().printStackTrace();
-        logger.debug("Cannot find object " + objectInList0 + " in set: " + arg1);
+        logger.debug("Cannot find object {} in set: {}", objectInList0, arg1);
         return 1;
       }
     }
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerTestFunctions.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerTestFunctions.java
index ca10f5af92..aa357bbda2 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerTestFunctions.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/CellDesignerTestFunctions.java
@@ -24,6 +24,7 @@ import lcsb.mapviewer.model.map.layout.graphics.Layer;
 import lcsb.mapviewer.model.map.layout.graphics.LayerText;
 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.species.Element;
 import lcsb.mapviewer.model.map.species.Gene;
@@ -91,13 +92,19 @@ public abstract class CellDesignerTestFunctions extends TestUtils {
     final InputStream is = new ByteArrayInputStream(xmlString.getBytes(StandardCharsets.UTF_8));
 
     final Model model2 = parser.createModel(new ConverterParams().inputStream(is, model.getName()).sizeAutoAdjust(false));
-    for (final Drawable bioEntity : model2.getDrawables()) {
-      bioEntity.setZ(null);
-    }
+    clearModelFromZ(model2);
+    clearModelFromZ(model);
+    return model2;
+  }
+
+  protected void clearModelFromZ(final Model model) {
     for (final Drawable bioEntity : model.getDrawables()) {
       bioEntity.setZ(null);
     }
-    return model2;
+  }
+
+  protected void clearModelFromZ(final ModelData modelData) {
+    clearModelFromZ(modelData.getModel());
   }
 
   private static int idCounter = 0;
@@ -246,6 +253,7 @@ public abstract class CellDesignerTestFunctions extends TestUtils {
 
   protected static Model createEmptyModel() {
     final Model model = new ModelFullIndexed(null);
+    model.setName(faker.witcher().monster());
     model.setIdModel("as");
     model.setWidth(100);
     model.setHeight(100);
diff --git a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ProjectExportTest.java b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ProjectExportTest.java
index e2a0795446..8b04264dc6 100644
--- a/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ProjectExportTest.java
+++ b/converter-CellDesigner/src/test/java/lcsb/mapviewer/converter/model/celldesigner/ProjectExportTest.java
@@ -2,12 +2,18 @@ package lcsb.mapviewer.converter.model.celldesigner;
 
 import lcsb.mapviewer.converter.ComplexZipConverter;
 import lcsb.mapviewer.converter.ComplexZipConverterParams;
+import lcsb.mapviewer.converter.ConverterException;
+import lcsb.mapviewer.converter.InvalidInputDataExecption;
 import lcsb.mapviewer.converter.ProjectFactory;
 import lcsb.mapviewer.converter.zip.ZipEntryFile;
 import lcsb.mapviewer.converter.zip.ZipEntryFileFactory;
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.ProjectComparator;
+import lcsb.mapviewer.model.map.InconsistentModelException;
 import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelData;
+import lcsb.mapviewer.model.map.model.ModelSubmodelConnection;
+import lcsb.mapviewer.model.map.model.SubmodelType;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -27,8 +33,13 @@ public class ProjectExportTest extends CellDesignerTestFunctions {
 
   private final ZipEntryFileFactory zefFactory = new ZipEntryFileFactory();
 
+  private ComplexZipConverter parser;
+  private ProjectFactory projectFactory;
+
   @Before
   public void setUp() throws Exception {
+    parser = new ComplexZipConverter(CellDesignerXmlParser.class);
+    projectFactory = new ProjectFactory(parser);
   }
 
   @After
@@ -41,22 +52,40 @@ public class ProjectExportTest extends CellDesignerTestFunctions {
     Model model = createEmptyModel();
     project.addModel(model);
 
-    final ComplexZipConverter parser = new ComplexZipConverter(CellDesignerXmlParser.class);
-    final ProjectFactory projectFactory = new ProjectFactory(parser);
+    testSerializationOverZip(project);
+  }
 
-    byte[] data = projectFactory.project2zip(project);
+  @Test
+  public void testWithManyModels() throws Exception {
+    Project project = createProject();
+    Model model = createEmptyModel();
+    project.addModel(model);
 
-    File tempFile = File.createTempFile("CD-", ".zip");
+    Model model2 = createEmptyModel();
+    model2.setWidth(260);
+    model2.addElement(createProtein());
+    project.addModel(model2);
+    model.addSubmodelConnection(new ModelSubmodelConnection(model2, SubmodelType.UNKNOWN, model2.getName()));
 
+    testSerializationOverZip(project);
+  }
+
+  private void testSerializationOverZip(final Project project) throws IOException, ConverterException, InconsistentModelException, InvalidInputDataExecption {
+    File tempFile = File.createTempFile("CD-", ".zip");
     try (FileOutputStream outputStream = new FileOutputStream(tempFile)) {
+      byte[] data = projectFactory.project2zip(project);
       outputStream.write(data);
     }
-    logger.debug(tempFile.getAbsolutePath());
-
     final ComplexZipConverterParams complexParams = createDefaultParams(tempFile);
-
     Project project2 = projectFactory.create(complexParams);
 
+    for (ModelData model : project.getModels()) {
+      clearModelFromZ(model);
+    }
+    for (ModelData model : project2.getModels()) {
+      clearModelFromZ(model);
+    }
+
     assertEquals(0, projectComparator.compare(project, project2));
   }
 
diff --git a/converter/src/main/java/lcsb/mapviewer/converter/ProjectFactory.java b/converter/src/main/java/lcsb/mapviewer/converter/ProjectFactory.java
index fe2b69e772..812e84783a 100644
--- a/converter/src/main/java/lcsb/mapviewer/converter/ProjectFactory.java
+++ b/converter/src/main/java/lcsb/mapviewer/converter/ProjectFactory.java
@@ -155,18 +155,26 @@ public class ProjectFactory {
 
   public byte[] project2zip(final Project project) throws ConverterException, InconsistentModelException {
     Converter converter = this.converter.createConverterInstance();
-    String topModelContent = converter.model2String(project.getTopModel());
 
     ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
     try (ZipOutputStream zos = new ZipOutputStream(byteArrayOutputStream)) {
-      ZipEntry entry = new ZipEntry(project.getTopModel().getName() + "." + converter.getFileExtensions().get(0));
-
-      zos.putNextEntry(entry);
-      zos.write(topModelContent.getBytes());
-      zos.closeEntry();
+      addModelFileToZip(project.getTopModel(), project.getTopModel().getName() + "." + converter.getFileExtensions().get(0), converter, zos);
+      for (ModelData model : project.getModels()) {
+        if (model != project.getTopModelData()) {
+          addModelFileToZip(model.getModel(), "submaps/" + model.getName() + "." + converter.getFileExtensions().get(0), converter, zos);
+        }
+      }
     } catch (IOException ioe) {
       throw new ConverterException(ioe);
     }
     return byteArrayOutputStream.toByteArray();
   }
+
+  private static void addModelFileToZip(final Model model, final String filename, final Converter converter, final ZipOutputStream zos) throws IOException, InconsistentModelException, ConverterException {
+    ZipEntry entry = new ZipEntry(filename);
+    zos.putNextEntry(entry);
+    String topModelContent = converter.model2String(model);
+    zos.write(topModelContent.getBytes());
+    zos.closeEntry();
+  }
 }
diff --git a/model/src/main/java/lcsb/mapviewer/model/ProjectComparator.java b/model/src/main/java/lcsb/mapviewer/model/ProjectComparator.java
index 0aa6694500..b1862ab796 100644
--- a/model/src/main/java/lcsb/mapviewer/model/ProjectComparator.java
+++ b/model/src/main/java/lcsb/mapviewer/model/ProjectComparator.java
@@ -28,9 +28,10 @@ public class ProjectComparator extends Comparator<Project> {
 
   @Override
   protected int internalCompare(final Project arg0, final Project arg1) {
-    if (modelComparator.compare(arg0.getTopModel(), arg1.getTopModel()) != 0) {
+    int compareResult = modelComparator.compare(arg0.getTopModel(), arg1.getTopModel());
+    if (compareResult != 0) {
       logger.debug("Top model different: {}, {}", arg0.getTopModel(), arg1.getTopModel());
-      return modelComparator.compare(arg0.getTopModel(), arg1.getTopModel());
+      return compareResult;
     }
 
     if (modelDataSetComparator.compare(arg0.getModels(), arg1.getModels()) != 0) {
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/model/SubmodelConnectionComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/model/SubmodelConnectionComparator.java
index ecbd93fbac..2cb72be7eb 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/model/SubmodelConnectionComparator.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/model/SubmodelConnectionComparator.java
@@ -1,36 +1,33 @@
 package lcsb.mapviewer.model.map.model;
 
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
 import lcsb.mapviewer.common.Comparator;
 import lcsb.mapviewer.common.Configuration;
 import lcsb.mapviewer.common.comparator.StringComparator;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 /**
  * This class implements comparator interface for {@link SubmodelConnection}. It
  * handles comparison of subclasses of {@link SubmodelConnection} class.
- * 
+ *
  * @author Piotr Gawron
- * 
  */
 public class SubmodelConnectionComparator extends Comparator<SubmodelConnection> {
 
   /**
    * Default class logger.
    */
-  private static Logger logger = LogManager.getLogger();
+  private static final Logger logger = LogManager.getLogger();
 
   /**
    * Epsilon value used for comparison of doubles.
    */
-  private double epsilon;
+  private final double epsilon;
 
   /**
    * Constructor that requires {@link #epsilon} parameter.
-   * 
-   * @param epsilon
-   *          {@link #epsilon}
+   *
+   * @param epsilon {@link #epsilon}
    */
   public SubmodelConnectionComparator(final double epsilon) {
     super(SubmodelConnection.class, true);
@@ -60,7 +57,7 @@ public class SubmodelConnectionComparator extends Comparator<SubmodelConnection>
     }
 
     if (stringComparator.compare(arg0.getName(), arg1.getName()) != 0) {
-      logger.debug("Name different: " + arg0.getName() + ", " + arg1.getName());
+      logger.debug("Name different: {}, {}", arg0.getName(), arg1.getName());
       return stringComparator.compare(arg0.getName(), arg1.getName());
     }
 
-- 
GitLab