JAL-2282 Renamed internal use of sequence id / db accession for
[jalview.git] / src / jalview / util / UrlLink.java
index c853941..0d92759 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9.0b2)
- * Copyright (C) 2015 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  */
 package jalview.util;
 
+import static jalview.util.UrlConstants.DB_ACCESSION;
+import static jalview.util.UrlConstants.SEQUENCE_ID;
+
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.SequenceI;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
 import java.util.Vector;
 
 public class UrlLink
@@ -37,6 +46,8 @@ public class UrlLink
 
   private boolean dynamic = false;
 
+  private boolean uses_db_accession = false;
+
   private String invalidMessage = null;
 
   /**
@@ -48,81 +59,40 @@ public class UrlLink
    */
   public UrlLink(String link)
   {
-    int sep = link.indexOf("|"), psqid = link.indexOf("$SEQUENCE_ID");
+    int sep = link.indexOf("|");
+    int psqid = link.indexOf("$" + DB_ACCESSION);
+    int nsqid = link.indexOf("$" + SEQUENCE_ID);
     if (psqid > -1)
     {
       dynamic = true;
-      int p = sep;
-      do
-      {
-        sep = p;
-        p = link.indexOf("|", sep + 1);
-      } while (p > sep && p < psqid);
-      // Assuming that the URL itself does not contain any '|' symbols
-      // sep now contains last pipe symbol position prior to any regex symbols
-      label = link.substring(0, sep);
-      if (label.indexOf("|") > -1)
-      {
-        // | terminated database name / www target at start of Label
-        target = label.substring(0, label.indexOf("|"));
-      }
-      else if (label.indexOf(" ") > 2)
-      {
-        // space separated Label - matches database name
-        target = label.substring(0, label.indexOf(" "));
-      }
-      else
-      {
-        target = label;
-      }
-      // Parse URL : Whole URL string first
-      url_prefix = link.substring(sep + 1, psqid);
-      if (link.indexOf("$SEQUENCE_ID=/") == psqid
-              && (p = link.indexOf("/=$", psqid + 14)) > psqid + 14)
-      {
-        // Extract Regex and suffix
-        url_suffix = link.substring(p + 3);
-        regexReplace = link.substring(psqid + 14, p);
-        try
-        {
-          com.stevesoft.pat.Regex rg = com.stevesoft.pat.Regex.perlCode("/"
-                  + regexReplace + "/");
-          if (rg == null)
-          {
-            invalidMessage = "Invalid Regular Expression : '"
-                    + regexReplace + "'\n";
-          }
-        } catch (Exception e)
-        {
-          invalidMessage = "Invalid Regular Expression : '" + regexReplace
-                  + "'\n";
-        }
-      }
-      else
-      {
-        regexReplace = null;
-        // verify format is really correct.
-        if (link.indexOf("$SEQUENCE_ID$") == psqid)
-        {
-          url_suffix = link.substring(psqid + 13);
-          regexReplace = null;
-        }
-        else
-        {
-          invalidMessage = "Warning: invalid regex structure for URL link : "
-                  + link;
-        }
-      }
+      uses_db_accession = true;
+
+      sep = parseTargetAndLabel(sep, psqid, link);
+
+      parseUrl(link, DB_ACCESSION, psqid, sep);
+    }
+    else if (nsqid > -1)
+    {
+      dynamic = true;
+      sep = parseTargetAndLabel(sep, nsqid, link);
+
+      parseUrl(link, SEQUENCE_ID, nsqid, sep);
     }
     else
     {
       target = link.substring(0, sep);
-      label = link.substring(0, sep = link.lastIndexOf("|"));
-      url_prefix = link.substring(sep + 1);
+      sep = link.lastIndexOf("|");
+      label = link.substring(0, sep);
+      url_prefix = link.substring(sep + 1).trim();
       regexReplace = null; // implies we trim any prefix if necessary //
       // regexReplace=".*\\|?(.*)";
       url_suffix = null;
     }
+
+    label = label.trim();
+    target = target.trim();
+    target = target.toUpperCase(); // DBRefEntry uppercases DB names
+    // NB getCanonicalName might be better but does not currently change case
   }
 
   /**
@@ -295,15 +265,237 @@ public class UrlLink
     }
   }
 
+  @Override
   public String toString()
   {
+    String var = (uses_db_accession ? DB_ACCESSION : SEQUENCE_ID);
+
     return label
             + "|"
             + url_prefix
-            + (dynamic ? ("$SEQUENCE_ID" + ((regexReplace != null) ? "="
+            + (dynamic ? ("$" + var + ((regexReplace != null) ? "="
                     + regexReplace + "=$" : "$")) : "")
             + ((url_suffix == null) ? "" : url_suffix);
+  }
+
+  /**
+   * 
+   * @param firstSep
+   *          Location of first occurrence of separator in link string
+   * @param psqid
+   *          Position of sequence id or name in link string
+   * @param link
+   *          Link string containing database name and url
+   * @return Position of last separator symbol prior to any regex symbols
+   */
+  protected int parseTargetAndLabel(int firstSep, int psqid, String link)
+  {
+    int p = firstSep;
+    int sep = firstSep;
+    do
+    {
+      sep = p;
+      p = link.indexOf("|", sep + 1);
+    } while (p > sep && p < psqid);
+    // Assuming that the URL itself does not contain any '|' symbols
+    // sep now contains last pipe symbol position prior to any regex symbols
+    label = link.substring(0, sep);
+    if (label.indexOf("|") > -1)
+    {
+      // | terminated database name / www target at start of Label
+      target = label.substring(0, label.indexOf("|"));
+    }
+    else if (label.indexOf(" ") > 2)
+    {
+      // space separated Label - matches database name
+      target = label.substring(0, label.indexOf(" "));
+    }
+    else
+    {
+      target = label;
+    }
+    return sep;
+  }
+
+  /**
+   * Parse the URL part of the link string
+   * 
+   * @param link
+   *          Link string containing database name and url
+   * @param varName
+   *          Name of variable in url string (e.g. SEQUENCE_ID, SEQUENCE_NAME)
+   * @param sqidPos
+   *          Position of id or name in link string
+   * @param sep
+   *          Position of separator in link string
+   */
+  protected void parseUrl(String link, String varName, int sqidPos, int sep)
+  {
+    url_prefix = link.substring(sep + 1, sqidPos).trim();
+
+    // delimiter at start of regex: e.g. $SEQUENCE_ID=/
+    String startDelimiter = "$" + varName + "=/";
+
+    // delimiter at end of regex: /=$
+    String endDelimiter = "/=$";
+
+    int startLength = startDelimiter.length();
+
+    // Parse URL : Whole URL string first
+    int p = link.indexOf(endDelimiter, sqidPos + startLength);
+
+    if (link.indexOf(startDelimiter) == sqidPos
+            && (p > sqidPos + startLength))
+    {
+      // Extract Regex and suffix
+      url_suffix = link.substring(p + endDelimiter.length());
+      regexReplace = link.substring(sqidPos + startLength, p);
+      try
+      {
+        com.stevesoft.pat.Regex rg = com.stevesoft.pat.Regex.perlCode("/"
+                + regexReplace + "/");
+        if (rg == null)
+        {
+          invalidMessage = "Invalid Regular Expression : '" + regexReplace
+                  + "'\n";
+        }
+      } catch (Exception e)
+      {
+        invalidMessage = "Invalid Regular Expression : '" + regexReplace
+                + "'\n";
+      }
+    }
+    else
+    {
+      // no regex
+      regexReplace = null;
+      // verify format is really correct.
+      if (link.indexOf("$" + varName + "$") == sqidPos)
+      {
+        url_suffix = link.substring(sqidPos + startLength - 1);
+        regexReplace = null;
+      }
+      else
+      {
+        invalidMessage = "Warning: invalid regex structure for URL link : "
+                + link;
+      }
+    }
+  }
+
+  /**
+   * Create a set of URL links for a sequence
+   * 
+   * @param seq
+   *          The sequence to create links for
+   * @param linkset
+   *          Map of links: key = id | link, value = [target, label, id, link]
+   */
+  public void createLinksFromSeq(final SequenceI seq,
+          Map<String, List<String>> linkset)
+  {
+    if (seq != null && dynamic)
+    {
+      createDynamicLinks(seq, linkset);
+    }
+    else
+    {
+      createStaticLink(linkset);
+    }
+  }
+
+  /**
+   * Create a static URL link
+   * 
+   * @param linkset
+   *          Map of links: key = id | link, value = [target, label, id, link]
+   */
+  protected void createStaticLink(Map<String, List<String>> linkset)
+  {
+    if (!linkset.containsKey(label + "|" + getUrl_prefix()))
+    {
+      // Add a non-dynamic link
+      linkset.put(label + "|" + getUrl_prefix(),
+              Arrays.asList(target, label, null, getUrl_prefix()));
+    }
+  }
 
