1 package var;
2 import java.io.Serializable;
3 import java.lang.reflect.Array;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.Set;
9 
10 import dna.Data;
11 import dna.Gene;
12 import dna.GeneSet;
13 import driver.Search;
14 import shared.Shared;
15 import shared.Tools;
16 import structures.Range;
17 
18 
19 
20 public class Variation implements Comparable<Variation>, Serializable, Cloneable {
21 
22 //	>locus  ploidy  haplotype       chromosome      begin   end     varType reference       alleleSeq       totalScore      hapLink xRef
23 
24 	/**
25 	 *
26 	 */
27 	private static final long serialVersionUID = -3847258470952802740l;
28 
Variation(VarLine line)29 	public Variation(VarLine line){
30 //		this(line.chromosome, line.beginLoc, line.endLoc, line.xRef, line.varType, line.ref, line.call);
31 		this(line.chromosome, line.beginLoc, line.endLoc, line.varType, line.ref, line.call);
32 
33 		assert(!((varType==INS || varType==DELINS || varType==SNP) && call==null)) : "\n"+line+"\n"+this+
34 		"\nline.ref="+line.ref+"\nline.call="+line.call+"\nref="+ref+"\ncall="+call;
35 
36 		assert(beginLoc<=endLoc) : line.toString();
37 
38 		assert(this.equals(line)) : "\n\n"+this+"\n!=\n"+line;
39 		assert(line.equals(this)) : "\n\n"+this+"\n!=\n"+line;
40 
41 
42 //		if(xRef==11429487){
43 //			System.out.println("\n"+this.toString());
44 //		}
45 	}
46 
47 //	public Variation(GeneVarLine line){
48 ////		this(line.chromosome, line.beginLoc, line.endLoc, line.xRef, line.varType, line.ref, line.call);
49 //		this(line.chromosome, line.beginLoc, line.endLoc, line.xRef, line.xRefArray, line.varType, line.ref, line.call);
50 //
51 //		assert(beginLoc<=endLoc) : line.toString();
52 //
53 //		assert(this.equals(line)) : "\n\n"+this+"\n!=\n"+line.toSuperString()+"\n\n"+line;
54 //		assert(line.equals(this)) : "\n\n"+this+"\n!=\n"+line.toSuperString()+"\n\n"+line;
55 //
56 //	}
57 
Variation(Variation line)58 	public Variation(Variation line){
59 		this(line.chromosome, line.beginLoc, line.endLoc, line.varType, line.ref, line.call);
60 
61 		assert(beginLoc<=endLoc) : line.toString();
62 
63 		assert(this.equals(line)) : "\n\n"+this+"\n!=\n"+line.toSuperString()+"\n\n"+line;
64 		assert(line.equals(this)) : "\n\n"+this+"\n!=\n"+line.toSuperString()+"\n\n"+line;
65 
66 	}
67 
Variation(int chr, int bLoc, int eLoc, byte vType, String rf, String ca)68 	public Variation(int chr, int bLoc, int eLoc, byte vType, String rf, String ca){
69 		chromosome=chr;
70 		beginLoc=bLoc;
71 		endLoc=eLoc;
72 		varType=vType;
73 
74 		setDetails(vType, rf, ca);
75 
76 		assert(beginLoc<=endLoc) : toString();
77 
78 	}
79 
Variation()80 	public Variation(){}
81 
82 
83 	@Override
clone()84 	public Variation clone(){
85 		Variation v=null;
86 		try {
87 			v=(Variation) super.clone();
88 		} catch (CloneNotSupportedException e) {
89 			// TODO Auto-generated catch block
90 			e.printStackTrace();
91 		}
92 		return v;
93 	}
94 
95 
toVariations(VarLine[] array, boolean retainEqual)96 	public static final HashSet<Variation> toVariations(VarLine[] array, boolean retainEqual){
97 		HashSet<Variation> set=new HashSet<Variation>(array.length);
98 		for(VarLine line : array){
99 			Variation var=new Variation(line);
100 			if(retainEqual || var.varType!=Variation.REF){
101 				if(!set.contains(var)){
102 					set.add(var);
103 				}
104 			}
105 		}
106 		return set;
107 	}
108 
toVariationArray(VarLine[][] array, boolean retainEqual)109 	public static final Variation[] toVariationArray(VarLine[][] array, boolean retainEqual){
110 		HashSet<Variation> set=toVariations(array[0], retainEqual);
111 		for(int i=1; i<array.length; i++){
112 			set.addAll(toVariations(array[i], retainEqual));
113 		}
114 		Variation[] vars=set.toArray(new Variation[set.size()]);
115 		Arrays.sort(vars);
116 		return vars;
117 	}
118 
toVariationArray(VarLine[] array, boolean retainEqual)119 	public static final Variation[] toVariationArray(VarLine[] array, boolean retainEqual){
120 		HashSet<Variation> set=toVariations(array, retainEqual);
121 		Variation[] vars=set.toArray(new Variation[set.size()]);
122 		Arrays.sort(vars);
123 		return vars;
124 	}
125 
126 	@SuppressWarnings("unchecked")
toArray(Class<X> c, Set<X> set)127 	public static final <X extends Comparable<? super X>> X[] toArray(Class<X> c, Set<X> set){
128 
129 		set.getClass().getTypeParameters();
130 		X[] array=(X[])Array.newInstance(c,set.size());
131 
132 		array=set.toArray(array);
133 		int i=0;
134 		for(X x : set){
135 			array[i]=x;
136 			i++;
137 		}
138 		Arrays.sort(array);
139 		return array;
140 	}
141 
142 
filterCodingVariances(VarLine[] variances, int chrom, boolean nearby)143 	public static VarLine[] filterCodingVariances(VarLine[] variances, int chrom, boolean nearby){
144 		Range[] ranges=(nearby ? Data.geneNearbyRangeMatrix(chrom) : Data.geneCodeAndExonRangeMatrix(chrom));
145 
146 		ArrayList<VarLine> list=new ArrayList<VarLine>(8+variances.length/8);
147 
148 		for(VarLine var : variances){
149 
150 			if(var.varType!=VarLine.REF && var.varType!=VarLine.NOREF){
151 				int loc=var.beginLoc;
152 				int rnum=Search.findPointBinary(loc, ranges);
153 
154 				if(ranges[rnum].intersects(var.beginLoc, var.endLoc)){
155 					list.add(var);
156 				}
157 
158 				for(int i=rnum; i<ranges.length; i++){
159 					Range r=ranges[i];
160 					if(r.a>var.endLoc){break;} //Out of range
161 
162 					if(r.intersects(var.beginLoc, var.endLoc)){
163 						list.add(var);
164 						break;
165 					}
166 				}
167 			}
168 		}
169 
170 		return list.toArray(new VarLine[list.size()]);
171 	}
172 
173 
174 
175 
176 	/**
177 	 * Generates an array of non-overlapping Ranges, sorted by index, ascending.
178 	 * To each is attached a list of all overlapping Variations from the input array.
179 	 * @param va
180 	 * @return The array of ranges
181 	 */
makeVarRanges(Variation[] va)182 	public static Range[] makeVarRanges(Variation[] va){
183 		//			System.out.println("va.length="+va.length);
184 
185 		if(va==null || va.length==0){
186 			return new Range[0];
187 		}
188 
189 		ArrayList<Range> ra=new ArrayList<Range>(va.length);
190 		for(Variation v : va){
191 			Range r=new Range(v.beginLoc, v.endLoc);
192 			r.obj1=new ArrayList<Variation>();
193 			((ArrayList<Variation>)r.obj1).add(v);
194 			ra.add(r);
195 		}
196 		Shared.sort(ra);
197 		ArrayList<Range> ra2=new ArrayList<Range>(va.length);
198 		Range current=null;
199 		//			System.out.println("ra.size="+ra.size());
200 		for(Range r : ra){
201 			//				System.out.println("\ncurrent="+current+", r="+r);
202 			if(current==null){current=r;}
203 			else if(current.intersects(r)){
204 				//					System.out.println("merged");
205 				Range temp=current.merge(r);
206 				temp.obj1=current.obj1;
207 				((ArrayList<Variation>)temp.obj1).addAll((ArrayList<Variation>)r.obj1);
208 				current=temp;
209 			}else{
210 				//					System.out.println("added");
211 				ra2.add(current);
212 				current=r;
213 			}
214 			//				System.out.println("current="+current+", r="+r);
215 		}
216 		//			System.out.println("\ncurrent="+current);
217 		//			System.out.println("ra2.size="+ra2.size());
218 		assert(current!=null); //Note: this could be null if input was empty, I guess...
219 		assert(ra2.size()==0 || ra2.get(ra2.size()-1)!=current);
220 		ra2.add(current);
221 		return ra2.toArray(new Range[ra2.size()]);
222 	}
223 
toRsid(String s)224 	public static final int toRsid(String s){return xRefToId(s);}
xRefToId(String s)225 	public static final int xRefToId(String s){
226 //		System.out.println(s);
227 		if(s==null || s.length()==0){return -1;}
228 //		assert(s.startsWith("dbsnp:rs")) : s;
229 
230 		if(s.contains(":")){
231 			s=s.substring(s.indexOf(':')+1);
232 		}
233 
234 		int i=0, max=s.length();
235 //		System.err.println(s);
236 		while(i<max && !Tools.isDigit(s.charAt(i))){i++;}
237 		if(i>=max){assert(s.equals(".")) : s; return -1;}
238 		s=s.substring(i);
239 
240 		return Integer.parseInt(s);
241 	}
242 
toRsidArray(String s)243 	public static final int[] toRsidArray(String s){return xRefToIdArray(s);}
xRefToIdArray(String s)244 	public static final int[] xRefToIdArray(String s){
245 		if(s==null || s.length()<1){return null;}
246 		String[] array=s.split("[,;]");
247 		int[] r=new int[array.length];
248 		for(int i=0; i<array.length; i++){
249 			r[i]=xRefToId(array[i]);
250 			if(r[i]==-1){
251 				if(r.length==1){return null;}
252 
253 				//This can be safely disabled.  But it is best to fix this case by making the array smaller.
254 				assert(false) : "Not a real rsID: "+s;
255 			}
256 		}
257 		return r;
258 	}
259 
matches(Variation line)260 	public boolean matches(Variation line){
261 		if(line==null || chromosome!=line.chromosome || beginLoc!=line.beginLoc || endLoc!=line.endLoc || varType!=line.varType){
262 			return false;
263 		}
264 		return matches(line.varType, line.ref, line.call);
265 	}
266 
267 //	public boolean matchesLoose(VarLine line){
268 //		if(line==null || chromosome!=line.chromosome || !intersects(line)){
269 //			return false;
270 //		}
271 //		if(isEqual() && line.isEqual()){return true;}
272 //		if(varType!=line.varType){return false;}
273 //		return matches(line.varType, line.ref, line.call);
274 //	}
275 
276 	/** Overlap and don't contradict each other */
matchesLoose(VarLine line)277 	public boolean matchesLoose(VarLine line){
278 		if(line==null || chromosome!=line.chromosome || !intersects(line)){
279 			return false;
280 		}
281 
282 		if(isTrueVariation()){
283 			if(varType!=line.varType){return false;}
284 			return matches(line.varType, line.ref, line.call);
285 		}else if(isRef()){
286 			return line.isRef();
287 		}else{
288 			assert(isUnsureVariation()) : this;
289 			return line.isUnsureVariation();
290 		}
291 	}
292 
matches(int type, String ref2, String call2)293 	private boolean matches(int type, String ref2, String call2){
294 		if(type==REF || type==REFPOINT || type==DEL || type==NOCALL){
295 			return true;
296 		}
297 		return call.equals(call2);
298 
299 	}
300 
setDetails(byte vt, String rf, String ca)301 	private void setDetails(byte vt, String rf, String ca){
302 
303 		ref=null;
304 		call=null;
305 
306 		switch(vt){
307 
308 			case REF: {
309 			}break;
310 			case SNP: {
311 				ref=rf; call=ca;
312 			}break;
313 			case INS: {
314 				call=ca;
315 			}break;
316 			case DEL: {
317 				ref=rf;
318 			}break;
319 			case DELINS: {
320 				ref=rf; call=ca;
321 			}break;
322 			case REFCON: {
323 				ref=rf; call=ca;
324 			}break;
325 			case REFINCON: {
326 				ref=rf; call=ca;
327 			}break;
328 			case NOCALL: {
329 				 //I can't remember if nocalls need N or null calls
330 //				ref=rf;
331 //				call=ca;
332 //				assert(ref!=null && call!=null && ref.length()==call.length()) : ref+", "+call;
333 			}break;
334 			case NOREF: {
335 				 //I can't remember if norefs need N or null refs
336 //				ref=rf;
337 				call=ca;
338 //				assert(ref!=null && call!=null && ref.length()==call.length()) : ref+", "+call;
339 			}break;
340 			case PAR: {
341 				ref=rf; call=ca;
342 			}break;
343 			case NULL: {
344 				ref=rf; call=ca;
345 			}break;
346 			case REFPOINT: {
347 				ref=call=null;
348 			}break;
349 
350 			default: {assert(false);}
351 		}
352 		intern();
353 	}
354 
locationString()355 	public String locationString(){
356 		return locationString(0);
357 	}
358 
locationString(int base)359 	public String locationString(int base){
360 		assert(base==0 || base==1);
361 
362 		if(beginLoc==endLoc){
363 			return "("+(beginLoc+base)+")";
364 		}
365 		return "("+(beginLoc+base)+" - "+(endLoc+base)+")";
366 
367 //		if(beginLoc==endLoc){
368 //			return (beginLoc+base)+"";
369 //		}
370 //		return (beginLoc+base)+"-"+(endLoc+base);
371 	}
372 
toSuperString()373 	public String toSuperString(){return toString();}
374 
375 	@Override
toString()376 	public String toString(){
377 		return toString(0);
378 	}
379 
toString(int base)380 	public String toString(int base){
381 		StringBuilder sb=new StringBuilder();
382 
383 		sb.append("chr"+Gene.chromCodes[chromosome]);
384 		while(sb.length()<5){sb.append(' ');}
385 		sb.append('\t');
386 		sb.append(locationString(base)+"\t");
387 
388 		sb.append(varTypeMap[varType]);
389 
390 		sb.append("\t"+(ref==null ? "" : ref));
391 		sb.append("\t"+(call==null ? "" : call));
392 
393 		sb.append('\t');
394 
395 		return sb.toString();
396 	}
397 
toSourceString()398 	public String toSourceString(){
399 		StringBuilder sb=new StringBuilder(64);
400 
401 		sb.append("chr"+Gene.chromCodes[chromosome]+"\t");
402 		sb.append(beginLoc+"\t");
403 
404 		if(varType==INS){
405 			sb.append(beginLoc+"\t");
406 		}else{
407 			sb.append((endLoc+1)+"\t");
408 		}
409 
410 		sb.append(varTypeMap[varType]+"\t");
411 		sb.append((ref==null ? "" : ref)+"\t");
412 		sb.append((call==null ? "" : call)+"\t");
413 
414 		return sb.toString();
415 	}
416 
header()417 	public static String header(){
418 
419 		return "chrom\tstart\tstop\ttype\tref\tcall\trsID";
420 	}
421 
toShortString()422 	public String toShortString(){
423 		StringBuilder sb=new StringBuilder();
424 
425 		sb.append(locationString()+"\t");
426 
427 		sb.append(varTypeMap[varType]);
428 
429 		if(ref!=null){sb.append("\t"+ref);}
430 		if(call!=null){sb.append("\t"+call);}
431 
432 		return sb.toString();
433 	}
434 
435 
find(String a, String[] array)436 	public static final int find(String a, String[] array){
437 		for(int i=0; i<array.length; i++){
438 			if(a.equals(array[i])){return i;}
439 		}
440 		assert(false) : "Can't find "+a+" in "+Arrays.toString(array);
441 		return -1;
442 	}
443 
lengthRef()444 	public final int lengthRef(){
445 		switch(varType){
446 			case SNP: {
447 				assert(endLoc-beginLoc+1==1) : "\n"+endLoc+"-"+beginLoc+"+1 = "+(endLoc-beginLoc+1)+" != "+1+"\n"+this.toString()+"\n";
448 				assert(call!=null && call.length()==1) : "\ncall= '"+call+"'\n"+this.toString();
449 				return 1;
450 			}
451 			case INS: {
452 				return 0;
453 			}
454 			case REFPOINT: {
455 				return 0;
456 			}
457 //			case NOREF: {
458 //				throw new RuntimeException();
459 //			}
460 //			case NULL: {
461 //				throw new RuntimeException();
462 //			}
463 			default: {
464 				break;
465 			}
466 		}
467 		return endLoc-beginLoc+1;
468 	}
469 
lengthMax()470 	public final int lengthMax(){return max(lengthRef(), lengthVar());}
lengthMin()471 	public final int lengthMin(){return min(lengthRef(), lengthVar());}
lengthDif()472 	public final int lengthDif(){return isNR_or_NC() ? 0 : lengthVar()-lengthRef();}
473 
lengthVar()474 	public final int lengthVar(){
475 		switch(varType){
476 
477 			case REF: {
478 				return endLoc-beginLoc+1;
479 			}
480 			case SNP: {
481 				assert(endLoc-beginLoc+1==1);
482 				assert(call!=null && call.length()==1);
483 				return 1;
484 			}
485 			case INS: {
486 				assert(call!=null);
487 				return call.length();
488 			}
489 			case REFPOINT: {
490 				return 0;
491 			}
492 			case DEL: {
493 				assert(call==null);
494 				return 0;
495 			}
496 			case DELINS: {
497 				assert(call!=null);
498 				return call.length();
499 			}
500 			case REFCON: {
501 				return endLoc-beginLoc+1;
502 			}
503 			case REFINCON: {
504 				assert(false) : "Warning - Length cannot be known for certain.";
505 				return endLoc-beginLoc+1;
506 			}
507 			case NOCALL: {
508 				assert(false) : "Warning - Length cannot be known for certain.";
509 				return endLoc-beginLoc+1;
510 			}
511 			case NOREF: {
512 				assert(false) : "Warning - Length cannot be known for certain.";
513 				return endLoc-beginLoc+1;
514 			}
515 			case PAR: {
516 				assert(call!=null);
517 				return call.length();
518 			}
519 			case NULL: {
520 				assert(false);
521 				throw new RuntimeException();
522 			}
523 
524 			default: {throw new RuntimeException();}
525 		}
526 	}
527 
528 
529 //	//TODO Note that this may be wrong for e.g. insertions, deletions, and if/when changed to half-open numbering.
530 //	public final int length(){
531 //		if(varType==INS){return 0;}
532 //		return endLoc-beginLoc+1;
533 //	}
534 //	public final int length2(){
535 //		if(varType==INS){return call==null ? 0 : call.length();}
536 //		if(varType==DELINS){return call==null ? (endLoc-beginLoc+1) : max(call.length(), endLoc-beginLoc+1);}
537 //		return endLoc-beginLoc+1;
538 //	}
539 
isPoint()540 	public final boolean isPoint(){
541 		return varType==INS || varType==REFPOINT;
542 	}
543 
isRef()544 	public final boolean isRef(){
545 		return varType==REF || varType==REFPOINT;
546 	}
547 
isTrueVariation()548 	public final boolean isTrueVariation(){
549 		return varType==SNP || varType==INS || varType==DEL || varType==DELINS;
550 	}
551 
isNoCall()552 	public final boolean isNoCall(){
553 		return varType==NOCALL || varType==REFCON || varType==REFINCON;
554 	}
555 
isNR_or_NC()556 	public final boolean isNR_or_NC(){
557 		return varType==NOCALL || varType==NOREF || varType==REFCON || varType==REFINCON;
558 	}
559 
isUnsureVariation()560 	public final boolean isUnsureVariation(){
561 		return varType==NOCALL || varType==NOREF || varType==REFINCON || varType==REFCON;
562 	}
563 
564 
565 //	/** TODO May be slow.  Perhaps add a boolean field. */
566 //	public boolean isCoding(){
567 //		int middle=((beginLoc+endLoc)/2);
568 //		GeneSet[] sets=Data.getNearestGeneSets(chromosome, middle);
569 //		for(GeneSet gs : sets){
570 //			for(Gene g : gs.genes){
571 //				if(g.intersectsCodeAndExon(beginLoc, endLoc)){
572 //					return true;
573 //				}
574 //			}
575 //		}
576 //		return false;
577 //	}
578 
579 
580 	/** Does this variation intersect within (range) of a coding region or splice site? */
isNearCodingOrSplice(int range, boolean includeExonsForUntranslatedGenes, boolean includeSplice)581 	public boolean isNearCodingOrSplice(int range, boolean includeExonsForUntranslatedGenes, boolean includeSplice){
582 		assert(beginLoc<=endLoc);
583 		int a=beginLoc-range, b=endLoc+range;
584 		return isNearCodingOrSplice(range, includeExonsForUntranslatedGenes, Data.getNearestGeneSets(chromosome, a, b), includeSplice);
585 	}
586 
587 
588 	/** Does this variation intersect within (range) of a coding region or splice site? */
isNearCodingOrSplice(int range, boolean includeExonsForUntranslatedGenes)589 	public boolean isNearCodingOrSplice(int range, boolean includeExonsForUntranslatedGenes){
590 		return isNearCodingOrSplice(range, includeExonsForUntranslatedGenes, true);
591 	}
592 
593 
594 	/** Does this variation lie at least partially within an intron? */
intersectsIntron()595 	public boolean intersectsIntron(){
596 		assert(beginLoc<=endLoc);
597 		int a=beginLoc, b=endLoc;
598 		return intersectsIntron(Data.getNearestGeneSets(chromosome, a, b));
599 	}
600 
601 
602 	/** Does this variation intersect within (range) of a coding region or splice site? */
isNearCodingOrSplice(int range, boolean includeExonsForUntranslatedGenes, GeneSet[] sets, boolean includeSplice)603 	public boolean isNearCodingOrSplice(int range, boolean includeExonsForUntranslatedGenes, GeneSet[] sets, boolean includeSplice){
604 		assert(beginLoc<=endLoc);
605 		int a=beginLoc-range, b=endLoc+range;
606 
607 //		int middle=((beginLoc+endLoc)/2);
608 //		GeneSet[] sets=Data.getNearestGeneSets(chromosome, middle);
609 
610 //		boolean flag=(chromosome==21 && intersects(9929078));//TODO UNDO
611 
612 //		if(flag){System.out.println("Found: "+Arrays.toString(sets));}
613 //		assert(false);
614 
615 		if(sets==null){
616 			assert(chromosome>=25);
617 			return true;
618 		}
619 
620 
621 		for(GeneSet gs : sets){
622 //			if(flag){System.out.println("### "+gs);}//TODO UNDO
623 			for(Gene g : gs.genes){
624 
625 				if(!g.untranslated){
626 
627 //					if(flag){System.out.println("*** "+g);}//TODO UNDO
628 
629 //					if(flag){
630 //						System.out.println("intersectsCodeAndExon: "+g.intersectsCodeAndExon(a, b));
631 //						System.out.println("intersectsCode: "+g.intersectsCode(a, b));
632 //						System.out.println("intersectsExon: "+g.intersectsExon(a, b));
633 //					}
634 
635 					if(g.intersectsCodeAndExon(a, b)){
636 						return true;
637 					}
638 
639 				}else if(includeExonsForUntranslatedGenes){
640 //					if(flag){System.out.println("*** "+g);}//TODO UNDO
641 //
642 //					if(flag){
643 //						System.out.println("intersectsExon: "+g.intersectsExon(a, b));
644 //					}
645 
646 					if(g.intersectsExon(a, b)){
647 						return true;
648 					}
649 
650 				}
651 
652 				if(includeSplice){
653 					int[] array=g.nearestSpliceSite(beginLoc, endLoc);
654 					if(array[0]<=range){return true;}
655 				}
656 
657 			}
658 		}
659 		return false;
660 	}
661 
662 
663 	/** Does this variation lie at least partially within an intron? */
intersectsIntron(GeneSet[] sets)664 	public boolean intersectsIntron(GeneSet[] sets){
665 		assert(beginLoc<=endLoc);
666 		int a=beginLoc, b=endLoc;
667 
668 //		int middle=((beginLoc+endLoc)/2);
669 //		GeneSet[] sets=Data.getNearestGeneSets(chromosome, middle);
670 
671 		if(sets==null){
672 			assert(chromosome>=25);
673 			return true;
674 		}
675 
676 
677 		for(GeneSet gs : sets){
678 			for(Gene g : gs.genes){
679 				if(g.intersectsIntron(a, b)){return true;}
680 			}
681 		}
682 		return false;
683 	}
684 
685 	public int beginLoc=-2;
686 	public int endLoc=-2;
687 
688 	public int chromosome=-1;
689 	public byte varType=-1;
690 
691 	public String ref=null;
692 	public String call=null;
693 
694 
695 	public static final HashMap<Object, Object> ploidyMap=makePloidyMap();
696 	public static final String[] haploMap={"0","1","2","all"};
697 
698 	public static final String[] varTypeMap={"ref","snp","ins","del","sub",
699 		"no-call-rc","no-call-ri","no-call","no-ref","PAR-called-in-X","null","refpoint"};
700 
701 	public static final HashMap<String, Byte> varTypeMap2=makeVarTypeMap();
702 
makeVarTypeMap()703 	private static final HashMap<String, Byte> makeVarTypeMap(){
704 		HashMap<String, Byte> r=new HashMap<String, Byte>(32);
705 
706 		for(byte i=0; i<varTypeMap.length; i++){r.put(varTypeMap[i], i);}
707 		r.put("=", REF);
708 		r.put("ref-consistent", REFCON);
709 		r.put("ref-inconsistent", REFINCON);
710 //		r.put("no-call-rc", REFCON);
711 //		r.put("no-call-ri", REFINCON);
712 		r.put("delins", DELINS);
713 
714 		return r;
715 	}
716 
717 	public static final byte REF=0;
718 	public static final byte SNP=1;
719 	public static final byte INS=2;
720 	public static final byte DEL=3;
721 	public static final byte DELINS=4;
722 	public static final byte REFCON=5;
723 	public static final byte REFINCON=6;
724 	public static final byte NOCALL=7;
725 	public static final byte NOREF=8;
726 	public static final byte PAR=9;
727 	public static final byte NULL=10;
728 	public static final byte REFPOINT=11;
729 
intern()730 	public void intern(){
731 //		assert(false) : ref+", "+call+", "+this;
732 		if(ref!=null){ref=Data.intern(ref);}
733 		if(call!=null){call=Data.intern(call);}
734 	}
735 
makePloidyMap()736 	private static HashMap<Object, Object> makePloidyMap(){
737 		HashMap<Object, Object> hashy=new HashMap<Object, Object>(64);
738 		for(int i=0; i<10; i++){
739 			hashy.put((Byte)(byte)i, i+"");
740 			hashy.put((Integer)i, i+"");
741 			hashy.put(i+"", (Byte)(byte)i);
742 		}
743 		hashy.put((Byte)(byte)-1, "?");
744 		hashy.put((Integer)(-1), "?");
745 		hashy.put("?",(Byte)(byte)-1);
746 		return hashy;
747 	}
748 
min(int x, int y)749 	private static final int min(int x, int y){return x<y ? x : y;}
max(int x, int y)750 	private static final int max(int x, int y){return x>y ? x : y;}
751 
752 	@Override
hashCode()753 	public final int hashCode(){
754 		long x=chromosome;
755 		x=x<<4;
756 		x^=varType;
757 		x=x<<28;
758 		x^=beginLoc;
759 		x=x<<16;
760 		x^=(endLoc-beginLoc+1);
761 		return new Long(x).hashCode(); //TODO: Slow
762 	}
763 
764 	@Override
compareTo(Variation other)765 	public int compareTo(Variation other) {
766 		if(chromosome!=other.chromosome){return other.chromosome>chromosome ? -1 : 1;}
767 		if(beginLoc!=other.beginLoc){return other.beginLoc>beginLoc ? -1 : 1;}
768 		if(endLoc!=other.endLoc){return other.endLoc>endLoc ? -1 : 1;}
769 		if(varType!=other.varType){return other.varType>varType ? -1 : 1;}
770 		if(varType==REF || varType==NOCALL){return 0;}
771 
772 		if(call==null){
773 			return other.call==null ? 0 : -1;
774 		}
775 		return other.call==null ? 1 : call.compareTo(other.call);
776 	}
777 
778 	@Override
equals(Object other)779 	public boolean equals(Object other){
780 		return equals((Variation)other);
781 	}
782 
equals(Variation other)783 	public boolean equals(Variation other){
784 		return compareTo(other)==0;
785 	}
786 
intersects(int point)787 	public boolean intersects(int point){
788 		return point>=beginLoc && point<=endLoc;
789 	}
790 
touches(int point)791 	public boolean touches(int point){
792 		return point>=beginLoc-1 && point<=endLoc+1;
793 	}
794 
795 	/** This is quite clever. */
overlap(int a1, int b1, int a2, int b2)796 	public static boolean overlap(int a1, int b1, int a2, int b2){
797 		assert(a1<=b1 && a2<=b2) : a1+", "+b1+", "+a2+", "+b2;
798 		return a2<=b1 && b2>=a1;
799 	}
touch(int a1, int b1, int a2, int b2)800 	public static boolean touch(int a1, int b1, int a2, int b2){
801 		assert(a1<=b1 && a2<=b2) : a1+", "+b1+", "+a2+", "+b2;
802 		return a2<=(b1+1) && b2>=(a1-1);
803 	}
804 
805 	/** Is (a1, b1) within (a2, b2) ? */
isWithin(int a1, int b1, int a2, int b2)806 	public static boolean isWithin(int a1, int b1, int a2, int b2){
807 		assert(a1<=b1 && a2<=b2) : a1+", "+b1+", "+a2+", "+b2;
808 		return a1>=a2 && b1<=b2;
809 	}
810 
isWithinNotTouching(int a1, int b1, int a2, int b2)811 	public static boolean isWithinNotTouching(int a1, int b1, int a2, int b2){
812 		assert(a1<=b1 && a2<=b2) : a1+", "+b1+", "+a2+", "+b2;
813 		return a1>a2 && b1<b2;
814 	}
815 
816 	//Slow if not inlined
intersects(int a2, int b2)817 	public boolean intersects(int a2, int b2){return overlap(beginLoc, endLoc, a2, b2);}
818 
isWithin(int a2, int b2)819 	public boolean isWithin(int a2, int b2){return isWithin(beginLoc, endLoc, a2, b2);}
820 
isWithinNotTouching(int a2, int b2)821 	public boolean isWithinNotTouching(int a2, int b2){return isWithinNotTouching(beginLoc, endLoc, a2, b2);}
822 
intersects(Variation v)823 	public boolean intersects(Variation v){
824 
825 		if(v.chromosome!=chromosome){
826 			return false;
827 		}
828 
829 		int len1=lengthRef();
830 		int len2=v.lengthRef();
831 
832 		if(len1<len2){
833 			return v.intersects(this);
834 		}
835 
836 //		if(v.beginLoc==46397336 || v.beginLoc==46397348){
837 //			System.err.println(len1+": "+this+"\n"+len2+": "+v+"\n");
838 //		}
839 		//Now, this is at least as long (ref-wise) as v.
840 
841 //		if(varType==EQUAL && v.varType==INS){
842 //			assert(false);
843 //		}
844 
845 		if(!touch(beginLoc, endLoc, v.beginLoc, v.endLoc)){return false;}
846 
847 //		if(v.beginLoc==46397336 || v.beginLoc==46397348){
848 //			System.err.println("Touch("+beginLoc+", "+endLoc+", "+v.beginLoc+", "+v.endLoc+")");
849 //		}
850 
851 		if(v.isPoint()){
852 //			if(v.beginLoc==46397336 || v.beginLoc==46397348){System.out.println("v");}
853 			if(isPoint()){
854 //				assert(beginLoc==v.beginLoc && endLoc==v.endLoc) : this+"\n"+v;
855 //				return true;
856 
857 				return beginLoc==v.beginLoc;
858 			}
859 //			if(v.beginLoc==46397336 || v.beginLoc==46397348){System.out.println("w");}
860 			if(this.isNoCall()){
861 				if(len1>0){return overlap(beginLoc, endLoc, v.beginLoc, v.endLoc);} //Normal case
862 				else{
863 					//TODO: Bad news! Original MAY have been a length 0 no-call in half-open coordinates.
864 					return overlap(beginLoc, endLoc+1, v.beginLoc, v.endLoc);
865 				}
866 			}
867 //			if(v.beginLoc==46397336 || v.beginLoc==46397348){System.out.println("x");}
868 			if(v.beginLoc<=beginLoc){return false;}
869 //			if(v.beginLoc==46397336 || v.beginLoc==46397348){System.out.println("y");}
870 		}
871 //		if(v.beginLoc==46397336 || v.beginLoc==46397348){System.out.println("z");}
872 
873 		return overlap(beginLoc, endLoc, v.beginLoc, v.endLoc);
874 	}
875 }
876