/*
* DelegatingDataSet.java
* Copyright 2014 Connor Petty <cpmeister@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 May 4, 2014, 5:35:52 PM
*/
package pcgen.gui2.facade;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import pcgen.facade.core.AbilityCategoryFacade;
import pcgen.facade.core.AbilityFacade;
import pcgen.facade.core.AlignmentFacade;
import pcgen.facade.core.BodyStructureFacade;
import pcgen.facade.core.CampaignFacade;
import pcgen.facade.core.ClassFacade;
import pcgen.facade.core.DataSetFacade;
import pcgen.facade.core.DeityFacade;
import pcgen.facade.core.EquipmentFacade;
import pcgen.facade.core.GameModeFacade;
import pcgen.facade.core.GearBuySellFacade;
import pcgen.facade.core.KitFacade;
import pcgen.facade.core.RaceFacade;
import pcgen.facade.core.SizeAdjustmentFacade;
import pcgen.facade.core.SkillFacade;
import pcgen.facade.core.StatFacade;
import pcgen.facade.core.TemplateFacade;
import pcgen.facade.util.event.MapEvent;
import pcgen.facade.util.event.MapListener;
import pcgen.facade.core.generator.StatGenerationFacade;
import pcgen.facade.util.AbstractMapFacade;
import pcgen.facade.util.DelegatingListFacade;
import pcgen.facade.util.ListFacade;
import pcgen.facade.util.MapFacade;
/**
* This class implements a {@code DataSetFacade} by delegating to another
* DataSetFacade. This class is the DataSetFacade returned by the
* {@code CharacterFacadeImpl} and is necessary to protect outside event
* listeners from directly listening to the real DataSetFacade. By adding this
* delegate layer, upon closing a character, the CFI can sever connections
* between the DelegatingDataSet and the actual DataSetFacade thus preventing an
* memory leaks that could occur from an outside event listener.
*
* @author Connor Petty <cpmeister@users.sourceforge.net>
*/
public class DelegatingDataSet implements DataSetFacade
{
private final DelegatingListFacade<RaceFacade> races;
private final DelegatingListFacade<ClassFacade> classes;
private final DelegatingListFacade<DeityFacade> deities;
private final DelegatingListFacade<SkillFacade> skills;
private final DelegatingListFacade<TemplateFacade> templates;
private final DelegatingListFacade<AlignmentFacade> alignments;
private final DelegatingListFacade<KitFacade> kits;
private final DelegatingListFacade<StatFacade> stats;
private final DelegatingAbilitiesMap abilities;
private final DelegatingListFacade<CampaignFacade> campaigns;
private final DelegatingListFacade<BodyStructureFacade> bodyStructures;
private final DelegatingListFacade<EquipmentFacade> equipment;
private final DelegatingListFacade<String> xpTableNames;
private final DelegatingListFacade<GearBuySellFacade> gearBuySellSchemes;
private final DelegatingListFacade<String> characterTypes;
private final DelegatingListFacade<SizeAdjustmentFacade> sizes;
private final DataSetFacade delegate;
public DelegatingDataSet(DataSetFacade delegate)
{
this.delegate = delegate;
this.abilities = new DelegatingAbilitiesMap(delegate.getAbilities());
this.races = new DelegatingListFacade<>(delegate.getRaces());
this.classes = new DelegatingListFacade<>(delegate.getClasses());
this.deities = new DelegatingListFacade<>(delegate.getDeities());
this.skills = new DelegatingListFacade<>(delegate.getSkills());
this.templates = new DelegatingListFacade<>(delegate.getTemplates());
this.alignments = new DelegatingListFacade<>(delegate.getAlignments());
this.kits = new DelegatingListFacade<>(delegate.getKits());
this.stats = new DelegatingListFacade<>(delegate.getStats());
this.campaigns = new DelegatingListFacade<>(delegate.getCampaigns());
this.bodyStructures = new DelegatingListFacade<>(delegate.getEquipmentLocations());
this.equipment = new DelegatingListFacade<>(delegate.getEquipment());
this.xpTableNames = new DelegatingListFacade<>(delegate.getXPTableNames());
this.gearBuySellSchemes = new DelegatingListFacade<>(delegate.getGearBuySellSchemes());
this.characterTypes = new DelegatingListFacade<>(delegate.getCharacterTypes());
this.sizes = new DelegatingListFacade<>(delegate.getSizes());
}
public void detachDelegates()
{
abilities.detach();
races.setDelegate(null);
classes.setDelegate(null);
deities.setDelegate(null);
skills.setDelegate(null);
templates.setDelegate(null);
alignments.setDelegate(null);
kits.setDelegate(null);
stats.setDelegate(null);
campaigns.setDelegate(null);
bodyStructures.setDelegate(null);
equipment.setDelegate(null);
xpTableNames.setDelegate(null);
gearBuySellSchemes.setDelegate(null);
characterTypes.setDelegate(null);
sizes.setDelegate(null);
}
@Override
public MapFacade<AbilityCategoryFacade, ListFacade<AbilityFacade>> getAbilities()
{
return abilities;
}
private class DelegatingAbilitiesMap extends AbstractMapFacade<AbilityCategoryFacade, ListFacade<AbilityFacade>>
implements MapListener<AbilityCategoryFacade, ListFacade<AbilityFacade>>
{
private final Map<AbilityCategoryFacade, DelegatingListFacade<AbilityFacade>> abilitiesMap;
private final MapFacade<AbilityCategoryFacade, ListFacade<AbilityFacade>> abilitiesDelegate;
public DelegatingAbilitiesMap(MapFacade<AbilityCategoryFacade, ListFacade<AbilityFacade>> abilitiesDelegate)
{
this.abilitiesDelegate = abilitiesDelegate;
this.abilitiesMap = new HashMap<>();
populateMap();
abilitiesDelegate.addMapListener(this);
}
public void detach()
{
abilitiesDelegate.removeMapListener(this);
for (DelegatingListFacade<AbilityFacade> list : abilitiesMap.values())
{
list.setDelegate(null);
}
}
@Override
public Set<AbilityCategoryFacade> getKeys()
{
return abilitiesDelegate.getKeys();
}
@Override
public ListFacade<AbilityFacade> getValue(AbilityCategoryFacade key)
{
return abilitiesMap.get(key);
}
@Override
public void keyAdded(MapEvent<AbilityCategoryFacade, ListFacade<AbilityFacade>> e)
{
AbilityCategoryFacade key = e.getKey();
DelegatingListFacade<AbilityFacade> newValue = new DelegatingListFacade<>(e.getNewValue());
abilitiesMap.put(key, newValue);
fireKeyAdded(this, key, newValue);
}
@Override
public void keyRemoved(MapEvent<AbilityCategoryFacade, ListFacade<AbilityFacade>> e)
{
AbilityCategoryFacade key = e.getKey();
DelegatingListFacade<AbilityFacade> oldValue = abilitiesMap.remove(key);
fireKeyRemoved(this, key, oldValue);
oldValue.setDelegate(null);
}
@Override
public void keyModified(MapEvent<AbilityCategoryFacade, ListFacade<AbilityFacade>> e)
{
fireKeyModified(this, e.getKey(), abilitiesMap.get(e.getKey()), e);
}
@Override
public void valueChanged(MapEvent<AbilityCategoryFacade, ListFacade<AbilityFacade>> e)
{
AbilityCategoryFacade key = e.getKey();
DelegatingListFacade<AbilityFacade> oldValue = abilitiesMap.get(key);
DelegatingListFacade<AbilityFacade> newValue = new DelegatingListFacade<>(e.getNewValue());
abilitiesMap.put(key, newValue);
fireValueChanged(this, key, oldValue, newValue);
oldValue.setDelegate(null);
}
@Override
public void valueModified(MapEvent<AbilityCategoryFacade, ListFacade<AbilityFacade>> e)
{
fireValueModified(this, e.getKey(), abilitiesMap.get(e.getKey()), e);
}
private void populateMap()
{
for (AbilityCategoryFacade key : abilitiesDelegate.getKeys())
{
DelegatingListFacade<AbilityFacade> value = new DelegatingListFacade<>(abilitiesDelegate.getValue(key));
abilitiesMap.put(key, value);
}
}
@Override
public void keysChanged(MapEvent<AbilityCategoryFacade, ListFacade<AbilityFacade>> e)
{
ArrayList<DelegatingListFacade<AbilityFacade>> deadLists = new ArrayList<>(abilitiesMap.values());
abilitiesMap.clear();
populateMap();
for (DelegatingListFacade<AbilityFacade> delegatingListFacade : deadLists)
{
delegatingListFacade.setDelegate(null);
}
}
}
@Override
public List<AbilityFacade> getPrereqAbilities(AbilityFacade abilityFacade)
{
return delegate.getPrereqAbilities(abilityFacade);
}
@Override
public ListFacade<SkillFacade> getSkills()
{
return skills;
}
@Override
public ListFacade<RaceFacade> getRaces()
{
return races;
}
@Override
public ListFacade<ClassFacade> getClasses()
{
return classes;
}
@Override
public ListFacade<DeityFacade> getDeities()
{
return deities;
}
@Override
public ListFacade<TemplateFacade> getTemplates()
{
return templates;
}
@Override
public ListFacade<CampaignFacade> getCampaigns()
{
return campaigns;
}
@Override
public GameModeFacade getGameMode()
{
return delegate.getGameMode();
}
@Override
public ListFacade<AlignmentFacade> getAlignments()
{
return alignments;
}
@Override
public ListFacade<StatFacade> getStats()
{
return stats;
}
@Override
public ListFacade<StatGenerationFacade> getStatGenerators()
{
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public SkillFacade getSpeakLanguageSkill()
{
return delegate.getSpeakLanguageSkill();
}
@Override
public ListFacade<EquipmentFacade> getEquipment()
{
return equipment;
}
@Override
public void addEquipment(EquipmentFacade equip)
{
delegate.addEquipment(equip);
}
@Override
public ListFacade<BodyStructureFacade> getEquipmentLocations()
{
return bodyStructures;
}
@Override
public ListFacade<String> getXPTableNames()
{
return xpTableNames;
}
@Override
public ListFacade<String> getCharacterTypes()
{
return characterTypes;
}
@Override
public ListFacade<GearBuySellFacade> getGearBuySellSchemes()
{
return gearBuySellSchemes;
}
@Override
public ListFacade<KitFacade> getKits()
{
return kits;
}
@Override
public ListFacade<SizeAdjustmentFacade> getSizes()
{
return sizes;
}
@Override
public void refreshEquipment()
{
delegate.refreshEquipment();
}
}