/*
* EquipmentBuilderFacadeImpl.java
* Copyright 2013 (C) James Dempsey <jdempsey@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
*
* Created on 18/09/2013
*
* $Id$
*/
package pcgen.gui2.facade;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import pcgen.cdom.base.Constants;
import pcgen.cdom.enumeration.IntegerKey;
import pcgen.cdom.enumeration.ListKey;
import pcgen.cdom.enumeration.ObjectKey;
import pcgen.cdom.enumeration.StringKey;
import pcgen.core.Equipment;
import pcgen.core.EquipmentModifier;
import pcgen.core.Globals;
import pcgen.core.PObject;
import pcgen.core.PlayerCharacter;
import pcgen.core.SizeAdjustment;
import pcgen.core.SpecialProperty;
import pcgen.core.analysis.EqModSpellInfo;
import pcgen.facade.core.AbilityFacade;
import pcgen.facade.util.DefaultReferenceFacade;
import pcgen.facade.core.EquipModFacade;
import pcgen.facade.core.EquipmentBuilderFacade;
import pcgen.facade.core.EquipmentFacade;
import pcgen.facade.core.InfoFacade;
import pcgen.facade.util.ReferenceFacade;
import pcgen.facade.core.SizeAdjustmentFacade;
import pcgen.facade.core.UIDelegate;
import pcgen.facade.util.DefaultListFacade;
import pcgen.facade.util.ListFacade;
import pcgen.core.spell.Spell;
import pcgen.system.LanguageBundle;
import pcgen.util.enumeration.View;
/**
* EquipmentBuilderFacadeImpl is an implementation of the
* {@link EquipmentBuilderFacade} interface for the new user interface. It is
* intended to allow the ui to control the creation of a custom item of
* equipment without direct interaction with the core.
*
*
* @author James Dempsey <jdempsey@users.sourceforge.net>
*/
public class EquipmentBuilderFacadeImpl implements EquipmentBuilderFacade
{
private final UIDelegate delegate;
private final Equipment equip;
private final Map<EquipmentHead, DefaultListFacade<EquipModFacade>> availListMap;
private final Map<EquipmentHead, DefaultListFacade<EquipModFacade>> selectedListMap;
private final PlayerCharacter character;
private final Equipment baseEquipment;
private final EnumSet<EquipmentHead> equipHeads;
private DefaultReferenceFacade<SizeAdjustmentFacade> sizeRef;
/**
* Create a new EquipmentBuilderFacadeImpl instance for the customization of
* a particular item of equipment for the character.
* @param equip The equipment item being customized (must not be the base item).
* @param character The character the equipment will be for.
* @param delegate The handler for UI functions such as dialogs.
*/
EquipmentBuilderFacadeImpl(Equipment equip, PlayerCharacter character, UIDelegate delegate)
{
this.equip = equip;
this.character = character;
this.delegate = delegate;
sizeRef =
new DefaultReferenceFacade<>(
equip.getSizeAdjustment());
final String sBaseKey = equip.getBaseItemKeyName();
baseEquipment = Globals.getContext().getReferenceContext().silentlyGetConstructedCDOMObject(
Equipment.class, sBaseKey);
equipHeads =
equip.isDouble() ? EnumSet.range(EquipmentHead.PRIMARY,
EquipmentHead.SECONDARY) : EnumSet
.of(EquipmentHead.PRIMARY);
availListMap =
new HashMap<>();
selectedListMap =
new HashMap<>();
for (EquipmentHead head : equipHeads)
{
availListMap.put(head, new DefaultListFacade<>());
DefaultListFacade<EquipModFacade> selectedList =
new DefaultListFacade<>();
selectedList.setContents(equip.getEqModifierList(head.isPrimary()));
selectedListMap.put(head, selectedList);
}
refreshAvailList();
}
@Override
public boolean addModToEquipment(EquipModFacade modifier, EquipmentHead head)
{
if (modifier == null || !(modifier instanceof EquipmentModifier)
|| head == null)
{
return false;
}
EquipmentModifier equipMod = (EquipmentModifier) modifier;
// Trash the cost modifications
equip.setCostMod("0");
// Handle spells
if (equipMod.getSafe(StringKey.CHOICE_STRING).startsWith("EQBUILDER.SPELL"))
{
if (!getSpellChoiceForEqMod(equipMod))
{
return false;
}
}
equip.addEqModifier(equipMod, head.isPrimary(), character);
if (equip.isDouble() && equipMod.getSafe(ObjectKey.ASSIGN_TO_ALL))
{
equip.addEqModifier(equipMod, !head.isPrimary(), character);
}
equip.nameItemFromModifiers(character);
refreshAvailList();
refreshSelectedList();
return true;
}
@Override
public boolean removeModFromEquipment(EquipModFacade modifier, EquipmentHead head)
{
if (modifier == null || !(modifier instanceof EquipmentModifier))
{
return false;
}
EquipmentModifier equipMod = (EquipmentModifier) modifier;
if (baseEquipment.getEqModifierList(true).contains(equipMod))
{
delegate.showErrorMessage(Constants.APPLICATION_NAME,
LanguageBundle.getFormattedString("in_eqCust_RemoveBaseErr", equipMod));
return false;
}
// Trash the cost modifications
equip.setCostMod("0");
equip.removeEqModifier(equipMod, head.isPrimary(), character);
equip.nameItemFromModifiers(character);
refreshAvailList();
refreshSelectedList();
return true;
}
@Override
public boolean setName(String name)
{
if (StringUtils.isEmpty(name))
{
return false;
}
String aString = name.trim();
if ((aString.indexOf('|') >= 0) || (aString.indexOf(':') >= 0)
|| (aString.indexOf(';') >= 0) || (aString.indexOf(',') >= 0))
{
delegate.showErrorMessage(Constants.APPLICATION_NAME,
LanguageBundle.getString("in_eqCust_InvalidNameChar"));
return false;
}
String oldName = "(" + equip.getItemNameFromModifiers() + ")";
// Replace illegal characters in old name
oldName = oldName.replaceAll(";:\\|,", "@");
if (!oldName.toString().toUpperCase()
.startsWith(Constants.GENERIC_ITEM))
{
equip.addToListFor(ListKey.SPECIAL_PROPERTIES,
SpecialProperty.createFromLst(oldName.toString()));
}
equip.setName(aString);
return true;
}
@Override
public boolean setSProp(String sprop)
{
String aString = StringUtils.trimToEmpty(sprop);
if ((aString.indexOf('|') >= 0) || (aString.indexOf(':') >= 0)
|| (aString.indexOf(';') >= 0))
{
delegate.showErrorMessage(Constants.APPLICATION_NAME,
LanguageBundle.getString("in_eqCust_InvalidSpropChar"));
return false;
}
equip.removeListFor(ListKey.SPECIAL_PROPERTIES);
if (!aString.equals(""))
{
equip.addToListFor(ListKey.SPECIAL_PROPERTIES,
SpecialProperty.createFromLst(aString));
}
return true;
}
@Override
public boolean setCost(String newValue)
{
if (StringUtils.isEmpty(newValue))
{
return false;
}
String aString = newValue.trim();
try
{
BigDecimal newCost = new BigDecimal(aString);
if (newCost.doubleValue() < 0)
{
delegate.showErrorMessage(Constants.APPLICATION_NAME,
LanguageBundle.getString("in_eqCust_CostNegativeErr"));
return false;
}
equip.setCostMod("0");
equip.setCostMod(newCost.subtract(equip.getCost(character)));
return true;
}
catch (Exception e)
{
delegate.showErrorMessage(Constants.APPLICATION_NAME,
LanguageBundle.getString("in_eqCust_InvalidNumberErr"));
}
return false;
}
@Override
public boolean setWeight(String newValue)
{
if (StringUtils.isEmpty(newValue))
{
return false;
}
String aString = newValue.trim();
try
{
BigDecimal newWeight = new BigDecimal(aString);
if (newWeight.doubleValue() < 0)
{
delegate.showErrorMessage(Constants.APPLICATION_NAME,
LanguageBundle.getString("in_eqCust_WeightNegativeErr"));
return false;
}
equip.put(ObjectKey.WEIGHT_MOD, BigDecimal.ZERO);
equip.put(ObjectKey.WEIGHT_MOD,
newWeight.subtract(new BigDecimal(equip
.getWeightAsDouble(character))));
return true;
}
catch (Exception e)
{
delegate.showErrorMessage(Constants.APPLICATION_NAME,
LanguageBundle.getString("in_eqCust_InvalidNumberErr"));
}
return false;
}
@Override
public boolean setDamage(String newValue)
{
if (StringUtils.isEmpty(newValue))
{
return false;
}
String aString = newValue.trim();
equip.put(StringKey.DAMAGE_OVERRIDE, aString);
return true;
}
@Override
public ListFacade<EquipModFacade> getAvailList(EquipmentHead head)
{
return availListMap.get(head);
}
@Override
public ListFacade<EquipModFacade> getSelectedList(EquipmentHead head)
{
return selectedListMap.get(head);
}
@Override
public EquipmentFacade getEquipment()
{
return equip;
}
private void refreshAvailList()
{
List<String> aFilter = equip.typeList();
for (EquipmentHead head : equipHeads)
{
List<EquipModFacade> newEqMods = new ArrayList<>();
for (EquipmentModifier aEqMod : Globals.getContext().getReferenceContext()
.getConstructedCDOMObjects(EquipmentModifier.class))
{
if (equip.isVisible(character, aEqMod, head.isPrimary(), View.VISIBLE_DISPLAY))
{
if (aEqMod.isType("ALL"))
{
newEqMods.add(aEqMod);
}
else
{
for (String aType : aFilter)
{
if (aEqMod.isType(aType))
{
newEqMods.add(aEqMod);
break;
}
}
}
}
}
availListMap.get(head).updateContents(newEqMods);
}
}
private void refreshSelectedList()
{
for (EquipmentHead eqHead : equipHeads)
{
selectedListMap.get(eqHead).updateContents(
equip.getEqModifierList(eqHead.isPrimary()));
}
}
@Override
public boolean canAddModifier(EquipModFacade eqModFacade, EquipmentHead head)
{
if (!(eqModFacade instanceof EquipmentModifier))
{
return false;
}
EquipmentModifier eqMod = (EquipmentModifier) eqModFacade;
return equip.canAddModifier(character, eqMod, head.isPrimary());
}
@Override
public boolean isResizable()
{
return Globals.canResizeHaveEffect(equip, equip.typeList());
}
@Override
public void setSize(SizeAdjustmentFacade newSize)
{
if (newSize == null || !(newSize instanceof SizeAdjustment))
{
return;
}
equip.resizeItem(character, (SizeAdjustment) newSize);
equip.nameItemFromModifiers(character);
sizeRef.set(newSize);
}
@Override
public ReferenceFacade<SizeAdjustmentFacade> getSizeRef()
{
return sizeRef;
}
@Override
public EnumSet<EquipmentHead> getEquipmentHeads()
{
return equipHeads;
}
private boolean getSpellChoiceForEqMod(EquipmentModifier eqMod)
{
String choiceValue = eqMod.getSafe(StringKey.CHOICE_STRING).substring(15);
SpellBuilderFacadeImpl spellBuilderFI =
new SpellBuilderFacadeImpl(choiceValue, character, equip);
if (!delegate.showCustomSpellDialog(spellBuilderFI))
{
return false;
}
InfoFacade castingClass = spellBuilderFI.getClassRef().get();
Spell theSpell = (Spell) spellBuilderFI.getSpellRef().get();
String variant = spellBuilderFI.getVariantRef().get();
if (variant == null)
{
variant = "";
}
String spellType = spellBuilderFI.getSpellTypeRef().get();
int baseSpellLevel = spellBuilderFI.getSpellLevelRef().get();
int casterLevel = spellBuilderFI.getCasterLevelRef().get();
ListFacade<AbilityFacade> metamagicFeatsList = spellBuilderFI.getSelectedMetamagicFeats();
Object[] metamagicFeats = new Object[metamagicFeatsList.getSize()];
for (int i = 0; i < metamagicFeats.length; i++)
{
metamagicFeats[i] = metamagicFeatsList.getElementAt(i);
}
int charges = getNumCharges(eqMod);
EquipmentModifier existingEqMod =
equip.getEqModifierKeyed(eqMod.getKeyName(), true);
if (existingEqMod == null)
{
equip.addEqModifier(eqMod, true, character);
}
existingEqMod = equip.getEqModifierKeyed(eqMod.getKeyName(), true);
EqModSpellInfo.setSpellInfo(equip, existingEqMod,
(PObject) castingClass, theSpell, variant, spellType,
baseSpellLevel, casterLevel, metamagicFeats, charges);
return true;
}
private int getNumCharges(EquipmentModifier eqMod)
{
int charges = -1;
Integer min = eqMod.get(IntegerKey.MIN_CHARGES);
if (min != null && min > 0)
{
Integer max = eqMod.get(IntegerKey.MAX_CHARGES);
for (;;)
{
String selectedValue =
delegate.showInputDialog(Constants.APPLICATION_NAME,
LanguageBundle.getFormattedString(
"in_csdChargesMessage", min, max), Integer
.toString(max));
if (selectedValue != null)
{
try
{
final String aString = selectedValue.trim();
charges = Integer.parseInt(aString);
if (charges < min)
{
continue;
}
if (charges > max)
{
continue;
}
break;
}
catch (NumberFormatException exc)
{
// Request a new charges figure
}
}
}
}
return charges;
}
@Override
public String getBaseItemName()
{
return equip.getBaseItemName();
}
@Override
public boolean isWeapon()
{
return equip.isWeapon();
}
@Override
public String getDamage()
{
return equip.getDamage(character);
}
}