/*
* Copyright (C) 2000 - 2010 TagServlet Ltd
*
* This file is part of Open BlueDragon (OpenBD) CFML Server Engine.
*
* OpenBD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Free Software Foundation,version 3.
*
* OpenBD 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenBD. If not, see http://www.gnu.org/licenses/
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with any of the JARS listed in the README.txt (or a modified version of
* (that library), containing parts covered by the terms of that JAR, the
* licensors of this Program grant you additional permission to convey the
* resulting work.
* README.txt @ http://www.openbluedragon.org/license/README.txt
*
* http://www.openbluedragon.org/
*/
package com.naryx.tagfusion.cfm.parser.script;
/**
* This class represents a switch statement.
*/
import java.util.List;
import org.antlr.runtime.Token;
import com.naryx.tagfusion.cfm.engine.cfBooleanData;
import com.naryx.tagfusion.cfm.engine.cfData;
import com.naryx.tagfusion.cfm.engine.cfNumberData;
import com.naryx.tagfusion.cfm.engine.cfmRunTimeException;
import com.naryx.tagfusion.cfm.engine.dataNotSupportedException;
import com.naryx.tagfusion.cfm.parser.CFContext;
import com.naryx.tagfusion.cfm.parser.CFExpression;
import com.naryx.tagfusion.cfm.parser.cfLData;
import com.naryx.tagfusion.cfm.tag.cfTag;
public class CFSwitchStatement extends CFParsedStatement implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private List<CFCase> cases;
private CFExpression variable;
public CFSwitchStatement( Token _token, CFExpression _variable,
List<CFCase> _cases ) {
super(_token);
cases = _cases;
variable = _variable;
}
public void checkIndirectAssignments( String[] scriptSource ) {
for (int i = 0; i < cases.size(); i++) {
cases.get(i).checkIndirectAssignments(scriptSource);
}
}
public void setHostTag( cfTag _parentTag ){
super.setHostTag( _parentTag );
for ( int i = 0; i < cases.size(); i++ ){
cases.get( i ).setHostTag( _parentTag );
}
}
public CFStatementResult Exec( CFContext context ) throws cfmRunTimeException {
setLineCol(context);
// this method probably could be more efficient
cfData value = variable.Eval(context);
if ( value.getDataType() == cfData.CFLDATA )
value = ((cfLData) value).Get(context);
boolean isBooleanCase = false;
boolean isNumberCase = false;
if ( value.getDataType() == cfData.CFBOOLEANDATA ) {
isBooleanCase = true;
} else if ( value.getDataType() == cfData.CFNUMBERDATA ) {
isNumberCase = true;
}
boolean execute = false; // set to true when the first case is matched
// it means that the following cases will be executed while there is no
// "break;"
CFStatementResult result = null;
int defaultIndex = -1; // hold the index of the defaultIndex
CFCase nextCase;
for (int i = 0; i < cases.size(); i++) {
nextCase = cases.get(i);
if ( !execute ) {
if ( nextCase.isDefault() )
defaultIndex = i;
else {
if ( isBooleanCase ) {
boolean boolVal = false;
try {
boolVal = nextCase.getConstant(context).getBoolean();
} catch (dataNotSupportedException ignored) { /* go with default */
}
if ( ((cfBooleanData) value).getBoolean() == boolVal )
execute = true;
} else if ( isNumberCase ) {
double doubleVal;
try {
doubleVal = nextCase.getConstant(context).getDouble();
if ( ((cfNumberData) value).getDouble() == doubleVal )
execute = true;
} catch (dataNotSupportedException ignored) {
}
} else {
String strVal = "";
try {
strVal = nextCase.getConstant(context).getString();
if ( value.getString().equalsIgnoreCase(strVal) )
execute = true;
} catch (dataNotSupportedException ignored) {
}
}
}
}
if ( execute ) {
result = nextCase.Exec(context);
if ( result != null ) {
return (result.isReturn() ? result : null);
}
}
}
// if a value wasn't found then execute from the default case if one
// exists.
if ( !execute && defaultIndex != -1 ) {
for (int i = defaultIndex; i < cases.size(); i++) {
nextCase = cases.get(i);
result = nextCase.Exec(context);
if ( result != null ) {
return (result.isReturn() ? result : null);
}
}
}
return result;
}
public String Decompile( int _indent ) {
StringBuilder sb = new StringBuilder();
sb.append( "switch (" );
sb.append( variable.Decompile( 0 ) );
sb.append( "){\n" );
for ( int i = 0; i < cases.size(); i++ ){
sb.append( ((CFCase) cases.get(i) ).Decompile( 0 ) );
}
sb.append( "\n}" );
return sb.toString();
}
}