package org.jactr.modules.pm.common.memory.map;
/*
* default logging
*/
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import javolution.util.FastSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.commonreality.identifier.IIdentifier;
import org.jactr.core.chunk.IChunk;
import org.jactr.core.production.request.ChunkTypeRequest;
import org.jactr.core.slot.IConditionalSlot;
import org.jactr.core.slot.ISlot;
import org.jactr.modules.pm.IPerceptualModule;
public abstract class AbstractSortedFeatureMap<T> extends AbstractFeatureMap<T>
{
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(AbstractSortedFeatureMap.class);
private SortedMap<T, Set<IIdentifier>> _valueMap;
private Map<IIdentifier, T> _currentValues;
public AbstractSortedFeatureMap(String requestSlotName, String crPropertyName)
{
super(requestSlotName, crPropertyName);
_valueMap = new TreeMap<T, Set<IIdentifier>>();
_currentValues = new HashMap<IIdentifier, T>();
}
@Override
protected void clearInternal()
{
_currentValues.clear();
_valueMap.clear();
}
@Override
protected T getCurrentValue(IIdentifier identifier)
{
return _currentValues.get(identifier);
}
protected void not(T value, Set<IIdentifier> container)
{
for (Map.Entry<T, Set<IIdentifier>> entry : _valueMap.entrySet())
if (!value.equals(entry.getKey())) container.addAll(entry.getValue());
}
protected void equals(T value, Set<IIdentifier> container)
{
Set<IIdentifier> tmp = _valueMap.get(value);
if (tmp != null) container.addAll(tmp);
}
protected void lessThan(T value, Set<IIdentifier> container)
{
for (Set<IIdentifier> ids : _valueMap.headMap(value).values())
container.addAll(ids);
}
protected void greaterThan(T value, Set<IIdentifier> container)
{
for (Map.Entry<T, Set<IIdentifier>> entry : _valueMap.tailMap(value)
.entrySet())
if (!value.equals(entry.getKey())) container.addAll(entry.getValue());
}
/**
* resolves lowest, highest
*
* @param request
* @see org.jactr.modules.pm.common.memory.map.IFeatureMap#normalizeRequest(org.jactr.core.production.request.ChunkTypeRequest)
*/
public void normalizeRequest(ChunkTypeRequest request)
{
String relevantSlot = getRelevantSlotName();
for (IConditionalSlot cSlot : request.getConditionalSlots())
if (cSlot.getName().equalsIgnoreCase(relevantSlot))
{
Object slotValue = cSlot.getValue();
String valueChunkName = null;
if (slotValue instanceof IChunk)
valueChunkName = ((IChunk) slotValue).getSymbolicChunk().getName();
try
{
if (IPerceptualModule.LOWEST_CHUNK.equalsIgnoreCase(valueChunkName))
{
T value = _valueMap.firstKey();
if (value != null)
cSlot.setValue(value);
else if (LOGGER.isDebugEnabled())
LOGGER.debug("No values in " + this + " to resolve "
+ valueChunkName);
}
else if (IPerceptualModule.HIGHEST_CHUNK
.equalsIgnoreCase(valueChunkName))
{
T value = _valueMap.lastKey();
if (value != null)
cSlot.setValue(value);
else if (LOGGER.isDebugEnabled())
LOGGER.debug("No values in " + this + " to resolve "
+ valueChunkName);
}
}
catch (NoSuchElementException nsef)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("No value in " + this + " to resolve "
+ valueChunkName);
}
}
}
/**
* converts a slot value to the appropriate type
*
* @param slot
* @return
*/
abstract protected T toData(ISlot slot);
/**
* tests to be sure the value of the slot is a valid type
*
* @param slot
* @return
*/
abstract protected boolean isValidValue(ISlot slot);
@Override
protected void getCandidates(ChunkTypeRequest request,
Set<IIdentifier> results)
{
boolean firstInsertion = true;
String slotName = getRelevantSlotName();
FastSet<IIdentifier> tmp = FastSet.newInstance();
for (IConditionalSlot slot : request.getConditionalSlots())
if (slot.getName().equalsIgnoreCase(slotName))
if (isValidValue(slot))
{
tmp.clear();
T value = toData(slot);
switch (slot.getCondition())
{
case IConditionalSlot.LESS_THAN_EQUALS:
equals(value, tmp);
case IConditionalSlot.LESS_THAN:
lessThan(value, tmp);
break;
case IConditionalSlot.GREATER_THAN_EQUALS:
equals(value, tmp);
case IConditionalSlot.GREATER_THAN:
greaterThan(value, tmp);
break;
case IConditionalSlot.NOT_EQUALS:
not(value, tmp);
break;
case IConditionalSlot.WITHIN:
LOGGER.warn("within is not implemented");
default:
equals(value, tmp);
break;
}
if (firstInsertion)
results.addAll(tmp);
else
results.retainAll(tmp);
firstInsertion = false;
if (results.size() == 0)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug(this + " No possible results, returning early");
break;
}
}
else if (LOGGER.isDebugEnabled())
LOGGER.debug(this + " " + slot + " value is not naturally ordered");
FastSet.recycle(tmp);
}
@Override
protected void addInformation(IIdentifier identifier, T data)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug(this + " Adding " + identifier + " has " + data);
Set<IIdentifier> identifiers = _valueMap.get(data);
if (identifiers == null)
{
identifiers = FastSet.newInstance();
_valueMap.put(data, identifiers);
}
identifiers.add(identifier);
_currentValues.put(identifier, data);
}
@Override
protected T removeInformation(IIdentifier identifier)
{
T value = _currentValues.get(identifier);
if (LOGGER.isDebugEnabled())
LOGGER.debug(this + " Removing " + identifier + " has " + value);
if (value != null)
{
Set<IIdentifier> identifiers = _valueMap.get(value);
if (identifiers != null)
{
identifiers.remove(identifier);
if (identifiers.size() == 0)
{
_valueMap.remove(value);
FastSet.recycle((FastSet) identifiers);
}
}
}
return value;
}
// public void fillSlotValues(ChunkTypeRequest mutableRequest,
// IIdentifier identifier, IChunk encodedChunk,
// ChunkTypeRequest originalSearchRequest)
// {
// String slotName = getRelevantSlotName();
// if (slotName == null) return;
//
// T value = getCurrentValue(identifier);
//
// if (value != null)
// mutableRequest.addSlot(new BasicSlot(slotName, value));
// else if (LOGGER.isWarnEnabled())
// LOGGER.warn("No " + slotName + " information for " + identifier);
// }
@Override
public String toString()
{
return getClass().getSimpleName();
}
}