/*
* Copyright (c) 2009 Tom Parker <thpr@users.sourceforge.net>
*
* This program 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 program 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package pcgen.cdom.enumeration;
import pcgen.util.Logging;
/**
* A GroupingState indicates how a PrimitiveChoiceSet or PrimitiveChoiceFilter
* can be combined.
*/
public enum GroupingState
{
/**
* INVALID indicates that the PrimitiveChoiceSet has been constructed in a
* way that means the result is non-sensical. For example, doing a logical
* OR between the ANY set and a TYPE is non-sensical, because the OR is
* wasteful (or with ANY is useless).
*/
INVALID
{
@Override
public GroupingState add(GroupingState state)
{
return INVALID;
}
@Override
public GroupingState negate()
{
return INVALID;
}
@Override
public GroupingState reduce()
{
return INVALID;
}
@Override
public GroupingState compound(GroupingState state)
{
return INVALID;
}
@Override
public boolean isValid()
{
return false;
}
},
/**
* ALLOWS_NONE indicates that the underlying Set cannot be logically
* combined with any other set. This is often the case for the ANY/ALL set
* (as any logical combination is useless)
*/
ALLOWS_NONE
{
@Override
public GroupingState add(GroupingState state)
{
if (state != EMPTY)
{
Logging.errorPrint("Attempt to add '" + state + "' grouping state to "
+ "'ALLOWS_NONE' resulted in 'INVALID'.");
return INVALID;
}
return state == EMPTY ? ALLOWS_NONE : INVALID;
}
@Override
public GroupingState negate()
{
return INVALID;
}
@Override
public GroupingState reduce()
{
return ANY;
}
@Override
public GroupingState compound(GroupingState state)
{
return ALLOWS_NONE;
}
@Override
public boolean isValid()
{
return true;
}
},
/**
* ALLOWS_INTERSECTION indicates that the underlying set can be combined in
* a logical AND (intersection), but not in a logical OR (union)
*/
ALLOWS_INTERSECTION
{
@Override
public GroupingState add(GroupingState state)
{
if (state == this || state == EMPTY || state == ANY)
{
return this;
}
Logging
.errorPrint("Attempt to add '" + state
+ "' grouping state to 'ALLOWS_INTERSECTION' "
+ "resulted in 'INVALID'.");
return INVALID;
}
@Override
public GroupingState negate()
{
return ANY;
}
@Override
public GroupingState reduce()
{
//TODO Need to check this logical behavior :)
return ANY;
}
@Override
public GroupingState compound(GroupingState state)
{
return state == ALLOWS_UNION ? INVALID : ANY;
}
@Override
public boolean isValid()
{
return true;
}
},
/**
* ALLOWS_UNION indicates that the underlying set can be combined in a
* logical OR (union), but not in a logical AND (intersection). This is
* often the case for a single reference (as a logical AND with any other
* set will return either only the object (useless) or nothing at all (less
* than useless?)
*/
ALLOWS_UNION
{
@Override
public GroupingState add(GroupingState state)
{
if (state == this || state == EMPTY || state == ANY)
{
return this;
}
Logging
.errorPrint("Attempt to add '"
+ state
+ "' grouping state to 'ALLOWS_UNION' resulted in 'INVALID'.");
return INVALID;
}
@Override
public GroupingState negate()
{
return ANY;
}
@Override
public GroupingState reduce()
{
return this;
}
@Override
public GroupingState compound(GroupingState state)
{
return state == ALLOWS_INTERSECTION ? INVALID : ANY;
}
@Override
public boolean isValid()
{
return true;
}
},
/**
* ANY indicates that any form of grouping (union or intersection) can be
* used with the set.
*/
ANY
{
@Override
public GroupingState add(GroupingState state)
{
if (state == ALLOWS_NONE)
{
Logging.errorPrint("Attempt to add 'ALLOWS_NONE' "
+ "grouping state to 'ANY' resulted in 'INVALID'.");
return INVALID;
}
return state == EMPTY ? ANY : state == ALLOWS_NONE ? INVALID
: state;
}
@Override
public GroupingState negate()
{
return this;
}
@Override
public GroupingState reduce()
{
return this;
}
@Override
public GroupingState compound(GroupingState state)
{
return this;
}
@Override
public boolean isValid()
{
return true;
}
},
/**
* EMPTY is a starting state of not having any GroupingState. This is an
* invalid state (basically being an empty set), but can be logically
* combined with any valid GroupingState.
*/
EMPTY
{
@Override
public GroupingState add(GroupingState state)
{
return state;
}
@Override
public GroupingState negate()
{
return ALLOWS_NONE;
}
@Override
public GroupingState reduce()
{
return this;
}
@Override
public GroupingState compound(GroupingState state)
{
return EMPTY;
}
@Override
public boolean isValid()
{
return false;
}
};
/**
* Adds the given GroupingState to this GroupingState, returning the
* GroupingState produced by a combination of the given GroupingState and
* this GroupingState.
*
* @param state
* The GroupingState to be combined with this GroupingState
* @return The GroupingState produced by a combination of the given
* GroupingState and this GroupingState
*/
public abstract GroupingState add(GroupingState state);
/**
* Returns the GroupingState that represents the behavior when this
* GroupingState is negated. Note that calling negate() twice does not
* necessarily return the original GroupingState, as negate is not a 1:1
* relationship.
*
* @return The GroupingState that represents the behavior when this
* GroupingState is negated
*/
public abstract GroupingState negate();
/**
* Returns the GroupingState represented when this GroupingState is placed
* into a combination represented by the given GroupingState.
*
* Note: this method is only defined if the given GroupingState is
* ALLOWS_UNION or ALLOWS_INTERSECTION.
*
* For example, if this GroupingState is ALLOWS_UNION, and the given
* GroupingState is ALLOWS_INTERSECTION, then this will return INVALID,
* since this GroupingState can only be combined under a union.
*
* @param state
* The GroupingState under which this GroupingState was combined.
*
* @return the GroupingState represented when this GroupingState is placed
* into a combination represented by the given GroupingState
*/
public abstract GroupingState compound(GroupingState state);
/**
* Returns true if this GroupingState is valid for use.
*
* @return true if this GroupingState is valid for use; false otherwise.
*/
public abstract boolean isValid();
/**
* Returns the GroupingState used when this GroupingState is reduced
*
* @return the GroupingState used when this GroupingState is reduced
*/
public abstract GroupingState reduce();
}