/*******************************************************************************
 * Copyright 2012 Google, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
package com.turbomanage.storm;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.DatabaseUtils.InsertHelper;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import com.turbomanage.storm.api.DatabaseFactory;
import com.turbomanage.storm.exception.TooManyResultsException;
import com.turbomanage.storm.query.Query;

/**
 * Base DAO class for entity DAOs. Most of the runtime is implemented
 * in this class. It is safe to construct new instances anywhere, as
 * this class holds a reference to the {@link Context}, which it passes
 * to the generated {@link DatabaseFactory} to obtain the singleton
 * {@link SQLiteOpenHelper}.
 *
 * @author David M. Chandler
 *
 * @param <T> Entity type
 */
public abstract class SQLiteDao<T> {

	private static final String TAG = SQLiteDao.class.getName();

	private final Context mContext;
	protected final TableHelper<T> th;

	/**
	 * Constructor requires the {@link Context}, which you typically
	 * obtain by calling {@link Activity#getApplicationContext()} in
	 * your Activity. The DAO maintains no database state, but rather
	 * only the {@link Context} to initialize the database if needed.
	 * It is safe to construct multiple instances of the DAO since all
	 * database access occurs a singleton instance of {@link SQLiteOpenHelper}
	 * provided by your generated {@link DatabaseFactory}.
	 *
	 * @param ctx Context
	 */
	@SuppressWarnings("unchecked")
	public SQLiteDao(Context ctx) {
		this.mContext = ctx;
		this.th = getTableHelper();
	}

	/**
	 * Generated subclasses implement to point to the correct
	 * {@link SQLiteOpenHelper} for the entity.
	 *
	 * @param Context ctx
	 * @return DatabaseHelper
	 */
	public abstract DatabaseHelper getDbHelper(Context ctx);

	/**
	 * Generated subclasses implement to provide the entity's
	 * {@link TableHelper}.
	 *
	 * @return TableHelper
	 */
	@SuppressWarnings("rawtypes")
	public abstract TableHelper getTableHelper();

	/**
	 * Deletes a single row by ID. Returns the number of rows deleted
	 * or 0 if unsuccessful.
	 *
	 * @param id
	 * @return count of rows deleted
	 */
	public int delete(Long id) {
		if (id != null) {
			return getWritableDb().delete(th.getTableName(), th.getIdCol() + "=?", new String[]{id.toString()});
		}
		return 0;
	}

	/**
	 * Deletes all rows in the entity's table. Returns the number of
	 * rows deleted.
	 *
	 * @return count of rows deleted
	 */
	public int deleteAll() {
		return getWritableDb().delete(th.getTableName(), null, null);
	}

	/**
	 * Returns a {@link Query} for the entity type. The default
	 * FilterBuilder constructs a query by ANDing all conditions.
	 *
	 * @return FilterBuilder
	 */
	@SuppressWarnings("unchecked")
	public Query<T> load() {
		return new Query<T>((SQLiteDao<T>) this);
	}

	/**
	 * Returns a single object by ID or null if no match found.
	 * If more than one match is found, throws
	 * {@link TooManyResultsException}.
	 *
	 * @param id
	 * @return One entity
	 */
	public T get(Long id) {
		return load().eq(th.getIdCol(), id).get();
	}

	/**
	 * Constructs a query from an example object and returns
	 * the matching entity or null. If more than one match is found,
	 * throws {@link TooManyResultsException}. Uses in the comparison
	 * only those fields of the example object which are different than
	 * their default values.
	 *
	 * @param exampleObj
	 * @return
	 */
	public T getByExample(T exampleObj) {
		return asObject(queryByExample(exampleObj));
	}

	/**
	 * Returns all rows in the entity table as a {@link List}.
	 *
	 * @return List<T>
	 */
	public List<T> listAll() {
		return asList(queryAll());
	}

	/**
	 * Returns all entities matching an example object. Uses in the comparison
	 * only those fields of the example object which are different than
	 * their default values.
	 *
	 * @param exampleObj
	 * @return
	 */
	public List<T> listByExample(T exampleObj) {
		return asList(queryByExample(exampleObj));
	}

	/**
	 * Inserts a row for the provided entity. If the entity's id is the
	 * default long (0), the database generates an id and populates the
	 * entity's ID field. Returns the generated ID or -1 if error.
	 *
	 * @param obj An entity
	 * @return ID of newly inserted row or -1 if err
	 */
	public long insert(T obj) {
		ContentValues cv = th.getEditableValues(obj);
		if (th.getId(obj) == 0) {
			// the default, remove from ContentValues to allow autoincrement
			cv.remove(th.getIdCol().toString());
		}
		long id = getWritableDb().insertOrThrow(th.getTableName(), null, cv);
		th.setId(obj, id);
		return id;
	}

	/**
	 * Efficiently insert a collection of entities using {@link InsertHelper}.
	 *
	 * @param many Collection of objects
	 * @return count of inserted objects or -1 immediately if any errors
	 */
	public long insertMany(Iterable<T> many) {
		long numInserted = 0;
		InsertHelper insertHelper = new DatabaseUtils.InsertHelper(getWritableDb(), th.getTableName());
		getWritableDb().beginTransaction();
		try {
			for (T obj : many) {
				ContentValues cv = th.getEditableValues(obj);
				if (th.getId(obj) == 0) {
					// the default, remove from ContentValues to allow autoincrement
					cv.remove(th.getIdCol().toString());
				}
				long id = insertHelper.insert(cv);
				if (id == -1)
					return -1;
				numInserted++;
			}
			getWritableDb().setTransactionSuccessful();
		} finally {
			getWritableDb().endTransaction();
		}
		return numInserted;
	}

	/**
	 * Insert or update.
	 *
	 * @param obj An entity
	 * @return 0 if updated, -1 if err, else new ID
	 */
	public long save(T obj) {
		if (th.getId(obj) == 0) {
			return insert(obj);
		}
		long updated = update(obj);
		if (updated == 1) {
			return 0;
		}
		return -1;
	}

	/**
	 * Update all columns for the row having the ID matching
	 * the provided entity's ID.
	 *
	 * @param obj An entity
	 * @return count of updated rows
	 */
	public long update(T obj) {
		ContentValues cv = th.getEditableValues(obj);
		Long id = th.getId(obj);
		int numRowsUpdated = getWritableDb().update(th.getTableName(), cv, th.getIdCol()
				+ "=?", new String[] { id.toString() });
		return numRowsUpdated;
	}

	// TODO beware leaky abstractions--who owns the cursor?
	/**
	 * Convenience method queries the entity table using the provided
	 * WHERE clause and parameters and returns a {@link Cursor}.
	 *
	 * The calling method MUST close the Cursor!
	 *
	 * @param where
	 * @param params
	 * @return Cursor
	 */
	public Cursor query(String where, String[] params) {
		return query(where, params, null);
	}

	/**
	 * Convenience method queries the entity table using the provided
	 * WHERE clause and parameters and returns a {@link Cursor}.
	 *
	 * The calling method MUST close the Cursor!
	 *
	 * @param where
	 * @param params
	 * @param orderBy
	 * @return
	 */
	public Cursor query(String where, String[] params, String orderBy) {
		return getReadableDb().query(th.getTableName(), null, where, params, null, null, orderBy);
	}

	/**
	 * Execute a query which returns all rows in the entity table.
	 *
	 * Calling method MUST close the {@link Cursor}!
	 *
	 * @return Cursor
	 */
	protected Cursor queryAll() {
		return query(null, null, null);
	}

	/**
	 * Executes a query which returns all rows in the entity table
	 * that match the fields of the example object having values other
	 * than the defaults.
	 *
	 * Calling method MUST close the {@link Cursor}!
	 *
	 * @return Cursor
	 */
	protected Cursor queryByExample(T obj) {
		return th.buildFilter(this.load(), obj).exec();
	}

	/**
	 * Converts all rows in a {@link Cursor} to a List of objects.
	 *
	 * @param c Cursor
	 * @return List<T>
	 */
	public List<T> asList(Cursor c) {
		// TODO consider returning Iterable<T> instead
		try {
			ArrayList<T> resultList = new ArrayList<T>();
			for (boolean hasItem = c.moveToFirst(); hasItem; hasItem = c.moveToNext()) {
				T obj = th.newInstance(c);
				resultList.add(obj);
			}
			return resultList;
		} finally {
			c.close();
		}
	}

	/**
	 * Converts a {@link Cursor} to an object. If there is more than one
	 * row in the Cursor, throws {@link TooManyResultsException}.
	 *
	 * @param c Cursor
	 * @return An entity
	 */
	public T asObject(Cursor c) {
		try {
			if (c.getCount() == 1) {
				c.moveToFirst();
				return th.newInstance(c);
			} else if (c.getCount() > 1) {
				throw new TooManyResultsException("Cursor returned " + c.getCount() + " rows");
			}
			return null;
		} finally {
			c.close();
		}
	}

	protected SQLiteDatabase getWritableDb() {
		return getDbHelper(mContext).getWritableDatabase();
	}

	protected SQLiteDatabase getReadableDb() {
		return getDbHelper(mContext).getReadableDatabase();
	}

}


package com.tri.persistence.jpql;

import java.util.ArrayList;
import java.util.Collection;

/**
 *

 * Logical structure item of a {@literal SQL} Where Clause (actually an
 * {@literal SQL} predicate). There are implementations for logically
 * {@code AND}/{@code OR} ({@link WhereAnd}, {@link WhereOr}) collections and
 * sub-queries ( {@link WhereSubquery}).
 *

 *

 * This class contains most needed helper methods to build the Where Clause of
 * an SQL Statement.
 *

 */
abstract public class WhereItems extends WhereItem {

	protected ArrayList<WhereItem> items = new ArrayList<WhereItem>();

	/**
	 * Constructor
	 *
	 * @param builder
	 *            {@link QueryBuilder} to associate
	 */
	public WhereItems(final QueryBuilder builder) {
		super(builder);
	}

