JAL-3438 spotless for 2.11.2.0
[jalview.git] / src / jalview / analysis / CrossRef.java
index 4a7a41b..9b90ca5 100644 (file)
@@ -24,6 +24,7 @@ import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.DBRefSource;
 import jalview.datamodel.Mapping;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceFeature;
@@ -98,7 +99,7 @@ public class CrossRef
    */
   public List<String> findXrefSourcesForSequences(boolean dna)
   {
-    List<String> sources = new ArrayList<String>();
+    List<String> sources = new ArrayList<>();
     for (SequenceI seq : fromSeqs)
     {
       if (seq != null)
@@ -106,6 +107,16 @@ public class CrossRef
         findXrefSourcesForSequence(seq, dna, sources);
       }
     }
+    sources.remove(DBRefSource.EMBL); // hack to prevent EMBL xrefs resulting in
+                                      // redundant datasets
+    if (dna)
+    {
+      sources.remove(DBRefSource.ENSEMBL); // hack to prevent Ensembl and
+                                           // EnsemblGenomes xref option shown
+                                           // from cdna panel
+      sources.remove(DBRefSource.ENSEMBLGENOMES);
+    }
+    // redundant datasets
     return sources;
   }
 
@@ -132,15 +143,17 @@ public class CrossRef
     /*
      * first find seq's xrefs (dna-to-peptide or peptide-to-dna)
      */
-    DBRefEntry[] rfs = DBRefUtils.selectDbRefs(!fromDna, seq.getDBRefs());
+    List<DBRefEntry> rfs = DBRefUtils.selectDbRefs(!fromDna,
+            seq.getDBRefs());
     addXrefsToSources(rfs, sources);
     if (dataset != null)
     {
       /*
        * find sequence's direct (dna-to-dna, peptide-to-peptide) xrefs
        */
-      DBRefEntry[] lrfs = DBRefUtils.selectDbRefs(fromDna, seq.getDBRefs());
-      List<SequenceI> foundSeqs = new ArrayList<SequenceI>();
+      List<DBRefEntry> lrfs = DBRefUtils.selectDbRefs(fromDna,
+              seq.getDBRefs());
+      List<SequenceI> foundSeqs = new ArrayList<>();
 
       /*
        * find sequences in the alignment which xref one of these DBRefs
@@ -153,8 +166,8 @@ public class CrossRef
        */
       for (SequenceI rs : foundSeqs)
       {
-        DBRefEntry[] xrs = DBRefUtils
-                .selectDbRefs(!fromDna, rs.getDBRefs());
+        List<DBRefEntry> xrs = DBRefUtils.selectDbRefs(!fromDna,
+                rs.getDBRefs());
         addXrefsToSources(xrs, sources);
       }
     }
@@ -167,7 +180,7 @@ public class CrossRef
    * @param xrefs
    * @param sources
    */
