Set job title correctly and pass reason why
[jalview.git] / src / jalview / ws / rest / params / SeqGroupIndexVector.java
1 package jalview.ws.rest.params;
2
3 import jalview.datamodel.AlignmentI;
4 import jalview.datamodel.SequenceGroup;
5 import jalview.datamodel.SequenceI;
6 import jalview.ws.rest.AlignmentProcessor;
7 import jalview.ws.rest.InputType;
8 import jalview.ws.rest.NoValidInputDataException;
9 import jalview.ws.rest.RestJob;
10 import jalview.ws.rest.InputType.molType;
11
12 import java.io.UnsupportedEncodingException;
13 import java.util.ArrayList;
14 import java.util.Vector;
15
16 import org.apache.http.entity.mime.content.ContentBody;
17 import org.apache.http.entity.mime.content.StringBody;
18
19 /**
20  * Represents the partitions defined on the alignment as indices e.g. for a
21  * partition (A,B,C),(D,E),(F) The indices would be 3,2,1. Note, the alignment
22  * must be ordered so groups are contiguous before this input type can be used.
23  * 
24  * @author JimP
25  * 
26  */
27 public class SeqGroupIndexVector extends InputType implements
28         AlignmentProcessor
29 {
30   public SeqGroupIndexVector()
31   {
32     super(new Class[]
33     { AlignmentI.class });
34   }
35
36   /**
37    * separator for list of sequence Indices - default is ','
38    */
39   public String sep = ",";
40
41   /**
42    * min size of each partition
43    */
44   public int minsize = 1;
45
46   molType type;
47
48   /**
49    * prepare the context alignment for this input
50    * 
51    * @param al
52    *          - alignment to be processed
53    * @return al or a new alignment with appropriate attributes/order for input
54    */
55   public AlignmentI prepareAlignment(AlignmentI al)
56   {
57     jalview.analysis.AlignmentSorter.sortByGroup(al);
58     return al;
59   }
60
61   @Override
62   public ContentBody formatForInput(RestJob rj)
63           throws UnsupportedEncodingException, NoValidInputDataException
64   {
65     StringBuffer idvector = new StringBuffer();
66     boolean list = false;
67     AlignmentI al = rj.getAlignmentForInput(token, type);
68     // assume that alignment is properly ordered so groups form consecutive
69     // blocks
70     ArrayList<int[]> gl = new ArrayList<int[]>();
71     int p=0;
72     for (SequenceGroup sg : (Vector<SequenceGroup>) al.getGroups())
73     {
74       if (sg.getSize()<minsize)
75       {
76         throw new NoValidInputDataException("Group contains less than "+minsize+" sequences.");
77       }
78       // TODO: refactor to sequenceGroup for efficiency -
79       // getAlignmentRowInterval(AlignmentI al)
80       int[] se = null;
81       for (SequenceI sq : sg.getSequencesInOrder(al))
82       {
83         p = al.findIndex(sq);
84         if (se == null)
85         {
86           se = new int[]
87           { p, p };
88         }
89         else
90         {
91           if (p < se[0])
92             se[0] = p;
93           if (p > se[1])
94             se[1] = p;
95         }
96       }
97       if (se != null)
98       {
99         gl.add(se);
100       }
101     }
102     // are there any more sequences ungrouped that should be added as a single remaining group ? - these might be at the start or the end
103     if (gl.size()>0)
104     {
105       int[] tail=gl.get(0);
106       if (tail[0]>0) {
107         if (1+tail[0]>minsize)
108       {
109         gl.add(0,new int[] { 0,tail[0]-1});
110       } else {
111         // lets be intelligent here - if the remaining sequences aren't enough to make a final group, then don't make one.
112         // throw new NoValidInputDataException("Group from remaining ungrouped sequences in input contains less than "+minsize+" sequences.");       
113       }
114       } else {
115         tail=gl.get(gl.size()-1);
116         if (1+tail[1]<al.getHeight())
117         {
118           if (al.getHeight()-(1+tail[1])>minsize) {
119             gl.add(new int[] { tail[1]+1, al.getHeight()-1});            
120           } else {
121             // lets be intelligent here - if the remaining sequences aren't enough to make a final group, then don't make one.
122             //  throw new NoValidInputDataException("Group from remaining ungrouped sequences in input contains less than "+minsize+" sequences.");       
123           }
124         }
125       }
126     } else {
127       gl.add(new int[] { 0, al.getHeight()-1});
128     }
129     if (min>=0 && gl.size()<min)
130     {
131       throw new NoValidInputDataException("Not enough sequence groups for input. Need at least "+min+" groups (including ungrouped regions).");
132     }
133     if (max>0 && gl.size()>max)
134     {
135       throw new NoValidInputDataException("Too many sequence groups for input. Need at most "+max+" groups (including ungrouped regions).");
136     }
137     int[][] vals = gl.toArray(new int[gl.size()][]);
138     int[] srt = new int[gl.size()];
139     for (int i = 0; i < vals.length; i++)
140       srt[i] = vals[i][0];
141     jalview.util.QuickSort.sort(srt, vals);
142     list = false;
143     int last = vals[0][0] - 1;
144     for (int[] range : vals)
145     {
146       if (range[1] > last)
147       {
148         if (list)
149         {
150           idvector.append(sep);
151         }
152         idvector.append(range[1] - last);
153         last = range[1];
154         list = true;
155       }
156     }
157     return new StringBody(idvector.toString());
158   }
159
160   /**
161    * set minimum number of sequences allowed in a partition. Default is 1 sequence.
162    * @param i (number greater than 1)
163    */
164   public void setMinsize(int i)
165   {
166     if (minsize>=1)
167       {
168       minsize=i;
169       } else {
170         minsize=1;
171       }
172   }
173 }