443 lines
12 KiB
Java
443 lines
12 KiB
Java
/*
|
|
ZZDimSpace.java
|
|
*
|
|
* Copyright (c) 2000, Ted Nelson and Tuomas Lukka
|
|
*
|
|
* You may use and distribute under the terms of either the GNU Lesser
|
|
* General Public License, either version 2 of the license or,
|
|
* at your choice, any later version. Alternatively, you may use and
|
|
* distribute under the terms of the XPL.
|
|
*
|
|
* See the LICENSE.lgpl and LICENSE.xpl files for the specific terms of
|
|
* the licenses.
|
|
*
|
|
* This software is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the README
|
|
* file for more details.
|
|
*
|
|
*/
|
|
/*
|
|
* Written by Tuomas Lukka (ID-stuff and d.cellcreation by Tuukka Hastrup)
|
|
*/
|
|
package org.gzigzag;
|
|
import java.util.*;
|
|
|
|
/** A dimension-centric implementation of a space.
|
|
* The internals of this implementation are done by dimension objects
|
|
* which know how cells are connected in their dimension.
|
|
* @see ZZDimension
|
|
*/
|
|
|
|
public class ZZDimSpace extends ZZSpace {
|
|
public static final String rcsid = "$Id: ZZDimSpace.java,v 1.49 2001/03/07 12:51:24 ajk Exp $";
|
|
|
|
// XXX These should be made garbage collectable ASAP!
|
|
|
|
/** ZZDimension given string. */
|
|
Hashtable dims = new Hashtable();
|
|
|
|
/** DimCell given id. */
|
|
Hashtable cells = new Hashtable();
|
|
|
|
/** Space parts by names. */
|
|
Hashtable spaceParts = new Hashtable();
|
|
|
|
/** Contents by id. */
|
|
Hashtable contents = new Hashtable();
|
|
|
|
/** Cell by span.
|
|
* If this is null, overlapping spans cannot be searched.
|
|
*/
|
|
SpanSet spanset = null;
|
|
|
|
public ZZDimSpace() { this(false); }
|
|
public ZZDimSpace(boolean readonly) {
|
|
super(readonly);
|
|
}
|
|
|
|
/** Obtain the space part corresponding to the given ID.
|
|
*/
|
|
public ZZSpacePart getSpacePartByID(String id) {
|
|
return (ZZSpacePart)spaceParts.get(id);
|
|
}
|
|
|
|
/** Obtain the ZZDimension corresponding to the given string.
|
|
*/
|
|
final public ZZDimension d(String s) {
|
|
ZZDimension r = (ZZDimension)dims.get(s);
|
|
if(r==null) {
|
|
r = createDimension(s);
|
|
if(r == null)
|
|
throw new ZZError("Illegal dimension: '"+s+"'");
|
|
dims.put(s,r);
|
|
if (!readonly) updateMasterDimList(s);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/** The cell given by the identifier, <b>if already created</b>.
|
|
* Note that this routine only returns existing cells,
|
|
* i.e. objects that have already been created.
|
|
* Dormant cells or virtual cells need to be obtained through
|
|
* getCellByID.
|
|
*/
|
|
DimCell c(String id) { return (DimCell)cells.get(id); }
|
|
|
|
/** Obtain the cell given by the identifier.
|
|
*/
|
|
public ZZCell getCellByID(String s) {
|
|
int at = s.indexOf('@');
|
|
if (at != -1 && getIDOrNull() != null && s.substring(at+1).equals(getID())) {
|
|
s = s.substring(0, at);
|
|
at = -1;
|
|
}
|
|
int ind = s.indexOf(':');
|
|
if (at == -1 && ind == -1) {
|
|
try {
|
|
if (nextID != null) {
|
|
long cid = Long.parseLong(s);
|
|
long nid = Long.parseLong(nextID);
|
|
if (cid >= nid) setNextID("" + (cid+1));
|
|
}
|
|
} catch(NumberFormatException e) {
|
|
return null;
|
|
}
|
|
}
|
|
if(ind != -1) {
|
|
ZZSpacePart part = getSpacePartByID(s.substring(0, ind));
|
|
if(part == null)
|
|
throw new ZZError("No such part for cell "+s);
|
|
return getCellByID(part, s.substring(ind+1));
|
|
}
|
|
return getCellByID(null, s);
|
|
}
|
|
|
|
/** Obtain a cell, possibly in a space part.
|
|
*/
|
|
public DimCell getCellByID(ZZSpacePart p, String s0) {
|
|
String s = (p != null ? p.id + ":" + s0 : s0);
|
|
DimCell ret = null;
|
|
if (p != null) ret = p.getCellByID(s0);
|
|
if (ret == null) ret = (DimCell) cells.get(s);
|
|
if(ret==null) {
|
|
DimCell d = new DimCell(s, p,
|
|
(p != null ? p.parseIDPart(s0) : null));
|
|
cells.put(d.id, d);
|
|
ret = d;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public DimCell getCellByID(ZZSpacePart p, String s0, Object o) {
|
|
String s = p.id + ":" + s0;
|
|
DimCell ret = null;
|
|
if (p != null) ret = p.getCellByID(s0);
|
|
if (ret == null) ret = (DimCell) cells.get(s);
|
|
if(ret==null) {
|
|
DimCell d = new DimCell(s, p, o);
|
|
cells.put(d.id, d);
|
|
ret = d;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public ZZCell[] overlaps(Span sp) {
|
|
if(spanset == null) return null;
|
|
Object[] o = spanset.overlaps(sp);
|
|
ZZCell[] res = new ZZCell[o.length];
|
|
for(int i=0; i<o.length; i++) res[i] = c((String)o[i]);
|
|
return res;
|
|
}
|
|
|
|
ZZObsTrigger textTrig = new ZZObsTrigger();
|
|
|
|
public void invalidateText(String id) {
|
|
DimCell dc = c(id);
|
|
if (dc == null) {
|
|
ZZLogger.log("FIXME: invalidateText called with a nonexistent ID!");
|
|
return;
|
|
}
|
|
// Do nothing now. Maybe?
|
|
}
|
|
|
|
protected Span getSpan(String id) {
|
|
return (Span) contents.get(id);
|
|
}
|
|
protected String getText(String id) {
|
|
String s = (String) contents.get(id);
|
|
return s;
|
|
}
|
|
protected void setText(String id, Object ct) {
|
|
contents.put(id,ct);
|
|
if(spanset != null && ct instanceof Span)
|
|
spanset.addSpan((Span)ct, id);
|
|
// XXX what if a span content is replaced by a non-span content?!?
|
|
// -- for now we can assume span contents don't change (I know
|
|
// no span-using code that does) but later, we'll need that?
|
|
}
|
|
|
|
/** A ZZCell in the dimspace representation.
|
|
* Interestingly, in this representation the cell is simply
|
|
* its identifier and the implicit reference to the surrounding
|
|
* ZZDimSpace object.
|
|
* <p>
|
|
* The reason for this is that it needs to be allowable for
|
|
* two cell objects with the same ID to be created without
|
|
* too much confusion.
|
|
* <p>
|
|
* This is because we're aiming for Java 1.1 which does not
|
|
* have weak references.
|
|
*/
|
|
public class DimCell extends ZZCellHandle {
|
|
|
|
protected DimCell(String id) {
|
|
super(id, null, null);
|
|
}
|
|
protected DimCell(ZZSpacePart part, Object parsedID) {
|
|
this(part.generateID(parsedID), part, parsedID);
|
|
}
|
|
|
|
protected DimCell(String id, ZZSpacePart p, Object o) {
|
|
super(id, p, o);
|
|
}
|
|
|
|
public String[] getRankNames() {
|
|
throw new ZZError("getRankNames Not implemented");
|
|
}
|
|
|
|
public final ZZSpace getSpace() { return ZZDimSpace.this; }
|
|
|
|
public void connect(String dim, ZZCell to) {
|
|
this.disconnect(dim, 1);
|
|
to.disconnect(dim, -1);
|
|
d(dim).connect(this, ((DimCell)to));
|
|
}
|
|
public void disconnect(String dim, int dir) {
|
|
d(dim).disconnect(this, dir);
|
|
}
|
|
public void insert(String dim, int dir, ZZCell to) {
|
|
d(dim).insert(this, dir, ((DimCell)to));
|
|
}
|
|
public void hop(String dim, int steps) {
|
|
d(dim).hop(this, steps);
|
|
}
|
|
|
|
public ZZCell s(String dim, int dir, ZZObs o) {
|
|
return d(dim).s(this, dir, o);
|
|
}
|
|
|
|
public ZZCell N(String dim, int dir, ZZObs o, long flags)
|
|
{
|
|
synchronized(ZZDimSpace.this) {
|
|
DimCell n = getNewCell(id);
|
|
insert(dim, dir, n);
|
|
if(o != null)
|
|
d(dim).s(this, dir, o);
|
|
return n;
|
|
}
|
|
}
|
|
|
|
public ZZCell N() {
|
|
synchronized(ZZDimSpace.this) {
|
|
return getNewCell(id);
|
|
}
|
|
}
|
|
|
|
public void setText(String text) {
|
|
synchronized(ZZDimSpace.this) {
|
|
ZZCell rootClone = getRootclone();
|
|
if(rootClone != this) {
|
|
rootClone.setText(text);
|
|
return;
|
|
}
|
|
if(part != null) {
|
|
part.setContent(this, text);
|
|
} else {
|
|
p("TEXT");
|
|
ZZDimSpace.this.setText(id, text);
|
|
textTrig.chg(id);
|
|
}
|
|
}
|
|
}
|
|
public void setSpan(Span text) {
|
|
synchronized(ZZDimSpace.this) {
|
|
ZZCell rootClone = getRootclone();
|
|
if(rootClone != this) {
|
|
rootClone.setSpan(text);
|
|
return;
|
|
}
|
|
if(part != null) {
|
|
part.setContent(this, text);
|
|
} else {
|
|
ZZDimSpace.this.setText(id, text);
|
|
textTrig.chg(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// XXX part.getText should NOT BE HERE!!!!
|
|
public String getText(ZZObs o) {
|
|
synchronized(ZZDimSpace.this) {
|
|
String s;
|
|
// XXX Interaction with slices??
|
|
// XXX Interaction with ZZObs
|
|
ZZCell rootClone = getRootclone();
|
|
if(rootClone != this)
|
|
return rootClone.getText(o);
|
|
if(o != null) textTrig.addObs(id, o);
|
|
if(part != null)
|
|
s = part.getText(this);
|
|
else
|
|
s = ZZDimSpace.this.getText(id);
|
|
if( s == null )
|
|
return "";
|
|
return s;
|
|
}
|
|
}
|
|
public Span getSpan(ZZObs o) {
|
|
synchronized(ZZDimSpace.this) {
|
|
ZZCell rootClone = getRootclone();
|
|
// XXX As in getText!!!
|
|
if(rootClone != this)
|
|
return rootClone.getSpan(o);
|
|
if(o != null) textTrig.addObs(id, o);
|
|
if(part != null)
|
|
return part.getSpan(this);
|
|
return ZZDimSpace.this.getSpan(id);
|
|
}
|
|
}
|
|
|
|
public boolean equals(ZZCell c) {
|
|
DimCell o = (DimCell)c;
|
|
return (this == o) ||
|
|
(ZZDimSpace.this == o.getSpace() &&
|
|
id.equals(o.id));
|
|
}
|
|
|
|
public void delete() {
|
|
synchronized(ZZDimSpace.this) {
|
|
ZZDimSpace.this.deleteCell(this);
|
|
}
|
|
}
|
|
|
|
public ZZCell h(String dim, int dir,
|
|
boolean ensuremove, ZZObs o) {
|
|
ZZCell res = d(dim).h(this, dir, o);
|
|
if(ensuremove && (res == this)) return null;
|
|
return res;
|
|
}
|
|
|
|
}
|
|
|
|
void deleteCell(ZZCell c) {
|
|
for(Enumeration e = dims.keys(); e.hasMoreElements(); ) {
|
|
((ZZDimension)(dims.get(e.nextElement()))).excise((DimCell)c);
|
|
}
|
|
}
|
|
|
|
String nextID="2"; // first cell is home cell, ID 1
|
|
protected void setNextID(String s) {
|
|
nextID = s;
|
|
}
|
|
|
|
/** Get the cell ID relative to a given ID, in creation order.
|
|
* @param id Given ID
|
|
* @param steps How many steps to take (negative means earlier)
|
|
*/
|
|
public String getRelativeCellID(String id, int steps) {
|
|
try {
|
|
long i = Long.parseLong(id);
|
|
if(i<0 || i+steps<1)
|
|
return null;
|
|
return ""+(i+steps);
|
|
} catch(NumberFormatException e) {
|
|
return null;
|
|
}
|
|
}
|
|
protected String getFreeCellID() {
|
|
String curID = nextID;
|
|
setNextID(getRelativeCellID(nextID, 1));
|
|
return curID;
|
|
}
|
|
|
|
// XXX What's this? (compared to the next)
|
|
protected DimCell getNewCell(String id) {
|
|
return getNewCell();
|
|
}
|
|
protected DimCell getNewCell() {
|
|
return (DimCell)getCellByID(nextID);
|
|
}
|
|
public ZZCell newCell() {
|
|
return getNewCell();
|
|
}
|
|
|
|
/** A simple dimension listing the cells in creation order.
|
|
* It uses getRelativeCellID() to find the cells, and will check
|
|
* nextID to know whether the cell doesn't exist yet.
|
|
* XXX The positive steps taken must be 1 or skipping nextID
|
|
* is possible!
|
|
*/
|
|
class IDDimension extends ZZRODimension {
|
|
/** get a cell ID along the dimension.
|
|
* XXX Obs doesn't work correctly.
|
|
*/
|
|
public ZZCellHandle s(ZZCellHandle c, int steps, ZZObs o) {
|
|
String id = getRelativeCellID(c.id, steps);
|
|
if(id == null || id.equals(nextID))
|
|
return null;
|
|
return (DimCell)getCellByID(id);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// XXX posConnections()?
|
|
public ZZCell[] findLongRankHeads(String dim) { return null; }
|
|
|
|
public void rmAllObs(ZZObs o) { }
|
|
|
|
public String getHomeCellID() {
|
|
return "1";
|
|
}
|
|
public ZZCell getHomeCell() {
|
|
return getCellByID(getHomeCellID());
|
|
}
|
|
|
|
/** Create a new dimension with the name s.
|
|
* In order to make things fast, this is the method
|
|
* to override instead of the d() method (which is final
|
|
* exactly because of that).
|
|
* <p>
|
|
* The default version simply returns a new ZZLocalDimension,
|
|
* except for d.cellcreation
|
|
* <p>
|
|
* Note that this routine should NOT touch the dimension hash
|
|
* but simply return the new dimension.
|
|
*/
|
|
protected ZZDimension createDimension(String s) {
|
|
if(s.indexOf(':') != -1) return createPartDimension(s);
|
|
if(!validDim(s)) return null;
|
|
ZZDimension l;
|
|
if(s.equals("d.cellcreation")) {
|
|
l = new IDDimension();
|
|
} else {
|
|
l = new ZZLocalDimension();
|
|
}
|
|
l.setSpace(this);
|
|
return l;
|
|
|
|
}
|
|
|
|
protected ZZDimension createPartDimension(String s) {
|
|
int ind = s.indexOf(':');
|
|
ZZSpacePart part = getSpacePartByID(s.substring(0, ind));
|
|
ZZDimension d = part.getDim(s.substring(ind+1));
|
|
d.setSpace(this);
|
|
return d;
|
|
}
|
|
|
|
|
|
}
|
|
|