/*
* Copyright 2007-14 (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 pcgen.rules.context;
import pcgen.cdom.base.CDOMObject;
import pcgen.cdom.base.Categorized;
import pcgen.cdom.base.Category;
import pcgen.cdom.base.ChooseInformation;
import pcgen.cdom.base.ClassIdentity;
import pcgen.cdom.base.Loadable;
import pcgen.cdom.enumeration.ObjectKey;
import pcgen.cdom.reference.CDOMSingleRef;
import pcgen.cdom.reference.ReferenceManufacturer;
import pcgen.cdom.reference.UnconstructedValidator;
import pcgen.rules.persistence.TokenLibrary;
import pcgen.util.Logging;
import pcgen.util.StringPClassUtil;
public final class ReferenceContextUtilities
{
private ReferenceContextUtilities()
{
//Do not instantiate utility class
}
/**
* Check the associations now that all the data is loaded.
*
* @param validator
* The helper object to track things such as FORWARDREF
* instances.
*/
public static void validateAssociations(AbstractReferenceContext refContext,
LoadValidator validator)
{
for (ReferenceManufacturer<?> rm : refContext.getAllManufacturers())
{
for (CDOMSingleRef<?> singleRef : rm.getReferenced())
{
String choice = singleRef.getChoice();
if (choice != null)
{
CDOMObject cdo = (CDOMObject) singleRef.get();
ChooseInformation<?> ci = cdo.get(ObjectKey.CHOOSE_INFO);
if (ci == null)
{
Logging.errorPrint("Found "
+ rm.getReferenceDescription() + " "
+ cdo.getKeyName() + " "
+ " that had association: " + choice
+ " but was not an object with CHOOSE");
rm.fireUnconstuctedEvent(singleRef);
continue;
}
ClassIdentity<?> clIdentity = ci.getClassIdentity();
if (choice.indexOf("%") > -1)
{
//patterns or %LIST are OK
//See CollectionToAbilitySelection.ExpandingConverter
continue;
}
Class<?> cl = clIdentity.getChoiceClass();
if (Loadable.class.isAssignableFrom(cl))
{
ReferenceManufacturer<? extends Loadable> mfg =
refContext
.getManufacturer((ClassIdentity<? extends Loadable>) clIdentity);
if (!mfg.containsObject(choice)
&& (TokenLibrary.getPrimitive(cl, choice) == null)
&& !report(validator, clIdentity.getChoiceClass(),
choice))
{
Logging.errorPrint("Found "
+ rm.getReferenceDescription() + " "
+ cdo.getKeyName() + " "
+ " that had association: " + choice
+ " but no such "
+ mfg.getReferenceDescription()
+ " was ever defined");
rm.fireUnconstuctedEvent(singleRef);
continue;
}
}
}
}
}
}
private static boolean report(UnconstructedValidator validator,
Class<?> cl, String key)
{
return validator != null && validator.allow(cl, key);
}
public static <T extends Categorized<T>> ReferenceManufacturer<? extends Loadable> getManufacturer(
AbstractReferenceContext refContext, String firstToken)
{
int equalLoc = firstToken.indexOf('=');
String className;
String categoryName;
if (equalLoc != firstToken.lastIndexOf('='))
{
Logging.log(Logging.LST_ERROR,
" Error encountered: Found second = in ObjectType=Category");
Logging.log(Logging.LST_ERROR,
" Format is: ObjectType[=Category]|Key[|Key] value was: "
+ firstToken);
Logging.log(Logging.LST_ERROR, " Valid ObjectTypes are: "
+ StringPClassUtil.getValidStrings());
return null;
}
else if ("FEAT".equals(firstToken))
{
className = "ABILITY";
categoryName = "FEAT";
}
else if (equalLoc == -1)
{
className = firstToken;
categoryName = null;
}
else
{
className = firstToken.substring(0, equalLoc);
categoryName = firstToken.substring(equalLoc + 1);
}
Class<? extends Loadable> c = StringPClassUtil.getClassFor(className);
if (c == null)
{
Logging.log(Logging.LST_ERROR, "Unrecognized ObjectType: "
+ className);
return null;
}
ReferenceManufacturer<? extends Loadable> rm;
if (Categorized.class.isAssignableFrom(c))
{
Class<? extends Category<T>> catClass =
(Class<? extends Category<T>>) StringPClassUtil
.getCategoryClassFor(className);
if (categoryName == null)
{
Logging
.log(Logging.LST_ERROR,
" Error encountered: Found Categorized Type without =Category");
Logging.log(Logging.LST_ERROR,
" Format is: ObjectType[=Category]|Key[|Key] value was: "
+ firstToken);
Logging.log(Logging.LST_ERROR, " Valid ObjectTypes are: "
+ StringPClassUtil.getValidStrings());
return null;
}
rm =
refContext.getManufacturer((Class<T>) c, catClass,
categoryName);
if (rm == null)
{
Logging.log(Logging.LST_ERROR, " Error encountered: "
+ className + " Category: " + categoryName + " not found");
return null;
}
}
else
{
if (categoryName != null)
{
Logging
.log(Logging.LST_ERROR,
" Error encountered: Found Non-Categorized Type with =Category");
Logging.log(Logging.LST_ERROR,
" Format is: ObjectType[=Category]|Key[|Key] value was: "
+ firstToken);
Logging.log(Logging.LST_ERROR, " Valid ObjectTypes are: "
+ StringPClassUtil.getValidStrings());
return null;
}
rm = refContext.getManufacturer(c);
}
return rm;
}
}