	@Override
	public Object clone() throws CloneNotSupportedException {
		final WhereItems clone = (WhereItems) super.clone();
		// deep copy
		clone.items = new ArrayList<WhereItem>(items.size());
		for (WhereItem item : items) {
			clone.items.add((WhereItem) item.clone());
		}
		return clone;
	}

	/**
	 * Associate given {@link QueryBuilder} with this object and all of its
	 * items.
	 *
	 * @param builder
	 *            {@link QueryBuilder} to associate
	 */
	void setBuilder(final QueryBuilder builder) {
		super.setBuilder(builder);
		for (WhereItem item : items) {
			item.setBuilder(builder);
		}
	}

	/**
	 * Add a {@link WhereItem} to this object.
	 *
	 * @param item
	 *            WhereItem to be added
	 * @return this object
	 */
	public WhereItem add(final WhereItem item) {
		items.add(item);
		item.setBuilder(builder());
		return this;
	}

	/**
	 * Adds a simple textual comparison predicate.
	 *
	 * @param predicate
	 *            comparison predicate, e.g. {@code field=:whatever}
	 * @return this object
	 */
	public WhereItems add(final String predicate) {
		items.add(new WhereTextual(builder(), predicate));
		return this;
	}

	public boolean isEmpty() {
		return items.isEmpty();
	}

	/**
	 * Adds an {@literal SQL} {@code AND} clause.
	 *
	 * @return the added {@code AND} clause as {@link WhereAnd} object
	 */
	public WhereAnd and() {
		final WhereAnd and = new WhereAnd(builder());
		items.add(and);
		return and;
	}

	/**
	 * Adds an {@literal SQL} {@code OR} clause.
	 *
	 * @return the added {@code OR} clause as {@link WhereOr} object
	 */
	public WhereOr or() {
		final WhereOr or = new WhereOr(builder());
		items.add(or);
		return or;
	}

	/**
	 * Adds an {@literal SQL} {@code IN} predicate.
	 *
	 * @param expression
	 *            {@literal SQL} expression, e.g. expression in
	 *            {@code expression IN (...)}, actually the left part of the
	 *            predicate
	 * @param collection
	 *            collection of literal values
	 * @return this object
	 */
	public <V extends Object> WhereItems in(final String expression,
			final Collection<V> collection) {
		items.add(new WhereIn(builder(), expression, false, collection));
		return this;
	}

	/**
	 * Adds an {@literal SQL} {@code IN} predicate.
	 *
	 * @param expression
	 *            {@literal SQL} expression, e.g. expression in
	 *            {@code expression IN (...)}, actually the left part of the
	 *            predicate
	 * @param array
	 *            array literal values
	 * @return this object
	 */
	public <V extends Object> WhereItems in(final String expression,
			final V... array) {
		items.add(new WhereIn(builder(), expression, false, array));
		return this;
	}

	/**
	 * Adds a {@code NOT IN} predicate.
	 *
	 * @param expression
	 *            SQL expression, e.g. expression in
	 *            {@code expression NOT IN (...)}, actually the left part of the
	 *            predicate
	 * @param collection
	 *            collection of literal values
	 * @return this object
	 */
	public <V extends Object> WhereItems notIn(final String expression,
			final Collection<V> collection) {
		items.add(new WhereIn(builder(), expression, true, collection));
		return this;
	}

	/**
	 * Adds a "NOT IN" predicate.
	 *
	 * @param expression
	 *            SQL expression, e.g. "expression" of
	 *            "expression NOT IN (...)", actually the left part of the
	 *            predicate
	 * @param array
	 *            array of literal values
	 * @return this object
	 */
	public <V extends Object> WhereItems notIn(final String expression,
			final V... array) {
		items.add(new WhereIn(builder(), expression, true, array));
		return this;
	}

	/**
	 * Adds a sub-query predicate.
	 *
	 * @param lhsPredicate
	 *            left hand side of the predicate, i.e. expression and operator,
	 *            e.g. "field IN" or "EXISTS"
	 * @return the added subquery builder
	 */
	public QueryBuilder subquery(final String lhsPredicate) {
		final WhereSubquery subquery = new WhereSubquery(builder(),
				lhsPredicate);
		items.add(subquery);
		return subquery.getQueryBuilder();
	}

}


package io.github.agentsoz.jill.example.tokenpassing;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.core.GlobalState;
import io.github.agentsoz.jill.lang.Agent;
import io.github.agentsoz.jill.lang.Goal;
import io.github.agentsoz.jill.lang.Plan;
import io.github.agentsoz.jill.lang.PlanStep;
import io.github.agentsoz.jill.util.Log;

import java.util.Map;

/**
 *
ReceiveToken2 class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
public class ReceiveToken2 extends Plan {

  /**
   *
Constructor for ReceiveToken2.

   *
   * @param agent a {@link io.github.agentsoz.jill.lang.Agent} object.
   * @param goal a {@link io.github.agentsoz.jill.lang.Goal} object.
   * @param name a {@link java.lang.String} object.
   */
  public ReceiveToken2(Agent agent, Goal goal, String name) {
    super(agent, goal, name);
    body = steps;
  }

  /**
   * {@inheritDoc}.
   */
  @Override
  public boolean context() {
    int myid = getAgent().getId();
    Token2 goal = (Token2) getGoal();
    return (myid == goal.getAgent());
  }

  /**
   * {@inheritDoc}.
   */
  @Override
  public void setPlanVariables(Map<String, Object> vars) {
    // No plan bindings to worry about
  }

  PlanStep[] steps = {new PlanStep() {
    public void step() {
      Token2 msg = (Token2) getGoal();
      int myid = getAgent().getId();
      // Agent0 is the book keeper
      if (myid == 0) {
        // Check if we are done with the rounds
        if (TokenAgent2.rounds != msg.getRound()) {
          // Not done, so start the next round
          int newRound = msg.getRound() + 1;
          msg.setRound(newRound);
          Log.debug("round " + newRound);
        } else {
          // All done, so return
          Log.debug("rounds complete");
          return;
        }
      }
      // Send the token to the next agent
      int nextAgent = (myid + 1) % GlobalState.agents.size();
      msg.setAgent(nextAgent);
      getAgent().send(nextAgent, msg);
    }
  },};
}


package io.github.agentsoz.jill.example.hanoi;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.lang.Agent;
import io.github.agentsoz.jill.lang.Goal;
import io.github.agentsoz.jill.lang.Plan;
import io.github.agentsoz.jill.lang.PlanStep;

import java.util.Map;

/**
 *
MoveTower class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
public class MoveTower extends Plan {

  Solve solve;

  /**
   * Creates a MoveTower plan.
   *
   * @param agent the agent that has this plan
   * @param goal the goal that this plan handles
   * @param name a name for this plan
   */
  public MoveTower(Agent agent, Goal goal, String name) {
    super(agent, goal, name);
    solve = (Solve) goal;
    body = steps;
  }

  /**
   * {@inheritDoc}.
   */
  @Override
  public boolean context() {
    return true; // null indicates true
  }

  /**
   * {@inheritDoc}.
   */
  @Override
  public void setPlanVariables(Map<String, Object> var) {
    // TODO Auto-generated method stub
  }

  /*package*/ void log() {
    Board board = ((Player) getAgent()).getBoard();
    Player.out
        .println("Moving disc " + solve.disc + " from pin " + solve.src + " to " + solve.dest);
    board.move(solve.src, solve.dest);
    Player.out.println(board.toString());
  }

  PlanStep[] steps = {new PlanStep() {
    public void step() {
      if (solve.disc == 1) {
        log();
      }
    }
  }, new PlanStep() {
    public void step() {
      if (solve.disc != 1) {
        post(new Solve("", solve.disc - 1, solve.src, solve.spare, solve.dest));
      }
    }
  }, new PlanStep() {
    public void step() {
      if (solve.disc != 1) {
        log();
      }
    }
  }, new PlanStep() {
    public void step() {
      if (solve.disc != 1) {
        post(new Solve("", solve.disc - 1, solve.spare, solve.dest, solve.src));
      }
    }
  },};
}


package io.github.agentsoz.jill.lang;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.util.Stack255;

/**
 * Manages the intention stacks of the agent (maximum number of allowed stacks is 255).
 *
 * @author dsingh
 * @version $Id: $Id
 */
public final class IntentionStacks {

  /** Stack of intention stacks. **/
  private final Stack255 stacks;

  /** Index of the active stack. **/
  private int activeStack;

  /**
   * Creates an intentions stack.
   */
  IntentionStacks() {
    stacks = new Stack255((byte) 8, (byte) 2); // set of intention stacks
    getEmptyIntentionStack(); // add a single stack to start with
    activeStack = 0; // set it as the active stack
  }

  /**
   * Gets the active intentions stack.
   * @return the active stack
   */
  Stack255 getActiveStack() {
    return (Stack255) stacks.get(activeStack);
  }

  /**
   * Makes the next intentions stack active using a round robin scheme.
   * @return the newly active stack.
   */
  Stack255 nextActiveStack() {
    activeStack = (activeStack + 1) % stacks.size();
    return (Stack255) stacks.get(activeStack);
  }

  /**
   * Returns an empty intentions stack.
   * Creates a new intentions stack and adds it to the list of stacks if needed.
   * @return the newly created stack
   */
  Stack255 getEmptyIntentionStack() {
    // If the active stack is empty then return it (don't check other stacks)
    if (!stacks.isEmpty() && getActiveStack().isEmpty()) {
      return getActiveStack();
    }
    // else create an empty stack, add it to the list ot stacks, and return it
    Stack255 stack = new Stack255((byte) 8, (byte) 2);
    stacks.push(stack);
    return stack;
  }

