JAL-2446 pseudo-random generator unit test, and fixes arising
[jalview.git] / src / jalview / datamodel / features / NCNode.java
1 package jalview.datamodel.features;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 /**
7  * Each node of the NCList tree consists of a range, and (optionally) the NCList
8  * of ranges it encloses
9  *
10  * @param <V>
11  */
12 class NCNode<V extends ContiguousI>
13 {
14   /*
15    * deep size (number of ranges included)
16    */
17   private int size;
18
19   private V region;
20
21   private NCList<V> subregions;
22
23   /**
24    * Constructor given a list of ranges
25    * 
26    * @param ranges
27    */
28   NCNode(List<V> ranges)
29   {
30     build(ranges);
31   }
32
33   /**
34    * Constructor given a single range
35    * 
36    * @param range
37    */
38   NCNode(V range)
39   {
40     List<V> ranges = new ArrayList<V>();
41     ranges.add(range);
42     build(ranges);
43   }
44
45   NCNode(V entry, NCList<V> newNCList)
46   {
47     region = entry;
48     subregions = newNCList;
49     // size = 1 + newNCList.size();
50   }
51
52   /**
53    * @param ranges
54    */
55   protected void build(List<V> ranges)
56   {
57     size = ranges.size();
58
59     if (!ranges.isEmpty())
60     {
61       region = ranges.get(0);
62     }
63     if (ranges.size() > 1)
64     {
65       subregions = new NCList<V>(ranges.subList(1, ranges.size()));
66     }
67   }
68
69   int getStart()
70   {
71     return region.getBegin();
72   }
73
74   int getEnd()
75   {
76     return region.getEnd();
77   }
78
79   /**
80    * Formats the node as a bracketed list e.g.
81    * 
82    * <pre>
83    * [1-100 [10-30 [10-20]], 15-30 [20-20]]
84    * </pre>
85    */
86   @Override
87   public String toString() {
88     StringBuilder sb = new StringBuilder(10 * size);
89     sb.append(region.getBegin()).append("-").append(region.getEnd());
90     if (subregions != null)
91     {
92       sb.append(" ").append(subregions.toString());
93     }
94     return sb.toString();
95   }
96
97   void prettyPrint(StringBuilder sb, int offset, int indent) {
98     for (int i = 0 ; i < offset ; i++) {
99       sb.append(" ");
100     }
101     sb.append(region.getBegin()).append("-").append(region.getEnd());
102     if (subregions != null)
103     {
104       sb.append(System.lineSeparator());
105       subregions.prettyPrint(sb, offset + 2, indent);
106     }
107   }
108   /**
109    * Add any ranges that overlap the from-to range to the result list
110    * 
111    * @param from
112    * @param to
113    * @param result
114    */
115   void addOverlaps(long from, long to, List<V> result)
116   {
117     if (region.getBegin() <= to && region.getEnd() >= from)
118     {
119       result.add(region);
120     }
121     if (subregions != null)
122     {
123       subregions.findOverlaps(from, to, result);
124     }
125   }
126
127   /**
128    * Add one range to this subrange
129    * 
130    * @param entry
131    */
132   synchronized void add(V entry)
133   {
134     if (entry.getBegin() < region.getBegin() || entry.getEnd() > region.getEnd()) {
135       throw new IllegalArgumentException(String.format(
136               "adding improper subrange %d-%d to range %d-%d",
137               entry.getBegin(), entry.getEnd(), region.getBegin(),
138               region.getEnd()));
139     }
140     if (subregions == null)
141     {
142       subregions = new NCList<V>(entry);
143     }
144     else
145     {
146       subregions.add(entry);
147     }
148   }
149
150   /**
151    * Answers true if the data held satisfy the rules of construction of an
152    * NCList, else false.
153    * 
154    * @return
155    */
156   boolean isValid()
157   {
158     if (subregions == null)
159     {
160       return true;
161     }
162     return subregions.isValid(getStart(), getEnd());
163   }
164 }