/*
* Copyright 2016 (C) Tom Parker <thpr@users.sourceforge.net>
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package plugin.function;
import java.util.Arrays;
import pcgen.base.formula.base.DependencyManager;
import pcgen.base.formula.base.EvaluationManager;
import pcgen.base.formula.base.FormulaManager;
import pcgen.base.formula.base.FormulaSemantics;
import pcgen.base.formula.base.Function;
import pcgen.base.formula.parse.Node;
import pcgen.base.formula.visitor.DependencyVisitor;
import pcgen.base.formula.visitor.EvaluateVisitor;
import pcgen.base.formula.visitor.SemanticsVisitor;
import pcgen.base.formula.visitor.StaticVisitor;
import pcgen.base.util.FormatManager;
import pcgen.cdom.format.table.ColumnFormatManager;
import pcgen.cdom.format.table.DataTable;
import pcgen.cdom.format.table.TableColumn;
import pcgen.cdom.format.table.TableFormatManager;
/**
* This is a Lookup function for finding items in a DataTable.
*
* This function requires 3 arguments: (1) The Table Name (2) The Value to be
* looked up in the first column (3) The Column name of the result to be
* returned
*/
public class LookupFunction implements Function
{
/**
* A constant referring to the TableColumn Class.
*/
@SuppressWarnings("rawtypes")
private static final Class<TableColumn> COLUMN_CLASS = TableColumn.class;
/**
* A constant referring to the Table Class.
*/
private static final Class<DataTable> DATATABLE_CLASS = DataTable.class;
/**
* {@inheritDoc}
*/
@Override
public String getFunctionName()
{
return "Lookup";
}
/**
* {@inheritDoc}
*/
@Override
public Boolean isStatic(StaticVisitor visitor, Node[] args)
{
return false;
}
/**
* {@inheritDoc}
*/
@Override
public FormatManager<?> allowArgs(SemanticsVisitor visitor, Node[] args,
FormulaSemantics semantics)
{
int argCount = args.length;
if (argCount != 3)
{
semantics.setInvalid("Function " + getFunctionName()
+ " received incorrect # of arguments, expected: 3 got "
+ args.length + " " + Arrays.asList(args));
return null;
}
//Table name node (must be a DataTable)
@SuppressWarnings("PMD.PrematureDeclaration")
Object tableFormat = args[0].jjtAccept(visitor,
semantics.getWith(FormulaSemantics.ASSERTED, DATATABLE_CLASS));
if (!semantics.isValid())
{
return null;
}
if (!(tableFormat instanceof TableFormatManager))
{
semantics.setInvalid(
"Parse Error: Invalid Object: " + tableFormat.getClass()
+ " found in location requiring a " + "TableFormatManager");
return null;
}
@SuppressWarnings("unchecked")
TableFormatManager tableFormatManager =
(TableFormatManager) tableFormat;
//Lookup value (at this point we don't know the format - only at runtime)
FormatManager<?> lookupFormat = tableFormatManager.getLookupFormat();
args[1].jjtAccept(visitor,
semantics.getWith(FormulaSemantics.ASSERTED, lookupFormat.getManagedClass()));
if (!semantics.isValid())
{
return null;
}
//Result Column Name (must be a String)
@SuppressWarnings("PMD.PrematureDeclaration")
Object resultColumn = args[2].jjtAccept(visitor,
semantics.getWith(FormulaSemantics.ASSERTED, COLUMN_CLASS));
if (!semantics.isValid())
{
return null;
}
if (!(resultColumn instanceof ColumnFormatManager))
{
semantics.setInvalid("Parse Error: Invalid Result Column Name: "
+ resultColumn.getClass()
+ " found in location requiring a Column");
return null;
}
ColumnFormatManager<?> cf = (ColumnFormatManager<?>) resultColumn;
FormatManager<?> rf = tableFormatManager.getResultFormat();
if (!rf.equals(cf.getComponentManager()))
{
semantics.setInvalid("Parse Error: Invalid Result Column Type: "
+ resultColumn.getClass()
+ " found in table that does not contain that type");
return null;
}
return rf;
}
/**
* {@inheritDoc}
*/
@Override
public Object evaluate(EvaluateVisitor visitor, Node[] args,
EvaluationManager manager)
{
//Table name node (must be a Table)
DataTable dataTable = (DataTable) args[0].jjtAccept(visitor,
manager.getWith(EvaluationManager.ASSERTED, DATATABLE_CLASS));
FormatManager<?> lookupFormat = dataTable.getFormat(0);
//Lookup value (format based on the table)
@SuppressWarnings("PMD.PrematureDeclaration")
Object lookupValue = args[1].jjtAccept(visitor,
manager.getWith(EvaluationManager.ASSERTED, lookupFormat.getManagedClass()));
//Result Column Name (must be a tableColumn)
TableColumn column = (TableColumn) args[2].jjtAccept(visitor,
manager.getWith(EvaluationManager.ASSERTED, COLUMN_CLASS));
String columnName = column.getName();
if (!dataTable.isColumn(columnName))
{
FormatManager<?> fmt = column.getFormatManager();
System.out.println("Lookup called on invalid column: '" + columnName
+ "' is not present on table '" + dataTable.getName()
+ "' assuming default for " + fmt.getIdentifierType());
FormulaManager fm = manager.get(EvaluationManager.FMANAGER);
return fm.getDefault(fmt.getManagedClass());
}
if (!dataTable.hasRow(lookupValue))
{
FormatManager<?> fmt = column.getFormatManager();
System.out.println("Lookup called on invalid item: '" + lookupValue
+ "' is not present in the first row of table '"
+ dataTable.getName() + "' assuming default for "
+ fmt.getIdentifierType());
FormulaManager fm = manager.get(EvaluationManager.FMANAGER);
return fm.getDefault(fmt.getManagedClass());
}
return dataTable.lookupExact(lookupValue, columnName);
}
/**
* {@inheritDoc}
*/
@Override
public void getDependencies(DependencyVisitor visitor,
DependencyManager manager, Node[] args)
{
args[0].jjtAccept(visitor,
manager.getWith(DependencyManager.ASSERTED, DATATABLE_CLASS));
//TODO a Semantics Check can tell what this is
args[1].jjtAccept(visitor, manager.getWith(DependencyManager.ASSERTED, null));
args[2].jjtAccept(visitor,
manager.getWith(DependencyManager.ASSERTED, COLUMN_CLASS));
}
}