/*
*
* Copyright (c) 2007
* Adrian Michel
* http://www.tradery.com
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Adrian Michel makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/
package com.tradery.contentmodel;
import com.tradery.contract.Contract;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Dictionary;
import java.util.Hashtable;
class StateMachineAll implements AbstractStateMachine
{
private Dictionary _d = null;
private int _index;
private class XX
{
private String _symbol = null;
private boolean _optional;
private int _index;
XX( String symbol, boolean optional, int index )
{
if( Contract.REQUIRE )
{
Contract.require( symbol != null );
}
_symbol = symbol;
_optional = optional;
_index = index;
}
String getSymbol()
{
return _symbol;
}
boolean isOptional()
{
return _optional;
}
int getIndex()
{
return _index;
}
}
static class State implements AbstractState
{
private Vector _v = null;
private int _size;
private StateMachineAll _sm = null;
private class YY
{
private boolean _wasEntered;
private boolean _optional;
private XX _xx = null;
YY( boolean optional, XX xx )
{
_wasEntered = false;
_optional = optional;
_xx = xx;
}
boolean wasEntered()
{
return _wasEntered;
}
boolean isOptional()
{
return _optional;
}
void setEntered()
{
_wasEntered = true;
}
String getSymbol()
{
return _xx.getSymbol();
}
}
State( StateMachineAll sm, int size, Enumeration e )
{
if( Contract.REQUIRE )
{
Contract.require( sm != null, "The StateMachineAll associated with a state object cannot be null" );
Contract.require( size >= 0, "The number of symbols in a state machine cannot be negative" );
Contract.require( e != null, "Enumeration of XX elements cannot be null in StateMachineAll.State" );
}
_size = size;
_v = new Vector( size );
_v.setSize( size );
int k = _v.size();
// init the vector
while( e.hasMoreElements() )
{
XX xx = (XX)e.nextElement();
_v.setElementAt( new YY( xx.isOptional(), xx ), xx.getIndex() );
}
_sm = sm;
}
public Enumeration getValidTransitions()
{
return new ValidTransitionsEnumeration( _v );
}
private class ValidTransitionsEnumeration implements Enumeration
{
int n;
Vector _v = null;
ValidTransitionsEnumeration( Vector v )
{
if( Contract.REQUIRE )
Contract.require( v != null, "vector cannot be null in ValidTransitionsEnumeration constructor" );
n = 0;
_v = v;
nextIndex();
}
private void nextIndex()
{
for(; n < _v.size(); n++ )
{
YY yy = (YY)_v.elementAt( n );
if( !yy.wasEntered() )
break;
}
}
public boolean hasMoreElements()
{
return n < _v.size();
}
public Object nextElement()
{
Object o = null;
if( hasMoreElements() )
{
YY yy = (YY)_v.elementAt( n++ );
o = yy.getSymbol();
}
nextIndex();
return o;
}
}
public boolean doTransition( String symbol )
{
if( Contract.REQUIRE )
{
Contract.require( symbol != null, "The symbol cannot be null in StateMachineAll.State.doTransition()" );
}
int n = _sm.getIndex( symbol );
if( Contract.CHECK )
{
Contract.check( n < _v.size() );
}
if( n < 0 )
// the symbol is not in the language described by the state machine
return false;
else
{
YY yy = (YY)_v.elementAt( n );
if( yy.wasEntered() )
{
// cannot add the same symbol twice - only supports optional
return false;
}
else
{
// mark the symbol as true (existent)
yy.setEntered();
return true;
}
}
}
public boolean isValidTransition( String symbol )
{
if( Contract.REQUIRE )
Contract.require( symbol != null, "The symbol cannot be null in StateMachineAll.State.doTransition()" );
int n = _sm.getIndex( symbol );
if( Contract.CHECK )
Contract.check( n < _v.size() );
if( n < 0 )
// the symbol is not in the language described by the state machine
return false;
else
{
return !( (YY)_v.elementAt( n ) ).wasEntered();
}
}
public boolean canTerminate()
{
for( int n = 0; n < _v.size(); n++ )
{
YY yy = (YY)_v.elementAt( n );
if( !yy.wasEntered() && !yy.isOptional() )
return false;
}
return true;
}
}
StateMachineAll()
{
_d = new Hashtable();
_index = 0;
}
boolean addTransition( String symbol, boolean optional )
{
if( Contract.REQUIRE )
Contract.require( symbol != null, "Cannot add a null symbol to the StateMachineAll" );
// return false if the symbol already there
return _d.put( symbol, new XX( symbol, optional, _index++ ) ) == null;
}
// returns a new state object set to the start state
public AbstractState getInitialState()
{
return new State( this, _d.size(), _d.elements() );
}
public void dump()
{
/** @todo implement the state machine all dump */
}
public void setFinalStates( Object o )
{
}
int getIndex( String symbol )
{
XX xx = (XX)_d.get( symbol );
if( xx == null )
// symobl not in language
return -1;
else
return xx.getIndex();
}
}