  int cleanup() {
    if (stacks.size() <= 1) {
      // nothing to clean if we have only one stack
      return stacks.size();
    }
    int size = stacks.size();
    Stack255 newStacks = new Stack255((byte) stacks.size(), (byte) 1);
    // filter out the empty stacks; but keep the last one empyy or not
    while (!stacks.isEmpty()) {
      Stack255 stack = (Stack255) stacks.pop();
      if (stacks.isEmpty() || !stack.isEmpty()) {
        // always add the last one; else add if not empty
        newStacks.push(stack);
      }
    }
    // write back the filtered stack set
    while (!newStacks.isEmpty()) {
      Stack255 stack = (Stack255) newStacks.pop();
      stacks.push(stack);
    }
    if (stacks.size() != size) {
      activeStack = 0; // reset the active stack if stacks size has changed
    }
    return stacks.size();
  }

}


package io.github.agentsoz.jill.lang;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.config.GlobalConstant.PlanSelectionPolicy;
import io.github.agentsoz.jill.core.beliefbase.Belief;
import io.github.agentsoz.jill.core.beliefbase.BeliefBaseException;
import io.github.agentsoz.jill.core.beliefbase.abs.ABeliefStore;
import io.github.agentsoz.jill.util.Log;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;

/**
 * Stores the set of bindings for a given plan type, and used for meta level reasoning.
 *
 * @author dsingh
 * @version $Id: $Id
 */
public class PlanBindings {

  private final Map<Plan, Set<Belief>> bindings;
  private int cachedsize;
  private final Random rand;

  /**
   * Creates a new plan binding.
   *
   * @param rand the random number generator to use for when selecting plan instances with
   *        {@link io.github.agentsoz.jill.config.GlobalConstant.PlanSelectionPolicy#RANDOM} policy
   */
  public PlanBindings(Random rand) {
    this.rand = (rand == null) ? new Random() : rand;
    bindings = new LinkedHashMap<Plan, Set<Belief>>();
    cachedsize = 0;
  }

  /**
   * Add the set of bindings for a given plan to this store. Any previously stored bindings for this
   * plan will be replaced.
   *
   * @param plan the plan type
   * @param planBindings the available bindings
   */
  public void add(Plan plan, Set<Belief> planBindings) {
    if (plan == null) {
      return;
    }
    // remove any old bindings, making sure to decrement the cached size
    if (this.bindings.containsKey(plan)) {
      Set<Belief> oldBindings = this.bindings.remove(plan);
      if (oldBindings == null || oldBindings.isEmpty()) {
        cachedsize--;
      } else {
        cachedsize -= oldBindings.size();
      }
    }
    // add this binding and update the cached size
    this.bindings.put(plan, planBindings);
    if (planBindings == null || planBindings.isEmpty()) {
      cachedsize++;
    } else {
      cachedsize += planBindings.size();
    }
  }

  /**
   * Returns a set of plan types that have bindings. For each plan type there may be various
   * bindings which can be retrieved using {@link #getBindings(Plan)}
   *
   * @return set of plan types
   */
  public Set<Plan> getPlans() {
    return bindings.keySet();
  }

  /**
   * Returns the set of bindings available for the given plan type. An empty set is representative
   * of plans whose context conditions do not bind any variables. A {@code null} set indicates that
   * no variable bindings exist for the given plan, as is the case when the context condition of the
   * plan simply returns true.
   *
   * @param plan the plan type
   * @return set of available bindings for this plan type
   */
  public Set<Belief> getBindings(Plan plan) {
    return bindings.get(plan);
  }

  /**
   * Clears all plan bindings from this store.
   */
  public void clear() {
    bindings.clear();
    cachedsize = 0;
  }

  /**
   * Returns the total number of bindings in this store. This is the sum of all plan bindings. Note
   * that plans with no bindings are counted as 1.
   *
   * @return the number of bindings in this store
   */
  public int size() {
    return cachedsize;
  }

  /*
   * Gets the plan binding at the given index, where 0 <= index < size returned by {@link
   * #size()}. The returned plan contains the variable bindings.
   *
   * @param index the index of the bound plan instance to retrieve
   *
   * @return the plan instance at this index
   */
  /*
   * public Plan get(int index) { int i = 0; for (Plan plan : bindings.keySet()) { HashSet<Belief>
   * vars = bindings.get(plan); boolean bindingsExist = (vars != null && !vars.isEmpty()); i +=
   * bindingsExist ? vars.size() : 1; if (i <= index) { continue; } if (bindingsExist) {
   * setPlanVariables(plan.getAgent(), plan, vars, index-(i-vars.size())); } return plan; } return
   * null; }
   */

  /**
   * Selects a plan instance from the set of plan bindings, using the given policy.
   *
   * @param policy the policy to use for plan selection
   * @return the selected plan, or {@code null} if something went wrong
   */
  public Plan selectPlan(PlanSelectionPolicy policy) {
    Plan plan = null;
    int index = 0;
    switch (policy) {
      case FIRST:
      case LAST:
        Plan[] plans = bindings.keySet().toArray(new Plan[0]);
        plan = (policy == PlanSelectionPolicy.FIRST) ? plans[0] : plans[plans.length - 1];
        index = (policy == PlanSelectionPolicy.FIRST) ? 0 : plans.length - 1;
        setPlanVariables(plan.getAgent(), plan, bindings.get(plan), index);
        break;
      case RANDOM:
        plan = selectPlanAtRandom();
        break;
      default:
        // TODO: ignore remaining polic
        break;
    }
    return plan;
  }

  /**
   * Selects a plan instance at random from the set of plan bindings.
   *
   * @return a randomly selected plan instance, or null if ther are no bindings to choose from
   */
  private Plan selectPlanAtRandom() {
    Plan plan = null;
    Set<Belief> vars = null;
    int index = rand.nextInt(size());
    int idx = 0;
    boolean bindingsExist = false;
    for (Plan p : bindings.keySet()) {
      vars = bindings.get(p);
      bindingsExist = (vars != null && !vars.isEmpty());
      idx += bindingsExist ? vars.size() : 1;
      if (idx > index) {
        plan = p;
        if (bindingsExist) {
          index = index - (idx - vars.size());
          setPlanVariables(plan.getAgent(), plan, vars, index);
        }
        break;
      }
    }
    return plan;
  }

  /**
   * Sets the plan instance variables using the given results set.
   *
   * @param agent the agent for which this operation applies
   * @param planInstance the plan instance that is to be populated
   * @param results the beliefs set representing all plan bindings
   * @param choice index of the belief that is to be used to populate the plan instance variables
   */
  private final void setPlanVariables(Agent agent, Plan planInstance, Set<Belief> results,
      int choice) {
    if (agent == null || planInstance == null) {
      return;
    }
    Belief belief = getResultAtIndex(results, choice);
    if (belief == null) {
      return;
    }
    Object[] tuple = belief.getTuple();
    if (tuple == null) {
      return;
    }
    int index = 0;
    HashMap<String, Object> vars = new HashMap<String, Object>();
    for (Object o : belief.getTuple()) {
      try {
        String fieldname = ABeliefStore.getFieldName(agent.getId(), belief.getBeliefset(), index);
        vars.put(fieldname, o);
      } catch (BeliefBaseException e) {
        Log.error(
            "Agent " + agent.getId() + " could not retrive belief set field: " + e.getMessage());
      }
      index++;
    }
    planInstance.setPlanVariables(vars);
  }

  /**
   * Gets the result at the given index from the results set.
   *
   * @param results results set (implementation must support predictable iteration order)
   * @param index the index within the set {@code (0 < index < results.size())} to retrieve
   * @return the result at the given index, or null if there was an error
   */
  private Belief getResultAtIndex(Set<Belief> results, int index) {
    Belief belief = null;
    if (!(results == null || index < 0 || index >= results.size())) {
      int idx = 0;
      for (Belief b : results) {
        if (idx == index) {
          belief = b;
          break;
        }
        idx++;
      }
    }
    return belief;
  }

}


package io.github.agentsoz.jill.struct;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

/**
 *
GoalPlanType class.

 *
 * @author dsingh
 * @version $Id: $Id
 * @since 0.3.4
 */
public class GoalPlanType extends AObject {

  private byte[] parents;
  private byte[] children;

  /**
   * Creates a new Goal-Plan type object.
   *
   * @param str a name for this object
   */
  public GoalPlanType(String str) {
    super(str);
    parents = null;
    children = null;
  }

  /**
   * Gets the parents of this object in the Goal-Plan tree.
   *
   * @return array of parent IDs, or null if this object has no parents
   */
  public byte[] getParents() {
    if (parents == null) {
      return null;
    }
    byte[] arr = new byte[parents.length];
    System.arraycopy(parents, 0, arr, 0, arr.length);
    return arr;
  }

  /**
   * Adds a parent for this object.
   *
   * @param parent ID of the parent
   */
  public void addParent(byte parent) {
    parents = grow(parents, 1);
    parents[parents.length - 1] = parent;
  }

  /**
   * Gets all the children of this object in the Goal-Plan tree.
   *
   * @return array of children IDs, or null if this object has no children
   */
  public byte[] getChildren() {
    if (children == null) {
      return null;
    }
    byte[] arr = new byte[children.length];
    System.arraycopy(children, 0, arr, 0, arr.length);
    return arr;
  }

  /**
   * Adds a new child for this object.
   *
   * @param child ID of the child
   */
  public void addChild(byte child) {
    children = grow(children, 1);
    children[children.length - 1] = child;
  }

  /**
   * Grows the given array by the given size.
   *
   * @param bytes the array to grow
   * @param increment the size by which to grow it
   * @return the new extended array with all the contents of the old array copied over
   */
  public static byte[] grow(byte[] bytes, int increment) {
    if (bytes == null) {
      return new byte[1];
    }
    byte[] temp = new byte[bytes.length + increment];
    System.arraycopy(bytes, 0, temp, 0, bytes.length);
    return temp;
  }

}


package io.github.agentsoz.jill.util;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.FileAppender;

import org.slf4j.LoggerFactory;

