JAL-3390 first pass refactoring for JalviewJmolBinding.showStructures
[jalview.git] / src / jalview / ext / rbvi / chimera / AtomSpecModel.java
index f923f7f..f0d1e84 100644 (file)
  */
 package jalview.ext.rbvi.chimera;
 
-import jalview.util.IntRangeComparator;
-
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
 /**
- * A class to model a Chimera atomspec pattern, for example
- * 
- * <pre>
- * #0:15.A,28.A,54.A,63.A,70-72.A,83-84.A,97-98.A|#1:2.A,6.A,11.A,13-14.A,70.A,82.A,96-97.A
- * </pre>
- * 
- * where
- * <ul>
- * <li>#0 is a model number</li>
- * <li>15 or 70-72 is a residue number, or range of residue numbers</li>
- * <li>.A is a chain identifier</li>
- * <li>residue ranges are separated by comma</li>
- * <li>atomspecs for distinct models are separated by | (or)</li>
- * </ul>
- * 
- * <pre>
- * &#64;see http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
- * </pre>
+ * A class to model a Chimera or Jmol residue set, as
+ * {@code Map<modelNumber, Map<chainId, List<residueRange>>>}. This can then be
+ * traversed to generate the required display command in Chimera or Jmol syntax.
  */
 public class AtomSpecModel
 {
@@ -58,7 +40,12 @@ public class AtomSpecModel
    */
   public AtomSpecModel()
   {
-    atomSpec = new TreeMap<Integer, Map<String, List<int[]>>>();
+    atomSpec = new TreeMap<>();
+  }
+
+  public Map<Integer, Map<String, List<int[]>>> getMap()
+  {
+    return atomSpec;
   }
 
   /**
@@ -77,7 +64,7 @@ public class AtomSpecModel
     Map<String, List<int[]>> modelData = atomSpec.get(model);
     if (modelData == null)
     {
-      atomSpec.put(model, modelData = new TreeMap<String, List<int[]>>());
+      atomSpec.put(model, modelData = new TreeMap<>());
     }
 
     /*
@@ -86,7 +73,7 @@ public class AtomSpecModel
     List<int[]> chainData = modelData.get(chain);
     if (chainData == null)
     {
-      chainData = new ArrayList<int[]>();
+      chainData = new ArrayList<>();
       modelData.put(chain, chainData);
     }
 
@@ -98,103 +85,42 @@ public class AtomSpecModel
   }
 
   /**
-   * Returns the range(s) formatted as a Chimera atomspec
+   * Answers an iterable set of the structure models in this model
    * 
    * @return
    */
-  public String getAtomSpec()
+  public Iterable<Integer> getModels()
   {
-    StringBuilder sb = new StringBuilder(128);
-    boolean firstModel = true;
-    for (Integer model : atomSpec.keySet())
-    {
-      if (!firstModel)
-      {
-        sb.append("|");
-      }
-      firstModel = false;
-      sb.append("#").append(model).append(":");
-
-      boolean firstPositionForModel = true;
-      final Map<String, List<int[]>> modelData = atomSpec.get(model);
-
-      for (String chain : modelData.keySet())
-      {
-        chain = chain.trim();
-
-        List<int[]> rangeList = modelData.get(chain);
-
-        /*
-         * sort ranges into ascending start position order
-         */
-        Collections.sort(rangeList, IntRangeComparator.ASCENDING);
-
-        int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
-        int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
-
-        Iterator<int[]> iterator = rangeList.iterator();
-        while (iterator.hasNext())
-        {
-          int[] range = iterator.next();
-          if (range[0] <= end + 1)
-          {
-            /*
-             * range overlaps or is contiguous with the last one
-             * - so just extend the end position, and carry on
-             * (unless this is the last in the list)
-             */
-            end = Math.max(end, range[1]);
-          }
-          else
-          {
-            /*
-             * we have a break so append the last range
-             */
-            appendRange(sb, start, end, chain, firstPositionForModel);
-            firstPositionForModel = false;
-            start = range[0];
-            end = range[1];
-          }
-        }
-
-        /*
-         * and append the last range
-         */
-        if (!rangeList.isEmpty())
-        {
-          appendRange(sb, start, end, chain, firstPositionForModel);
-          firstPositionForModel = false;
-        }
-      }
-    }
-    return sb.toString();
+    return atomSpec.keySet();
   }
 
   /**
-   * @param sb
-   * @param start
-   * @param end
-   * @param chain
-   * @param firstPositionForModel
+   * Answers an iterable set of the chains in this model for the given structure
+   * model, or an empty set if none
+   * 
+   * @param model
+   * @return
    */
-  protected void appendRange(StringBuilder sb, int start, int end,
-          String chain, boolean firstPositionForModel)
+  public Iterable<String> getChains(Integer model)
   {
-    if (!firstPositionForModel)
-    {
-      sb.append(",");
-    }
-    if (end == start)
+    if (atomSpec.containsKey(model))
     {
-      sb.append(start);
+      return atomSpec.get(model).keySet();
     }
-    else
-    {
-      sb.append(start).append("-").append(end);
-    }
-    if (chain.length() > 0)
+    return Collections.emptySet();
+  }
+
+  public List<int[]> getRanges(Integer model, String chain)
+  {
+    Map<String, List<int[]>> modelData = atomSpec.get(model);
+    if (modelData != null)
     {
-      sb.append(".").append(chain);
+      List<int[]> chainData = modelData.get(chain);
+      if (chainData != null)
+      {
+        return chainData;
+      }
     }
+    return Collections.EMPTY_LIST;
   }
 }