/*
* Copyright 2001 (C) Bryan McRoberts <merton_monk@yahoo.com>
*
* 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 April 21, 2001, 2:15 PM
*
* Current Ver: $Revision$
*
*/
package pcgen.core;
import java.io.Serializable;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import pcgen.base.lang.StringUtil;
import pcgen.cdom.base.CDOMObject;
import pcgen.cdom.base.QualifyingObject;
import pcgen.cdom.enumeration.DataSetID;
import pcgen.cdom.enumeration.ListKey;
import pcgen.cdom.enumeration.ObjectKey;
import pcgen.cdom.enumeration.SourceFormat;
import pcgen.cdom.enumeration.StringKey;
import pcgen.cdom.enumeration.Type;
import pcgen.cdom.facet.FacetLibrary;
import pcgen.cdom.facet.HiddenTypeFacet;
import pcgen.core.analysis.OutputNameFormatting;
import pcgen.core.utils.KeyedListContainer;
import pcgen.persistence.lst.output.prereq.PrerequisiteWriter;
import pcgen.system.PCGenSettings;
/**
* {@code PObject}<br>
* This is the base class for several objects in the PCGen database.
*
* @author Bryan McRoberts <merton_monk@users.sourceforge.net>
* @author Joe.Frazier
*
*/
public class PObject extends CDOMObject implements Cloneable, Serializable, Comparable<Object>,
KeyedListContainer, QualifyingObject
{
private HiddenTypeFacet hiddenTypeFacet = FacetLibrary.getFacet(HiddenTypeFacet.class);
/** Standard serialVersionUID for Serializable objects */
private static final long serialVersionUID = 1;
private final Class<?> myClass = getClass();
/* ************
* Methods
* ************/
/**
* if a class implements the Cloneable interface then it should have a
* public" 'clone ()' method It should be declared to throw
* CloneNotSupportedException', but subclasses do not need the "throws"
* declaration unless their 'clone ()' method will throw the exception
* Thus subclasses can decide to not support 'Cloneable' by implementing
* the 'clone ()' method to throw 'CloneNotSupportedException'
* If this rule were ignored and the parent did not have the "throws"
* declaration then subclasses that should not be cloned would be forced
* to implement a trivial 'clone ()' to satisfy inheritance
* final" classes implementing 'Cloneable' should not be declared to
* throw 'CloneNotSupportedException" because their implementation of
* clone ()' should be a fully functional method that will not
* throw the exception.
* @return cloned object
* @throws CloneNotSupportedException
*/
@Override
public PObject clone() throws CloneNotSupportedException
{
return (PObject) super.clone();
}
/**
* Compares the keys of the object.
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(final Object obj)
{
if (obj != null)
{
//this should throw a ClassCastException for non-PObjects, like the Comparable interface calls for
return this.getKeyName().compareToIgnoreCase(((PObject) obj).getKeyName());
}
return 1;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals( final Object obj )
{
return obj instanceof PObject
&& getKeyName().equalsIgnoreCase(((PObject) obj).getKeyName());
}
//Temporarily commented out since unit tests are badly behaved, see COD#E-1895
// @Override
// public int hashCode()
// {
// return getKeyName().hashCode();
// }
/**
* Set the name (sets keyname also)
* @param aString
*/
@Override
public void setName(final String aString)
{
if (!aString.endsWith(".MOD"))
{
super.setName(aString);
put(StringKey.KEY_NAME, aString);
}
}
///////////////////////////////////////////////////////////////////////
// Accessor(s) and Mutator(s)
///////////////////////////////////////////////////////////////////////
public final String getOutputName()
{
return OutputNameFormatting.getOutputName(this);
}
/**
* Get the type of PObject
*
* @return the type of PObject
*/
public String getType()
{
return StringUtil.join(getTrueTypeList(false), ".");
}
public final List<Type> getTrueTypeList(final boolean visibleOnly)
{
final List<Type> ret = getSafeListFor(ListKey.TYPE);
if (visibleOnly)
{
for (Iterator<Type> it = ret.iterator(); it.hasNext();)
{
DataSetID id = Globals.getContext().getDataSetID();
if (hiddenTypeFacet.contains(id, myClass, it.next()))
{
it.remove();
}
}
}
return Collections.unmodifiableList(ret);
}
/**
* If aType begins with an " (Exclamation Mark) the " will be
* removed before checking the type.
*
* @param aType
* @return Whether the item is of this type
*
* Note: This method is overridden in Equipment.java
*/
@Override
public boolean isType(final String aType)
{
final String myType;
if (aType.isEmpty())
{
return false;
}
else if (aType.charAt(0) == '!')
{
myType = aType.substring(1).toUpperCase();
}
else if (aType.startsWith("TYPE=") || aType.startsWith("TYPE.")) //$NON-NLS-1$ //$NON-NLS-2$
{
myType = aType.substring(5).toUpperCase();
}
else
{
myType = aType.toUpperCase();
}
//
// Must match all listed types in order to qualify
//
StringTokenizer tok = new StringTokenizer(myType, ".");
while (tok.hasMoreTokens())
{
if (!containsInList(ListKey.TYPE, Type.getConstant(tok.nextToken())))
{
return false;
}
}
return true;
}
@Override
public String toString()
{
if (PCGenSettings.OPTIONS_CONTEXT.getBoolean(
PCGenSettings.OPTION_SHOW_OUTPUT_NAME_FOR_OTHER_ITEMS, false))
{
return getOutputName();
}
return getDisplayName();
}
/**
* @return true if the name of this item is Product Identity (i.e owned by the publisher)
*/
public boolean isNamePI()
{
return getSafe(ObjectKey.NAME_PI);
}
/**
* Get the PCC text with the saved name
* @return the PCC text with the saved name
*/
public String getPCCText()
{
final StringBuilder txt = new StringBuilder(200);
txt.append(getDisplayName());
txt.append("\t");
txt.append(StringUtil.joinToStringBuilder(Globals.getContext().unparse(
this), "\t"));
txt.append("\t");
txt.append(PrerequisiteWriter.prereqsToString(this));
return txt.toString();
}
public String getSource()
{
return SourceFormat.getFormattedString(this,
Globals.getSourceDisplay(), true);
}
public String getSourceForNodeDisplay()
{
return SourceFormat.getFormattedString(this,
SourceFormat.LONG, false);
}
}