/**
*	ProdSys.java - 
*   class for production system engine
*/

import java.util.*;
import sheffield.*;
import pmatch.*; 

public class ProdSys {

    private ArrayList prods; // the prodn set
    private Vector stm; // the current short term memory
    
	private EasyWriter scr = new EasyWriter();

	
    public  ProdSys (ArrayList rl) { //constructor is given the prod set
    	prods=rl;
    	} 
  
	
	// the prodn system engine
    public Vector run_PS (Vector s) { //is given the initial stm
    	scr.println("RUNNING PRODUCTION SYSTEM");
    	stm = s;
    	boolean prod_fired=true;
    	
    	while (prod_fired) { // continue until no production fires
    		scr.println("------------------------------------------------------------------");
    		scr.println("STM= "+stm);
    		scr.println();
    		
    		prod_fired=false; //will be reset to true when a prodn is fired
    		
    		MStringVector stm_matcher=new MStringVector(stm);
			
			Iterator i = prods.iterator();
			
			while (i.hasNext()&&!prod_fired){ //iterate over the prods until one fires or run out
				Prodn r = (Prodn) i.next(); //next prodn
				MStringVector antes = new MStringVector(r.getAntes()); //its antecedants as an MStringVector
				ArrayList partials = new ArrayList(); // partial matches
				partials.add(new MatchDetails(new HashMap(),"",antes)); // initiallly 1 partial with all the antes & an empty context
				
				//try to develop partials by matching next ante
				//continue until partials run out or a prod fires
				
				while (!partials.isEmpty()&&!prod_fired){
					MatchDetails p=(MatchDetails) partials.get(0); //next partial
					partials.remove(0); // remove it
					HashMap con=p.getContext(); //its context
					MStringVector rest = p.getRest(); // the remaining antes
					
					//if no more antes and the prodn's predicate returns true in the context, fire the prodn
					if (rest.isEmpty()) {
						if (r.pred(con)){
							fire_prodn(r,con);
							prod_fired=true;
						}
					}
					
						else { //there are more antes, find matches for the first one & create new partials
						String next_ante= (String)rest.firstElement(); //next ante to try
						rest.remove(0); //remainder after that
				
						boolean cres=stm_matcher.matchall(next_ante, con); //match against stm
							 
							 if (cres) { //matches found, each one creates new partial
							 	ArrayList cp=stm_matcher.getMatchDetails();
							 	for (Iterator j = cp.iterator(); j.hasNext();){
							 		MatchDetails d = (MatchDetails) j.next();
							 		d.setRest(rest); //in which this ante is now removed
							 		} //these partials have remaining antes
							 	
							 	partials.addAll(0,cp); //put them at the front of the partial list
							 } //end of if (cres)
					    } //end of else to if rest.isEmpty
				} //end of while 3
			}//end of while 2
		}//end of while 1
		scr.println("RUN TERMINATED");
		return stm; // return final stm
	}// end of run_PS
	
	// fire a given prodn, given the context
	private void fire_prodn(Prodn p, HashMap c) {
		HashMap con=p.modify_context(c); //call the context modifier
		String name = p.getName();
 	    MStringVector addsm = new MStringVector(p.getAdds());//make MStringVectors for the prods adds, dels & remarks
 		MStringVector delsm = new MStringVector(p.getDels());
 		MStringVector remsm = new MStringVector(p.getRemarks());
 		
 		Vector adds=addsm.msubst(c); //use these to substitute for the context
 		Vector dels=delsm.msubst(c);
 		Vector rems=remsm.msubst(c);
 		
 		scr.println("Firing "+name);
 		scr.println(" in context "+c.toString());
 		
 		stm.removeAll(dels); //remove the deletions from the stm
 		stm.addAll(adds);    //add the additions
 		scr.println(name+" remarks:");
 		for (Iterator r=rems.iterator();r.hasNext();) {scr.println("  "+r.next());} //make the remarks
 		
 	}
 
}
		
							 	
			