001: /*
002: * CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
003: * NETSCAPE COMMUNICATIONS CORPORATION
004: *
005: * Copyright (c) 1996 Netscape Communications Corporation.
006: * All Rights Reserved.
007: * Use of this Source Code is subject to the terms of the applicable
008: * license agreement from Netscape Communications Corporation.
009: */
010:
011: package soif;
012:
013: import util.BinaryTree;
014: import util.BTreeNode;
015: import util.ReportError;
016:
017: import java.util.Enumeration;
018: import java.util.Vector;
019:
020: /**
021: * Represent the taxonomy.
022: */
023: public class Taxonomy {
024: private String taxonomyId;
025: private SOIF taxs;
026:
027: /**
028: * Since position in the tree is significant,
029: * it is possible that this should not be public.
030: * You have been warned.
031: */
032: public BinaryTree binaryTree;
033:
034: private int tmpI, tmpP, tmpN;
035: private TaxonomyNode tnArr[];
036: private String pidArr[];
037: private boolean doneArr[];
038:
039: private boolean track(String s) {
040: // SGP: would be good to study the advance/tmpP chicanery
041: // to see if it actually helps w/ performance.
042: boolean advance = true;
043:
044: for (int i = tmpP; i < tmpN; i++) {
045: if (advance && doneArr[i])
046: tmpP = i;
047: if (!doneArr[i]) {
048: advance = false;
049: if (s.compareTo(tnArr[i].getParentId()) == 0) {
050: doneArr[i] = true;
051: tmpI = i;
052: return true;
053: }
054: }
055: }
056:
057: return false;
058: }
059:
060: private void setBack(BTreeNode btn) {
061: if (btn == null) {
062: binaryTree.resetEnumeration();
063: binaryTree.nextElement();
064: } else
065: binaryTree.setEnumeration(btn);
066: }
067:
068: private void buildNother() {
069: TaxonomyNode tn;
070: String s;
071: BTreeNode btn = binaryTree.getCurrent();
072:
073: if (btn == null) {
074: if (binaryTree.isEmpty()) {
075: btn = binaryTree.createChild(taxonomyId,
076: new TaxonomyNode(taxs));
077:
078: if (track("ROOT")) {
079: btn = binaryTree.createChild(
080: tnArr[tmpI].getLabel(), tnArr[tmpI]);
081: }
082: } else
083: return; // SGP: ?
084: }
085:
086: tn = (TaxonomyNode) btn.getValue();
087: if (tn == null) {
088: return;
089: }
090:
091: if (track(tn.getId())) {
092: binaryTree.createChild(tnArr[tmpI].getLabel(), tnArr[tmpI]);
093: buildNother();
094: setBack(btn);
095: }
096:
097: if (track(tn.getParentId())) {
098: binaryTree.createNext(tnArr[tmpI].getLabel(), tnArr[tmpI]);
099: buildNother();
100: setBack(btn);
101: }
102: }
103:
104: /**
105: * Constructor for simple default taxonomy.
106: */
107: public Taxonomy() {
108: this ((new SOIFParser("@TAXONOMY { -\n" + "id{3}:\tTop\n"
109: + "}\n").getSOIF()));
110:
111: /*
112: this( (new SOIFParser(
113: "@TAXONOMY { -\n"
114: + "id{3}: Top\n"
115: + "}\n"
116: + "@CLASSIFICATION { -\n"
117: + "taxonomy-id{3}: Top\n"
118: + "id{4}: ROOT\n"
119: + "}\n",
120: false
121: ).getSOIF())
122: );
123: */
124:
125: binaryTree.setEnumerationType(BinaryTree.DEPTHFIRSTSORTED);
126: }
127:
128: /**
129: * Constructor.
130: * @param soif soif
131: */
132: public Taxonomy(SOIF soif) {
133: String prev = "";
134: int i = 0;
135:
136: taxonomyId = soif.getValue("Id");
137: taxs = soif;
138:
139: binaryTree = new BinaryTree(BinaryTree.DEPTHFIRST);
140:
141: tmpI = 0;
142: tmpP = 0;
143: tmpN = soif.count() - 1;
144:
145: tnArr = new TaxonomyNode[tmpN];
146: pidArr = new String[tmpN];
147: doneArr = new boolean[tmpN];
148:
149: for (SOIF s = soif.next; s != null; s = s.next) {
150: /* SGP: in v3, a CLASSIFICATION node of ROOT
151: ** is introduced. in order to preserve backward
152: ** compatability, this is tossed and the quasi-root
153: ** node is derived in the old way. it would be
154: ** better to take advantage of the new scheme,
155: ** however (after fixing all the code that
156: ** breaks because this CLASSIFICATION hasn't
157: ** got a parentId). the weed out is not
158: ** very efficient, either.
159: */
160: TaxonomyNode tmptn = new TaxonomyNode(s);
161: if (tmptn.getId().compareTo("ROOT") != 0) {
162: tnArr[i] = tmptn;
163: pidArr[i] = tmptn.getParentId();
164: doneArr[i] = false;
165: i++;
166: }
167: }
168:
169: /* adjusts so that tmpN is correct whether
170: ** a ROOT was around to be dropped or not.
171: */
172: tmpN = i;
173:
174: buildNother();
175: binaryTree.resetEnumeration();
176:
177: tnArr = null;
178: pidArr = null;
179: doneArr = null;
180:
181: binaryTree.setEnumerationType(BinaryTree.DEPTHFIRSTSORTED);
182: }
183:
184: /**
185: * Set the taxonomy id throughout the tree.
186: * @param s taxonomy id
187: */
188: public void setTaxonomyId(String s) {
189: Object o;
190:
191: binaryTree.currentBackup();
192: binaryTree.resetEnumeration();
193:
194: while (binaryTree.hasMoreElements(true)) {
195: binaryTree.nextElement(true);
196: o = binaryTree.getValue();
197: ((TaxonomyNode) o).setValue("taxonomy-id", s);
198: }
199: binaryTree.currentRestore();
200: }
201:
202: /**
203: * Return the taxonomyId.
204: */
205: public String getTaxonomyId() {
206: return taxonomyId;
207: }
208:
209: /**
210: * Synchronize ids when they're changed.
211: */
212: public void synchId(BTreeNode btn, String s) {
213: // System.out.println("synchId() beg");
214: // System.out.println(toStringTree(true, false, false));
215: // toStringTree(true, false, false);
216: // System.out.println("-----------");
217: // System.out.println("synchId() 1");
218: // System.out.println("-----------");
219:
220: binaryTree.currentBackup();
221: binaryTree.setEnumeration(btn);
222:
223: TaxonomyNode tn = (TaxonomyNode) btn.getValue();
224: String pid = tn.getParentId();
225:
226: if (pid == null) {
227: taxonomyId = s;
228: tn.setValue("Id", s);
229: while (binaryTree.hasMoreElements(true)) {
230: binaryTree.nextElement(true);
231: ((TaxonomyNode) binaryTree.getCurrent().getValue())
232: .setValue("Taxonomy-Id", s);
233: }
234: binaryTree.currentRestore();
235: return;
236: } else if (pid.compareTo("ROOT") == 0)
237: tn.setValue("Id", s);
238: else
239: tn.setValue("Id", tn.getParentId() + ":" + s);
240:
241: while (binaryTree.hasMoreElements(true)) {
242: binaryTree.nextElement(true);
243: if (btn.getUnaryDepth() >= binaryTree.getUnaryDepth())
244: break;
245:
246: BTreeNode pbtn = binaryTree.getUnaryParent();
247: if (pbtn != null) {
248: ((TaxonomyNode) binaryTree.getCurrent().getValue())
249: .setValue("Parent-Id", ((TaxonomyNode) pbtn
250: .getValue()).getId());
251: }
252: }
253:
254: binaryTree.currentRestore();
255:
256: // System.out.println(toStringTree(true, false, false));
257: // System.out.println("synchId() end");
258: }
259:
260: /**
261: * Synchronize tree adter drag and drop.
262: * A node and any children have been moved in the tree. This method
263: * will traverse the node and all it's children resetting it's parent
264: * and ID. Both are in node:node:node format.
265: */
266: public void synchTree(BTreeNode btn) {
267:
268: binaryTree.currentBackup();
269: binaryTree.setEnumeration(btn);
270:
271: TaxonomyNode tn = (TaxonomyNode) btn.getValue(); // Moved node
272: TaxonomyNode ptn = null; // Parent nodes
273: TaxonomyNode ctn = null; // Child nodes
274:
275: if (btn.getUnaryParent().getParent() == null) { // Moving to root level
276: tn.setValue("Parent-Id", "ROOT");
277: tn.setValue("Id", "" + btn.getKey());
278: } else { // Reset parent and ID
279: ptn = (TaxonomyNode) btn.getUnaryParent().getValue();
280: tn.setValue("Parent-Id", "" + ptn.getId());
281: tn.setValue("Id", ptn.getId() + ":" + btn.getKey());
282: }
283:
284: while (binaryTree.hasMoreElements(true)) { // Loop thru children
285: binaryTree.nextElement(true);
286: // New node?
287: if (btn.getUnaryDepth() >= binaryTree.getUnaryDepth())
288: break;
289:
290: BTreeNode pbtn = binaryTree.getUnaryParent();
291: ptn = (TaxonomyNode) pbtn.getValue();
292:
293: if (pbtn != null) {
294: ctn = ((TaxonomyNode) binaryTree.getCurrent()
295: .getValue());
296: ctn.setValue("Parent-Id", "" + ptn.getId());
297: ctn.setValue("Id", ptn.getId() + ":" + ctn.getLabel());
298: }
299: }
300:
301: binaryTree.currentRestore();
302: }
303:
304: /**
305: * Get the nodes with the parent named s.
306: * @param s the parent name
307: */
308: public Vector getChildPeers(String s, boolean all) {
309: Object o;
310:
311: binaryTree.currentBackup();
312: binaryTree.resetEnumeration();
313:
314: while (binaryTree.hasMoreElements(all)) {
315: binaryTree.nextElement(all);
316: o = binaryTree.getValue();
317: if (((TaxonomyNode) o).getId().compareTo(s) == 0) {
318: Vector v = binaryTree.getChildPeers(all);
319: binaryTree.currentRestore();
320: return v;
321: }
322: }
323:
324: binaryTree.currentRestore();
325: return null;
326: }
327:
328: /**
329: * Get the node whose id is s.
330: * @param s target id
331: */
332: public BTreeNode findNode(String s) {
333: Object o;
334:
335: binaryTree.currentBackup();
336: binaryTree.resetEnumeration();
337:
338: while (binaryTree.hasMoreElements(true)) {
339: binaryTree.nextElement(true);
340: o = binaryTree.getValue();
341: if (((TaxonomyNode) o).getId().equalsIgnoreCase(s) == true) {
342: BTreeNode btn = binaryTree.getCurrent();
343: binaryTree.currentRestore();
344: return btn;
345: }
346: }
347:
348: binaryTree.currentRestore();
349: return null;
350: }
351:
352: /**
353: * Tack a new next down there.
354: */
355: public void newNext() {
356: TaxonomyNode currTn = (TaxonomyNode) binaryTree.getValue();
357: TaxonomyNode tn = new TaxonomyNode(currTn.getParentId()
358: + ":new", currTn.getParentId(), taxonomyId, "");
359: binaryTree.createNext(tn.getLabel(), tn);
360: }
361:
362: /**
363: * Tack a new child down there.
364: */
365: public void newChild() {
366: TaxonomyNode currTn = (TaxonomyNode) binaryTree.getValue();
367: TaxonomyNode tn = new TaxonomyNode(currTn.getId() + ":new",
368: currTn.getId(), taxonomyId, "");
369: binaryTree.createChild(tn.getLabel(), tn);
370: }
371:
372: /**
373: * Spit out as SOIF.
374: */
375: public String toSOIF() {
376: StringBuffer sb = new StringBuffer();
377: TaxonomyNode tn;
378:
379: binaryTree.currentBackup();
380: binaryTree.resetEnumeration();
381:
382: while (binaryTree.hasMoreElements(true)) {
383: binaryTree.nextElement(true);
384: tn = (TaxonomyNode) binaryTree.getValue();
385: sb.append(tn.toSOIF());
386: }
387:
388: binaryTree.currentRestore();
389: return sb.toString();
390: }
391:
392: public String toString() {
393: return "Taxonomy instance: (" + Header.VERSION + ")\n"
394: + "\ttaxonomyId\t= [" + taxonomyId + "]\n";
395: }
396:
397: /**
398: * Dump the tree out in a couple of different ways.
399: * @param fullnode dump the info in the node
400: * @param tree dump the tree structure
401: * @param id dump id list
402: */
403: public String toStringTree(boolean fullnode, boolean tree,
404: boolean id) {
405: StringBuffer sb = new StringBuffer(toString());
406: TaxonomyNode tn;
407:
408: binaryTree.currentBackup();
409: binaryTree.resetEnumeration();
410: if (binaryTree.isEmpty()) {
411: return sb.toString();
412: }
413:
414: if (fullnode) {
415: sb.append("---< full node >-----\n");
416:
417: binaryTree.resetEnumeration();
418:
419: while (binaryTree.hasMoreElements(true)) {
420: binaryTree.nextElement(true);
421: BTreeNode btn = binaryTree.getCurrent();
422: sb.append(btn.toString() + "\n");
423: sb.append("---" + "\n");
424: }
425:
426: sb.append("---------------------\n");
427: }
428:
429: if (tree) {
430: sb.append("---< tree >----------\n");
431:
432: binaryTree.resetEnumeration();
433:
434: while (binaryTree.hasMoreElements(true)) {
435: binaryTree.nextElement(true);
436: tn = (TaxonomyNode) binaryTree.getValue();
437: StringBuffer indent = new StringBuffer();
438: for (int i = 0; i <= binaryTree.getUnaryDepth(); i++)
439: indent.append(" ");
440: sb.append(indent.toString() + tn.getLabel() + "\n");
441: }
442:
443: sb.append("---------------------\n");
444: }
445:
446: if (id) {
447: sb.append("---< id >------------\n");
448:
449: binaryTree.resetEnumeration();
450:
451: while (binaryTree.hasMoreElements(true)) {
452: binaryTree.nextElement(true);
453: tn = (TaxonomyNode) binaryTree.getValue();
454: StringBuffer indent = new StringBuffer();
455: for (int i = 0; i <= binaryTree.getUnaryDepth(); i++)
456: indent.append(" ");
457: sb.append(indent.toString() + tn.getId() + "\n");
458: }
459:
460: sb.append("---------------------\n");
461: }
462:
463: binaryTree.currentRestore();
464: return sb.toString();
465: }
466:
467: }
|