/**
 *
Log class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
public final class Log {

  private static Logger logger;

  /**
   * This class cannot be instantiated.
   */
  private Log() {

  }

  /**
   *
info.

   *
   * @param msg a {@link java.lang.String} object.
   */
  public static void info(String msg) {
    logger.info(msg);
  }

  /**
   *
trace.

   *
   * @param msg a {@link java.lang.String} object.
   */
  public static void trace(String msg) {
    logger.trace(msg);
  }

  /**
   *
warn.

   *
   * @param msg a {@link java.lang.String} object.
   */
  public static void warn(String msg) {
    logger.warn(msg);
  }

  /**
   *
debug.

   *
   * @param msg a {@link java.lang.String} object.
   */
  public static void debug(String msg) {
    logger.debug(msg);
  }

  /**
   *
error.

   *
   * @param msg a {@link java.lang.String} object.
   */
  public static void error(String msg) {
    logger.error(msg);
  }

  /**
   * Creates a new logger.
   *
   * @param name a name for the logger
   * @param level the logging level for the logger
   * @param file the file to output all logging to
   * @return the created logger
   */
  public static Logger createLogger(String name, Level level, String file) {
    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    PatternLayoutEncoder ple = new PatternLayoutEncoder();
    ple.setPattern("%date %level [%thread] %logger{10} [%file:%line]%n%msg%n%n");
    ple.setContext(lc);
    ple.start();
    FileAppender<ILoggingEvent> fileAppender = new FileAppender<ILoggingEvent>();
    fileAppender.setFile(file);
    fileAppender.setEncoder(ple);
    fileAppender.setAppend(false);
    fileAppender.setContext(lc);
    fileAppender.start();
    logger = (Logger) LoggerFactory.getLogger(name);
    logger.detachAndStopAllAppenders(); // detach console (doesn't seem to work)
    logger.addAppender(fileAppender); // attach file appender
    logger.setLevel(level);
    logger.setAdditive(true); // set to true if root should log too

    return logger;
  }

  /**
   * Returns a agent name string to use for logging.
   *
   * @param idx ID of the agent
   * @return string to use for logging
   * @since 0.3.4
   */
  public static String logPrefix(int idx) {
    return "Agent " + idx + ":";
  }

  /**
   * Returns a formatted string for logging the duration between two timestamps.
   *
   * @param start start time in ms
   * @param end end time in ms
   * @return formatted duration string
   * @since 0.3.4
   */
  public static String formattedDuration(long start, long end) {
    return "(" + (end - start) + " ms)";
  }

}


package io.github.agentsoz.jill.lang;

import java.util.Map;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

/**
 *
Abstract Plan class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
public abstract class Plan {

  private final Agent agent;
  private final Goal goal;
  private byte index;

  public PlanStep[] body;

  /**
   * Creates a new plan for the gven goal for the given agent.
   *
   * @param agent the agent to which this plan applies
   * @param goal the goal that this plan handles
   * @param name a name for this plan
   */
  public Plan(Agent agent, Goal goal, String name) { // NOPMD - ignore unused param 'name'
    this.agent = agent;
    this.goal = goal;
  }

  /**
   *
context.

   *
   * @return a boolean.
   */
  public abstract boolean context();

  /**
   *
setPlanVariables.

   *
   * @param vars a {@link java.util.Map} object.
   */
  public abstract void setPlanVariables(Map<String, Object> vars);

  /**
   *
Getter for the field agent.

   *
   * @return a {@link io.github.agentsoz.jill.lang.Agent} object.
   */
  public Agent getAgent() {
    return agent;
  }

  /**
   *
Getter for the field goal.

   *
   * @return a {@link io.github.agentsoz.jill.lang.Goal} object.
   */
  public Goal getGoal() {
    return goal;
  }

  /**
   *
Posts a top-level goal in a new intention stack

   *
   * @param goal a {@link io.github.agentsoz.jill.lang.Goal} object.
   */
  public void post(Goal goal) {
    getAgent().post(goal);
  }

  /**
   *
Adds a new (sub) goal to the active intention stack

   *
   * @param goal a {@link io.github.agentsoz.jill.lang.Goal} object.
   */
  public void subgoal(Goal goal) {
    getAgent().subgoal(goal);
  }

  /**
   * Performs a single step of this plan, i.e., progresses this intention.
   */
  public void step() {
    if (body == null || body.length == 0 || index < 0 || index >= body.length) {
      return;
    }
    body[index++].step();
  }

  /**
   * Checks if this plan has finished executing.
   *
   * @return true if this plan has finished executing, false otherwise
   */
  public boolean hasfinished() {
    return (body == null || body.length == 0 || index < 0 || index >= body.length);
  }

}


package io.github.agentsoz.jill.struct;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

/**
 *
AgentType class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
public class AgentType extends AObject {

  private Class<?> agentClass;

  private byte[] goals; // This agent's goal-plan tree

  /**
   *
Constructor for AgentType.

   *
   * @param name a {@link java.lang.String} object.
   */
  public AgentType(String name) {
    super(name);
    goals = null;
  }

  /**
   *
Getter for the field agentClass.

   *
   * @return a {@link java.lang.Class} object.
   */
  public Class<?> getAgentClass() {
    return agentClass;
  }

  /**
   *
Setter for the field agentClass.

   *
   * @param agentClass a {@link java.lang.Class} object.
   */
  public void setAgentClass(Class<?> agentClass) {
    this.agentClass = agentClass;
  }

  /**
   * Gets the list of goals for this agent.
   *
   * @return array of goal IDs
   */
  public byte[] getGoals() {
    if (goals == null) {
      return null;
    }
    byte[] arr = new byte[goals.length];
    System.arraycopy(goals, 0, arr, 0, arr.length);
    return arr;
  }

  /**
   * Sets the list of goals for this agent.
   *
   * @param arr array of goal IDs
   */
  public void setGoals(byte[] arr) {
    if (arr == null) {
      goals = null;
      return;
    }
    goals = new byte[arr.length];
    System.arraycopy(arr, 0, goals, 0, goals.length);
  }

  /**
   *
addGoal.

   *
   * @param goal a byte.
   */
  public void addGoal(byte goal) {
    goals = GoalPlanType.grow(goals, 1);
    goals[goals.length - 1] = goal;
  }
}


package io.github.agentsoz.jill;

/*-
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3 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 General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.config.Config;
import io.github.agentsoz.jill.core.GlobalState;
import io.github.agentsoz.jill.core.IntentionSelector;
import io.github.agentsoz.jill.core.ProgramLoader;
import io.github.agentsoz.jill.lang.JillExtension;

import java.util.Scanner;

/**
 *
Program class.

 *
 * @author dsingh
 * @version $Id: $Id
 * @since 0.3.4
 */
public final class Program {

  /**
   * This class cannot be instantiated.
   */
  private Program() {}

  /**
   * Waits for user to press a key before continuing. Useful for connecting to a profiler
   */
  static void pauseForUserInput() {
    System.out.println("Press the Enter/Return key to continue..");
    Scanner in = new Scanner(System.in);
    in.nextLine();
    in.close();
  }

  /**
   * Initialises the intention selection pools.
   *
   * @param nagents total number of agents to distribution between the intention selection pools
   * @param ncores total number of cores
   */
  public static void initIntentionSelectionPools(int nagents, int ncores) {
    Main.poolsize = (nagents > ncores) ? (nagents / ncores) : 1;
    Main.npools = (nagents > ncores) ? ncores : nagents;
  }

  /**
   * Starts the intention selection threads that each handle a pool of agents.
   *
   * @param config the global configuration object
   */
  static void initIntentionSelectionThreads(Config config) {
    int ncores = config.getNumThreads();
    Main.intentionSelectors = new IntentionSelector[ncores];
    for (int i = 0; i < Main.npools; i++) {
      Main.intentionSelectors[i] = new IntentionSelector(i, config.getRandomSeed());
    }
  }

  /**
   * Starts the intention selection threads.
   */
  static void startIntentionSelectionThreads() {
    for (int i = 0; i < Main.npools; i++) {
      Thread thread = new Thread(Main.intentionSelectors[i]);
      thread.setName("jill-" + i);
      thread.start(); // start and wait at the entry barrier
    }
  }

  /**
   * Stops the intention selection threads.
   */
  static void shutdownIntentionSelectionThreads() {
    for (int i = 0; i < Main.npools; i++) {
      Main.intentionSelectors[i].shutdown();
    }
  }

  /**
   * Loads any configured extensions (see {@link JillExtension}).
   *
   * @param config a valid configuration
   * @return true if successfully loaded, false otherwise
   */
  static boolean loadExtensions(Config config) {
    if (config.getExtensions() == null) {
      return true;
    }
    for (Config.ExtensionData extensionData : config.getExtensions()) {
      JillExtension extension = ProgramLoader.loadExtension(extensionData.getClassname());
      if (extension != null) {
        Program.registerExtension(extension);
        extension.init(extensionData.getArgs().toArray(new String[0]));
      } else {
        return false;
      }
    }
    return true;
  }

  /**
   * Registers a new Jill extension.
   *
   * @param extension the extension to register
   */
  public static void registerExtension(JillExtension extension) {
    if (extension != null) {
      GlobalState.eventHandlers.add(extension);
      Main.logger.info("Registered Jill extension: " + extension);
    } else {
      Main.logger.warn("Cannot register null extension; will ignore.");
    }
  }

}


package io.github.agentsoz.jill.example.tokenpassing;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.core.GlobalState;
import io.github.agentsoz.jill.core.beliefbase.BeliefBaseException;
import io.github.agentsoz.jill.core.beliefbase.BeliefSetField;
import io.github.agentsoz.jill.lang.Agent;
import io.github.agentsoz.jill.lang.AgentInfo;
import io.github.agentsoz.jill.util.Log;

import java.io.PrintStream;

