JAL-2759 fix getHiddenOffset iterating backwards
[jalview.git] / src / jalview / datamodel / HiddenColumnsCursor.java
1 package jalview.datamodel;
2
3 import java.util.List;
4
5 public class HiddenColumnsCursor
6 {
7   // absolute position of first hidden column
8   private int firstColumn;
9
10   // absolute position of last hidden column
11   private int lastColumn;
12
13   // index of last visited region
14   private int regionIndex;
15
16   // number of hidden columns before last visited region
17   private int hiddenSoFar;
18
19   private List<int[]> hiddenColumns;
20
21   protected HiddenColumnsCursor()
22   {
23
24   }
25
26   /**
27    * Set the cursor to a position
28    * 
29    * @param first
30    *          absolute position of first hidden column
31    * @param last
32    *          absolute position of last hidden column
33    * @param index
34    *          index of last visited region
35    * @param hiddenCount
36    *          number of hidden columns before last visited region
37    */
38   protected void resetCursor(List<int[]> hiddenCols)
39   {
40     synchronized (this)
41     {
42       if ((hiddenCols != null) && (!hiddenCols.isEmpty()))
43       {
44         hiddenColumns = hiddenCols;
45         firstColumn = hiddenColumns.get(0)[0];
46         lastColumn = hiddenColumns.get(hiddenColumns.size() - 1)[1];
47         regionIndex = 0;
48         hiddenSoFar = 0;
49       }
50     }
51   }
52
53   protected void updateCursor(int index, int hiddenCount)
54   {
55     synchronized (this)
56     {
57       regionIndex = index;
58       hiddenSoFar = hiddenCount;
59     }
60   }
61
62   private synchronized int getIndex()
63   {
64     return regionIndex;
65   }
66
67   private synchronized int getHiddenSoFar()
68   {
69     return hiddenSoFar;
70   }
71
72
73   /**
74    * Get the index of the region that column is within (if column is hidden) or
75    * which is to the right of column (if column is visible). If no hidden
76    * columns are to the right, will return size of hiddenColumns. If hidden
77    * columns is empty returns -1.
78    * 
79    * @param column
80    *          absolute position of a column in the alignment
81    * @return region index
82    */
83   protected int findRegionForColumn(int column)
84   {
85     if (hiddenColumns == null)
86     {
87       return -1;
88     }
89
90     int index = regionIndex;
91     int hiddenCount = hiddenSoFar;
92
93     if (index == hiddenColumns.size())
94     {
95       // went past the end of hiddenColumns collection last time
96       index--;
97       int[] region = hiddenColumns.get(index);
98       hiddenCount -= region[1] - region[0] + 1;
99     }
100
101     if ((hiddenColumns.get(index)[0] <= column)
102             && (hiddenColumns.get(index)[1] >= column))
103     {
104       // we hit the jackpot
105       // don't need to move index
106     }
107     else if (column < firstColumn)
108     {
109       index = 0;
110       hiddenCount = 0;
111     }
112     /*else if (column > lastColumn)
113     {
114       index = hiddenColumns.size();
115       // TODO resolve here - need full hidden count
116     }*/
117     else if (column > hiddenColumns.get(index)[1]) // includes if column >
118                                                    // lastColumn
119     {
120       // iterate from where we are now, if we're lucky we'll be close by
121       // (but still better than iterating from 0)
122       while ((index < hiddenColumns.size())
123               && (hiddenColumns.get(index)[0] <= column))
124       {
125         int[] region = hiddenColumns.get(index);
126         hiddenCount += region[1] - region[0] + 1;
127         index++;
128       }
129
130     }
131     else // (column < hiddenColumns.get(regionIndex)[0])
132     {
133       while ((index > 0) && (hiddenColumns.get(index)[1] > column))
134       {
135         index--;
136         int[] region = hiddenColumns.get(index);
137         hiddenCount -= region[1] - region[0] + 1;
138       }
139     }
140     updateCursor(index, hiddenCount);
141     return index;
142   }
143
144   protected int getHiddenOffset(int column)
145   {
146     if (hiddenColumns == null)
147     {
148       return -1;
149     }
150
151     int index = getIndex();
152     int hiddenCount = getHiddenSoFar();
153
154     if (column < firstColumn)
155     {
156       index = 0;
157       hiddenCount = 0;
158     }
159     else if ((index < hiddenColumns.size())
160             && (hiddenColumns.get(index)[0] <= column + hiddenCount))
161     {
162       // iterate from where we are now, if we're lucky we'll be close by
163       // (but still better than iterating from 0)
164       while ((index < hiddenColumns.size())
165               && (hiddenColumns.get(index)[0] <= column + hiddenCount))
166       {
167         int[] region = hiddenColumns.get(index);
168         hiddenCount += region[1] - region[0] + 1;
169         index++;
170       }
171     }
172     else if (index < hiddenColumns.size())
173     {
174       while ((index > 0)
175               && (hiddenColumns.get(index - 1)[1] >= column + hiddenCount))
176       {
177         index--;
178         int[] region = hiddenColumns.get(index);
179         hiddenCount -= region[1] - region[0] + 1;
180       }
181
182     }
183     updateCursor(index, hiddenCount);
184     return hiddenCount;
185   }
186 }