/*
* Copyright 2014 (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.modifier.set;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import pcgen.base.calculation.PCGenModifier;
import pcgen.base.formula.base.DependencyManager;
import pcgen.base.formula.base.EvaluationManager;
import pcgen.base.formula.base.FormulaManager;
import pcgen.base.formula.base.LegalScope;
import pcgen.base.formula.base.ManagerFactory;
import pcgen.base.solver.Modifier;
import pcgen.base.util.FormatManager;
import pcgen.base.util.Indirect;
import pcgen.rules.persistence.token.ModifierFactory;
/**
* An AddModifierFactory is a ModifierFactory that adds a specific set of items
* to the input set when a Modifier produced by this AddModifierFactory is
* processed.
*
* @param <T>
* The Class of object contained in the arrays processed by this
* AddModifierFactory
*/
public class AddModifierFactory<T> implements ModifierFactory<T[]>
{
@SuppressWarnings("rawtypes")
private static final Class ARRAY_CLASS = new Object[0].getClass();
/**
* Identifies that this AddModifier acts upon java.util.Set objects.
*
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public Class<T[]> getVariableFormat()
{
return ARRAY_CLASS;
}
/**
* Returns an Identifier for this type of Modifier
*
* {@inheritDoc}
*/
@Override
public String getIdentification()
{
return "ADD";
}
/**
* @see pcgen.rules.persistence.token.ModifierFactory#getModifier(int,
* java.lang.String, pcgen.base.formula.manager.FormulaManager,
* pcgen.base.formula.base.LegalScope, pcgen.base.format.FormatManager)
*/
@Override
public PCGenModifier<T[]> getModifier(int userPriority, String instructions,
ManagerFactory managerFactory, FormulaManager ignored, LegalScope varScope,
FormatManager<T[]> formatManager)
{
Indirect<T[]> indirect = formatManager.convertIndirect(instructions);
return new AddIndirectArrayModifier(formatManager, userPriority,
indirect);
}
@Override
public Modifier<T[]> getFixedModifier(int userPriority,
FormatManager<T[]> fmtManager, String instructions)
{
T[] toAdd = fmtManager.convert(instructions);
return new AddDirectArrayModifier(fmtManager, userPriority, toAdd);
}
/**
* An AddDirectArrayModifier is a PCGenModifier that contains a set of objects to be
* used by the Modifier when executed.
*/
private final class AddDirectArrayModifier extends AddArrayModifier
{
/**
* The objects to be added to the active set when this AddModifier is
* processed
*/
private T[] toAdd;
private AddDirectArrayModifier(FormatManager<T[]> formatManager,
int userPriority, T[] toAdd)
{
super(formatManager, userPriority);
this.toAdd = toAdd;
}
@Override
public String getInstructions()
{
return getFormatManager().unconvert(toAdd);
}
@Override
protected T[] getArray()
{
return toAdd;
}
}
/**
* An AddIndirectArrayModifier is a PCGenModifier that contains a set of Indirect
* objects to be resolved and used by the Modifier when executed.
*/
private final class AddIndirectArrayModifier extends AddArrayModifier
{
/**
* The objects to be added to the active set when this AddModifier is
* processed
*/
private Indirect<T[]> toAdd;
private AddIndirectArrayModifier(FormatManager<T[]> formatManager,
int userPriority, Indirect<T[]> toAdd)
{
super(formatManager, userPriority);
this.toAdd = toAdd;
}
@Override
public String getInstructions()
{
return toAdd.getUnconverted();
}
@Override
protected T[] getArray()
{
return toAdd.get();
}
}
/**
* The Modifier that implements ADD for Set objects
*/
private abstract class AddArrayModifier implements PCGenModifier<T[]>
{
/**
* The user priority of this AddModifier
*/
private final int userPriority;
private final FormatManager<T[]> fmtManager;
protected AddArrayModifier(FormatManager<T[]> formatManager,
int userPriority)
{
this.fmtManager = formatManager;
this.userPriority = userPriority;
}
@Override
public int getUserPriority()
{
return userPriority;
}
@Override
public long getPriority()
{
return ((long) userPriority << 32) + 3;
}
@Override
public T[] process(EvaluationManager evalManager)
{
@SuppressWarnings("unchecked")
T[] input = (T[]) evalManager.get(EvaluationManager.INPUT);
Set<T> newSet = new HashSet<>();
Collections.addAll(newSet, input);
Collections.addAll(newSet, getArray());
Class<?> component =
fmtManager.getManagedClass().getComponentType();
@SuppressWarnings("unchecked")
T[] newArray = (T[]) Array.newInstance(component, newSet.size());
return newSet.toArray(newArray);
}
/**
* Returns the array to be added during process().
*
* @return The array to be added during process()
*/
protected abstract T[] getArray();
@Override
public Class<T[]> getVariableFormat()
{
return fmtManager.getManagedClass();
}
@Override
@SuppressWarnings("PMD.EmptyMethodInAbstractClassShouldBeAbstract")
public void getDependencies(DependencyManager fdm)
{
}
@Override
public String getIdentification()
{
return AddModifierFactory.this.getIdentification();
}
/**
* Returns the FormatManager for this AddArrayModifier.
*
* @return The FormatManager for this AddArrayModifier
*/
public FormatManager<T[]> getFormatManager()
{
return fmtManager;
}
}
}