/**
*	FChain.java - 
*   class for forward chaining engine
*/

import java.util.*;
import sheffield.*;
import pmatch.*; 

public class FChain {

    private ArrayList rules; // the rule set
    private Vector known_facts; // all facts given & deduced so far
    private MStringVector kfmvec; //the facts as an MStringVector
    private Vector to_pursue; //facts waiting for expansion
    private String f; //the fact currently being pursued
	private EasyWriter scr = new EasyWriter();

	
    public  FChain (ArrayList rl) {rules=rl;} //constructor is given the rule set
  
    public Vector getKF (){ return known_facts;} //accessor for known_facts
     
	
	// the forward chaining engine
    public Vector run_FC (Vector kf) { //is given starting facts
    	known_facts = new Vector();
    	to_pursue =new Vector();
    	known_facts.addAll(kf);
    	to_pursue.addAll(kf);
    	
    	while (!to_pursue.isEmpty()) { // continue until nothing left to pursue
    		scr.println("---------------");
    		scr.println("kf= "+known_facts);
    		scr.println("tp= "+to_pursue);
    		f= (String) to_pursue.get(0); //explore from first node on to_pursue - f
			to_pursue.remove(0); //& remove it from to_pursue
			
			scr.println("pursuing "+f);
			
			for (Iterator i = rules.iterator(); i.hasNext();){ //iterate over the rules looking for antes matching f 	
				Rule r = (Rule) i.next(); //next rule
				MStringVector antes = new MStringVector(r.getAntes()); //its antecedants as an MStringVector
				boolean res=antes.matchall(f); //match for f?
				
				
				if (res) { // match, go for the remaining antes
					scr.println("match for rule with antes "+r.getAntes());
					ArrayList partials = antes.getMatchDetails(); //matchall returns partial match list
					while (!partials.isEmpty()){ //explore each partial
						MatchDetails p=(MatchDetails) partials.get(0); //next partial
						partials.remove(0); // remove it
						HashMap con=p.getContext(); //its context
						String matcher = p.getMatcher(); //the ante which matched
						MStringVector rest = p.getRest(); // the rest
						
						if (rest.isEmpty()) {//no more antecedants - deduction
							MString cm = new MString(r.getConseq()); //consequent of the rule
							String deduction=cm.msubst(con); //substitute in it
							scr.println("Deduced "+ deduction);
							known_facts.add(deduction); //to get the deduction - add to known_facts and to_pursue
							to_pursue.add(deduction);
    						
							kfmvec=new MStringVector(known_facts); //set the known_facts up for matching
							}
							// there are more antes - can we mnatch them against known_facts?
							else {
							 String next_ante= (String)rest.firstElement(); //next ante to try
							 rest.remove(0); //remainder after that
							 scr.println("matching "+next_ante);
							 scr.println("in context "+con);
							 boolean cres=kfmvec.matchall(next_ante, con); //match against known facts
							 scr.println("result = "+cres);
							 if (cres) { //matches found, each one creates new partial
							 	ArrayList cp=kfmvec.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 (!partials.isEmpty())
			}//end of if (res)
		}//end of for over the rules
	}//end of while something to pursue
	return known_facts;
	} //end of run_FC
} //end of class
							