/* VariableValueIterator - Decompiled by JODE
 * Visit http://jode.sourceforge.net/
 */
package alloy.transl;
import java.util.Iterator;

import alloy.ast.ArrowMultExpr;
import alloy.ast.ComprehensionExpr;
import alloy.ast.LeafId;
import alloy.ast.MultiplicityExpr;
import alloy.ast.RelMultiplicity;
import alloy.ast.SetMultExpr;
import alloy.type.RelationType;
import alloy.util.Dbg;
import alloy.util.PermIter;

public abstract class VariableValueIterator implements Iterator
{
    protected long _boolSwitchValue;
    private RelationType _relType;
    private int[] _dimSize;
    
    private static class PermutationIterator extends VariableValueIterator
    {
	private PermIter _permIter;
	
	PermutationIterator(RelationType relationtype) {
	    super(relationtype);
	    Dbg.chk(relationtype.numBasicTypes() == 2
		    && relationtype.getBasicTypeAt(0)
			   .equals(relationtype.getBasicTypeAt(1)));
	    _permIter
		= new PermIter(relationtype.getBasicTypeAt(0).getScope());
	}
	
	public Object next() {
	    int[] is = (int[]) _permIter.next();
	    this._boolSwitchValue = 0L;
	    for (int i = 0; i < is.length; i++)
		this.setTuple(new int[] { i, is[i] });
	    return new Long(this._boolSwitchValue);
	}
	
	public boolean hasNext() {
	    return _permIter.hasNext();
	}
    }
    
    private static class AllValuesIterator extends VariableValueIterator
    {
	private long _leftToReturn = 1L;
	
	AllValuesIterator(RelationType relationtype) {
	    super(relationtype);
	    for (int i = 0; i < relationtype.numBasicTypes(); i++)
		_leftToReturn
		    *= (long) relationtype.getBasicTypeAt(i).getScope();
	    _leftToReturn = (long) (1 << (int) _leftToReturn);
	    Dbg.chk(_leftToReturn > 0L);
	}
	
	public Object next() {
	    Long var_long = new Long(this._boolSwitchValue++);
	    _leftToReturn--;
	    return var_long;
	}
	
	public boolean hasNext() {
	    return _leftToReturn > 0L;
	}
    }
    
    private static class SingleTupleIterator extends VariableValueIterator
    {
	private int _leftToReturn;
	
	SingleTupleIterator(RelationType relationtype, boolean bool) {
	    super(relationtype);
	    this._boolSwitchValue = bool ? 0L : 1L;
	    _leftToReturn = 1;
	    for (int i = 0; i < relationtype.numBasicTypes(); i++)
		_leftToReturn *= relationtype.getBasicTypeAt(i).getScope();
	    if (bool)
		_leftToReturn++;
	}
	
	public Object next() {
	    Long var_long = new Long(this._boolSwitchValue);
	    if (this._boolSwitchValue == 0L)
		this._boolSwitchValue = 1L;
	    else {
		this._boolSwitchValue = this._boolSwitchValue << 1;
		Dbg.chk(this._boolSwitchValue > 0L);
	    }
	    _leftToReturn--;
	    return var_long;
	}
	
	public boolean hasNext() {
	    return _leftToReturn > 0;
	}
    }
    
    protected VariableValueIterator(RelationType relationtype) {
	_relType = relationtype;
	_dimSize = new int[relationtype.numBasicTypes()];
	int i = 1;
	int i_0_ = 1;
	for (int i_1_ = relationtype.numBasicTypes() - 1; i_1_ >= 0; i_1_--) {
	    _dimSize[i_1_] = i_0_;
	    int i_2_ = relationtype.getBasicTypeAt(i_1_).getScope();
	    i_0_ *= i_2_;
	    i *= i_2_;
	}
	Dbg.chk(i <= 64);
    }
    
    protected int getBitForTuple(int[] is) {
	int i = 0;
	for (int i_3_ = 0; i_3_ < is.length; i_3_++)
	    i += is[i_3_] * _dimSize[i_3_];
	return i;
    }
    
    protected void setTuple(int[] is) {
	_boolSwitchValue |= (long) (1 << getBitForTuple(is));
    }
    
    public static Iterator makeIterator(LeafId leafid, TranslInfo translinfo) {
	RelationType relationtype = translinfo.getLeafType(leafid);
	MultiplicityExpr multiplicityexpr
	    = translinfo.getLeafMultiplicity(leafid);
	boolean bool
	    = translinfo.getVarCreator(leafid) instanceof ComprehensionExpr;
	return makeIterator(relationtype, multiplicityexpr, bool);
    }
    
    public static Iterator makeIterator(RelationType relationtype,
					MultiplicityExpr multiplicityexpr,
					boolean bool) {
	if (bool)
	    return makeSingleTupleIterator(relationtype, false);
	if (relationtype.numBasicTypes() == 1) {
	    switch (((SetMultExpr) multiplicityexpr).getSetMult()
			.getOpCode()) {
	    case 1:
	    case 3:
		return makeSingleTupleIterator(relationtype, false);
	    case 2:
		return makeSingleTupleIterator(relationtype, true);
	    case 0:
		return new AllValuesIterator(relationtype);
	    default:
		return null;
	    }
	}
	if (multiplicityexpr instanceof ArrowMultExpr) {
	    ArrowMultExpr arrowmultexpr = (ArrowMultExpr) multiplicityexpr;
	    RelMultiplicity relmultiplicity = arrowmultexpr.getLeftMult();
	    RelMultiplicity relmultiplicity_4_ = arrowmultexpr.getRightMult();
	    if (relmultiplicity.getOpCode() == 0
		&& relmultiplicity_4_.getOpCode() == 0)
		return new PermutationIterator(relationtype);
	}
	return new AllValuesIterator(relationtype);
    }
    
    public static Iterator makeSingleTupleIterator(RelationType relationtype,
						   boolean bool) {
	return new SingleTupleIterator(relationtype, bool);
    }
    
    public abstract Object next();
    
    public abstract boolean hasNext();
    
    public void remove() throws UnsupportedOperationException {
	throw new UnsupportedOperationException("DeclIter.remove()");
    }
}
