JAL-1432 updated copyright notices
[jalview.git] / src / jalview / ws / rest / params / SeqGroupIndexVector.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
3  * Copyright (C) 2014 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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 package jalview.ws.rest.params;
20
21 import jalview.datamodel.AlignmentI;
22 import jalview.datamodel.SequenceGroup;
23 import jalview.datamodel.SequenceI;
24 import jalview.ws.params.OptionI;
25 import jalview.ws.params.simple.IntegerParameter;
26 import jalview.ws.params.simple.Option;
27 import jalview.ws.rest.AlignmentProcessor;
28 import jalview.ws.rest.InputType;
29 import jalview.ws.rest.NoValidInputDataException;
30 import jalview.ws.rest.RestJob;
31
32 import java.io.UnsupportedEncodingException;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.List;
36
37 import org.apache.http.entity.mime.content.ContentBody;
38 import org.apache.http.entity.mime.content.StringBody;
39
40 /**
41  * Represents the partitions defined on the alignment as indices e.g. for a
42  * partition (A,B,C),(D,E),(F) The indices would be 3,2,1. Note, the alignment
43  * must be ordered so groups are contiguous before this input type can be used.
44  * 
45  * @author JimP
46  * 
47  */
48 public class SeqGroupIndexVector extends InputType implements
49         AlignmentProcessor
50 {
51   public SeqGroupIndexVector()
52   {
53     super(new Class[]
54     { AlignmentI.class });
55   }
56
57   /**
58    * separator for list of sequence Indices - default is ','
59    */
60   public String sep = ",";
61
62   /**
63    * min size of each partition
64    */
65   public int minsize = 1;
66
67   molType type;
68
69   /**
70    * prepare the context alignment for this input
71    * 
72    * @param al
73    *          - alignment to be processed
74    * @return al or a new alignment with appropriate attributes/order for input
75    */
76   public AlignmentI prepareAlignment(AlignmentI al)
77   {
78     jalview.analysis.AlignmentSorter.sortByGroup(al);
79     return al;
80   }
81
82   @Override
83   public ContentBody formatForInput(RestJob rj)
84           throws UnsupportedEncodingException, NoValidInputDataException
85   {
86     StringBuffer idvector = new StringBuffer();
87     boolean list = false;
88     AlignmentI al = rj.getAlignmentForInput(token, type);
89     // assume that alignment is properly ordered so groups form consecutive
90     // blocks
91     ArrayList<int[]> gl = new ArrayList<int[]>();
92     int p = 0,lowest=al.getHeight(), highest=0;
93     List<SequenceGroup> sgs;
94     synchronized (sgs = al.getGroups())
95     {
96       for (SequenceGroup sg : sgs)
97       {
98         if (sg.getSize() < minsize)
99         {
100           throw new NoValidInputDataException("Group contains less than "
101                   + minsize + " sequences.");
102         }
103         // TODO: refactor to sequenceGroup for efficiency -
104         // getAlignmentRowInterval(AlignmentI al)
105         int[] se = null;
106         for (SequenceI sq : sg.getSequencesInOrder(al))
107         {
108           p = al.findIndex(sq);
109           if (lowest>p)
110           {
111             lowest=p;
112           }
113           if (highest<p)
114           {
115             highest=p;
116           }
117           if (se == null)
118           {
119             se = new int[]
120             { p, p };
121           }
122           else
123           {
124             if (p < se[0])
125               se[0] = p;
126             if (p > se[1])
127               se[1] = p;
128           }
129         }
130         if (se != null)
131         {
132           gl.add(se);
133         }
134       }
135     }
136     // are there any more sequences ungrouped that should be added as a single
137     // remaining group ? - these might be at the start or the end
138     if (gl.size() > 0)
139     {
140       if (lowest-1>minsize)
141       {
142         gl.add(0, new int[]
143           { 0, lowest-2});
144       }
145       if ((al.getHeight()-1-highest)>minsize)
146       {
147         gl.add(new int[] { highest+1, al.getHeight()-1});
148       }
149     }
150     else
151     {
152       gl.add(new int[]
153       { 0, al.getHeight() - 1 });
154     }
155     if (min >= 0 && gl.size() < min)
156     {
157       throw new NoValidInputDataException(
158               "Not enough sequence groups for input. Need at least " + min
159                       + " groups (including ungrouped regions).");
160     }
161     if (max > 0 && gl.size() > max)
162     {
163       throw new NoValidInputDataException(
164               "Too many sequence groups for input. Need at most " + max
165                       + " groups (including ungrouped regions).");
166     }
167     int[][] vals = gl.toArray(new int[gl.size()][]);
168     int[] srt = new int[gl.size()];
169     for (int i = 0; i < vals.length; i++)
170       srt[i] = vals[i][0];
171     jalview.util.QuickSort.sort(srt, vals);
172     list = false;
173     int last = vals[0][0] - 1;
174     for (int[] range : vals)
175     {
176       if (range[1] > last)
177       {
178         if (list)
179         {
180           idvector.append(sep);
181         }
182         idvector.append(range[1] - last);
183         last = range[1];
184         list = true;
185       }
186     }
187     return new StringBody(idvector.toString());
188   }
189
190   /**
191    * set minimum number of sequences allowed in a partition. Default is 1
192    * sequence.
193    * 
194    * @param i
195    *          (number greater than 1)
196    */
197   public void setMinsize(int i)
198   {
199     if (minsize >= 1)
200     {
201       minsize = i;
202     }
203     else
204     {
205       minsize = 1;
206     }
207   }
208
209   @Override
210   public List<String> getURLEncodedParameter()
211   {
212     ArrayList<String> prms = new ArrayList<String>();
213     super.addBaseParams(prms);
214     prms.add("minsize='" + minsize + "'");
215     prms.add("sep='" + sep + "'");
216     if (type != null)
217     {
218       prms.add("type='" + type + "'");
219     }
220     return prms;
221   }
222
223   @Override
224   public String getURLtokenPrefix()
225   {
226     return "PARTITION";
227   }
228
229   @Override
230   public boolean configureProperty(String tok, String val,
231           StringBuffer warnings)
232   {
233
234     if (tok.startsWith("sep"))
235     {
236       sep = val;
237       return true;
238     }
239     if (tok.startsWith("minsize"))
240     {
241       try
242       {
243         minsize = Integer.valueOf(val);
244         if (minsize >= 0)
245           return true;
246       } catch (Exception x)
247       {
248
249       }
250       warnings.append("Invalid minsize value '" + val
251               + "'. Must be a positive integer.\n");
252     }
253     if (tok.startsWith("type"))
254     {
255       try
256       {
257         type = molType.valueOf(val);
258         return true;
259       } catch (Exception x)
260       {
261         warnings.append("Invalid molecule type '" + val
262                 + "'. Must be one of (");
263         for (molType v : molType.values())
264         {
265           warnings.append(" " + v);
266         }
267         warnings.append(")\n");
268       }
269     }
270     return false;
271   }
272
273   @Override
274   public List<OptionI> getOptions()
275   {
276     List<OptionI> lst = getBaseOptions();
277     lst.add(new Option("sep",
278             "Separator character between elements of vector", true, ",",
279             sep, Arrays.asList(new String[]
280             { " ", ",", ";", "\t", "|" }), null));
281     lst.add(new IntegerParameter("minsize",
282             "Minimum size of partition allowed by service", true, 1,
283             minsize, 1, 0));
284     lst.add(createMolTypeOption("type", "Sequence type", false, type,
285             molType.MIX));
286     return lst;
287   }
288
289 }