sclass WebNode implements _SetField { Web web; new L labels; O visInfo; // visualisation info public void _setField(S f, O x) { if (f.equals('web)) web = (Web) x; else if (f.equals('labels)) labels = (L) x; else if (f.equals('visInfo)) visInfo = x; } *() {} *(Web *web) { web.fireNewNode(this); } void addLabel(S label) { addLabel(web.parseLabel(label)); } void addLabel(Lisp label) { if (setAdd(labels, label) && web != null) web.index(label, this); } void addLabels(Collection l) { for (Lisp lbl : l) addLabel(lbl); } void addStrings(Collection l) { for (S lbl : l) addLabel(lbl); } bool hasLabel(Lisp label) { ret labels.contains(label); } bool hasLabel(S label) { ret labels.contains(web.parseLabel(label)); } toString { ret l(labels) == 1 ? str(first(labels)) : str(labels); } int count() { ret 1 + l(labels); } S text() { ret web.unparseLabel(first(labels)); } L texts() { ret web.unparseLabels(labels); } void relation(S arrow, S b) { web.getRelation(this, web.node(b)).addLabel(arrow); } Lisp parseLabel(S l) { ret web.parseLabel(l); } S unparseLabel(Lisp l) { ret web.unparseLabel(l); } L labels() { ret labels; } bool hasLabels() { ret nempty(labels); } void setLabel(int i, Lisp l) { labels.set(i, l); } } sclass WebRelation extends WebNode { WebNode a, b; public void _setField(S f, O x) { if (f.equals('a)) a = (WebNode) x; else if (f.equals('b)) b = (WebNode) x; else super._setField(f, x); } *() {} *(Web web, WebNode a, WebNode b) { super(web); this.a = a; this.b = b; } } sclass Web { new L nodes; // Relations are also nodes Map, WebRelation> relations; MultiMap index; // label -> node //Map> pots = new Map; transient Lock lock = reentrantLock(true); //int size; //int flags; // TODO bool useCLParse = true; bool labelsToUpper; S title; O globalID = aGlobalID(); S source; bool unverified; long created = nowUnlessLoading(); static new L onNewNode; // L static new L onNewLabel; // L static int F_useCLParse = 1; static int F_labelsToupper = 2; static int F_unverified = 3; /*bool potNotEmpty(S pot) { ret nempty(getPot(pot)); } L clearPot(S pot) { L l = getPot(pot); L l2 = cloneList(l); l.clear(); ret l2; }*/ /*L getPot(S pot) { L l = pots.get(pot); if (l == null) pots.put(pot, l = cloneList(nodes)); ret l; }*/ void relation(WebNode a, S arrow, WebNode b) { getRelation(a, b).addLabel(arrow); } Pair relation(S a, S arrow, S b) { ret relation(lisp(arrow, a, b)); } Pair relation(Lisp l) { if (l(l) == 1) { findNode(l.get(0)).addLabel(lisp("wvuyakuvuelmxpwp", l.head)); null; } else if (l(l) == 2) { S a = lisp2label(l.get(0)), b = lisp2label(l.get(1)); if (l.is("fgvvrzypbkqomktd")) { // X is Y. findNode(a).addLabel(b); findNode(b).addLabel(a); } WebNode na = findNode(a), nb = findNode(b); getRelation(na, nb).addLabel(l.head); ret pair(na, nb); } null; } void relations(L l) { for (Lisp li : l) relation(li); } WebRelation getRelation(S a, S b) { ret getRelation(findNode(a), findNode(b)); } WebRelation getRelation(WebNode a, WebNode b) { ret getRelation(pair(a, b)); } WebRelation relation(WebNode a, WebNode b) { ret getRelation(a, b); } WebRelation relation(Pair p) { ret getRelation(p); } WebRelation getRelationOpt(WebNode a, WebNode b) { if (relations != null) ret relations.get(pair(a, b)); for (WebNode n : nodes) if (n instanceof WebRelation) { WebRelation r = n/WebRelation; if (r.a == a && r.b == b) ret r; } null; } WebRelation getRelation(Pair p) { WebRelation r = relations != null ? relations.get(p) : getRelationOpt(p.a, p.b); if (r == null) { r = _newRelation(p.a, p.b); if (relations != null) relations.put(p, r); } ret r; } WebRelation _newRelation(WebNode a, WebNode b) { WebRelation r = new WebRelation(this, a, b); nodes.add(r); //for (L l : values(pots)) l.add(r); ret r; } WebNode newNode() { WebNode node = new WebNode(this); nodes.add(node); //for (L l : values(pots)) l.add(node); ret node; } WebNode newNode(S s) { WebNode node = newNode(); node.addLabel(parseLabel(s)); ret node; } WebNode node(S s) { ret findNode(s); } WebNode node(Lisp l) { ret findNode(l); } WebNode findNode(S s) { ret findNode(parseLabel(s)); } WebNode findNode(Lisp l) { WebNode n = findNodeOpt(l); ret n != null ? n : newNode(l); } WebNode findNodeOpt(Lisp l) { if (index != null) ret first(index.get(l)); for (WebNode n : nodes) if (n.labels.contains(l)) ret n; null; } WebNode newNode(S... labels) { WebNode n = newNode(); for (S label : labels) n.addLabel(label); ret n; } WebNode newNode(Lisp... labels) { WebNode n = newNode(); for (Lisp label : labels) n.addLabel(label); ret n; } toString { ret webToString(this); } void index(Lisp label, WebNode n) { if (index != null) index.put(label, n); fireNewLabel(n, label); } void clear { clearAll(nodes, relations, index/*, pots*/); } Lisp parseLabel(S s) { ifndef noCLParse if (useCLParse) ret clParse(s); endifndef ret lisp(labelsToUpper ? upper(s) : s); } S unparseLabel(Lisp l) { ifndef noCLParse if (useCLParse) ret clUnparse(l); endifndef ret lispHead(l); } L parseLabels(L l) { L x = new L(l(l)); for (S s : l) x.add(parseLabel(s)); ret x; } L unparseLabels(L l) { L x = new L(l(l)); for (Lisp lbl : l) x.add(unparseLabel(lbl)); ret x; } void fireNewNode(WebNode node) { for (O f : onNewNode) pcallF(f, node); } void fireNewLabel(WebNode node, Lisp label) { for (O f : onNewLabel) pcallF(f, node, label); } void removeNode(WebNode n) { if (n == null || !nodes.contains(n)) ret; n.web = null; L> relationsToDelete = pairList_lookupAnySide(keys(relations), n); if (index != null) for (Lisp label : n.labels) index.remove(label, n); nodes.remove(n); for (Pair p : relationsToDelete) removeRelation(p.a, p.b); } void removeRelation(WebNode a, WebNode b) { Pair p = pair(a, b); WebNode r = relations.get(p); if (r == null) ret; relations.remove(p); removeNode(r); } bool verified() { ret !unverified; } S globalID() { ret strOrNull(globalID); } GlobalID globalIDObj() { ret globalID instanceof S ? GlobalID((S) globalID : (GlobalID) globalID; } }