package eu.geclipse.jsdl.parametric.internal;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.xml.xpath.XPathExpressionException;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import eu.geclipse.jsdl.parametric.ParametricJsdlException;
import eu.geclipse.jsdl.xpath.XPathDocument;
/**
* Function, which can assign next integer values to parameter over the loop.
* This function accept also exceptions.
*/
class FunctionIntegerLoop implements IFunction {
int start;
int end;
int step;
Set<Integer> exceptions;
FunctionIntegerLoop( final NodeList nodes, final XPathDocument xpath ) throws ParametricJsdlException {
if( nodes.getLength() == 1 ) {
Node item = nodes.item( 0 );
this.start = getIntAttribute( item, "sweepfunc:start", true, 0 ); //$NON-NLS-1$
this.end = getIntAttribute( item, "sweepfunc:end", true, 0 ); //$NON-NLS-1$
this.step = getIntAttribute( item, "sweepfunc:step", false, 1 ); //$NON-NLS-1$
if( this.step == 0 ) {
throw new ParametricJsdlException( "<sweepfunc:Loop> cannot has step equal to 0." ); //$NON-NLS-1$
}
this.exceptions = readExceptions( item, xpath );
} else {
throw new ParametricJsdlException( "<sweep:Assignment> can contain only one <sweepfunc:Loop>, whilst contain %d loops." ); //$NON-NLS-1$
}
}
private int getIntAttribute( final Node item, final String attrName, final boolean mandatory, final int defaultValue ) throws ParametricJsdlException {
int value = defaultValue;
String textContent = null;
try {
NamedNodeMap attributes = item.getAttributes();
Node attr = attributes.getNamedItem( attrName );
if( attr != null ) {
textContent = attr.getTextContent();
value = Integer.parseInt( textContent );
} else if( mandatory ) {
String msg = String.format( "Attribute <%s> is missing", attrName ); //$NON-NLS-1$
throw new ParametricJsdlException( msg );
}
} catch( NumberFormatException exception ) {
String msg = String.format( "<%s> should contain integer number, whilst it contain value '%s'", attrName, textContent == null ? "" : textContent ); //$NON-NLS-1$ //$NON-NLS-2$
throw new ParametricJsdlException( msg, exception );
}
return value;
}
private Set<Integer> readExceptions( final Node loopNode,
final XPathDocument xpath )
throws ParametricJsdlException
{
try {
Set<Integer> exceptionsSet = new HashSet<Integer>();
if( loopNode instanceof Element ) {
Element loopElement = ( Element )loopNode;
NodeList nodeList;
nodeList = xpath.getNodes( loopElement, "./sweepfunc:Exception" ); //$NON-NLS-1$
for( int index = 0; index < nodeList.getLength(); index++ ) {
Node exceptionNode = nodeList.item( index );
exceptionsSet.add( Integer.valueOf( getIntAttribute( exceptionNode,
"sweepfunc:value", false, 0 ) ) ); //$NON-NLS-1$
}
}
return exceptionsSet;
} catch( XPathExpressionException exception ) {
throw new ParametricJsdlException( "Error occured during calling XPath query", exception ); //$NON-NLS-1$
}
}
public Iterator<String> iterator() {
return new LoopIterator();
}
class LoopIterator implements Iterator<String> {
private int currentValue = FunctionIntegerLoop.this.start - FunctionIntegerLoop.this.step;
public boolean hasNext() {
int value = this.currentValue + FunctionIntegerLoop.this.step;
while( FunctionIntegerLoop.this.exceptions.contains( Integer.valueOf( value ) ) && value < FunctionIntegerLoop.this.end ) {
value += FunctionIntegerLoop.this.step;
}
return value <= FunctionIntegerLoop.this.end;
}
public String next() {
do{
this.currentValue += FunctionIntegerLoop.this.step;
} while( FunctionIntegerLoop.this.exceptions.contains( Integer.valueOf( this.currentValue ) ) && this.currentValue < FunctionIntegerLoop.this.end );
return Integer.toString( this.currentValue );
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}