sclass WebNode { Web web; O labels; // SmallestList O visInfo; // visualisation info *() {} *(Web *web) { web.fireNewNode(this); } void addLabel(S label) { addLabel(web.parseLabel(label)); } void addLabel(Lisp label) { if (!smallestList_contains(labels, label)) { //labels = smallestList_add(labels, label); if (web != null) web.index(label, this); } } /*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); } 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); } } sclass WebRelation extends WebNode { WebNode a, b; *() {} *(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 = new HashMap; new 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, 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) { ret relations.get(pair(a, b)); } WebRelation getRelation(Pair p) { WebRelation r = relations.get(p); if (r == null) relations.put(p, r = _newRelation(p.a, p.b)); 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) { 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) { 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) { ret map(func(S s) { parseLabel(s) }, l); } L unparseLabels(L l) { ret map(func(Lisp l) { unparseLabel(l) }, l); } 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); 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); } }