1 package tax;
2 
3 import java.io.Serializable;
4 import java.util.Comparator;
5 
6 import shared.Tools;
7 
8 /**
9  * Represents a taxonomic identifier, such as a specific genus.
10  * Includes the name, NCBI numeric id, parent id, and taxonomic level.
11  * @author Brian Bushnell
12  * @date Mar 6, 2015
13  *
14  */
15 public class TaxNode implements Serializable{
16 
17 	/**
18 	 *
19 	 */
20 	private static final long serialVersionUID = -4618526038942239246L;
21 
22 	/*--------------------------------------------------------------*/
23 	/*----------------        Initialization        ----------------*/
24 	/*--------------------------------------------------------------*/
25 
TaxNode(int id_, String name_)26 	public TaxNode(int id_, String name_){
27 		this(id_, -1, -1, -1, name_);
28 	}
29 
TaxNode(int id_, int parent_, int level_, int levelExtended_, String name_)30 	public TaxNode(int id_, int parent_, int level_, int levelExtended_, String name_){
31 		id=id_;
32 		pid=parent_;
33 		level=level_;
34 		levelExtended=levelExtended_;
35 		setOriginalLevel(levelExtended);
36 		name=name_;
37 	}
38 
39 	/*--------------------------------------------------------------*/
40 	/*----------------           Methods            ----------------*/
41 	/*--------------------------------------------------------------*/
42 
43 	/**
44 	 * @param split
45 	 * @param idx
46 	 * @return True if the node's name matches the
47 	 */
matchesName(String[] split, int idx, TaxTree tree)48 	public boolean matchesName(String[] split, int idx, TaxTree tree) {
49 		if(idx<0){return true;}
50 		if(!split[idx].equalsIgnoreCase(name)){return false;}
51 		return tree.getNode(pid).matchesName(split, idx-1, tree);
52 	}
53 
54 	@Override
toString()55 	public String toString(){
56 		return "("+id+","+pid+","+countRaw+","+countSum+",'"+levelStringExtended(false)+"',"+(canonical() ? "T" : "F")+",'"+name+"')";
57 	}
58 
equals(TaxNode b)59 	public boolean equals(TaxNode b){
60 		if(id!=b.id || pid!=b.pid || levelExtended!=b.levelExtended || flag!=b.flag){return false;}
61 		if(name==b.name){return true;}
62 		if((name==null) != (b.name==null)){return false;}
63 		return name.equals(b.name);
64 	}
65 
incrementRaw(long amt)66 	public long incrementRaw(long amt){
67 		if(amt==0){return countRaw;}
68 		if(verbose){System.err.println("incrementRaw("+amt+") node: "+this);}
69 		countRaw+=amt;
70 		assert(countRaw>=0) : "Overflow! "+countRaw+", "+amt;
71 		return countRaw;
72 	}
73 
incrementSum(long amt)74 	public long incrementSum(long amt){
75 		if(amt==0){return countSum;}
76 		if(verbose){System.err.println("incrementSum("+amt+") node: "+this);}
77 		countSum+=amt;
78 		assert(countSum>=0 || amt<0) : "Overflow! "+countSum+", "+amt;
79 		return countSum;
80 	}
81 
isSimple()82 	public boolean isSimple(){
83 		return TaxTree.isSimple(levelExtended);
84 	}
85 
isSimple2()86 	public boolean isSimple2(){
87 		return TaxTree.isSimple2(levelExtended);
88 	}
89 
90 //	public String levelString(){return level<0 ? "unknown" : TaxTree.levelToString(level);}
91 
levelStringExtended(boolean original)92 	public String levelStringExtended(boolean original){
93 		int x=(original ? originalLevel() : levelExtended);
94 		return x<0 ? "unknown" : TaxTree.levelToStringExtended(x);
95 	}
96 
levelToStringShort()97 	public String levelToStringShort() {return level<0 ? "x" : TaxTree.levelToStringShort(level);}
98 
99 
100 
isUnclassified()101 	public boolean isUnclassified(){
102 		return name.startsWith("unclassified");
103 	}
104 
isEnvironmentalSample()105 	public boolean isEnvironmentalSample(){
106 		return name.startsWith("environmental");
107 	}
108 
109 	/*--------------------------------------------------------------*/
110 	/*----------------        Nested Classes        ----------------*/
111 	/*--------------------------------------------------------------*/
112 
113 	public static class CountComparator implements Comparator<TaxNode>{
114 
115 		@Override
compare(TaxNode a, TaxNode b)116 		public int compare(TaxNode a, TaxNode b) {
117 			long x=b.countSum-a.countSum;
118 //			System.err.println("x="+x+" -> "+Tools.longToInt(x));
119 			if(x!=0){return Tools.longToInt(x);}
120 			return a.levelExtended==b.levelExtended ? a.id-b.id : a.levelExtended-b.levelExtended;
121 		}
122 
123 	}
124 
125 	/*--------------------------------------------------------------*/
126 	/*----------------           Getters            ----------------*/
127 	/*--------------------------------------------------------------*/
128 
129 	@Override
hashCode()130 	public final int hashCode(){return id;}
131 
132 	/*--------------------------------------------------------------*/
133 
canonical()134 	public boolean canonical(){
135 		return (flag&CANON_MASK)==CANON_MASK;
136 	}
137 
levelChanged()138 	public boolean levelChanged(){
139 		return originalLevel()!=levelExtended;
140 	}
141 
originalLevel()142 	public int originalLevel(){
143 		int x=(int)(flag&ORIGINAL_LEVEL_MASK);
144 		return x==ORIGINAL_LEVEL_MASK ? -1 : x;
145 	}
146 
cellularOrganisms()147 	public boolean cellularOrganisms(){
148 		return id==TaxTree.CELLULAR_ORGANISMS_ID;
149 	}
150 
151 //	public int numChildren(){
152 //		return numChildren;
153 //	}
154 //
155 //	public int minParentLevelExtended(){
156 //		return minParentLevelExtended;
157 //	}
158 //
159 //	public int maxChildLevelExtended(){
160 //		return maxChildLevelExtended;
161 //	}
162 
minAncestorLevelIncludingSelf()163 	int minAncestorLevelIncludingSelf(){
164 		return levelExtended<1 ? minParentLevelExtended : levelExtended;
165 	}
166 
maxDescendantLevelIncludingSelf()167 	int maxDescendantLevelIncludingSelf(){
168 		return levelExtended<1 ? maxChildLevelExtended : levelExtended;
169 	}
170 
simpleName()171 	public String simpleName(){
172 		if(name==null){return null;}
173 		StringBuilder sb=new StringBuilder();
174 		char last='?';
175 		for(int i=0; i<name.length(); i++){
176 			char c=name.charAt(i);
177 			if((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='1' && c<='0')){
178 				sb.append(c);
179 				last=c;
180 			}else{
181 				if(sb.length()>0 && last!=' '){sb.append(' ');}
182 				last=' ';
183 			}
184 		}
185 		String s=sb.toString().trim();
186 		return s.replace(' ', '_');
187 	}
188 
isRanked()189 	public boolean isRanked() {return levelExtended!=TaxTree.NO_RANK_E;}
190 
191 	/*--------------------------------------------------------------*/
192 	/*----------------           Setters            ----------------*/
193 	/*--------------------------------------------------------------*/
194 
setCanonical(boolean b)195 	public void setCanonical(boolean b){
196 		if(b){flag=flag|CANON_MASK;}
197 		else{flag=flag&~CANON_MASK;}
198 	}
199 
setOriginalLevel(int x)200 	public void setOriginalLevel(int x){
201 		flag=(flag&~ORIGINAL_LEVEL_MASK)|(x&ORIGINAL_LEVEL_MASK);
202 	}
203 
204 	/** Return true if changed */
discussWithParent(TaxNode parent)205 	boolean discussWithParent(TaxNode parent){
206 		final int oldChildLevel=parent.maxChildLevelExtended;
207 		final int oldParentLevel=minParentLevelExtended;
208 		parent.maxChildLevelExtended=Tools.max(parent.maxChildLevelExtended, maxDescendantLevelIncludingSelf());
209 		minParentLevelExtended=Tools.min(parent.minAncestorLevelIncludingSelf(), minParentLevelExtended);
210 		return oldChildLevel!=parent.maxChildLevelExtended || oldParentLevel!=minParentLevelExtended;
211 	}
212 
213 	/*--------------------------------------------------------------*/
214 	/*----------------            Fields            ----------------*/
215 	/*--------------------------------------------------------------*/
216 
217 	public final int id;
218 	public final String name;
219 	public int pid;
220 	public int level;
221 	public int levelExtended;
222 
223 	public int numChildren=0;
224 	public int minParentLevelExtended=TaxTree.LIFE_E;
225 	public int maxChildLevelExtended=TaxTree.NO_RANK_E;
226 
227 	private long flag=0;
228 
229 	public long countRaw=0;
230 	public long countSum=0;
231 
232 	/*--------------------------------------------------------------*/
233 	/*----------------          Constants           ----------------*/
234 	/*--------------------------------------------------------------*/
235 
236 	private static final long ORIGINAL_LEVEL_MASK=63; //bits 0-5
237 	private static final long CANON_MASK=64; //bit 6
238 
239 	/*--------------------------------------------------------------*/
240 	/*----------------           Statics            ----------------*/
241 	/*--------------------------------------------------------------*/
242 
243 	public static final boolean verbose=false;
244 	public static final CountComparator countComparator=new CountComparator();
245 
246 
247 }
248