package at.oefai.aaa.agent.jam;

import java.io.Serializable;
import java.util.List;

import at.oefai.aaa.agent.jam.types.DList;
import at.oefai.aaa.agent.jam.types.IndexedMap;

/**
 * A JAM agent's plan library.
 * @author Marc Huber
 * @author Jaeho Lee
 */
public class PlanTable implements Serializable {
    // the tables store plans per relationname (goal-/conclude/perceive-name)
    // and indexable sequentially
    private IndexedMap<String,Plan> goalPlanMap = new IndexedMap<String,Plan>();
    private IndexedMap<String,Plan> concludePlanMap = new IndexedMap<String,Plan>();
    private IndexedMap<String,Plan> perceiveAssertPlanMap = new IndexedMap<String,Plan>();
    private IndexedMap<String,Plan> perceiveRetractPlanMap = new IndexedMap<String,Plan>();
    private Plan observer = null; // the observer plan, for cyclic functionality

    /** package level constructor */
    PlanTable() {
        // package level only
    }

    public Plan getObserver() {
        return this.observer;
    }

    public void setObserver(Plan p) {
        this.observer = p;
    }

    public void add(Plan plan) {
        if (plan.getGoalSpecification() != null) {
            String s = plan.getGoalSpecification().getGoal().getName();
            this.goalPlanMap.put(s, plan);
        } else if (plan.getConcludeSpecification() != null) {
            String s = plan.getConcludeSpecification().getName();
            this.concludePlanMap.put(s, plan);
        } else if (plan.getPerceiveAssertSpecification() != null) {
            String s = plan.getPerceiveAssertSpecification().getName();
            this.perceiveAssertPlanMap.put(s, plan);
        } else if (plan.getPerceiveRetractSpecification() != null) {
            String s = plan.getPerceiveRetractSpecification().getName();
            this.perceiveRetractPlanMap.put(s, plan);
        } else { // unreachable ?
            assert false : "unknown plantype wants to be added: " + plan.verboseString(null);
        }
    }

    /** Returns all the goal plans with the given goalname. */
    public DList<Plan> getGoalPlans(String goalname) {
        return this.goalPlanMap.getBucket(goalname);
    }

    /** Returns all the perceive ASSERT plans with the given relationname. */
    public DList<Plan> getPerceiveAssertPlans(String relationname) {
        return this.perceiveAssertPlanMap.getBucket(relationname);
    }

    /** Returns all the perceive RETRACT plans with the given relationname. */
    public DList<Plan> getPerceiveRetractPlans(String relationname) {
        return this.perceiveRetractPlanMap.getBucket(relationname);
    }

    /**
     * returns a new list that holds all conclude plans
     * @return list of conclude plans
     */
    public List<Plan> getConcludePlans() {
        return this.concludePlanMap.asList();
    }

    /** Displays a summary of all of the plans in the plan library */
    public String verboseString() {
        Plan plan;
        StringBuffer sb = new StringBuffer("PlanTable:\n");
        // Go through each entry in each map, use for(int) loop to get plan number
        for (int i = 0; i < this.goalPlanMap.size(); i++) {
            plan = this.goalPlanMap.get(i);
            sb.append("GoalPlan " + i + ":\n");
            sb.append("  Name:\t" + plan.getName() + "\n");
            sb.append("  #Constructs:\t" + plan.getBody().getNumConstructs() + "\n");
        }
        for (int i = 0; i < this.concludePlanMap.size(); i++) {
            plan = this.concludePlanMap.get(i);
            sb.append("ConcludePlan " + i + ":\n");
            sb.append("  Name:\t" + plan.getName() + "\n");
            sb.append("  #Constructs:\t" + plan.getBody().getNumConstructs() + "\n");
        }
        for (int i = 0; i < this.perceiveAssertPlanMap.size(); i++) {
            plan = this.perceiveAssertPlanMap.get(i);
            sb.append("PerceiveAssertPlan " + i + ":\n");
            sb.append("  Name:\t" + plan.getName() + "\n");
            sb.append("  #Constructs:\t" + plan.getBody().getNumConstructs() + "\n");
        }
        for (int i = 0; i < this.perceiveRetractPlanMap.size(); i++) {
            plan = this.perceiveRetractPlanMap.get(i);
            sb.append("PerceiveRetractPlan " + i + ":\n");
            sb.append("  Name:\t" + plan.getName() + "\n");
            sb.append("  #Constructs:\t" + plan.getBody().getNumConstructs() + "\n");
        }
        return sb.toString();
    }


}

