/*
* CDOMChoiceManager.java
* Missing License Header, Copyright 2016 (C) Andrew Maitland <amaitland@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 pcgen.core.chooser;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import pcgen.base.formula.Formula;
import pcgen.cdom.base.ChooseDriver;
import pcgen.cdom.base.ChooseInformation;
import pcgen.core.Globals;
import pcgen.core.PlayerCharacter;
import pcgen.facade.core.ChooserFacade.ChooserTreeViewType;
import pcgen.gui2.facade.Gui2InfoFactory;
import pcgen.system.LanguageBundle;
import pcgen.util.Logging;
import pcgen.util.chooser.ChooserFactory;
public class CDOMChoiceManager<T> implements ChoiceManagerList<T>
{
private final ChooseDriver owner;
private final Integer numberOfChoices;
protected final int choicesPerUnitCost;
protected ChooseController<T> controller = new ChooseController<>();
protected final ChooseInformation<T> info;
private transient int preChooserChoices;
public CDOMChoiceManager(ChooseDriver cdo,
ChooseInformation<T> chooseType, Integer numChoices,
int cost)
{
numberOfChoices = numChoices;
owner = cdo;
info = chooseType;
choicesPerUnitCost = cost;
}
@Override
public void getChoices(PlayerCharacter pc, List<T> availableList,
List<T> selectedList)
{
availableList.addAll(info.getSet(pc));
List<? extends T> selected = info.getChoiceActor()
.getCurrentlySelected(owner, pc);
if (selected != null)
{
selectedList.addAll(selected);
}
preChooserChoices = selectedList.size();
}
@Override
public String typeHandled()
{
throw new UnsupportedOperationException();
}
/**
* Conditionally add the selected item
*
* @param pc
* @param item
*/
@Override
public boolean conditionallyApply(PlayerCharacter pc, T item)
{
List<? extends T> oldSelections = info.getChoiceActor().getCurrentlySelected(
owner, pc);
boolean applied = false;
if (oldSelections == null || !oldSelections.contains(item))
{
if (info.getSet(pc).contains(item))
{
info.getChoiceActor().applyChoice(owner, item, pc);
applied = true;
}
}
adjustPool(info.getChoiceActor().getCurrentlySelected(owner, pc));
return applied;
}
/**
* Add the selected Feat proficiencies
*
* @param pc
* @param selected
*/
@Override
public boolean applyChoices(PlayerCharacter pc, List<T> selected)
{
List<? extends T> oldSelections = info.getChoiceActor().getCurrentlySelected(
owner, pc);
List<T> toAdd = new ArrayList<>();
for (T obj : selected)
{
if (oldSelections == null || !oldSelections.remove(obj))
{
toAdd.add(obj);
}
}
int oldSize = 0;
if (oldSelections != null)
{
oldSize = oldSelections.size();
for (T obj : oldSelections)
{
info.getChoiceActor().removeChoice(pc, owner, obj);
}
}
for (T obj : toAdd)
{
info.getChoiceActor().applyChoice(owner, obj, pc);
}
adjustPool(selected);
return oldSize != selected.size();
}
/**
* Display a chooser to the user.
*
* @param aPc The character the choice is for.
* @param availableList The list of possible choices.
* @param selectedList The list of existing selections.
* @return list The list of the new selections made by the user (unchanged if the dialog was cancelled)
*/
@Override
public List<T> doChooser(PlayerCharacter aPc, final List<T> availableList,
final List<T> selectedList, final List<String> reservedList)
{
int effectiveChoices = getNumEffectiveChoices(selectedList, reservedList, aPc);
boolean dupsAllowed = controller.isMultYes() && controller.isStackYes();
/*
* TODO This is temporarily commented out until the correct behavior of
* the "available" list is established. This is done to make
* CDOMChoiceManager not remove items when selected, which is consistent
* with the (buggy?) old Choose system
*/
if (!dupsAllowed)
{
// availableList.removeAll(reservedList);
availableList.removeAll(selectedList);
}
Globals.sortChooserLists(availableList, selectedList);
String title = StringUtils.isBlank(info.getTitle()) ? "in_chooser" //$NON-NLS-1$
: info.getTitle();
if (title.startsWith("in_")) //$NON-NLS-1$
{
title = LanguageBundle.getString(title);
}
CDOMChooserFacadeImpl<T> chooserFacade =
new CDOMChooserFacadeImpl<>(title, availableList,
selectedList, effectiveChoices);
chooserFacade.setDefaultView(ChooserTreeViewType.NAME);
chooserFacade.setAllowsDups(dupsAllowed);
chooserFacade.setInfoFactory(new Gui2InfoFactory(aPc));
ChooserFactory.getDelegate().showGeneralChooser(chooserFacade);
return chooserFacade.getFinalSelected();
}
/**
* Calculate the number of effective choices the user can make.
*
* @param selectedList The list of already selected items.
* @param reservedList The list of options which cannot be offered.
* @param aPc The character the choice applies to.
* @return The number of choices that may be made
*/
@Override
public int getNumEffectiveChoices(final List<? extends T> selectedList,
final List<String> reservedList, PlayerCharacter aPc)
{
int selectedPoolValue = (selectedList.size() + (choicesPerUnitCost - 1))
/ choicesPerUnitCost;
int reservedPoolValue = (reservedList.size() + (choicesPerUnitCost - 1))
/ choicesPerUnitCost;
int effectiveTotalChoices;
if (numberOfChoices == null)
{
effectiveTotalChoices = controller.getTotalChoices();
}
else
{
effectiveTotalChoices = (numberOfChoices - reservedPoolValue + selectedPoolValue);
}
int effectiveChoices = Math
.min(controller.getPool() + selectedPoolValue,
effectiveTotalChoices / choicesPerUnitCost);
effectiveChoices *= choicesPerUnitCost;
Formula formula = owner.getNumChoices();
if (formula != null)
{
int numChoices = formula.resolve(aPc, owner.getFormulaSource()).intValue();
if (numChoices > 0)
{
effectiveChoices = Math.min(effectiveChoices, numChoices);
}
}
effectiveChoices -= selectedList.size();
return effectiveChoices;
}
/**
*
* @param pc
* @param availableList
* @param selectedList
*/
@Override
public List<T> doChooserRemove(PlayerCharacter pc, List<T> availableList,
List<T> selectedList, List<String> reservedList)
{
return doChooser(pc, availableList, selectedList, reservedList);
}
protected void adjustPool(List<? extends T> selected)
{
controller.adjustPool(selected);
}
@Override
public void setController(ChooseController<T> cc)
{
controller = cc;
}
@Override
public int getChoicesPerUnitCost()
{
return choicesPerUnitCost;
}
@Override
public int getPreChooserChoices()
{
return preChooserChoices;
}
@Override
public void restoreChoice(PlayerCharacter pc, ChooseDriver target, String choice)
{
if (!choice.isEmpty())
{
T ch = info.decodeChoice(Globals.getContext(), choice);
if (ch == null)
{
Logging.errorPrint("Error finding "
+ info.getClassIdentity().getName() + " " + choice
+ ": Not Found");
}
else
{
info.restoreChoice(pc, target, ch);
}
}
}
protected String getTitle()
{
return new StringBuilder(50).append(info.getTitle()).append(" (")
.append(owner.getDisplayName()).append(')').toString();
}
@Override
public void removeChoice(PlayerCharacter pc, ChooseDriver obj, T selection)
{
info.removeChoice(pc, obj, selection);
}
@Override
public T decodeChoice(String choice)
{
return info.decodeChoice(Globals.getContext(), choice);
}
@Override
public void applyChoice(PlayerCharacter pc, ChooseDriver cdo, T selection)
{
info.getChoiceActor().applyChoice(cdo, selection, pc);
}
public String encodeChoice(T obj)
{
return info.encodeChoice(obj);
}
}