package bdi4jade.extension.remediation.goal;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import bdi4jade.core.BDIAgent;
import bdi4jade.event.GoalEvent;
import bdi4jade.event.GoalListener;
import bdi4jade.extension.remediation.graph.CauseEffectRelationship;
import bdi4jade.extension.remediation.logics.Fact;
import bdi4jade.goal.BeliefValueGoal;
import bdi4jade.goal.Goal;
import bdi4jade.goal.GoalStatus;

public class CauseEffectProblem implements GoalListener {

	public enum CauseEffectProblemStatus {
		CAUSE_PARTIALLY_RESOLVED, CAUSE_RESOLVED, FULLY_RESOLVED, MITIGATED, PARTIALLY_RESOLVED, UNSUCCESSFUL;
	}

	private final CauseEffectRelationship causeEffectRelationship;
	private Map<Fact, CauseFactorStatus> causeFactorStatus;
	private final BeliefValueGoal<?, ?> effectGoal;
	private final Goal parentGoal;
	private GoalStatus effectGoalStatus;
	private CauseEffectProblemStatus status;

	public CauseEffectProblem(BeliefValueGoal<?, ?> effectGoal, CauseEffectRelationship causeEffectRelationship,
			BDIAgent agent, Goal parentGoal) {
		this.effectGoal = effectGoal;
		this.parentGoal = parentGoal;
		this.causeEffectRelationship = causeEffectRelationship;
		if (parentGoal != null) {
			agent.addGoalListener(parentGoal, this);
		} else {
			agent.addGoalListener(effectGoal, this);
		}

		this.causeFactorStatus = new HashMap<>();
		for (Fact fact : causeEffectRelationship.getAllPossibleCauses()) {
			causeFactorStatus.put(fact, new CauseFactorStatus(fact));
		}

		this.effectGoalStatus = null;
		this.status = null;
	}

	public void setCauseFactorStatus(Set<CauseFactorStatus> cause) {
		this.causeFactorStatus = new HashMap<>();
		for (CauseFactorStatus cf : cause) {
			this.causeFactorStatus.put(cf.getFact(), cf);
		}
	}

	public Collection<CauseFactorStatus> getCauseFactorStatus() {
		return causeFactorStatus.values();
	}

	public CauseFactorStatus getCauseFactorStatus(Fact fact) {
		return causeFactorStatus.get(fact);
	}

	public Goal getEffectGoal() {
		return effectGoal;
	}

	public GoalStatus getEffectGoalStatus() {
		return effectGoalStatus;
	}

	public CauseEffectProblemStatus getStatus() {
		return status;
	}

	@Override
	public void goalPerformed(GoalEvent event) {
		if ((event.getGoal() == effectGoal || event.getGoal() == parentGoal) && event.getStatus().isFinished()) {
			setEffectGoalStatus(event.getStatus());
		}
	}

	public void setEffectGoalStatus(GoalStatus effectGoalStatus) {
		this.effectGoalStatus = effectGoalStatus;
	}

	public void setStatus(CauseEffectProblemStatus status) {
		this.status = status;
	}

	public CauseEffectRelationship getCauseEffectRelationship() {
		return causeEffectRelationship;
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("< ").append(effectGoal).append(" [").append(effectGoalStatus).append("], {\n");
		for (CauseFactorStatus cf : causeFactorStatus.values()) {
			sb.append("\t").append(cf).append("\n");
		}
		sb.append("} > = ").append(status);
		return sb.toString();
	}

}
