package s3.core.services.memory;
import ovm.core.execution.Activation;
import ovm.core.execution.Context;
import ovm.core.services.memory.VM_Address;
import ovm.core.stitcher.InvisibleStitcher;
import ovm.core.stitcher.InvisibleStitcher.PragmaStitchSingleton;
import ovm.util.Iterator;

public abstract class LocalReferenceIterator {
    protected abstract boolean moreReferencesInThread();
    protected abstract VM_Address nextReferenceInThread();
    protected abstract void setThread(Context thread,
				      Activation topFrame);

    private Activation topFrameInCurrentThread;
    private Context currentThread;
    private Iterator contexts;

    private void nextThread() {
	Context thr = (Context) contexts.next();
	setThread(thr, (thr == currentThread
			? topFrameInCurrentThread
			: thr.getCurrentActivation()));
    }

    public boolean hasNext() {
	return moreReferencesInThread() || contexts.hasNext();
    }

    public VM_Address next() {
	if (!moreReferencesInThread())
	    nextThread();
        return nextReferenceInThread();
    }

    protected LocalReferenceIterator(Activation topFrameInCurrentThread) {
        this.topFrameInCurrentThread = topFrameInCurrentThread;
        currentThread = Context.getCurrentContext();
        contexts = Context.iterator();
	// assume there is at least 1 thread!
	nextThread();
    }
    
    public interface Factory {
	LocalReferenceIterator make(Activation topFrameInCurrentThread);
    }

    public static Factory factory() throws PragmaStitchSingleton {
	return (Factory) InvisibleStitcher.singletonFor(Factory.class);
    }
}
