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