+  /**
+   * Create dynamic URL links
+   * 
+   * @param seq
+   *          The sequence to create links for
+   * @param linkset
+   *          Map of links: key = id | link, value = [target, label, id, link]
+   */
+  protected void createDynamicLinks(final SequenceI seq,
+          Map<String, List<String>> linkset)
+  {
+    // collect id string too
+    String id = seq.getName();
+    String descr = seq.getDescription();
+    if (descr != null && descr.length() < 1)
+    {
+      descr = null;
+    }
+
+    if (usesDBAccession()) // link is ID
+    {
+      // collect matching db-refs
+      DBRefEntry[] dbr = DBRefUtils.selectRefs(seq.getDBRefs(),
+              new String[] { target });
+
+      // if there are any dbrefs which match up with the link
+      if (dbr != null)
+      {
+        for (int r = 0; r < dbr.length; r++)
+        {
+          // create Bare ID link for this URL
+          createBareURLLink(dbr[r].getAccessionId(), true, linkset);
+        }
+      }
+    }
+    else if (!usesDBAccession() && id != null) // link is name
+    {
+      // create Bare ID link for this URL
+      createBareURLLink(id, false, linkset);
+    }
+
+    // Create urls from description but only for URL links which are regex
+    // links
+    if (descr != null && getRegexReplace() != null)
+    {
+      // create link for this URL from description where regex matches
+      createBareURLLink(descr, false, linkset);
+    }
+  }
+
+  /*
+   * Create a bare URL Link
+   * Returns map where key = id | link, and value = [target, label, id, link]
+   */
+  protected void createBareURLLink(String id, Boolean combineLabel,
+          Map<String, List<String>> linkset)
+  {
+    String[] urls = makeUrls(id, true);
+    if (urls != null)
+    {
+      for (int u = 0; u < urls.length; u += 2)
+      {
+        if (!linkset.containsKey(urls[u] + "|" + urls[u + 1]))
+        {
+          String thisLabel = label;
+          if (combineLabel)
+          {
+            // incorporate label with idstring
+            thisLabel = label + "|" + urls[u];
+          }
+
+          linkset.put(urls[u] + "|" + urls[u + 1],
+                  Arrays.asList(target, thisLabel, urls[u], urls[u + 1]));
+        }
+      }
+    }
   }
 
   private static void testUrls(UrlLink ul, String idstring, String[] urls)
@@ -341,7 +533,8 @@ public class UrlLink
      * "PF3|http://us.expasy.org/cgi-bin/niceprot.pl?$SEQUENCE_ID=/PFAM:(.+)/=$"
      * , "NOTFER|http://notfer.org/$SEQUENCE_ID=/(?<!\\s)(.+)/=$",
      */
-    "NESTED|http://nested/$SEQUENCE_ID=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=$/nested" };
+    "NESTED|http://nested/$" + DB_ACCESSION
+            + "=/^(?:Label:)?(?:(?:gi\\|(\\d+))|([^:]+))/=$/nested" };
     String[] idstrings = new String[] {
     /*
      * //"LGUL_human", //"QWIQW_123123", "uniprot|why_do+_12313_foo",
@@ -385,10 +578,14 @@ public class UrlLink
 
   public boolean isDynamic()
   {
-    // TODO Auto-generated method stub
     return dynamic;
   }
 
+  public boolean usesDBAccession()
+  {
+    return uses_db_accession;
+  }
+
   public void setLabel(String newlabel)
   {
     this.label = newlabel;