-  void addXrefsToSources(DBRefEntry[] xrefs, List<String> sources)
+  void addXrefsToSources(List<DBRefEntry> xrefs, List<String> sources)
   {
     if (xrefs != null)
     {
@@ -207,10 +220,9 @@ public class CrossRef
   public Alignment findXrefSequences(String source, boolean fromDna)
   {
 
-    rseqs = new ArrayList<SequenceI>();
+    rseqs = new ArrayList<>();
     AlignedCodonFrame cf = new AlignedCodonFrame();
-    matcher = new SequenceIdMatcher(
-            dataset.getSequences());
+    matcher = new SequenceIdMatcher(dataset.getSequences());
 
     for (SequenceI seq : fromSeqs)
     {
@@ -220,18 +232,18 @@ public class CrossRef
         dss = dss.getDatasetSequence();
       }
       boolean found = false;
-      DBRefEntry[] xrfs = DBRefUtils
-              .selectDbRefs(!fromDna, dss.getDBRefs());
+      List<DBRefEntry> xrfs = DBRefUtils.selectDbRefs(!fromDna,
+              dss.getDBRefs());
       // ENST & ENSP comes in to both Protein and nucleotide, so we need to
       // filter them
       // out later.
-      if ((xrfs == null || xrfs.length == 0) && dataset != null)
+      if ((xrfs == null || xrfs.size() == 0) && dataset != null)
       {
         /*
          * found no suitable dbrefs on sequence - look for sequences in the
          * alignment which share a dbref with this one
          */
-        DBRefEntry[] lrfs = DBRefUtils.selectDbRefs(fromDna,
+        List<DBRefEntry> lrfs = DBRefUtils.selectDbRefs(fromDna,
                 seq.getDBRefs());
 
         /*
@@ -281,13 +293,10 @@ public class CrossRef
             if (matchInDataset != null && xref.getMap().getTo() != null
                     && matchInDataset != xref.getMap().getTo())
             {
-              System.err
-                      .println("Implementation problem (reopen JAL-2154): CrossRef.findInDataset seems to have recovered a different sequence than the one explicitly mapped for xref."
-                              + "Found:"
-                              + matchInDataset
-                              + "\nExpected:"
-                              + xref.getMap().getTo()
-                              + "\nFor xref:"
+              System.err.println(
+                      "Implementation problem (reopen JAL-2154): CrossRef.findInDataset seems to have recovered a different sequence than the one explicitly mapped for xref."
+                              + "Found:" + matchInDataset + "\nExpected:"
+                              + xref.getMap().getTo() + "\nFor xref:"
                               + xref);
             }
             /*matcher.findIdMatch(mappedTo);*/
@@ -313,8 +322,9 @@ public class CrossRef
                 }
                 else
                 {
-                  cf.addMap(matchInDataset, dss, xref.getMap().getMap()
-                          .getInverse(), xref.getMap().getMappedFromId());
+                  cf.addMap(matchInDataset, dss,
+                          xref.getMap().getMap().getInverse(),
+                          xref.getMap().getMappedFromId());
                 }
               }
 
@@ -330,8 +340,8 @@ public class CrossRef
               if (fromDna)
               {
                 // map is from dna seq to a protein product
-                cf.addMap(dss, rsq, xref.getMap().getMap(), xref.getMap()
-                        .getMappedFromId());
+                cf.addMap(dss, rsq, xref.getMap().getMap(),
+                        xref.getMap().getMappedFromId());
               }
               else
               {
@@ -345,8 +355,8 @@ public class CrossRef
 
         if (!found)
         {
-          SequenceI matchedSeq = matcher.findIdMatch(xref.getSource() + "|"
-                  + xref.getAccessionId());
+          SequenceI matchedSeq = matcher.findIdMatch(
+                  xref.getSource() + "|" + xref.getAccessionId());
           // if there was a match, check it's at least the right type of
           // molecule!
           if (matchedSeq != null && matchedSeq.isProtein() == fromDna)
@@ -362,7 +372,8 @@ public class CrossRef
         {
           // do a bit more work - search for sequences with references matching
           // xrefs on this sequence.
-          found = searchDataset(fromDna, dss, xref, rseqs, cf, false);
+          found = searchDataset(fromDna, dss, xref, rseqs, cf, false,
+                  DBRefUtils.SEARCH_MODE_FULL);
         }
         if (found)
         {
@@ -392,37 +403,16 @@ public class CrossRef
   }
 
   private void retrieveCrossRef(List<DBRefEntry> sourceRefs, SequenceI seq,
-          DBRefEntry[] xrfs, boolean fromDna, AlignedCodonFrame cf)
+          List<DBRefEntry> xrfs, boolean fromDna, AlignedCodonFrame cf)
   {
     ASequenceFetcher sftch = SequenceFetcherFactory.getSequenceFetcher();
     SequenceI[] retrieved = null;
-    SequenceI dss = seq.getDatasetSequence() == null ? seq : seq
-            .getDatasetSequence();
+    SequenceI dss = seq.getDatasetSequence() == null ? seq
+            : seq.getDatasetSequence();
     // first filter in case we are retrieving crossrefs that have already been
     // retrieved. this happens for cases where a database record doesn't yield
     // protein products for CDS
-    DBRefEntry[] dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]);
-    for (SequenceI sq : dataset.getSequences())
-    {
-      boolean dupeFound = false;
-      // !fromDna means we are looking only for nucleotide sequences, not
-      // protein
-      if (sq.isProtein() == fromDna)
-      {
-        for (DBRefEntry dbr : sq.getPrimaryDBRefs())
-        {
-          for (DBRefEntry found : DBRefUtils.searchRefs(dbrSourceSet, dbr))
-          {
-            sourceRefs.remove(found);
-            dupeFound = true;
-          }
-        }
-      }
-      if (dupeFound)
-      {
-        dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]);
-      }
-    }
+    removeAlreadyRetrievedSeqs(sourceRefs, fromDna);
     if (sourceRefs.size() == 0)
     {
       // no more work to do! We already had all requested sequence records in
@@ -434,140 +424,265 @@ public class CrossRef
       retrieved = sftch.getSequences(sourceRefs, !fromDna);
     } catch (Exception e)
     {
-      System.err
-              .println("Problem whilst retrieving cross references for Sequence : "
+      System.err.println(
+              "Problem whilst retrieving cross references for Sequence : "
                       + seq.getName());
       e.printStackTrace();
     }
 
     if (retrieved != null)
     {
-      updateDbrefMappings(seq, xrfs, retrieved, cf, fromDna);
+      boolean addedXref = false;
+      List<SequenceI> newDsSeqs = new ArrayList<>(),
+              doNotAdd = new ArrayList<>();
+
       for (SequenceI retrievedSequence : retrieved)
       {
         // dataset gets contaminated ccwith non-ds sequences. why ??!
         // try: Ensembl -> Nuc->Ensembl, Nuc->Uniprot-->Protein->EMBL->
-        SequenceI retrievedDss = retrievedSequence.getDatasetSequence() == null ? retrievedSequence
-                : retrievedSequence.getDatasetSequence();
-        DBRefEntry[] dbr = retrievedSequence.getDBRefs();
-        if (dbr != null)
+        SequenceI retrievedDss = retrievedSequence
+                .getDatasetSequence() == null ? retrievedSequence
+                        : retrievedSequence.getDatasetSequence();
+        addedXref |= importCrossRefSeq(cf, newDsSeqs, doNotAdd, dss,
+                retrievedDss);
+      }
+      // JBPNote: What assumptions are made for dbref structures on
+      // retrieved sequences ?
+      // addedXref will be true means importCrossRefSeq found
+      // sequences with dbrefs with mappings to sequences congruent with dss
+
+      if (!addedXref)
+      {
+        // try again, after looking for matching IDs
+        // shouldn't need to do this unless the dbref mechanism has broken.
+        updateDbrefMappings(seq, xrfs, retrieved, cf, fromDna);
+        for (SequenceI retrievedSequence : retrieved)
+        {
+          // dataset gets contaminated ccwith non-ds sequences. why ??!
+          // try: Ensembl -> Nuc->Ensembl, Nuc->Uniprot-->Protein->EMBL->
+          SequenceI retrievedDss = retrievedSequence
+                  .getDatasetSequence() == null ? retrievedSequence
+                          : retrievedSequence.getDatasetSequence();
+          addedXref |= importCrossRefSeq(cf, newDsSeqs, doNotAdd, dss,
+                  retrievedDss);
+        }
+      }
+      for (SequenceI newToSeq : newDsSeqs)
+      {
+        if (!doNotAdd.contains(newToSeq)
+                && dataset.findIndex(newToSeq) == -1)
         {
-          for (DBRefEntry dbref : dbr)
+          dataset.addSequence(newToSeq);
+          matcher.add(newToSeq);
+        }
+      }
+    }
+  }
+
+  /**
+   * Search dataset for sequences with a primary reference contained in
+   * sourceRefs.
+   * 
+   * @param sourceRefs
+   *          - list of references to filter.
+   * @param fromDna
+   *          - type of sequence to search for matching primary reference.
+   */
+  private void removeAlreadyRetrievedSeqs(List<DBRefEntry> sourceRefs,
+          boolean fromDna)
+  {
+    List<DBRefEntry> dbrSourceSet = new ArrayList<>(sourceRefs);
+    List<SequenceI> dsSeqs = dataset.getSequences();
+    for (int ids = 0, nds = dsSeqs.size(); ids < nds; ids++)
+    {
+      SequenceI sq = dsSeqs.get(ids);
+      boolean dupeFound = false;
+      // !fromDna means we are looking only for nucleotide sequences, not
+      // protein
+      if (sq.isProtein() == fromDna)
+      {
+        List<DBRefEntry> sqdbrefs = sq.getPrimaryDBRefs();
+        for (int idb = 0, ndb = sqdbrefs.size(); idb < ndb; idb++)
+        {
+          DBRefEntry dbr = sqdbrefs.get(idb);
+          List<DBRefEntry> searchrefs = DBRefUtils.searchRefs(dbrSourceSet,
+                  dbr, DBRefUtils.SEARCH_MODE_FULL);
+          for (int isr = 0, nsr = searchrefs.size(); isr < nsr; isr++)
           {
-            // find any entry where we should put in the sequence being
-            // cross-referenced into the map
-            Mapping map = dbref.getMap();
-            if (map != null)
+            sourceRefs.remove(searchrefs.get(isr));
+            dupeFound = true;
+          }
+        }
+      }
+      if (dupeFound)
+      {
+        // rebuild the search array from the filtered sourceRefs list
+        dbrSourceSet.clear();
+        dbrSourceSet.addAll(sourceRefs);
+      }
+    }
+  }
+
+  /**
+   * process sequence retrieved via a dbref on source sequence to resolve and
+   * transfer data JBPNote: as of 2022-02-03 - this assumes retrievedSequence
+   * has dbRefs with Mapping references to a sequence congruent with
+   * sourceSequence
+   * 
+   * @param cf
+   * @param sourceSequence
+   * @param retrievedSequence
+   * @return true if retrieveSequence was imported
+   */
+  private boolean importCrossRefSeq(AlignedCodonFrame cf,
+          List<SequenceI> newDsSeqs, List<SequenceI> doNotAdd,
+          SequenceI sourceSequence, SequenceI retrievedSequence)
+  {
+    /**
+     * set when retrievedSequence has been verified as a crossreference for
+     * sourceSequence
+     */
+    boolean imported = false;
+    List<DBRefEntry> dbr = retrievedSequence.getDBRefs();
+    if (dbr != null)
+    {
+      for (int ib = 0, nb = dbr.size(); ib < nb; ib++)
+      {
+
+        DBRefEntry dbref = dbr.get(ib);
+        // matched will return null if the dbref has no map
+        SequenceI matched = findInDataset(dbref);
+        if (matched == sourceSequence)
+        {
+          // verified retrieved and source sequence cross-reference each other
+          imported = true;
+        }
+        // find any entry where we should put in the sequence being
+        // cross-referenced into the map
+        Mapping map = dbref.getMap();
+        if (map != null)
+        {
+          SequenceI ms = map.getTo();
+          if (ms != null && map.getMap() != null)
+          {
+            if (ms == sourceSequence)
             {
-              if (map.getTo() != null && map.getMap() != null)
+              // already called to import once, and most likely this sequence
+              // already imported !
+              continue;
+            }
+            if (matched == null)
+            {
+              /*
+               * sequence is new to dataset, so save a reference so it can be added. 
+               */
+              newDsSeqs.add(ms);
+              continue;
+            }
+
+            /*
+             * there was a matching sequence in dataset, so now, check to see if we can update the map.getTo() sequence to the existing one.
+             */
+
+            try
+            {
+              // compare ms with dss and replace with dss in mapping
+              // if map is congruent
+              // TODO findInDataset requires exact sequence match but
+              // 'congruent' test is only for the mapped part
+              // maybe not a problem in practice since only ENA provide a
+              // mapping and it is to the full protein translation of CDS
+              // matcher.findIdMatch(map.getTo());
+              // TODO addendum: if matched is shorter than getTo, this will fail
+              // - when it should really succeed.
+              int sf = map.getMap().getToLowest();
+              int st = map.getMap().getToHighest();
+              SequenceI mappedrg = ms.getSubSequence(sf, st);
+              if (mappedrg.getLength() > 0 && ms.getSequenceAsString()
+                      .equals(matched.getSequenceAsString()))
               {
-                // TODO findInDataset requires exact sequence match but
-                // 'congruent' test is only for the mapped part
-                // maybe not a problem in practice since only ENA provide a
-                // mapping and it is to the full protein translation of CDS
-                SequenceI matched = findInDataset(dbref);
-                // matcher.findIdMatch(map.getTo());
-                if (matched != null)
+                /*
+                 * sequences were a match, 
+                 */
+                String msg = "Mapping updated from " + ms.getName()
+                        + " to retrieved crossreference "
+                        + matched.getName();
+                System.out.println(msg);
+
+                List<DBRefEntry> toRefs = map.getTo().getDBRefs();
+                if (toRefs != null)
                 {
                   /*
-                   * already got an xref to this sequence; update this
-                   * map to point to the same sequence, and add
-                   * any new dbrefs to it
+                   * transfer database refs
                    */
-                  DBRefEntry[] toRefs = map.getTo().getDBRefs();
-                  if (toRefs != null)
+                  for (DBRefEntry ref : toRefs)
                   {
-                    for (DBRefEntry ref : toRefs)
+                    if (dbref.getSrcAccString()
+                            .equals(ref.getSrcAccString()))
                     {
-                      matched.addDBRef(ref); // add or update mapping
+                      continue; // avoid overwriting the ref on source sequence
                     }
-                  }
-                  map.setTo(matched);
-                }
-                else
-                {
-                  if (dataset.findIndex(map.getTo()) == -1)
-                  {
-                    dataset.addSequence(map.getTo());
-                    matcher.add(map.getTo());
+                    matched.addDBRef(ref); // add or update mapping
                   }
                 }
-                try
-                {
-                  // compare ms with dss and replace with dss in mapping
-                  // if map is congruent
-                  SequenceI ms = map.getTo();
-                  int sf = map.getMap().getToLowest();
-                  int st = map.getMap().getToHighest();
-                  SequenceI mappedrg = ms.getSubSequence(sf, st);
-                  // SequenceI loc = dss.getSubSequence(sf, st);
-                  if (mappedrg.getLength() > 0
-                          && ms.getSequenceAsString().equals(
-                                  dss.getSequenceAsString()))
-                  // && mappedrg.getSequenceAsString().equals(
-                  // loc.getSequenceAsString()))
-                  {
-                    String msg = "Mapping updated from " + ms.getName()
-                            + " to retrieved crossreference "
-                            + dss.getName();
-                    System.out.println(msg);
-                    map.setTo(dss);
+                doNotAdd.add(map.getTo());
+                map.setTo(matched);
 
-                    /*
-                     * give the reverse reference the inverse mapping 
-                     * (if it doesn't have one already)
-                     */
-                    setReverseMapping(dss, dbref, cf);
+                /*
+                 * give the reverse reference the inverse mapping 
+                 * (if it doesn't have one already)
+                 */
+                setReverseMapping(matched, dbref, cf);
 
-                    /*
-                     * copy sequence features as well, avoiding
-                     * duplication (e.g. same variation from two 
-                     * transcripts)
-                     */
-                    SequenceFeature[] sfs = ms.getSequenceFeatures();
-                    if (sfs != null)
+                /*
+                 * copy sequence features as well, avoiding
+                 * duplication (e.g. same variation from two 
+                 * transcripts)
+                 */
+                List<SequenceFeature> sfs = ms.getFeatures()
+                        .getAllFeatures();
+                for (SequenceFeature feat : sfs)
+                {
+                  /*
+                   * make a flyweight feature object which ignores Parent
+                   * attribute in equality test; this avoids creating many
+                   * otherwise duplicate exon features on genomic sequence
+                   */
+                  SequenceFeature newFeature = new SequenceFeature(feat)
+                  {
+                    @Override
+                    public boolean equals(Object o)
                     {
-                      for (SequenceFeature feat : sfs)
-                      {
-                        /*
-                         * make a flyweight feature object which ignores Parent
-                         * attribute in equality test; this avoids creating many
-                         * otherwise duplicate exon features on genomic sequence
-                         */
-                        SequenceFeature newFeature = new SequenceFeature(
-                                feat)
-                        {
-                          @Override
-                          public boolean equals(Object o)
-                          {
-                            return super.equals(o, true);
-                          }
-                        };
-                        dss.addSequenceFeature(newFeature);
-                      }
+                      return super.equals(o, true);
                     }
-                  }
-                  cf.addMap(retrievedDss, map.getTo(), map.getMap());
-                } catch (Exception e)
-                {
-                  System.err
-                          .println("Exception when consolidating Mapped sequence set...");
-                  e.printStackTrace(System.err);
+                  };
+                  matched.addSequenceFeature(newFeature);
                 }
               }
+              cf.addMap(retrievedSequence, map.getTo(), map.getMap());
+            } catch (Exception e)
+            {
+              System.err.println(
+                      "Exception when consolidating Mapped sequence set...");
+              e.printStackTrace(System.err);
             }
           }
         }
-        retrievedSequence.updatePDBIds();
-        rseqs.add(retrievedDss);
-        if (dataset.findIndex(retrievedDss) == -1)
-        {
-          dataset.addSequence(retrievedDss);
-          matcher.add(retrievedDss);
-        }
       }
     }
+    if (imported)
+    {
+      retrievedSequence.updatePDBIds();
+      rseqs.add(retrievedSequence);
+      if (dataset.findIndex(retrievedSequence) == -1)
+      {
+        dataset.addSequence(retrievedSequence);
+        matcher.add(retrievedSequence);
+      }
+    }
+    return imported;
   }
+
   /**
    * Sets the inverse sequence mapping in the corresponding dbref of the mapped
    * to sequence (if any). This is used after fetching a cross-referenced
@@ -587,7 +702,7 @@ public class CrossRef
     {
       return;
     }
-    DBRefEntry[] dbrefs = mapTo.getDBRefs();
+    List<DBRefEntry> dbrefs = mapTo.getDBRefs();
     if (dbrefs == null)
     {
       return;
@@ -610,9 +725,13 @@ public class CrossRef
   }
 
   /**
-   * Returns the first identical sequence in the dataset if any, else null
+   * Returns null or the first sequence in the dataset which is identical to
+   * xref.mapTo, and has a) a primary dbref matching xref, or if none found, the
+   * first one with an ID source|xrefacc JBPNote: Could refactor this to
+   * AlignmentI/DatasetI
    * 
    * @param xref
+   *          with map and mapped-to sequence
    * @return
    */
   SequenceI findInDataset(DBRefEntry xref)
@@ -624,30 +743,43 @@ public class CrossRef
     SequenceI mapsTo = xref.getMap().getTo();
     String name = xref.getAccessionId();
     String name2 = xref.getSource() + "|" + name;
-    SequenceI dss = mapsTo.getDatasetSequence() == null ? mapsTo : mapsTo
-            .getDatasetSequence();
+    SequenceI dss = mapsTo.getDatasetSequence() == null ? mapsTo
+            : mapsTo.getDatasetSequence();
     // first check ds if ds is directly referenced
     if (dataset.findIndex(dss) > -1)
     {
       return dss;
     }
-    ;
+    DBRefEntry template = new DBRefEntry(xref.getSource(), null,
+            xref.getAccessionId());
+    /**
+     * remember the first ID match - in case we don't find a match to template
+     */
+    SequenceI firstIdMatch = null;
     for (SequenceI seq : dataset.getSequences())
     {
+      // first check primary refs.
+      List<DBRefEntry> match = DBRefUtils.searchRefs(seq.getPrimaryDBRefs(),
+              template, DBRefUtils.SEARCH_MODE_FULL);
+      if (match != null && match.size() == 1 && sameSequence(seq, dss))
+      {
+        return seq;
+      }
       /*
        * clumsy alternative to using SequenceIdMatcher which currently
        * returns sequences with a dbref to the matched accession id 
        * which we don't want
        */
-      if (name.equals(seq.getName()) || seq.getName().startsWith(name2))
+      if (firstIdMatch == null && (name.equals(seq.getName())
+              || seq.getName().startsWith(name2)))
       {
         if (sameSequence(seq, dss))
         {
-          return seq;
+          firstIdMatch = seq;
         }
       }
     }
-    return null;
+    return firstIdMatch;
   }
 
   /**
@@ -671,15 +803,15 @@ public class CrossRef
     {
       return false;
     }
-    char[] c1 = seq1.getSequence();
-    char[] c2 = seq2.getSequence();
-    if (c1.length != c2.length)
+
+    if (seq1.getLength() != seq2.getLength())
     {
       return false;
     }
-    for (int i = 0; i < c1.length; i++)
+    int length = seq1.getLength();
+    for (int i = 0; i < length; i++)
     {
-      int diff = c1[i] - c2[i];
+      int diff = seq1.getCharAt(i) - seq2.getCharAt(i);
       /*
        * same char or differ in case only ('a'-'A' == 32)
        */
@@ -694,14 +826,15 @@ public class CrossRef
   /**
    * Updates any empty mappings in the cross-references with one to a compatible
    * retrieved sequence if found, and adds any new mappings to the
-   * AlignedCodonFrame
+   * AlignedCodonFrame JBPNote: TODO: this relies on sequence IDs like
+   * UNIPROT|ACCESSION - which do not always happen.
    * 
    * @param mapFrom
    * @param xrefs
    * @param retrieved
    * @param acf
    */
-  void updateDbrefMappings(SequenceI mapFrom, DBRefEntry[] xrefs,
+  void updateDbrefMappings(SequenceI mapFrom, List<DBRefEntry> xrefs,
           SequenceI[] retrieved, AlignedCodonFrame acf, boolean fromDna)
   {
     SequenceIdMatcher idMatcher = new SequenceIdMatcher(retrieved);
@@ -810,7 +943,7 @@ public class CrossRef
 
     if (fromDna)
     {
-      AlignmentUtils.computeProteinFeatures(mapFrom, mapTo, mapping);
+      // AlignmentUtils.computeProteinFeatures(mapFrom, mapTo, mapping);
       mappings.addMap(mapFrom, mapTo, mapping);
     }
     else
@@ -835,20 +968,22 @@ public class CrossRef
    * @return true if matches were found.
    */
   private boolean searchDatasetXrefs(boolean fromDna, SequenceI sequenceI,
-          DBRefEntry[] lrfs, List<SequenceI> foundSeqs, AlignedCodonFrame cf)
+          List<DBRefEntry> lrfs, List<SequenceI> foundSeqs,
+          AlignedCodonFrame cf)
   {
     boolean found = false;
     if (lrfs == null)
     {
       return false;
     }
-    for (int i = 0; i < lrfs.length; i++)
+    for (int i = 0, n = lrfs.size(); i < n; i++)
     {
-      DBRefEntry xref = new DBRefEntry(lrfs[i]);
-      // add in wildcards
-      xref.setVersion(null);
-      xref.setMap(null);
-      found |= searchDataset(fromDna, sequenceI, xref, foundSeqs, cf, false);
+      // DBRefEntry xref = new DBRefEntry(lrfs.get(i));
+      // // add in wildcards
+      // xref.setVersion(null);
+      // xref.setMap(null);
+      found |= searchDataset(fromDna, sequenceI, lrfs.get(i), foundSeqs, cf,
+              false, DBRefUtils.SEARCH_MODE_NO_MAP_NO_VERSION);
     }
     return found;
   }
@@ -879,11 +1014,13 @@ public class CrossRef
    *          sequenceI or all the returned sequences (eg a genomic reference
    *          associated with a locus and one or more transcripts)</li>
    *          </ul>
+   * @param mode
+   *          SEARCH_MODE_FULL for all; SEARCH_MODE_NO_MAP_NO_VERSION optional
    * @return true if relationship found and sequence added.
    */
   boolean searchDataset(boolean fromDna, SequenceI fromSeq, DBRefEntry xrf,
           List<SequenceI> foundSeqs, AlignedCodonFrame mappings,
-          boolean direct)
+          boolean direct, int mode)
   {
     boolean found = false;
     if (dataset == null)
@@ -895,8 +1032,8 @@ public class CrossRef
       System.err.println("Empty dataset sequence set - NO VECTOR");
       return false;
     }
-    List<SequenceI> ds;
-    synchronized (ds = dataset.getSequences())
+    List<SequenceI> ds = dataset.getSequences();
+    synchronized (ds)
     {
       for (SequenceI nxt : ds)
       {
@@ -904,10 +1041,9 @@ public class CrossRef
         {
           if (nxt.getDatasetSequence() != null)
           {
-            System.err
-                    .println("Implementation warning: CrossRef initialised with a dataset alignment with non-dataset sequences in it! ("
-                            + nxt.getDisplayId(true)
-                            + " has ds reference "
+            System.err.println(
+                    "Implementation warning: CrossRef initialised with a dataset alignment with non-dataset sequences in it! ("
+                            + nxt.getDisplayId(true) + " has ds reference "
                             + nxt.getDatasetSequence().getDisplayId(true)
                             + ")");
           }
@@ -929,13 +1065,13 @@ public class CrossRef
           }
 
           // look for direct or indirect references in common
-          DBRefEntry[] poss = nxt.getDBRefs();
+          List<DBRefEntry> poss = nxt.getDBRefs();
           List<DBRefEntry> cands = null;
 
           // todo: indirect specifies we select either direct references to nxt
           // that match xrf which is indirect to sequenceI, or indirect
           // references to nxt that match xrf which is direct to sequenceI
-          cands = DBRefUtils.searchRefs(poss, xrf);
+          cands = DBRefUtils.searchRefs(poss, xrf, mode);
           // else
           // {
           // poss = DBRefUtils.selectDbRefs(nxt.isProtein()!fromDna, poss);