/**
* Copyright (C) 2001-3, Anthony Harrison anh23@pitt.edu 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 org.jactr.core.production.action;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.buffer.IActivationBuffer;
import org.jactr.core.chunk.IChunk;
import org.jactr.core.logging.Logger;
import org.jactr.core.model.IModel;
import org.jactr.core.production.CannotInstantiateException;
import org.jactr.core.production.IInstantiation;
import org.jactr.core.queue.timedevents.AbstractTimedEvent;
import org.jactr.core.queue.timedevents.IBufferBasedTimedEvent;
import org.jactr.core.slot.DefaultMutableSlot;
import org.jactr.core.slot.IMutableSlot;
import org.jactr.core.slot.ISlot;
import org.jactr.core.utils.StringUtilities;
/**
* The ModifyAction is used to modify the slot values of a chunk residing within
* a specific buffer. The IChunk is neither added nor removed. If upon firing
* there is no chunk in the buffer, an IllegalActionStateException is thrown.
*
* @author harrison
* @created January 22, 2003
*/
public class ModifyAction extends DefaultAction implements IBufferAction,
org.jactr.core.slot.ISlotContainer
{
// logging mechanism
private static transient Log LOGGER = LogFactory
.getLog(ModifyAction.class
.getName());
/**
* name of the buffer that is to have its contents modified
*
* @since
*/
private String _bufferName;
private Collection<IMutableSlot> _slots;
private IChunk _boundChunk;
/**
* Constructor merely takes the name of the buffer where the chunk will
* reside.
*
* @param bufferName
* Description of Parameter
* @since
*/
@SuppressWarnings("unchecked")
public ModifyAction(String bufferName)
{
this(bufferName, Collections.EMPTY_LIST);
}
/**
* Constructor for the ModifyAction object
*
* @since
*/
public ModifyAction()
{
this(IActivationBuffer.GOAL);
}
public ModifyAction(String bufferName, Collection<? extends ISlot> slots)
{
_bufferName = bufferName.toLowerCase();
_slots = new ArrayList<IMutableSlot>();
for (ISlot slot : slots)
addSlot(slot);
}
/**
* Description of the Method
*
* @since
*/
@Override
public void dispose()
{
super.dispose();
if (_slots != null) _slots.clear();
_slots = null;
}
/**
* Description of the Method
*
* @return Description of the Return Value
*/
public boolean canModify()
{
return true;
}
public IAction bind(Map<String, Object> variableBindings)
throws CannotInstantiateException
{
ModifyAction act = new ModifyAction(getBufferName(), getSlotsInternal());
act.bindSlotValues(variableBindings, act.getSlotsInternal());
act.bindChunk(variableBindings);
return act;
}
protected void bindChunk(Map<String, Object> bindings)
throws CannotInstantiateException
{
_boundChunk = (IChunk) bindings.get("=" + getBufferName());
if (_boundChunk == null)
throw new CannotInstantiateException("Could not get chunk bound to ="
+ getBufferName());
}
public String getBufferName()
{
return _bufferName;
}
public void setBufferName(String name)
{
_bufferName = name.toLowerCase();
}
/**
* returns actual backing collection
*/
protected Collection<IMutableSlot> getSlotsInternal()
{
return _slots;
}
public Collection<? extends ISlot> getSlots()
{
return Collections.unmodifiableCollection(_slots);
}
public Collection<ISlot> getSlots(Collection<ISlot> slots)
{
if (slots == null) slots = new ArrayList<ISlot>();
slots.addAll(_slots);
return slots;
}
public void addSlot(ISlot s)
{
_slots.add(new DefaultMutableSlot(s));
}
public void removeSlot(ISlot s)
{
_slots.remove(s);
}
protected IChunk getBoundChunk()
{
return _boundChunk;
}
/**
* fire this modify action this will actually post a timed event to the timed
* event queue that will do the work..
*
* @since
*/
@Override
public double fire(IInstantiation instantiation, double firingTime)
{
IModel model = instantiation.getModel();
double fireAt = firingTime
+ model.getProceduralModule().getDefaultProductionFiringTime();
IActivationBuffer buffer = model.getActivationBuffer(getBufferName());
ModifyActionTimedEvent modify = new ModifyActionTimedEvent(firingTime,
fireAt, buffer, getBoundChunk(), getSlots());
model.getTimedEventQueue().enqueue(modify);
return 0;
}
public class ModifyActionTimedEvent extends AbstractTimedEvent implements
IBufferBasedTimedEvent
{
final IChunk _chunkToModify;
final Collection<? extends ISlot> _slotsToChange;
final IActivationBuffer _buffer;
final String _label;
public ModifyActionTimedEvent(double now, double whenToFire,
IActivationBuffer buffer, IChunk chunkToModify,
Collection<? extends ISlot> slots)
{
setTimes(now, whenToFire);
_buffer = buffer;
_chunkToModify = chunkToModify;
_slotsToChange = new ArrayList<ISlot>(slots);
_label = String.format("Modify(%1$s in %2$s @ %3$.2f)", _chunkToModify
.getSymbolicChunk().getName(), _buffer.getName(), whenToFire);
}
@Override
public String toString()
{
return _label;
}
@SuppressWarnings("synthetic-access")
@Override
public void fire(double now)
{
super.fire(now);
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("Modifying " + _chunkToModify + " @ " + now + " "
+ StringUtilities.toString(_chunkToModify));
LOGGER.debug("Using slots " + _slotsToChange);
}
if (!_buffer.getSourceChunks().contains(_chunkToModify))
{
IModel model = _chunkToModify.getModel();
if (LOGGER.isWarnEnabled() || Logger.hasLoggers(model))
{
String msg = _chunkToModify + " is no longer in " + _buffer
+ " cannot modify";
Logger.log(model, Logger.Stream.EXCEPTION, msg);
LOGGER.warn(msg);
}
return;
}
updateSlots(_chunkToModify, _slotsToChange);
if (LOGGER.isDebugEnabled())
LOGGER.debug("Result " + StringUtilities.toString(_chunkToModify));
}
/**
* @see org.jactr.core.queue.timedevents.IBufferBasedTimedEvent#getBuffer()
*/
public IActivationBuffer getBuffer()
{
return _buffer;
}
public IChunk getBoundChunk()
{
return _chunkToModify;
}
}
}