/**
 *
TokenAgent3 class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
@AgentInfo(hasGoals = {"io.github.agentsoz.jill.example.tokenpassing.Token3"})
public class TokenAgent3 extends Agent {

  /** Constant out. */
  public static PrintStream out;
  private static final String beliefset = "neighbour";

  // Defaults
  /** Constant rounds=1. */
  public static int rounds = 1;
  private static int neighbourhood = 2;

  /**
   *
Constructor for TokenAgent3.

   *
   * @param str a {@link java.lang.String} object.
   */
  public TokenAgent3(String str) {
    super(str);
  }

  /**
   * {@inheritDoc}.
   */
  @Override
  public void start(PrintStream writer, String[] params) {
    parse(params);
    out = writer;

    // Create a new belief set about neighbours
    BeliefSetField[] fields = {new BeliefSetField("name", String.class, true),};

    try {
      // Attach this belief set to this agent
      this.createBeliefSet(beliefset, fields);

      int numAgents = GlobalState.agents.size();

      // Cannot have more neighbours than agents
      if (neighbourhood >= numAgents) {
        Log.error("Agent " + getName() + " cannot add " + neighbourhood
            + " neighbours, when there are only " + numAgents + " agents all up");
        System.exit(-1);
      }
      // Add beliefs about neighbours
      for (int i = 1; i <= neighbourhood; i++) {
        int neighbour = (getId() + i) % numAgents;
        this.addBelief(beliefset, Integer.toString(neighbour));
        Log.debug("Agent " + getName() + " added neighbour " + neighbour);
      }
      Log.debug("Agent " + getName() + " is initialising with neighbourhood size of "
          + neighbourhood + " on each side (so " + (neighbourhood * 2) + " neighbours)");

      // Let Agent 0 start the token passing
      if (getId() == 0) {
        Log.debug("round 1");
        Token3 token = new Token3(1, 1);
        token.setHops(1);
        send(1, token);
      }
    } catch (BeliefBaseException e) {
      Log.error(e.getMessage());
    }
  }

  /**
   * Parses the command line arguments.
   *
   * @param args the command line arguments
   */
  public static void parse(String[] args) {
    for (int i = 0; i < args.length; i++) {
      switch (args[i]) {
        case "-neighbourhood":
          if (i + 1 < args.length) {
            i++;
            try {
              neighbourhood = Integer.parseInt(args[i]);
            } catch (NumberFormatException e) {
              Log.warn("Value '" + args[i] + "' is not a number");
            }
          }
          break;
        case "-rounds":
          if (i + 1 < args.length) {
            i++;
            try {
              rounds = Integer.parseInt(args[i]);
            } catch (NumberFormatException e) {
              Log.warn("Value '" + args[i] + "' is not a number");
            }
          }
          break;
        default:
          // Ignore all other arguments
          break;
      }
    }
  }
}


package io.github.agentsoz.jill.core;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.core.beliefbase.abs.ABeliefStore;
import io.github.agentsoz.jill.lang.JillExtension;
import io.github.agentsoz.jill.util.AObjectCatalog;

import java.util.HashSet;
import java.util.Set;

/**
 * A catalog of all known agent, goal and plan types.
 *
 * @author dsingh
 * @version $Id: $Id
 */
public final class GlobalState {

  /**
   * Catalog of all agent types in the system, loaded at runtime. Each entry in the catalog is
   * assigned an automatically created ID.
   */
  public static AObjectCatalog agentTypes;

  /**
   * Catalog of all goal types in the system, loaded at runtime. Each entry in the catalog is
   * assigned an automatically created ID.
   */
  public static AObjectCatalog goalTypes;

  /**
   * Catalog of all plan types in the system, loaded at runtime. Each entry in the catalog is
   * assigned an automatically created ID.
   */
  public static AObjectCatalog planTypes;

  /**
   * Catalog of all initialised agents in the system. Each entry in the catalog is assigned an
   * automatically created ID.
   */
  public static AObjectCatalog agents;

  /**
   * The central belief base to store all beliefs of all agents.
   */
  public static ABeliefStore beliefbase;

  /**
   * The list of registered external event handlers (jill extensions).
   */
  public static Set<JillExtension> eventHandlers = new HashSet<JillExtension>();

  /**
   * This class cannot be instantiated.
   */
  private GlobalState() {

  }

  /**
   * Resets the global state.
   */
  public static void reset() {
    agentTypes = new AObjectCatalog("agentTypes", 5, 5);
    goalTypes = new AObjectCatalog("goalTypes", 10, 5);
    planTypes = new AObjectCatalog("planTypes", 20, 5);
    agents = null;
    beliefbase = null;
    eventHandlers = new HashSet<JillExtension>();
  }
}


package io.github.agentsoz.jill.core;

import io.github.agentsoz.jill.Main;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.core.GlobalState;
import io.github.agentsoz.jill.lang.Agent;
import io.github.agentsoz.jill.lang.AgentInfo;
import io.github.agentsoz.jill.lang.Goal;
import io.github.agentsoz.jill.lang.GoalInfo;
import io.github.agentsoz.jill.lang.JillExtension;
import io.github.agentsoz.jill.lang.Plan;
import io.github.agentsoz.jill.lang.PlanInfo;
import io.github.agentsoz.jill.struct.AgentType;
import io.github.agentsoz.jill.struct.GoalType;
import io.github.agentsoz.jill.struct.PlanType;
import io.github.agentsoz.jill.util.AObjectCatalog;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;

