//----------------------------------------------------------------------------
// Copyright (C) 2018  João Faccin
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// To contact the authors:
// http://inf.ufrgs.br/prosoft/bdi4jade/
//
//----------------------------------------------------------------------------

package bdi4jade.extension.undo;

import java.util.Map;
import java.util.stream.Collectors;

import bdi4jade.core.AbstractBDIAgent;
import bdi4jade.core.Capability;
import bdi4jade.core.Intention;
import bdi4jade.event.GoalListener;
import bdi4jade.extension.remediation.logics.Predicate;
import bdi4jade.goal.Goal;
import bdi4jade.goal.PredicateGoal;

/**
 * This class is an extension of {@link AbstractBDIAgent}. It provides a method
 * to add reversible goals, i.e. goals with a corresponding
 * {@link GoalAchievementMetadata}, to the set of agent goals.
 * 
 * @author João Faccin
 */
public class RevertingBDIAgent extends AbstractBDIAgent {

	private static final long serialVersionUID = 7351855722581311736L;

	/**
	 * Adds a new goal to be achieved by this agent. Additionally, it creates and
	 * sets a corresponding {@link GoalAchievementMetadata} for the new goal.
	 * 
	 * @param dispatcher
	 *            the capability that dispatched this goal.
	 * @param goal
	 *            the goal to be achieved.
	 * @param goalListener
	 *            the listener to be notified.
	 * @param reversionTrigger
	 *            a list of {@link Predicate} that specifies the condition in which
	 *            a reversion of the actions performed to achieve this goal will be
	 *            activated.
	 * @param rollback
	 *            a flag that indicates the desire of a rollback in case of a plan
	 *            failure when achieving this goal.
	 * @param maxExecutedPlans
	 *            the number of plans that can be executed after achieving this goal
	 *            before the corresponding goal achievement metadata is discarded.
	 * @param maxTime
	 *            the time that can pass after achieving this goal before the
	 *            corresponding goal achievement metadata is discarded.
	 * @return true if the goal was added, false otherwise.
	 */
	public final boolean addGoal(Capability dispatcher, Goal goal, GoalListener goalListener,
			Map<Predicate, Boolean> reversionTrigger, Boolean rollback, Integer maxExecutedPlans, Integer maxTime) {

		if (super.addGoal(dispatcher, goal, goalListener)) {
			if (goal instanceof PredicateGoal<?>) {
				if (dispatcher instanceof RevertingCapability) {
					Intention intention = this.getIntentions().stream().filter(g -> g.getGoal().equals(goal))
							.collect(Collectors.toList()).get(0);
					((RevertingCapability) dispatcher).createGoalAchievementMetadata((PredicateGoal<?>) goal, intention,
							rollback, reversionTrigger, maxExecutedPlans, maxTime);
				}
			}
			return true;
		}
		return false;
	}

}
