Merge branch 'alpha/JAL-3362_Jalview_212_alpha' into alpha/merge_212_JalviewJS_2112
[jalview.git] / src / jalview / ws / jws2 / jabaws2 / JabawsAnnotationInstance.java
diff --git a/src/jalview/ws/jws2/jabaws2/JabawsAnnotationInstance.java b/src/jalview/ws/jws2/jabaws2/JabawsAnnotationInstance.java
new file mode 100644 (file)
index 0000000..a52b515
--- /dev/null
@@ -0,0 +1,279 @@
+package jalview.ws.jws2.jabaws2;
+
+import jalview.api.FeatureColourI;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.util.MessageManager;
+import jalview.ws.api.JobId;
+import jalview.ws.api.SequenceAnnotationServiceI;
+import jalview.ws.jws2.JabaParamStore;
+import jalview.ws.jws2.JabaPreset;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import compbio.data.msa.SequenceAnnotation;
+import compbio.data.sequence.FastaSequence;
+import compbio.data.sequence.Score;
+import compbio.data.sequence.ScoreManager;
+import compbio.metadata.JobSubmissionException;
+import compbio.metadata.WrongParameterException;
+
+public abstract class JabawsAnnotationInstance
+        extends JabawsServiceInstance<SequenceAnnotation>
+        implements SequenceAnnotationServiceI
+{
+
+  /**
+   * holds last results obtained when non-null. TODO: remove this as a field ?
+   */
+  protected ScoreManager scoremanager = null;
+
+  public JabawsAnnotationInstance(Jws2Instance handle)
+  {
+    super(handle);
+  }
+
+
+  /**
+   * 
+   * @return the calcId for this Jabaws Service (convenience method).
+   * 
+   *         TODO: decide if this is really convenient since manager and
+   *         instance have same method !
+   */
+  public String getCalcId()
+  {
+    return our.getAlignAnalysisUI() == null ? null
+            : our.getAlignAnalysisUI().getCalcId();
+  }
+
+  @Override
+  public JobId submitToService(List<SequenceI> seqs, WsParamSetI preset,
+          List<ArgumentI> arguments) throws Throwable
+  {
+    String rslt = null;
+    scoremanager = null;
+    List<FastaSequence> jabaseqs = new ArrayList(seqs.size());
+    for (SequenceI seq : seqs)
+    {
+      jabaseqs.add(
+              new FastaSequence(seq.getName(), seq.getSequenceAsString()));
+    }
+    if (preset == null && arguments == null)
+    {
+      rslt = service.analize(jabaseqs);
+    }
+    if (preset != null)
+    {
+      if (preset instanceof JabaPreset)
+      {
+        // TODO: verify behaviour is really the same, since preset analyze was
+        // never called in Jalview 2.11.x
+        rslt = service.presetAnalize(jabaseqs,
+                ((JabaPreset) preset).getJabaPreset());
+      }
+      else
+      {
+        rslt = service.customAnalize(jabaseqs,
+                JabaParamStore.getJabafromJwsArgs(preset.getArguments()));
+      }
+    }
+    else if (arguments != null && arguments.size() > 0)
+    {
+      try
+      {
+        rslt = service.customAnalize(jabaseqs,
+                JabaParamStore.getJabafromJwsArgs(arguments));
+      } catch (WrongParameterException x)
+      {
+        throw new JobSubmissionException(MessageManager.getString(
+                "exception.jobsubmission_invalid_params_set"), x);
+
+      }
+    }
+
+    if (rslt == null)
+    {
+      return null;
+    }
+    return new JobId(our.getServiceType(), our.getName(), rslt);
+  }
+
+
+  @Override
+  public
+  List<AlignmentAnnotation> getAnnotationResult(JobId job,
+          List<SequenceI> seqs, Map<String, FeatureColourI> featureColours,
+          Map<String, FeatureMatcherSetI> featureFilters) throws Throwable
+  {
+    if (scoremanager == null)
+    {
+      // TODO: raise annotation unavailable exception ?
+      scoremanager = service.getAnnotation(job.getJobId());
+    }
+    if (scoremanager == null)
+    {
+      return List.of();
+    }
+    /**
+     * dummy alignment to perform annotation on
+     */
+    AlignmentI newal = new Alignment(seqs.toArray(new SequenceI[0]));
+    List<AlignmentAnnotation> ourAnnot = annotationFromScoreManager(newal,
+            featureColours, featureFilters);
+    return ourAnnot;
+  }
+
+  /**
+   * service specific annotation creation method
+   * 
+   * @param seqs
+   *          - sequences to be annotated with results
+   * @param featureColours
+   *          - - updated with any colours imported during result processing
+   * @param featureFilters
+   *          - updated with any filters imported during result processing
+   * 
+   * @return
+   */
+  abstract List<AlignmentAnnotation> annotationFromScoreManager(
+          AlignmentI seqs, Map<String, FeatureColourI> featureColours,
+          Map<String, FeatureMatcherSetI> featureFilters);
+
+
+  /**
+   * create and complete an annotation row from a JABAWS score object
+   * 
+   * @param alignViewport
+   * @param gapMap
+   * @param ourAnnot
+   * @param calcId
+   * @param alWidth
+   * @param scr
+   */
+
+  protected void createAnnotationRowsForScores(AlignmentI al_result,
+          boolean[] gapMap, List<AlignmentAnnotation> ourAnnot,
+          String calcId,
+          int alWidth, Score scr)
+  {
+    // simple annotation row
+    AlignmentAnnotation annotation = al_result
+            .findOrCreateAnnotation(scr.getMethod(), calcId, true, null,
+                    null);
+    if (gapMap == null || alWidth == gapMap.length) // scr.getScores().size())
+    {
+      constructAnnotationFromScore(gapMap, annotation, 0,
+              alWidth, scr);
+      ourAnnot.add(annotation);
+    }
+  }
+
+  /**
+   * create a sequence associated annotation row for JABAWS score object scr
+   * 
+   * @param alignViewport
+   * @param gapMap
+   * @param ourAnnot
+   * @param typeName
+   * @param calcId
+   * @param dseq
+   * @param base
+   * @param scr
+   * @return
+   */
+  protected AlignmentAnnotation createAnnotationRowsForScores(
+          AlignmentI alignment, boolean[] gapMap,
+          List<AlignmentAnnotation> ourAnnot, String typeName,
+          String calcId, SequenceI dseq, int base, Score scr)
+  {
+    System.out.println("Creating annotation on dseq:" + dseq.getStart()
+            + " base is " + base + " and length=" + dseq.getLength()
+            + " == " + scr.getScores().size());
+    // AlignmentAnnotation annotation = new AlignmentAnnotation(
+    // scr.getMethod(), typeName, new Annotation[]
+    // {}, 0, -1, AlignmentAnnotation.LINE_GRAPH);
+    // annotation.setCalcId(calcId);
+    AlignmentAnnotation annotation = alignment
+            .findOrCreateAnnotation(typeName, calcId, false, dseq, null);
+    constructAnnotationFromScore(gapMap, annotation, 0, dseq.getLength(),
+            scr);
+    annotation.createSequenceMapping(dseq, base, false);
+    annotation.adjustForAlignment();
+    dseq.addAlignmentAnnotation(annotation);
+    ourAnnot.add(annotation);
+    return annotation;
+  }
+
+  /**
+   * create column annotation elements from Jabaws score object
+   * 
+   * @param gapMap
+   * @param annotation
+   * @param base
+   * @param alWidth
+   * @param scr
+   *          JABAWS score object
+   */
+  protected void constructAnnotationFromScore(boolean[] gapMap,
+          AlignmentAnnotation annotation,
+          int base, int alWidth, Score scr)
+  {
+    Annotation[] elm = new Annotation[alWidth];
+    Iterator<Float> vals = scr.getScores().iterator();
+    float m = 0f, x = 0f;
+    for (int i = 0; vals.hasNext(); i++)
+    {
+      float val = vals.next().floatValue();
+      if (i == 0)
+      {
+        m = val;
+        x = val;
+      }
+      else
+      {
+        if (m > val)
+        {
+          m = val;
+        }
+        ;
+        if (x < val)
+        {
+          x = val;
+        }
+      }
+      // if we're at a gapped column then skip to next ungapped position
+      if (gapMap != null && gapMap.length > 0)
+      {
+        // if gapMap is a different length to the result then it may be out of
+        // sync with the job.
+        while (i < gapMap.length && !gapMap[i])
+        {
+          elm[i++] = new Annotation("", "", ' ', Float.NaN);
+        }
+      }
+      elm[i] = new Annotation("", "" + val, ' ', val);
+    }
+
+    annotation.annotations = elm;
+    annotation.belowAlignment = true;
+    if (x < 0)
+    {
+      x = 0;
+    }
+    x += (x - m) * 0.1;
+    annotation.graphMax = x;
+    annotation.graphMin = m;
+    annotation.validateRangeAndDisplay();
+  }
+
+}