/**
 *
ProgramLoader class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
public final class ProgramLoader {

  private static final Logger logger = LoggerFactory.getLogger(Main.LOGGER_NAME);

  private static final String knowsNothing =
      "annotation. Without it, the BDI execution engine does not know anything ";

  /**
   * This class cannot be instantiated.
   */
  private ProgramLoader() {

  }

  /**
   * Creates a given number of agents of a given Class, and adds the newly created agents to the
   * given store.
   *
   * @param className the fully qualified Java classname for the agents begin created
   * @param num the number of agents (class instances) to create
   * @param agents the store to which these agents should be added
   * @return true if agents were successfully created and added, false otherwise
   */
  public static boolean loadAgent(String className, int num, AObjectCatalog agents) {

    // Load the Agent class
    Class<?> aclass = loadClass(className, Agent.class);
    if (aclass == null) {
      return false;
    }

    // Save this agent type to the catalog of known agent types
    AgentType atype = new AgentType(className);
    atype.setAgentClass(aclass);
    GlobalState.agentTypes.push(atype);

    // Find the goals that this agent has
    String[] goals = getGoalsFromAgentInfoAnnotation(aclass);
    if (goals.length == 0) {
      return false;
    }

    // First pass: get the goals and their plans (flat goal-plan list)
    loadGoalPlanNodes(atype, goals);

    // Second pass: complete the goal-plan hierarchy
    completeGoalPlanHierarchy();

    // Now create the specified number of instances of this agent type
    createAgentsInCatalog(agents, atype, aclass, num);

    // return success
    return true;
  }

  private static boolean loadGoalPlanNodes(AgentType atype, String[] goals) {
    for (int i = 0; i < goals.length; i++) {
      // Load the Goal class
      Class<?> gclass = loadClass(goals[i], Goal.class);
      if (gclass == null) {
        return false;
      }
      // Found the goal class, so add this goal to the catalog of known goal types
      GoalType gtype = new GoalType(gclass.getName());
      gtype.setGoalClass(gclass);
      GlobalState.goalTypes.push(gtype);
      atype.addGoal((byte) gtype.getId());
      // Find the plans that this goal has
      String[] plans = getPlansFromGoalsInfoAnnotation(gclass);
      if (plans.length == 0) {
        return false;
      }
      // Process the plans
      if (!processPlansForGoal(gtype, plans)) {
        return false;
      }
    }
    return true;
  }

  /**
   * Loads the given plan classes and sets up parent-child links with the given goal type.
   *
   * @param gtype the goal for which the list of plans is provided
   * @param plans list of plans to be loaded
   * @return true if successful, false otherwise
   */
  private static boolean processPlansForGoal(GoalType gtype, String[] plans) {
    for (int j = 0; j < plans.length; j++) {
      // Load the Plan class
      Class<?> pclass = loadClass(plans[j], Plan.class);
      if (pclass == null) {
        return false;
      }
      // Found the plan class, so add this plan to the catalog of known plan types
      logger.info("Found Plan " + pclass.getName() + " that handles Goal " + gtype.getName());
      PlanType ptype = new PlanType(pclass.getName());
      ptype.setPlanClass(pclass);
      GlobalState.planTypes.push(ptype);
      // Set up the parent/child links between them (makings of a goal-plan tree)
      ptype.addParent((byte) gtype.getId());
      gtype.addChild((byte) ptype.getId());
    }
    return true;
  }

  /**
   * Completes the Goal-Plan hierarchy linkages between all {@link GlobalState#goalTypes} and
   * {@link GlobalState#planTypes}.
   *
   * @return true if successful, false otherwise
   */
  private static boolean completeGoalPlanHierarchy() {
    for (int i = 0; i < GlobalState.planTypes.size(); i++) {
      PlanType ptype = (PlanType) GlobalState.planTypes.get(i);
      String[] postsGoals = getGoalsFromPlanInfoAnnotation(ptype.getPlanClass());
      // A @PlanInfo is optional, and only present if this plan posts goals
      if (postsGoals == null) {
        continue;
      }
      // But if @PlanInfo was given then it cannot be incomplete
      if (postsGoals.length == 0) {
        return false;
      }
      // All good, so find the goals that this plan posts and set up the Goal-Plan tree links
      for (String goalname : postsGoals) {
        GoalType gtype = (GoalType) GlobalState.goalTypes.find(goalname);
        if (gtype == null) {
          logger.error("Plan " + ptype.getName() + " posts goal " + goalname
              + "which is not a known goal type.");
          return false;
        }
        // Found a goal posted by the plan, so setup the parent-child links
        ptype.addChild((byte) gtype.getId());
        gtype.addParent((byte) ptype.getId());
      }
    }
    return true;
  }

  /**
   * Creates the specified number of agent instances of the given type and adds them to the catalog.
   *
   * @param agents the catalog to add agents to
   * @param atype the type of agents to create
   * @param aclass the class of that agent type
   * @param num the number of instances of that agent (class) to create
   */
  private static void createAgentsInCatalog(AObjectCatalog agents, AgentType atype, Class<?> aclass,
      int num) {
    int added = 0;
    try {
      for (int i = 0; i < num; i++) {
        // Create a new instance (name prefix 'a' for agents)
        Agent agent =
            (Agent) (aclass.getConstructor(String.class).newInstance("a" + Integer.toString(i)));
        // Assign the static goal plan tree hierarchy to this instance
        agent.setGoals(atype.getGoals());
        // Add this instance to the catalog of agent instances
        agents.push(agent);
        added++;
      }
      logger.info("Finished loading {} agents", added);

    } catch (NoSuchMethodException | SecurityException | InstantiationException
        | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
      logger.error("Could not create instance of class " + aclass.getName());
    }

  }

  /**
   * Gets the list of goals specified in the @AgentInfo annotation of the given agent class.
   *
   * @param aclass the agent class containing the @AgentInfo annotation
   * @return list of goals specified in the @AgentInfo annotation, or an empty array if unsuccessful
   */
  private static String[] getGoalsFromAgentInfoAnnotation(Class<?> aclass) {
    // Find the goals that this agent has
    Annotation annotation = aclass.getAnnotation(AgentInfo.class);
    if (annotation == null) {
      logger.error("Agent " + aclass.getName() + " is missing the "
          + "@AgentInfo(hasGoals={\"package.GoalClass1, package.GoalClass2, ...\"}) " + knowsNothing
          + "about this agent's goals and plans.");
      return new String[0];
    }
    AgentInfo ainfo = (AgentInfo) annotation;
    String[] goals = ainfo.hasGoals();
    if (goals.length == 0) {
      logger.error("Agent " + aclass.getName()
          + " does not have any goals defined. Was expecting something like "
          + "@AgentInfo(hasGoals={\"package.GoalClass1, package.GoalClass2, ...\"}) " + knowsNothing
          + "about this agent's goals and plans.");
    }
    return goals;
  }

  /**
   * Gets the list of plans specified in the @GoalInfo annotation of the given goal class.
   *
   * @param gclass the goal class containing the @GoalInfo annotation
   * @return list of plans specified in the @GoalInfo annotation, or an empty array if unsuccessful
   */
  private static String[] getPlansFromGoalsInfoAnnotation(Class<?> gclass) {
    // Find the plans that this goal has
    Annotation annotation = gclass.getAnnotation(GoalInfo.class);
    if (annotation == null) {
      logger.error("Goal " + gclass.getName() + " is missing the "
          + "@GoalInfo(hasPlans={\"package.PlanClass1, package.PlanClass2, ...\"}) " + knowsNothing
          + "about which plans can handle this goal.");
      return new String[0];
    }
    GoalInfo ginfo = (GoalInfo) annotation;
    String[] plans = ginfo.hasPlans();
    if (plans.length == 0) {
      logger.error("Goal " + gclass.getName()
          + " does not have any plans defined. Was expecting something like "
          + "@GoalInfo(hasPlans={\"package.PlanClass1, package.PlanClass2, ...\"}) " + knowsNothing
          + "about which plans can handle this goal.");
    }
    return plans;
  }

  /**
   * Gets the list of goals specified in the @PlanInfo annotation of the given plan class.
   *
   * @param pclass the plan class containing the @PlanInfo annotation
   * @return list of goals specified in the @PlanInfo annotation; or null if the annotioan was not
   *         present; or an empty array if the annotation has errors
   */
  private static String[] getGoalsFromPlanInfoAnnotation(Class<?> pclass) {
    Annotation annotation = pclass.getAnnotation(PlanInfo.class);
    PlanInfo pinfo = (PlanInfo) annotation;
    // A @PlanInfo is optional, and only present if this plan posts goals
    if (pinfo == null) {
      return null;
    }
    String[] postsGoals = pinfo.postsGoals();
    if (postsGoals.length == 0) {
      logger.error("Plan " + pclass.getName() + " has incomplete "
          + "@PlanInfo(postsGoals={\"package.GoalClass1\", \"package.GoalClass2\", ...})) "
          + "annotation");
    } else {
      logger.info("Plan " + pclass.getName() + " posts " + postsGoals.length + " goals");
    }
    return postsGoals;
  }

  /**
   * Loads the class of given name and type.
   *
   * @param className the fully qualified class name
   * @param classType the class type to check against
   * @return the loaded class, or null if unsuccessful
   */
  private static Class<?> loadClass(String className, Class<?> classType) {
    Class<?> aclass = null;
    try {
      aclass = Class.forName(className);
    } catch (ClassNotFoundException e) {
      logger.error("Class not found: " + className, e);
      return null;
    }
    if (!classType.isAssignableFrom(aclass)) {
      logger.error("Class '" + className + "' is not of type " + classType.getName());
      return null;
    }
    logger.info("Found class " + className + " of type " + classType.getName());
    return aclass;
  }

  /**
   * Loads a Jill extension.
   *
   * @param className the fully qalified Java classname of the extension
   * @return an instance of the Jill extension class
   */
  public static JillExtension loadExtension(String className) {
    JillExtension extension = null;
    Class<?> eclass;
    try {
      // Check that we have the extension class, else abort
      eclass = Class.forName(className);
      if (!JillExtension.class.isAssignableFrom(eclass)) {
        logger
            .error("Class '" + className + "' does not implement " + JillExtension.class.getName());
        return null;
      }
      logger.info("Loading extension " + className);
      extension = (JillExtension) (eclass.newInstance());
    } catch (ClassNotFoundException | SecurityException | InstantiationException
        | IllegalAccessException | IllegalArgumentException e) {
      logger.error("Could not load extension " + className, e);
    }
    return extension;
  }
}


package io.github.agentsoz.jill.struct;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.config.GlobalConstant;
import io.github.agentsoz.jill.util.AString;

/**
 * AObject is meant to serve as a base class for all objects that require a unique identifier and a
 * name. It stores this information in a compact form which is useful for in-memory storage.
 *
 * @author dsingh
 * @version $Id: $Id
 */
public class AObject {

  /**
   * The unique identifier for this object. Upto 2^31 unique ids are supported
   */
  private int id = GlobalConstant.NULLID;

  /** The String name of this object, stored as a compacted byte array. */
  private byte[] name;

  /**
   * Constructs an AObject with the given str name and id of NULLID.
   *
   * @param str the name of this object
   * @see GlobalConstant#NULLID
   */
  public AObject(String str) {
    this.name = AString.toBytes(str);
  }

  /**
   * Gets the id of this object.
   *
   * @return the object id
   */
  public int getId() {
    return id;
  }

  /**
   * Sets the id of this object.
   *
   * @param id the new id
   */
  public void setId(int id) {
    this.id = id;
  }

  /**
   * Gets the name of this object.
   *
   * @return the object name
   */
  public String getName() {
    return AString.toString(name);
  }

  /**
   * Sets the name of this object.
   *
   * @param str the new name
   */
  public void setName(String str) {
    this.name = AString.toBytes(str);
  }

  /**
   * Returns a String representation of this object.
   *
   * @return a {@link java.lang.String} object.
   */
  public String toString() {
    return AString.toString(name) + ":" + id;
  }

  /**
   * Checks if two objects have the same name. The check is case sensitive.
   *
   * @param obj1 the first object
   * @param obj2 the second object
   * @return true if the objects have the same non-null non-empty name, and false otherwise
   */
  public static boolean isNameEqual(AObject obj1, AObject obj2) {
    // Not equal if the names are null, or empty, or not the same size
    if (obj1.name == null || obj2.name == null || obj1.name.length != obj2.name.length
        || obj1.name.length == 0) {
      return false;
    }
    // Not equal if any name character is different
    for (int i = 0; i < obj1.name.length; i++) {
      if (obj1.name[i] != obj2.name[i]) {
        return false;
      }
    }
    // Else equal
    return true;
  }

}


package io.github.agentsoz.jill.util;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;

import io.github.agentsoz.jill.Main;
import io.github.agentsoz.jill.config.Config;
import io.github.agentsoz.jill.config.GlobalConstant;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;

