package jadex.bdi.planlib;
import jadex.application.space.envsupport.environment.IEnvironmentSpace;
import jadex.application.space.envsupport.environment.IPerceptProcessor;
import jadex.application.space.envsupport.environment.ISpaceObject;
import jadex.application.space.envsupport.environment.space2d.Space2D;
import jadex.application.space.envsupport.math.IVector1;
import jadex.application.space.envsupport.math.IVector2;
import jadex.application.space.envsupport.math.Vector1Double;
import jadex.bdi.runtime.IBDIExternalAccess;
import jadex.bdi.runtime.IBDIInternalAccess;
import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IComponentManagementService;
import jadex.bridge.IComponentStep;
import jadex.bridge.IInternalAccess;
import jadex.commons.IFuture;
import jadex.commons.SUtil;
import jadex.commons.SimplePropertyObject;
import jadex.commons.ThreadSuspendable;
import jadex.commons.concurrent.IResultListener;
import jadex.commons.service.SServiceProvider;
import jadex.javaparser.IParsedExpression;
import jadex.javaparser.IValueFetcher;
import jadex.javaparser.SimpleValueFetcher;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Default bdi agent vision processor.
* Updates the agent's beliefsets according to the percepts of new/disappeared waste.
*/
public class DefaultBDIVisionProcessor extends SimplePropertyObject implements IPerceptProcessor
{
//-------- constants --------
/** The percept types property. */
public static String PROPERTY_PERCEPTTYPES = "percepttypes";
/** The add action. */
public static String ADD = "add";
/** The remove action. */
public static String REMOVE = "remove";
/** The remove_outdated action (checks all entries in the belief set, if they should be seen, but are no longer there). */
public static String REMOVE_OUTDATED = "remove_outdated";
/** The set action. */
public static String SET = "set";
/** The unset action (sets a belief fact to null). */
public static String UNSET = "unset";
/** The maxrange property. */
public static String PROPERTY_MAXRANGE = "range";
/** The maxrange property. */
public static String PROPERTY_RANGE = "range_property";
//-------- attributes --------
/** The percepttypes infos. */
protected Map percepttypes;
//-------- methods --------
/**
* Process a new percept.
* @param space The space.
* @param type The type.
* @param percept The percept.
* @param agent The agent identifier.
* @param agent The avatar of the agent (if any).
*/
public void processPercept(final IEnvironmentSpace space, final String type, final Object percept, final IComponentIdentifier agent, final ISpaceObject avatar)
{
boolean invoke = false;
final String[][] metainfos = getMetaInfos(type);
for(int i=0; !invoke && metainfos!=null && i<metainfos.length; i++)
{
invoke = ADD.equals(metainfos[i][0])
|| REMOVE.equals(metainfos[i][0])
|| SET.equals(metainfos[i][0])
|| UNSET.equals(metainfos[i][0])
|| REMOVE_OUTDATED.equals(metainfos[i][0]) && percept.equals(avatar);
}
if(invoke)
{
// HACK!!! todo
IComponentManagementService ces = (IComponentManagementService)SServiceProvider.getService(
space.getContext().getServiceProvider(), IComponentManagementService.class).get(new ThreadSuspendable());
IFuture fut = ces.getExternalAccess(agent);
fut.addResultListener(new IResultListener()
{
public void exceptionOccurred(Object source, Exception exception)
{
// exception.printStackTrace();
}
public void resultAvailable(Object source, Object result)
{
final IBDIExternalAccess exta = (IBDIExternalAccess)result;
for(int i=0; i<metainfos.length; i++)
{
final IParsedExpression cond = metainfos[i].length==2 ? null
: (IParsedExpression)getProperty(metainfos[i][2]);
final SimpleValueFetcher fetcher = new SimpleValueFetcher();
if(cond!=null)
{
// fetcher = new SimpleValueFetcher();
fetcher.setValue("$space", space);
fetcher.setValue("$percept", percept);
fetcher.setValue("$avatar", avatar);
fetcher.setValue("$type", type);
fetcher.setValue("$aid", agent);
fetcher.setValue("$scope", exta);
}
final String name = metainfos[i][1];
if(ADD.equals(metainfos[i][0]))
{
exta.scheduleStep(new IComponentStep()
{
public Object execute(IInternalAccess ia)
{
IBDIInternalAccess scope = (IBDIInternalAccess)ia;
Object[] facts = scope.getBeliefbase().getBeliefSet(name).getFacts();
if(cond!=null)
fetcher.setValue("$facts", facts);
if(!SUtil.arrayContains(facts, percept) && (cond==null || evaluate(cond, fetcher)))
{
scope.getBeliefbase().getBeliefSet(name).addFact(percept);
// System.out.println("added: "+percept+" to: "+belset);
}
return null;
}
});
}
else if(REMOVE.equals(metainfos[i][0]))
{
exta.scheduleStep(new IComponentStep()
{
public Object execute(IInternalAccess ia)
{
IBDIInternalAccess scope = (IBDIInternalAccess)ia;
Object[] facts = scope.getBeliefbase().getBeliefSet(name).getFacts();
if(cond!=null)
fetcher.setValue("$facts", facts);
if(SUtil.arrayContains(facts, percept) && (cond==null || evaluate(cond, fetcher)))
{
scope.getBeliefbase().getBeliefSet(name).removeFact(percept);
// System.out.println("removed: "+percept+" from: "+belset);
}
return null;
}
});
}
else if(SET.equals(metainfos[i][0]))
{
exta.scheduleStep(new IComponentStep()
{
public Object execute(IInternalAccess ia)
{
IBDIInternalAccess scope = (IBDIInternalAccess)ia;
Object fact = scope.getBeliefbase().getBelief(name).getFact();
if(cond!=null)
fetcher.setValue("$fact", fact);
if(cond==null || evaluate(cond, fetcher))
{
scope.getBeliefbase().getBelief(name).setFact(percept);
// System.out.println("set: "+percept+" on: "+belset);
}
return null;
}
});
}
else if(UNSET.equals(metainfos[i][0]))
{
exta.scheduleStep(new IComponentStep()
{
public Object execute(IInternalAccess ia)
{
IBDIInternalAccess scope = (IBDIInternalAccess)ia;
Object fact = scope.getBeliefbase().getBelief(name).getFact();
if(cond!=null)
fetcher.setValue("$fact", fact);
if(cond==null || evaluate(cond, fetcher))
{
scope.getBeliefbase().getBelief(name).setFact(null);
// System.out.println("unset: "+percept+" on: "+belset);
}
return null;
}
});
}
else if(REMOVE_OUTDATED.equals(metainfos[i][0]) && percept.equals(avatar))
{
exta.scheduleStep(new IComponentStep()
{
public Object execute(IInternalAccess ia)
{
IBDIInternalAccess scope = (IBDIInternalAccess)ia;
Object[] facts = scope.getBeliefbase().getBeliefSet(name).getFacts();
if(cond!=null)
fetcher.setValue("$facts", facts);
if(cond==null || evaluate(cond, fetcher))
{
IVector1 vision = getRange(avatar);
Space2D space2d = (Space2D)space;
IVector2 mypos = (IVector2)avatar.getProperty(Space2D.PROPERTY_POSITION);
ISpaceObject[] known = (ISpaceObject[])facts;
Set seen = space2d.getNearObjects(mypos, vision);
for(int j=0; j<known.length; j++)
{
IVector2 knownpos = (IVector2)known[j].getProperty(Space2D.PROPERTY_POSITION);
// Hack!!! Shouldn't react to knownpos==null
if(!seen.contains(known[j]) && (knownpos==null || !vision.less(space2d.getDistance(mypos, knownpos))))
{
// System.out.println("Removing disappeared object: "+percept+", "+known[j]);
scope.getBeliefbase().getBeliefSet(name).removeFact(known[j]);
}
}
}
return null;
}
});
}
}
}
});
}
}
/**
* Get the percept types defined for this generator.
* @return The percept types.
*/
protected Object[] getPerceptTypes()
{
return (Object[])getProperty(PROPERTY_PERCEPTTYPES);
}
/**
* Get meta infos about a percept type.
*/
protected String[][] getMetaInfos(String percepttype)
{
if(percepttypes==null)
{
this.percepttypes = new HashMap();
Object[] percepttypes = getPerceptTypes();
for(int i=0; i<percepttypes.length; i++)
{
String[] per = (String[])percepttypes[i];
String[][] newmis = per.length==3 ? new String[][]{{per[1], per[2]}} : new String[][]{{per[1], per[2], per[3]}};
String[][] oldmis = (String[][])this.percepttypes.get(per[0]);
if(oldmis!=null)
newmis = (String[][])SUtil.joinArrays(oldmis, newmis);
this.percepttypes.put(per[0], newmis);
}
}
return (String[][])percepttypes.get(percepttype);
}
// Todo: unify range handling!?
/**
* Get the range.
* @return The range.
*/
protected IVector1 getRange(ISpaceObject avatar)
{
Object tmp = avatar.getProperty(getRangePropertyName());
return tmp==null? getDefaultRange(): tmp instanceof Number? new Vector1Double(((Number)tmp).doubleValue()): (IVector1)tmp;
}
/**
* Get the default range.
* @return The range.
*/
protected IVector1 getDefaultRange()
{
Object tmp = getProperty(PROPERTY_MAXRANGE);
return tmp==null? Vector1Double.ZERO: tmp instanceof Number? new Vector1Double(((Number)tmp).doubleValue()): (IVector1)tmp;
}
/**
* Get the range property name.
* @return The range property name.
*/
protected String getRangePropertyName()
{
Object tmp = getProperty(PROPERTY_RANGE);
return tmp==null? "range": (String)tmp;
}
/**
* Evaluate a condition.
* @param exp The expression.
* @param fetcher The value fetcher.
*/
protected boolean evaluate(IParsedExpression exp, IValueFetcher fetcher)
{
boolean ret = false;
try
{
ret = ((Boolean)exp.getValue(fetcher)).booleanValue();
}
catch(Exception e)
{
e.printStackTrace();
}
return ret;
}
}