JAL-3253 preliminary static fixes for JavaScript part 3 of 3
[jalview.git] / src / jalview / util / GroupUrlLink.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.util;
22
23 import jalview.datamodel.SequenceI;
24
25 import java.util.Hashtable;
26
27 /**
28  * This class is not implemented because Preferences never puts anything in
29  * groupURLLinks.
30  * 
31  * @author hansonr
32  *
33  */
34 public class GroupUrlLink
35 {
36   @SuppressWarnings("serial")
37   public class UrlStringTooLongException extends Exception
38   {
39     public UrlStringTooLongException(int lng)
40     {
41       urlLength = lng;
42     }
43
44     public int urlLength;
45
46     @Override
47     public String toString()
48     {
49       return "Generated url is estimated to be too long (" + urlLength
50               + ")";
51     }
52   }
53
54   /**
55    * Helper class based on the UrlLink class which enables URLs to be
56    * constructed from sequences or IDs associated with a group of sequences. URL
57    * definitions consist of a pipe separated string containing a <label>|<url
58    * construct>|<separator character>[|<sequence separator character>]. The url
59    * construct includes regex qualified tokens which are replaced with seuqence
60    * IDs ($SEQUENCE_IDS$) and/or seuqence regions ($SEQUENCES$) that are
61    * extracted from the group. See <code>UrlLink</code> for more information
62    * about the approach, and the original implementation. Documentation to come.
63    * Note - groupUrls can be very big!
64    */
65   private String url_prefix, target, label;
66
67   /**
68    * these are all filled in order of the occurence of each token in the url
69    * string template
70    */
71   private String url_suffix[], separators[], regexReplace[];
72
73   private String invalidMessage = null;
74
75   /**
76    * position of each token (which can appear once only) in the url
77    */
78   private int[] segs;
79
80   /**
81    * contains tokens in the order they appear in the URL template.
82    */
83   private String[] mtch;
84
85   /**
86    * tokens that can be replaced in the URL.
87    */
88   private static final String[] tokens = new String[] { "SEQUENCEIDS",
89       "SEQUENCES", "DATASETID" };
90
91   // /**
92   // * test for GroupURLType bitfield (with default tokens)
93   // */
94   // private static final int SEQUENCEIDS = 1;
95   //
96   // /**
97   // * test for GroupURLType bitfield (with default tokens)
98   // */
99   // private static final int SEQUENCES = 2;
100   //
101   // /**
102   // * test for GroupURLType bitfield (with default tokens)
103   // */
104   // private static final int DATASETID = 4;
105   //
106   // private int idseg = -1, seqseg = -1;
107
108   /**
109    * 
110    * called by PopupMenu.buildGroupURLMenu()
111    * 
112    * parse the given linkString of the form '<label>|<url>|separator
113    * char[|optional sequence separator char]' into parts. url may contain a
114    * string $SEQUENCEIDS<=optional regex=>$ where <=optional regex=> must be of
115    * the form =/<perl style regex>/=$ or $SEQUENCES<=optional regex=>$ or
116    * $SEQUENCES<=optional regex=>$.
117    * 
118    * @param link
119    */
120   public GroupUrlLink(String link)
121   {
122     int sep = link.indexOf("|");
123     segs = new int[tokens.length];
124     int ntoks = 0;
125     for (int i = 0; i < segs.length; i++)
126     {
127       if ((segs[i] = link.indexOf("$" + tokens[i])) > -1)
128       {
129         ntoks++;
130       }
131     }
132     // expect at least one token
133     if (ntoks == 0)
134     {
135       invalidMessage = "Group URL string must contain at least one of ";
136       for (int i = 0; i < segs.length; i++)
137       {
138         invalidMessage += " '$" + tokens[i] + "[=/regex=/]$'";
139       }
140       return;
141     }
142
143     int[] ptok = new int[ntoks + 1];
144     String[] tmtch = new String[ntoks + 1];
145     mtch = new String[ntoks];
146     for (int i = 0, t = 0; i < segs.length; i++)
147     {
148       if (segs[i] > -1)
149       {
150         ptok[t] = segs[i];
151         tmtch[t++] = tokens[i];
152       }
153     }
154     ptok[ntoks] = link.length();
155     tmtch[ntoks] = "$$$$$$$$$";
156     jalview.util.QuickSort.sort(ptok, tmtch);
157     for (int i = 0; i < ntoks; i++)
158     {
159       mtch[i] = tmtch[i]; // TODO: check order is ascending
160     }
161     /*
162      * replaces the specific code below {}; if (psqids > -1 && pseqs > -1) { if
163      * (psqids > pseqs) { idseg = 1; seqseg = 0;
164      * 
165      * ptok = new int[] { pseqs, psqids, link.length() }; mtch = new String[] {
166      * "$SEQUENCES", "$SEQUENCEIDS" }; } else { idseg = 0; seqseg = 1; ptok =
167      * new int[] { psqids, pseqs, link.length() }; mtch = new String[] {
168      * "$SEQUENCEIDS", "$SEQUENCES" }; } } else { if (psqids != -1) { idseg = 0;
169      * ptok = new int[] { psqids, link.length() }; mtch = new String[] {
170      * "$SEQUENCEIDS" }; } else { seqseg = 0; ptok = new int[] { pseqs,
171      * link.length() }; mtch = new String[] { "$SEQUENCES" }; } }
172      */
173
174     int p = sep;
175     // first get the label and target part before the first |
176     do
177     {
178       sep = p;
179       p = link.indexOf("|", sep + 1);
180     } while (p > sep && p < ptok[0]);
181     // Assuming that the URL itself does not contain any '|' symbols
182     // sep now contains last pipe symbol position prior to any regex symbols
183     label = link.substring(0, sep);
184     if (label.indexOf("|") > -1)
185     {
186       // | terminated database name / www target at start of Label
187       target = label.substring(0, label.indexOf("|"));
188     }
189     else if (label.indexOf(" ") > 2)
190     {
191       // space separated Label - matches database name
192       target = label.substring(0, label.indexOf(" "));
193     }
194     else
195     {
196       target = label;
197     }
198     // Now Parse URL : Whole URL string first
199     url_prefix = link.substring(sep + 1, ptok[0]);
200     url_suffix = new String[mtch.length];
201     regexReplace = new String[mtch.length];
202     // and loop through tokens
203     for (int pass = 0; pass < mtch.length; pass++)
204     {
205       int mlength = 3 + mtch[pass].length();
206       if (link.indexOf("$" + mtch[pass] + "=/") == ptok[pass] && (p = link
207               .indexOf("/=$", ptok[pass] + mlength)) > ptok[pass] + mlength)
208       {
209         // Extract Regex and suffix
210         if (ptok[pass + 1] < p + 3)
211         {
212           // tokens are not allowed inside other tokens - e.g. inserting a
213           // $sequences$ into the regex match for the sequenceid
214           invalidMessage = "Token regexes cannot contain other regexes (did you terminate the $"
215                   + mtch[pass] + " regex with a '/=$' ?";
216           return;
217         }
218         url_suffix[pass] = link.substring(p + 3, ptok[pass + 1]);
219         regexReplace[pass] = link.substring(ptok[pass] + mlength, p);
220         try
221         {
222           com.stevesoft.pat.Regex rg = com.stevesoft.pat.Regex
223                   .perlCode("/" + regexReplace[pass] + "/");
224           if (rg == null)
225           {
226             invalidMessage = "Invalid Regular Expression : '"
227                     + regexReplace[pass] + "'\n";
228           }
229         } catch (Exception e)
230         {
231           invalidMessage = "Invalid Regular Expression : '"
232                   + regexReplace[pass] + "'\n";
233         }
234       }
235       else
236       {
237         regexReplace[pass] = null;
238         // verify format is really correct.
239         if ((p = link.indexOf("$" + mtch[pass] + "$")) == ptok[pass])
240         {
241           url_suffix[pass] = link.substring(p + mtch[pass].length() + 2,
242                   ptok[pass + 1]);
243         }
244         else
245         {
246           invalidMessage = "Warning: invalid regex structure (after '"
247                   + mtch[0] + "') for URL link : " + link;
248         }
249       }
250     }
251     int pass = 0;
252     separators = new String[url_suffix.length];
253     String suffices = url_suffix[url_suffix.length - 1], lastsep = ",";
254     // have a look in the last suffix for any more separators.
255     while ((p = suffices.indexOf('|')) > -1)
256     {
257       separators[pass] = suffices.substring(p + 1);
258       if (pass == 0)
259       {
260         // trim the original suffix string
261         url_suffix[url_suffix.length - 1] = suffices.substring(0, p);
262       }
263       else
264       {
265         lastsep = (separators[pass - 1] = separators[pass - 1].substring(0,
266                 p));
267       }
268       suffices = separators[pass];
269       pass++;
270     }
271     if (pass > 0)
272     {
273       lastsep = separators[pass - 1];
274     }
275     // last separator is always used for all the remaining separators
276     while (pass < separators.length)
277     {
278       separators[pass++] = lastsep;
279     }
280   }
281
282   /**
283    * @return the url_suffix
284    */
285   public String getUrl_suffix()
286   {
287     return url_suffix[url_suffix.length - 1];
288   }
289
290   /**
291    * 
292    * called by PopupMenu.addShowLink()
293    * 
294    * @return the url_prefix
295    */
296   public String getUrl_prefix()
297   {
298     return url_prefix;
299   }
300
301   /**
302    * called by PopupMenu.buildGroupURLMenu()
303    * 
304    * @return the target
305    */
306   public String getTarget()
307   {
308     return target;
309   }
310
311   /**
312    * 
313    * called by PopupMenu.buildGroupURLMenu()
314    * 
315    * @return the label
316    */
317   public String getLabel()
318   {
319     return label;
320   }
321
322   /**
323    * 
324    * called by PopupMenu.buildGroupURLMenu()
325    * 
326    * @return the invalidMessage
327    */
328   public String getInvalidMessage()
329   {
330     return invalidMessage;
331   }
332
333   /**
334    * called by PopupMenu.buildGroupURLMenu()
335    * 
336    * Check if URL string was parsed properly.
337    * 
338    * @return boolean - if false then <code>getInvalidMessage</code> returns an
339    *         error message
340    */
341   public boolean isValid()
342   {
343     return invalidMessage == null;
344   }
345
346   /**
347    * 
348    * called by PopupMenu.buildGroupURLMenu()
349    * 
350    * This method is never called, because PopupMenu.buildGroupMenu() is never
351    * called. It relates to the popup menu for the idPanel.
352    * 
353    * @param ids
354    * @param seqstr
355    * @param string
356    * @param onlyIfMatches
357    * @return URL stub objects ready to pass to constructFrom in the form of
358    *         Object[] { int[], boolean[], Hashtable&lt;String, String[]&gt;,
359    *         boolean[] }
360    * @throws UrlStringTooLongException
361    */
362   public Object[] makeUrlStubs(String[] ids, String[] seqstr, String string,
363           boolean onlyIfMatches) throws UrlStringTooLongException
364   {
365     Hashtable<String, String[]> rstrings = replacementArgs(ids, seqstr,
366             string);
367     boolean createFullURL = false;
368     Object[] stubs = makeUrlsIf(createFullURL, rstrings, onlyIfMatches);
369     // stubs is just { int[] boolean[] }
370     return stubs == null ? null
371             : new Object[]
372             { stubs[0], stubs[1], rstrings,
373                 new boolean[]
374                 { onlyIfMatches } }; // int[] boolean[] Hashtable boolean[]
375   }
376
377   /**
378    * gathers input into a hashtable
379    * 
380    * @param idstrings
381    * @param seqstrings
382    * @param dsstring
383    * @return
384    */
385   private Hashtable<String, String[]> replacementArgs(String[] idstrings,
386           String[] seqstrings, String dsstring)
387   {
388     Hashtable<String, String[]> rstrings = new Hashtable<>();
389     rstrings.put(tokens[0], idstrings);
390     rstrings.put(tokens[1], seqstrings);
391     rstrings.put(tokens[2], new String[] { dsstring });
392     if (idstrings.length != seqstrings.length)
393     {
394       throw new Error(MessageManager.getString(
395               "error.idstring_seqstrings_only_one_per_sequence"));
396     }
397     return rstrings;
398   }
399
400   /**
401    * Called from PopupMenu.addShowLink action listener
402    * 
403    * generate the URL for the given URL stub object array returned from
404    * makeUrlStubs
405    * 
406    * @param stubs
407    *          Object[] { int[] { number of matches seqs }, boolean[] { which
408    *          matched }, (if createFullUrl also has StringBuffer[] { segment
409    *          generated from inputs that is used in URL }, String[] { url })}
410    * @return URL string
411    * @throws UrlStringTooLongException
412    */
413   @SuppressWarnings("unchecked")
414   public String constructFrom(Object[] stubs)
415           throws UrlStringTooLongException
416   {
417     // Object[] {
418     // int[] { number of matches seqs },
419     // boolean[] { which matched }
420     // }
421
422     boolean createFullURL = true;
423     Hashtable<String, String[]> repstrings = (Hashtable<String, String[]>) stubs[2];
424     boolean onlyIfMatches = ((boolean[]) stubs[3])[0];
425     String url = ((String[]) makeUrlsIf(createFullURL, repstrings,
426             onlyIfMatches)[3])[0];
427     return url;
428   }
429
430   /**
431    * conditionally generate urls or stubs for a given input.
432    * 
433    * @param createFullUrl
434    *          set to false if you only want to test if URLs would be generated.
435    * @param repstrings
436    * @param onlyIfMatches
437    * @return null if no url is generated. Object[] { int[] { number of matches
438    *         seqs }, boolean[] { which matched }, (if createFullUrl also has
439    *         StringBuffer[] { segment generated from inputs that is used in URL
440    *         }, String[] { url })}
441    * @throws UrlStringTooLongException
442    */
443   private Object[] makeUrlsIf(boolean createFullUrl,
444           Hashtable<String, String[]> repstrings,
445           boolean onlyIfMatches) throws UrlStringTooLongException
446   {
447     int pass = 0;
448
449     // prepare string arrays in correct order to be assembled into URL input
450     String[][] idseq = new String[mtch.length][]; // indexed by pass
451     int mins = 0, maxs = 0; // allowed two values, 1 or n-sequences.
452     for (int i = 0; i < mtch.length; i++)
453     {
454       idseq[i] = repstrings.get(mtch[i]);
455       if (idseq[i].length >= 1)
456       {
457         if (mins == 0 && idseq[i].length == 1)
458         {
459           mins = 1;
460         }
461         if (maxs < 2)
462         {
463           maxs = idseq[i].length;
464         }
465         else
466         {
467           if (maxs != idseq[i].length)
468           {
469             throw new Error(MessageManager.formatMessage(
470                     "error.cannot_have_mixed_length_replacement_vectors",
471                     new String[]
472                     { (mtch[i]),
473                         Integer.valueOf(idseq[i].length).toString(),
474                         Integer.valueOf(maxs).toString() }));
475           }
476         }
477       }
478       else
479       {
480         throw new Error(MessageManager.getString(
481                 "error.cannot_have_zero_length_vector_replacement_strings"));
482       }
483     }
484     // iterate through input, collating segments to be inserted into url
485     StringBuffer matched[] = new StringBuffer[idseq.length];
486     // and precompile regexes
487     com.stevesoft.pat.Regex[] rgxs = new com.stevesoft.pat.Regex[matched.length];
488     for (pass = 0; pass < matched.length; pass++)
489     {
490       matched[pass] = new StringBuffer();
491       if (regexReplace[pass] != null)
492       {
493         rgxs[pass] = com.stevesoft.pat.Regex
494                 .perlCode("/" + regexReplace[pass] + "/");
495       }
496       else
497       {
498         rgxs[pass] = null;
499       }
500     }
501     // tot up the invariant lengths for this url
502     int urllength = url_prefix.length();
503     for (pass = 0; pass < matched.length; pass++)
504     {
505       urllength += url_suffix[pass].length();
506     }
507
508     // flags to record which of the input sequences were actually used to
509     // generate the
510     // url
511     boolean[] thismatched = new boolean[maxs];
512     int seqsmatched = 0;
513     for (int sq = 0; sq < maxs; sq++)
514     {
515       // initialise flag for match
516       thismatched[sq] = false;
517       StringBuffer[] thematches = new StringBuffer[rgxs.length];
518       for (pass = 0; pass < rgxs.length; pass++)
519       {
520         thematches[pass] = new StringBuffer(); // initialise - in case there are
521                                                // no more
522         // matches.
523         // if a regex is provided, then it must match for all sequences in all
524         // tokens for it to be considered.
525         if (idseq[pass].length <= sq)
526         {
527           // no more replacement strings to try for this token
528           continue;
529         }
530         if (rgxs[pass] != null)
531         {
532           com.stevesoft.pat.Regex rg = rgxs[pass];
533           int rematchat = 0;
534           // concatenate all matches of re in the given string!
535           while (rg.searchFrom(idseq[pass][sq], rematchat))
536           {
537             rematchat = rg.matchedTo();
538             thismatched[sq] |= true;
539             urllength += rg.charsMatched(); // count length
540             if ((urllength + 32) > Platform.getMaxCommandLineLength())
541             {
542               throw new UrlStringTooLongException(urllength);
543             }
544
545             if (!createFullUrl)
546             {
547               continue; // don't bother making the URL replacement text.
548             }
549             // do we take the cartesian products of the substituents ?
550             int ns = rg.numSubs();
551             if (ns == 0)
552             {
553               thematches[pass].append(rg.stringMatched());// take whole regex
554             }
555             /*
556              * else if (ns==1) { // take only subgroup match return new String[]
557              * { rg.stringMatched(1), url_prefix+rg.stringMatched(1)+url_suffix
558              * }; }
559              */
560             // deal with multiple submatch case - for moment we do the simplest
561             // - concatenate the matched regions, instead of creating a complete
562             // list for each alternate match over all sequences.
563             // TODO: specify a 'replace pattern' - next refinement
564             else
565             {
566               // debug
567               /*
568                * for (int s = 0; s <= rg.numSubs(); s++) {
569                * System.err.println("Sub " + s + " : " + rg.matchedFrom(s) +
570                * " : " + rg.matchedTo(s) + " : '" + rg.stringMatched(s) + "'");
571                * }
572                */
573               // try to collate subgroup matches
574               StringBuffer subs = new StringBuffer();
575               // have to loop through submatches, collating them at top level
576               // match
577               int s = 0; // 1;
578               while (s <= ns)
579               {
580                 if (s + 1 <= ns && rg.matchedTo(s) > -1
581                         && rg.matchedTo(s + 1) > -1
582                         && rg.matchedTo(s + 1) < rg.matchedTo(s))
583                 {
584                   // s is top level submatch. search for submatches enclosed by
585                   // this one
586                   int r = s + 1;
587                   StringBuffer rmtch = new StringBuffer();
588                   while (r <= ns && rg.matchedTo(r) <= rg.matchedTo(s))
589                   {
590                     if (rg.matchedFrom(r) > -1)
591                     {
592                       rmtch.append(rg.stringMatched(r));
593                     }
594                     r++;
595                   }
596                   if (rmtch.length() > 0)
597                   {
598                     subs.append(rmtch); // simply concatenate
599                   }
600                   s = r;
601                 }
602                 else
603                 {
604                   if (rg.matchedFrom(s) > -1)
605                   {
606                     subs.append(rg.stringMatched(s)); // concatenate
607                   }
608                   s++;
609                 }
610               }
611               thematches[pass].append(subs);
612             }
613           }
614         }
615         else
616         {
617           // are we only supposed to take regex matches ?
618           if (!onlyIfMatches)
619           {
620             thismatched[sq] |= true;
621             urllength += idseq[pass][sq].length(); // tot up length
622             if (createFullUrl)
623             {
624               thematches[pass] = new StringBuffer(idseq[pass][sq]); // take
625                                                                     // whole
626                                                                     // string -
627               // regardless - probably not a
628               // good idea!
629               /*
630                * TODO: do some boilerplate trimming of the fields to make them
631                * sensible e.g. trim off any 'prefix' in the id string (see
632                * UrlLink for the below) - pre 2.4 Jalview behaviour if
633                * (idstring.indexOf("|") > -1) { idstring =
634                * idstring.substring(idstring.lastIndexOf("|") + 1); }
635                */
636             }
637
638           }
639         }
640       }
641
642       // check if we are going to add this sequence's results ? all token
643       // replacements must be valid for this to happen!
644       // (including single value replacements - eg. dataset name)
645       if (thismatched[sq])
646       {
647         if (createFullUrl)
648         {
649           for (pass = 0; pass < matched.length; pass++)
650           {
651             if (idseq[pass].length > 1 && matched[pass].length() > 0)
652             {
653               matched[pass].append(separators[pass]);
654             }
655             matched[pass].append(thematches[pass]);
656           }
657         }
658         seqsmatched++;
659       }
660     }
661     // finally, if any sequences matched, then form the URL and return
662     if (seqsmatched == 0 || (createFullUrl && matched[0].length() == 0))
663     {
664       // no matches - no url generated
665       return null;
666     }
667     // check if we are beyond the feasible command line string limit for this
668     // platform
669     if ((urllength + 32) > Platform.getMaxCommandLineLength())
670     {
671       throw new UrlStringTooLongException(urllength);
672     }
673     if (!createFullUrl)
674     {
675       // just return the essential info about what the URL would be generated
676       // from
677       return new Object[] { new int[] { seqsmatched }, thismatched // boolean[]
678       };
679     }
680     // otherwise, create the URL completely.
681
682     StringBuffer submiturl = new StringBuffer();
683     submiturl.append(url_prefix);
684     for (pass = 0; pass < matched.length; pass++)
685     {
686       submiturl.append(matched[pass]);
687       if (url_suffix[pass] != null)
688       {
689         submiturl.append(url_suffix[pass]);
690       }
691     }
692
693     // full return
694     return new Object[] { new int[] { seqsmatched }, thismatched, // boolean[]
695         matched, // StringBuffer[]
696         new String[]
697         { submiturl.toString() } };
698   }
699
700   /**
701    * 
702    * Called by PopupMenu.addShowLinks()
703    * 
704    * @param urlstub
705    * @return number of distinct sequence (id or seuqence) replacements predicted
706    *         for this stub
707    */
708   public int getNumberInvolved(Object[] urlstub)
709   {
710     return ((int[]) urlstub[0])[0]; // returns seqsmatched from
711                                     // makeUrlsIf(false,...)
712   }
713
714   /**
715    * called by PopupMenu.buildGroupURLMenu()
716    * 
717    * get token types present in this url as a bitfield indicating presence of
718    * each token from tokens (LSB->MSB).
719    * 
720    * @return groupURL class as integer
721    */
722   public int getGroupURLType()
723   {
724     int r = 0;
725     for (int pass = 0; pass < tokens.length; pass++)
726     {
727       for (int i = 0; i < mtch.length; i++)
728       {
729         if (mtch[i].equals(tokens[pass]))
730         {
731           r += 1 << pass;
732         }
733       }
734     }
735     return r;
736   }
737
738   /**
739    * called by PopupMenu.buildGroupURLMenu()
740    * 
741    * covenience method to generate the id and sequence string vector from a set
742    * of seuqences using each sequence's getName() and getSequenceAsString()
743    * method
744    * 
745    * @param seqs
746    * @return String[][] {{sequence ids},{sequence strings}}
747    */
748   public static String[][] formStrings(SequenceI[] seqs)
749   {
750     String[][] idset = new String[2][seqs.length];
751     for (int i = 0; i < seqs.length; i++)
752     {
753       idset[0][i] = seqs[i].getName();
754       idset[1][i] = seqs[i].getSequenceAsString();
755     }
756     return idset;
757   }
758
759   // commented out test code
760   //
761   // /**
762   // *
763   // * @param argv
764   // * @j2sIgnore
765   // */
766   // public static void main(String argv[])
767   // {
768   // // note - JAL-1383 - these services are all dead
769   // String[] links = new String[] {
770   // "EnVision2|IDS|http://www.ebi.ac.uk/enfin-srv/envision2/pages/linkin.jsf?workflow=Enfin%20Default%20Workflow&datasetName=linkInDatasetFromJalview&input=$SEQUENCEIDS$&inputType=0|,",
771   // "EnVision2|Seqs|http://www.ebi.ac.uk/enfin-srv/envision2/pages/linkin.jsf?workflow=Enfin%20Default%20Workflow&datasetName=linkInDatasetFromJalview&input=$SEQUENCES$&inputType=1|,",
772   // "EnVision2|IDS|http://www.ebi.ac.uk/enfin-srv/envision2/pages/linkin.jsf?workflow=Enfin%20Default%20Workflow&datasetName=$DATASETID$&input=$SEQUENCEIDS$&inputType=0|,",
773   // "EnVision2|Seqs|http://www.ebi.ac.uk/enfin-srv/envision2/pages/linkin.jsf?workflow=Enfin%20Default%20Workflow&datasetName=$DATASETID$&input=$SEQUENCES$&inputType=1|,",
774   // "EnVision2|IDS|http://www.ebi.ac.uk/enfin-srv/envision2/pages/linkin.jsf?workflow=$SEQUENCEIDS$&datasetName=linkInDatasetFromJalview&input=$SEQUENCEIDS$&inputType=0|,",
775   // "EnVision2|Seqs|http://www.ebi.ac.uk/enfin-srv/envision2/pages/linkin.jsf?workflow=$SEQUENCEIDS$&datasetName=$DATASETID$&input=$SEQUENCES$&inputType=1|,",
776   // "EnVision2
777   // Seqs|http://www.ebi.ac.uk/enfin-srv/envision2/pages/linkin.jsf?workflow=Default&datasetName=JalviewSeqs$DATASETID$&input=$SEQUENCES=/([a-zA-Z]+)/=$&inputType=1|,",
778   // "EnVision2
779   // Seqs|http://www.ebi.ac.uk/enfin-srv/envision2/pages/linkin.jsf?workflow=Default&datasetName=JalviewSeqs$DATASETID$&input=$SEQUENCES=/[A-Za-z]+/=$&inputType=1|,"
780   // /*
781   // *
782   // http://www.ebi.ac.uk/enfin-srv/envision2/pages/linkin.jsf?input=P38389,P38398
783   // * &inputType=0&workflow=Enfin%20Default%20Workflow&datasetName=
784   // * linkInDatasetFromPRIDE
785   // */
786   // };
787   //
788   // SequenceI[] seqs = new SequenceI[] {
789   // new Sequence("StupidLabel:gi|9234|pdb|102L|A",
790   // "asdiasdpasdpadpwpadasdpaspdw"), };
791   // String[][] seqsandids = formStrings(seqs);
792   // for (int i = 0; i < links.length; i++)
793   // {
794   // GroupUrlLink ul = new GroupUrlLink(links[i]);
795   // if (ul.isValid())
796   // {
797   // System.out.println("\n\n\n");
798   // System.out.println(
799   // "Link " + i + " " + links[i] + " : " + ul.toString());
800   // System.out.println(" pref : " + ul.getUrl_prefix());
801   // System.out.println(" IdReplace : " + ul.getIDRegexReplace());
802   // System.out.println(" SeqReplace : " + ul.getSeqRegexReplace());
803   // System.out.println(" Suffixes : " + ul.getUrl_suffix());
804   //
805   // System.out.println(
806   // "<insert input id and sequence strings here> Without onlyIfMatches:");
807   // Object[] urls;
808   // try
809   // {
810   // urls = ul.makeUrls(seqsandids[0], seqsandids[1], "mydataset",
811   // false);
812   // testUrls(ul, seqsandids, urls);
813   // } catch (UrlStringTooLongException ex)
814   // {
815   // System.out.println("too long exception " + ex);
816   // }
817   // System.out.println(
818   // "<insert input id and sequence strings here> With onlyIfMatches set:");
819   // try
820   // {
821   // urls = ul.makeUrls(seqsandids[0], seqsandids[1], "mydataset",
822   // true);
823   // testUrls(ul, seqsandids, urls);
824   // } catch (UrlStringTooLongException ex)
825   // {
826   // System.out.println("too long exception " + ex);
827   // }
828   // }
829   // else
830   // {
831   // System.err.println("Invalid URLLink : " + links[i] + " : "
832   // + ul.getInvalidMessage());
833   // }
834   // }
835   // }
836   // /**
837   // * @return the sequence ID regexReplace
838   // */
839   // private String getIDRegexReplace()
840   // {
841   // String token = tokens[0];
842   // for (int i = 0; i < mtch.length; i++)
843   // {
844   // if (segs[i] > -1 && mtch[i].equals(token))
845   // {
846   // return regexReplace[i];
847   // }
848   // }
849   // return null;
850   // }
851   //
852   // /**
853   // * @return the sequence ID regexReplace
854   // */
855   // private String getSeqRegexReplace()
856   // {
857   // return _replaceFor(tokens[1]);
858   // }
859   //
860   // /**
861   // * report stats about the generated url string given an input set
862   // *
863   // * @param ul
864   // * @param idstring
865   // * @param url
866   // */
867   // private static void testUrls(GroupUrlLink ul, String[][] idstring,
868   // Object[] url)
869   // {
870   //
871   // if (url == null)
872   // {
873   // System.out.println("Created NO urls.");
874   // }
875   // else
876   // {
877   // System.out.println("Created a url from " + ((int[]) url[0])[0]
878   // + "out of " + idstring[0].length + " sequences.");
879   // System.out.println("Sequences that did not match:");
880   // for (int sq = 0; sq < idstring[0].length; sq++)
881   // {
882   // if (!((boolean[]) url[1])[sq])
883   // {
884   // System.out.println("Seq " + sq + ": " + idstring[0][sq] + "\t: "
885   // + idstring[1][sq]);
886   // }
887   // }
888   // System.out.println("Sequences that DID match:");
889   // for (int sq = 0; sq < idstring[0].length; sq++)
890   // {
891   // if (((boolean[]) url[1])[sq])
892   // {
893   // System.out.println("Seq " + sq + ": " + idstring[0][sq] + "\t: "
894   // + idstring[1][sq]);
895   // }
896   // }
897   // System.out.println("The generated URL:");
898   // System.out.println(((String[]) url[3])[0]);
899   // }
900   // }
901   //
902   // public void setLabel(String newlabel)
903   // {
904   // this.label = newlabel;
905   // }
906   // /**
907   // * return one or more URL strings by applying regex to the given idstring
908   // *
909   // * @param idstrings
910   // * array of id strings to pass to service
911   // * @param seqstrings
912   // * array of seq strings to pass to service
913   // * @param onlyIfMatches
914   // * - when true url strings are only made if regex is defined and
915   // * matches for all qualified tokens in groupURL - TODO: consider if
916   // * onlyIfMatches is really a useful parameter!
917   // * @return null or Object[] { int[] { number of seqs substituted},boolean[]
918   // {
919   // * which seqs were substituted }, StringBuffer[] { substituted lists
920   // * for each token }, String[] { url } }
921   // * @throws UrlStringTooLongException
922   // */
923   // private Object[] makeUrls(String[] idstrings, String[] seqstrings,
924   // String dsstring, boolean onlyIfMatches)
925   // throws UrlStringTooLongException
926   // {
927   // Hashtable<String, String[]> rstrings = replacementArgs(idstrings,
928   // seqstrings, dsstring);
929   // return makeUrls(rstrings, onlyIfMatches);
930   // }
931   //
932   // /**
933   // *
934   // * @param repstrings
935   // * @param onlyIfMatches
936   // * @return Object[] {int[], boolean[], StringBuffer[], String[] }
937   // * @throws UrlStringTooLongException
938   // */
939   // private Object[] makeUrls(Hashtable<String, String[]> repstrings,
940   // boolean onlyIfMatches)
941   // throws UrlStringTooLongException
942   // {
943   // return makeUrlsIf(true, repstrings, onlyIfMatches);
944   // }
945   //
946
947   @Override
948   public String toString()
949   {
950     StringBuffer result = new StringBuffer();
951     result.append(label + "|" + url_prefix);
952     int r;
953     for (r = 0; r < url_suffix.length; r++)
954     {
955       result.append("$");
956       result.append(mtch[r]);
957       if (regexReplace[r] != null)
958       {
959         result.append("=/");
960         result.append(regexReplace[r]);
961         result.append("/=");
962       }
963       result.append("$");
964       result.append(url_suffix[r]);
965     }
966     for (r = 0; r < separators.length; r++)
967     {
968       result.append("|");
969       result.append(separators[r]);
970     }
971     return result.toString();
972   }
973
974 }