/**
 *
ArgumentsLoader class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
public final class ArgumentsLoader {

  private static Config config;

  /**
   * This class cannot be instantiated.
   */
  private ArgumentsLoader() {

  }

  /**
   * Returns a usage string for the Jill command line arguments.
   *
   * @return the usage string
   */
  public static String usage() {
    return GlobalConstant.APP_HEADER + "\n\n" + "usage: " + Main.class.getName()
        + "  [options] --agent-class <agentclass> --num-agents <numagents>" + "\n"
        + "   --config <string>                 load configuration from string" + "\n"
        + "   --configfile <file>               load configuration from file" + "\n"
        + "   --exit-on-idle <boolean>          forces system exit when all agents are "
        + "idle (default is '" + GlobalConstant.EXIT_ON_IDLE + "')\n"
        + "   --help                            print this usage message and exit \n"
        + "   --plan-selection-policy <policy>  policy for selecting from plan instances "
        + "(FIRST, RANDOM, or LAST (default is '" + GlobalConstant.PLAN_SELECTION_POLICY + "')\n"
        + "   --plan-instances-limit <number>   maximum number of applicable plan instances "
        + "to consider (default is '" + GlobalConstant.PLAN_INSTANCES_LIMIT + "')\n";
  }

  /**
   * Parses the given command line arguments.
   *
   * @param args the command line arguments
   */
  public static void parse(String[] args) {
    for (int i = 0; args != null && i < args.length; i++) {
      // First parse args that don't require an option
      if ("--help".equals(args[i])) {
        abort(null);
      }
      // Now parse args that must be accompanied by an option
      if (i + 1 < args.length) {
        parseArgumentWithOption(args[i], args[++i]); // force increment the counter
      }
    }
    // Abort if required args were not given
    if (config == null) {
      abort("Configuration file or string was not given");
    } else if (config.getAgents() == null || config.getAgents().isEmpty()) {
      abort("Configuration is missing agents specification");
    }
  }

  /**
   * Parses the given command line argument and associated option. Will abort if an unrecoverable
   * error occurs.
   *
   * @param arg the argument to parse
   * @param opt the options to parse for that argument
   */
  private static void parseArgumentWithOption(String arg, String opt) {
    switch (arg) {
      case "--config":
        config = loadConfigFromString(opt);
        break;
      case "--configfile":
        config = loadConfigFromFile(opt);
        break;
      case "--exit-on-idle":
        GlobalConstant.EXIT_ON_IDLE = Boolean.parseBoolean(opt);
        break;
      case "--plan-selection-policy":
        try {
          GlobalConstant.PLAN_SELECTION_POLICY = GlobalConstant.PlanSelectionPolicy.valueOf(opt);
        } catch (IllegalArgumentException e) {
          abort("Unknown plan selection policy '" + opt + "'");
        }
        break;
      case "--plan-instances-limit":
        try {
          GlobalConstant.PLAN_INSTANCES_LIMIT = Integer.parseInt(opt);
        } catch (NumberFormatException e) {
          abort("Option value '" + opt + "' is not a number");
        }
        break;
      default:
        // Ignore any other arguments (which may be used by components external to Jill)
        break;
    }
  }

  private static void abort(String err) {
    int withCode = 0;
    if (err != null) {
      withCode = 1;
      System.err.println("\nERROR: " + err + "\n");
    }
    System.out.println(usage());
    System.exit(withCode);
  }

  /**
   *
getExtensions.

   *
   * @return an array of {@link java.lang.String} objects.
   */
  public static String[] getExtensions() {
    return new String[0];
  }

  /**
   *
Getter for the field config.

   *
   * @return a {@link io.github.agentsoz.jill.config.Config} object.
   */
  public static Config getConfig() {
    return config;
  }

  /**
   * Loads the Jill startup configuration object.
 Configuration is specified at run time via one
   * of the following two options:

{@code --config <string>}

   * {@code --configfile <file>}

 The contents of {@code <string>} or {@code <file>} are
   * parsed in exactly the same way. The expected syntax is JSON format. If both options are
   * specified, then last specified option will overrule.

   *
   * @return the Jill startup configuration object
   */
  static Config loadConfigFromString(String str) {
    Gson gson = new Gson();
    Config config = null;
    try {
      config = gson.fromJson(str, Config.class);
    } catch (JsonSyntaxException e) {
      abort("Invalid JSON syntax in " + str + ": " + e.getMessage());
    }
    return config;
  }

  static Config loadConfigFromFile(String str) {
    Gson gson = new Gson();
    Config config = null;
    try {
      config = gson.fromJson(new BufferedReader(new FileReader(str)), Config.class);
    } catch (JsonSyntaxException e) {
      abort("Invalid JSON syntax in " + str + ": " + e.getMessage());
    } catch (JsonIOException e) {
      abort("Could not read config from " + str + ": " + e.getMessage());
    } catch (FileNotFoundException e) {
      abort("Config file " + str + " not found: " + e.getMessage());
    }
    return config;
  }

  /**
   *
reset.

   */
  public static void reset() {
    config = null;
  }
}


package io.github.agentsoz.jill.core.beliefbase;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import ch.qos.logback.classic.Level;

import io.github.agentsoz.jill.core.beliefbase.abs.ABeliefStore;
import io.github.agentsoz.jill.util.Log;

import java.util.Set;

/**
 *
Abstract BeliefBase class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
public abstract class BeliefBase {

  /**
   *
createBeliefSet.

   *
   * @param agentid a int.
   * @param name a {@link java.lang.String} object.
   * @param fields an array of {@link io.github.agentsoz.jill.core.beliefbase.BeliefSetField}
   *        objects.
   * @return a boolean.
   * @throws io.github.agentsoz.jill.core.beliefbase.BeliefBaseException if any.
   */
  public abstract boolean createBeliefSet(int agentid, String name, BeliefSetField[] fields)
      throws BeliefBaseException;

  /**
   *
addBelief.

   *
   * @param agentid a int.
   * @param beliefsetName a {@link java.lang.String} object.
   * @param tuple a {@link java.lang.Object} object.
   * @return a boolean.
   * @throws io.github.agentsoz.jill.core.beliefbase.BeliefBaseException if any.
   */
  public abstract boolean addBelief(int agentid, String beliefsetName, Object... tuple)
      throws BeliefBaseException;

  /**
   *
eval.

   *
   * @param agentid a int.
   * @param query a {@link java.lang.String} object.
   * @return a boolean.
   * @throws io.github.agentsoz.jill.core.beliefbase.BeliefBaseException if any.
   */
  public abstract boolean eval(int agentid, String query) throws BeliefBaseException;

  /**
   *
query.

   *
   * @param agentid a int.
   * @param key a {@link java.lang.String} object.
   * @return a {@link java.util.Set} object.
   * @throws io.github.agentsoz.jill.core.beliefbase.BeliefBaseException if any.
   */
  public abstract Set<Belief> query(int agentid, String key) throws BeliefBaseException;

  /**
   * Sample program to test belief base evaluation speeds.
   *
   * @param args command line arguments
   * @throws BeliefBaseException on belief base update or evaluation errors
   */
  public static void main(String[] args) throws BeliefBaseException {
    // Configure logging
    Log.createLogger("", Level.INFO, "BeliefBase.log");
    // BeliefBase bb = new H2BeliefBase("jdbc:h2:mem:agents;CACHE_SIZE=1048576");

    String bs1 = "neighbour";
    String bs2 = "hascar";

    long t0;
    long t1;

    int numAgents = 10000;
    int numNeighbours = 1000;
    BeliefBase bb = new ABeliefStore(numAgents, 4);
    Log.info("Initialising " + numAgents + " agents with " + numNeighbours + " beliefs each");
    BeliefSetField[] fields1 = {new BeliefSetField("name", String.class, true),
        new BeliefSetField("gender", String.class, false),};
    BeliefSetField[] fields2 = {new BeliefSetField("name", String.class, true),
        new BeliefSetField("car", Boolean.class, false),};

    long t2 = System.currentTimeMillis();
    for (int i = 0; i < numAgents; i++) {
      t0 = System.currentTimeMillis();
      bb.createBeliefSet(i, bs1, fields1);
      t1 = System.currentTimeMillis();
      Log.debug("Created belief set '" + bs1 + "' " + Log.formattedDuration(t0, t1));
      t0 = System.currentTimeMillis();
      for (int j = 0; j < numNeighbours; j++) {
        bb.addBelief(i, bs1, "agent" + j, ((j % 2) == 0) ? "male" : "female");
      }
      t1 = System.currentTimeMillis();
      Log.debug("Agent " + i + " added " + numNeighbours + " beliefs to belief set '" + bs1 + "' ("
          + (t1 - t0) + " ms)");
    }
    long t3 = System.currentTimeMillis();
    Log.info("Finished initialising " + numAgents + " agents with " + numNeighbours
        + " beliefs each for belief set '" + bs1 + "' " + Log.formattedDuration(t2, t3));

    t2 = System.currentTimeMillis();
    for (int i = 0; i < numAgents; i++) {
      t0 = System.currentTimeMillis();
      bb.createBeliefSet(i, bs2, fields2);
      t1 = System.currentTimeMillis();
      Log.debug("Created belief set '" + bs2 + "' " + Log.formattedDuration(t0, t1));
      t0 = System.currentTimeMillis();
      for (int j = 0; j < numNeighbours; j++) {
        bb.addBelief(i, bs2, "agent" + j, ((j % 2) == 0) ? true : false);
      }
      t1 = System.currentTimeMillis();
      Log.debug("Agent " + i + " added " + numNeighbours + " beliefs to belief set '" + bs2 + "' ("
          + (t1 - t0) + " ms)");
    }
    t3 = System.currentTimeMillis();
    Log.info("Finished initialising " + numAgents + " agents with " + numNeighbours
        + " beliefs each for belief set '" + bs2 + "' " + Log.formattedDuration(t2, t3));

    final String opstr = ".name=agent";
    int agentId = 0;
    int neighbourId = 0;
    doEval(bb, agentId, bs1 + opstr + neighbourId);

    agentId = 0;
    neighbourId = numNeighbours - 1;
    doEval(bb, agentId, bs1 + opstr + neighbourId);

    agentId = numAgents - 1;
    neighbourId = numNeighbours - 1;
    doEval(bb, agentId, bs1 + opstr + neighbourId);

    agentId = 0;
    neighbourId = 0;
    doEval(bb, agentId, bs1 + opstr + neighbourId);

    agentId = 0;
    neighbourId = numNeighbours - 1;
    doEval(bb, agentId, bs1 + opstr + neighbourId);

    agentId = numAgents - 1;
    neighbourId = numNeighbours - 1;
    doEval(bb, agentId, bs1 + opstr + neighbourId);
  }

  /**
   * Evaluates the given query on the given belief base for the agent.
   *
   * @param bb the belief base to query
   * @param agentId the agent for which the query applies
   * @param query the belief query
   * @throws BeliefBaseException on query evaluation error
   * @since 0.3.4
   */
  public static void doEval(BeliefBase bb, int agentId, String query) throws BeliefBaseException {
    final long t0 = System.currentTimeMillis();
    bb.eval(agentId, query);
    final long t1 = System.currentTimeMillis();
    Log.info("Agent " + agentId + " searched for '" + query + "' " + Log.formattedDuration(t0, t1));
  }

}


package io.github.agentsoz.jill.util;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.config.GlobalConstant;
import io.github.agentsoz.jill.struct.AObject;

/**
 *
AObjectCatalog class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
public class AObjectCatalog extends AObject {

  private int nextid = GlobalConstant.NULLID + 1;
  private final int increment;
  private AObject[] objects;

  /**
   * Constructs a object catalog.
   *
   * @param name s nsme for the catalog
   * @param size the initial size of the catalog
   * @param inc the size by which the catalog should grow when it reaches capacity
   */
  public AObjectCatalog(String name, int size, int inc) {
    super(name);
    increment = inc;
    objects = new AObject[size];
  }

  /**
   * Gets the object at the given index of the catalog.
   *
   * @param index the index of the object
   * @return the object at that index
   */
  public AObject get(int index) {
    if (index >= 0 && index < objects.length) {
      return objects[index];
    }
    return null;
  }

  /**
   * Find an object by name. Can be very expensive for large catalogs, since a name comparison is
   * performed in sequence on the objects in the catalog, until a match is found. Search is case
   * sensitive.
   *
   * @param name the name to find
   * @return an AObject with a matching name, or null if not found
   */
  public AObject find(String name) {
    for (int i = 0; i < nextid; i++) {
      if (objects[i].getName().equals(name)) {
        return objects[i];
      }
    }
    return null;
  }

  /**
   * Pushes a new object to the top of the catalog.
   *
   * @param obj the object to add
   */
  public void push(AObject obj) {
    if (obj == null || obj.getId() != GlobalConstant.NULLID) {
      return;
    }
    // Grow if we are at capacity
    if (nextid == objects.length) {
      grow();
    }
    obj.setId(nextid);
    objects[nextid++] = obj;
  }

  /**
   * Pops (removes) the object at the top of the catalog.
   *
   * @return the object at the top, or null if the catalog is empty
   */
  public AObject pop() {
    if (nextid > GlobalConstant.NULLID) {
      nextid--;
      AObject obj = objects[nextid];
      objects[nextid] = null;
      return obj;
    }
    return null;
  }

  /**
   *
size.

   *
   * @return a int.
   */
  public int size() {
    return nextid;
  }

  /**
   * Grows the Catalog by a factor of {@link #increment}.
   */
  private void grow() {
    AObject[] temp = new AObject[objects.length + increment];
    System.arraycopy(objects, 0, temp, 0, objects.length);
    objects = temp;
  }
}


package io.github.agentsoz.jill.example.tokenpassing;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.core.GlobalState;
import io.github.agentsoz.jill.core.beliefbase.BeliefBaseException;
import io.github.agentsoz.jill.lang.Agent;
import io.github.agentsoz.jill.lang.Goal;
import io.github.agentsoz.jill.lang.Plan;
import io.github.agentsoz.jill.lang.PlanStep;
import io.github.agentsoz.jill.util.Log;

import java.util.Map;

/**
 *
ReceiveToken3 class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
public class ReceiveToken3 extends Plan {

  /*package*/ String neighbour;

  /**
   *
Constructor for ReceiveToken3.

   *
   * @param agent a {@link io.github.agentsoz.jill.lang.Agent} object.
   * @param goal a {@link io.github.agentsoz.jill.lang.Goal} object.
   * @param name a {@link java.lang.String} object.
   */
  public ReceiveToken3(Agent agent, Goal goal, String name) {
    super(agent, goal, name);
    body = steps;
  }

  /**
   * {@inheritDoc}.
   */
  @Override
  public boolean context() {
    Agent agent = getAgent();
    int myid = agent.getId();
    int goalid = ((Token3) getGoal()).getAgent();
    try {
      return (myid == goalid) && agent.eval("neighbour.name = *");
    } catch (BeliefBaseException e) {
      Log.error(e.getMessage());
    }
    return false;
  }

  /**
   * {@inheritDoc}.
   */
  @Override
  public void setPlanVariables(Map<String, Object> vars) {
    for (String attribute : vars.keySet()) {
      if ("name".equals(attribute)) {
        neighbour = (String) (vars.get(attribute));
      }
    }
  }

  PlanStep[] steps = {new PlanStep() {
    public void step() {
      Token3 msg = (Token3) getGoal();
      // int myid = getAgent().getId();
      // Agent performaing the last hop is the book keeper
      if (msg.getHops() == GlobalState.agents.size()) {
        // Check if we are done with the rounds
        if (TokenAgent3.rounds != msg.getRound()) {
          // Not done, so start the next round
          int newRound = msg.getRound() + 1;
          msg.setRound(newRound);
          msg.setHops(1);
          Log.debug("round " + newRound);
        } else {
          // All done, so return
          Log.debug("rounds complete");
          return;
        }
      }
      // Send the token to the next agent
      // int nextAgent = (myid+1)%GlobalState.agents.size();
      int nextAgent = Integer.parseInt(neighbour);
      msg.setAgent(nextAgent);
      msg.setHops(msg.getHops() + 1);
      getAgent().send(nextAgent, msg);
    }
  },};
}


package io.github.agentsoz.jill.util;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

/**
 * Implements a stack of objects, with maximum capacity of 255.
 *
 * @author dsingh
 * @version $Id: $Id
 */
public class Stack255 {

  /** Maximum capacity of the stack (byte size). */
  private static final int MAXIMUM_CAPACITY = 255;

  /** Current size of the stack. */
  private int size;

  /**
   * Specifies the increment by which the capacity should be extended, once the stack reaches full
   * capacity.
   */
  private final int increment;

  /**
   * Objects in this stack.
   */
  private Object[] objects;

  /**
   * Creates a stack with the given initial capacity, to be extended by the given incrementSize as
   * needed upon reaching full capacity. Typically it should suffice to initialise the stack with
   * the full capacity, if it is known upfront, since increasing capacity at runtime is expensive
   * (it requires an array copy using {@link java.lang.System#arraycopy(Object,int,Object,int,int)
   * System.arraycopy(...)}).
   *
   * <p>The maximum capacity of the stack is 255 (the size of one byte). There is no provision to
   * shrink the stack at the moment.
   *
   * @param initialCapacity the initial capacity of the stack
   * @param incrementSize capacity is increased by this amount when the stack becomes full; if
   *        incrementSize <= 0, then the default value of 1 is used
   */
  public Stack255(byte initialCapacity, byte incrementSize) {
    size = 0;
    increment = (0xff & incrementSize) | 1;
    objects = new Object[initialCapacity & 0xff];
  }

  /**
   * Gets the object at the given index in the catalog.
   *
   * @param idx the position of the Object
   * @return the Object, or null if the index is invalid
   */
  public Object get(int idx) {
    int index = idx & 0xff;
    if (isEmpty()) {
      // System.err.println("index "+index+" is invalid as stack is empty");
      return null;
    } else if (index < 0 || index >= size) {
      // System.err.println("index "+index+" is outside of range [0,"+(size-1)+"]");
      return null;
    }
    return objects[index];
  }

  /**
   * Pushes an object on to the top of the stack.
   *
   * @param obj the Object to place on the stack
   * @return true if successfully added, false if the stack was full
   */
  public boolean push(Object obj) {
    // Cannot add beyond maximum capacity
    if (isFull()) {
      return false;
    }
    // Grow if we are at capacity
    if (size == objects.length) {
      grow();
    }
    objects[size++] = obj;
    return true;
  }

  /**
   * Pops the Object at the top of the stack.
   *
   * @return the Object, or null if the stack is empty
   */
  public Object pop() {
    if (isEmpty()) {
      return null;
    }
    size--;
    Object obj = objects[size];
    objects[size] = null;
    return obj;
  }

  /**
   * Gets the current size of the stack.
   *
   * @return the size of the stack
   */
  public int size() {
    return size & 0xff;
  }

  /**
   * Checks if the stack is empty.
   *
   * @return true if the stack is empty, false otherwise
   */
  public boolean isEmpty() {
    return size == 0;
  }

  /**
   * Checks if the stack is full.
   *
   * @return true if the stack is full, false otherwise
   */
  public boolean isFull() {
    return size == MAXIMUM_CAPACITY;
  }

  /**
   * Gets the current capacity of the stack.
   *
   * @return the capacity of the stack
   */
  public int capacity() {
    return objects.length;
  }

  /**
   * Grows the stack capacity by {@link #increment} up to the maximum capacity of 255 (byte size).
   *
   * @return true if the stack was successfully increased, false otherwise
   */
  private boolean grow() {
    if (objects.length == MAXIMUM_CAPACITY) {
      // Cannot grow beyond the maximum capacity
      return false;
    }
    int newsize = objects.length + increment;
    if (newsize > MAXIMUM_CAPACITY) {
      newsize = MAXIMUM_CAPACITY;
    }
    Object[] temp = new Object[newsize];
    System.arraycopy(objects, 0, temp, 0, objects.length);
    objects = temp;
    return true;
  }
}


package io.github.agentsoz.jill.example.hanoi;

/*
 * #%L
 * Jill Cognitive Agents Platform
 * %%
 * Copyright (C) 2014 - 2019 by its authors. See AUTHORS file.
 * %%
 * 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 3
 * 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
 * General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public License along with this program.
 * If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
 * #L%
 */

import io.github.agentsoz.jill.lang.Agent;
import io.github.agentsoz.jill.lang.AgentInfo;
import io.github.agentsoz.jill.util.Log;

import java.io.PrintStream;

/**
 *
Player class.

 *
 * @author dsingh
 * @version $Id: $Id
 */
@AgentInfo(hasGoals = {"io.github.agentsoz.jill.example.hanoi.Solve"})
public class Player extends Agent {

  /** Constant out. */
  public static PrintStream out;

  // Defaults
  private static int ndiscs = 5;
  private Board board;

  /**
   *
Constructor for Player.

   *
   * @param name a {@link java.lang.String} object.
   */
  public Player(String name) {
    super(name);
  }

  /**
   *
Getter for the field board.

   *
   * @return a {@link io.github.agentsoz.jill.example.hanoi.Board} object.
   */
  public Board getBoard() {
    return board;
  }

  /**
   * {@inheritDoc}.
   */
  @Override
  public void start(PrintStream writer, String[] params) {
    out = writer;

    // Parse the arguments
    parse(params);

    // Create the board
    board = new Board(ndiscs);
    out.println("Initialised hanoi board with " + ndiscs + " discs:");
    out.println(board.toString());

    // Solve the board
    post(new Solve("s", ndiscs, 0, 2, 1));
  }

  /**
   * Parses the command line arguments.
   *
   * @param args the command line arguments
   */
  public static void parse(String[] args) {
    for (int i = 0; i < args.length; i++) {
      if ("-discs".equals(args[i]) && (i + 1 < args.length)) {
        i++;
        try {
          ndiscs = Integer.parseInt(args[i]);
        } catch (NumberFormatException e) {
          Log.warn("Number od discs value '" + args[i] + "' is not a number");
        }
      }
    }
  }

}