/* RuleBase 

        Micro Projet ARTC 1997/1998
        (C) 1998 DPSV Team Touts Droits Réservés
        Marc-Aurèle DARCHE
        Emmanuel PIERRE
        Marc-Olivier VARROY
        Antoine SOULIEZ

*/

import java.util.*;
import java.io.*;
import java.awt.* ;

public class RuleBase {

 String name ;
 Hashtable variableList ;    // toutes les variables dans la base de règles
 Clause clauseVarList[];
 Vector ruleList ;           // liste de toutes les règles
 Vector conclusionVarList ;  // liste des variables
 Rule rulePtr ;              // pointeur courant sur la règle utilisée
 Clause clausePtr ;          // pointeur courant sur la clause utilisée
 Stack goalClauseStack;      // pour les buts et sous-buts

 static TextArea textArea1 ;
 public void setDisplay(TextArea txtArea) { textArea1 = txtArea; }

 RuleBase(String Name) { name = Name; }
 public static void appendText(String text) { textArea1.appendText(text); }

 // pour le tracage - affiche toutes les variables et leurs valeurs
 public void displayVariables(TextArea textArea) {

   Enumeration enum = variableList.elements() ;
   while(enum.hasMoreElements()) {
     RuleVariable temp = (RuleVariable)enum.nextElement() ;
     textArea.appendText("\n" + temp.name + " valeur = " + temp.value) ;
   }
 }

// pour le tracage - affiche toutes les règles
 public void displayRules(TextArea textArea) {
   textArea.appendText("\nBase de Regle: " + name + "\n");
   Enumeration enum = ruleList.elements() ;
   while(enum.hasMoreElements()) {
     Rule temp = (Rule)enum.nextElement() ;
     temp.display(textArea) ;
   }
 }

 // pour le tracage - affiche toutes les règles en conflit
 public void displayConflictSet(Vector ruleSet) {
   textArea1.appendText("\n" + " -- Ensemble des Regles en conflit:\n");
   Enumeration enum = ruleSet.elements() ;
   if (!(enum.hasMoreElements())) {
     textArea1.appendText("Aucune ! \n") ;
   }
   while(enum.hasMoreElements()) {
     Rule temp = (Rule)enum.nextElement() ;
     textArea1.appendText(temp.name + "(" + temp.numAntecedents()+ "), " ) ;
   }

 }


 // réinitialise la base de règles pour une nouvelle inférence
 // en mettant toutes les variables à null
 public void reset() {
   textArea1.appendText("\n --- Mets tous les " + name + " variables a null");
   Enumeration enum = variableList.elements() ;
   RuleVariable[] Temp= new RuleVariable[variableList.size()];
   for(int i=0; i< Temp.length; i++) {
			Temp[i]= (RuleVariable)enum.nextElement();
	 } 
   for(int i=0; i< Temp.length; i++) {
     Temp[i].setValue(null) ;
   }
 }

  // pour toutes les clauses déduites qui font référence à la goalVar
  // on essaye de trouver une valeur de goalVar via une règle qui est vraie
  //	si la règle est vraie alors affiche, assigne une valeur, et réévalue la règle
  //	si la règle est fausse alors affiche, et continue
  //	si la règle est null alors on ne peut pas trouver une valeur 
  //
 public void backwardChain(String goalVarName)
 {

  RuleVariable goalVar = (RuleVariable)variableList.get(goalVarName);
  Enumeration goalClauses = goalVar.clauseRefs.elements() ;

  while (goalClauses.hasMoreElements()) {
     Clause goalClause = (Clause)goalClauses.nextElement() ;
     if (goalClause.consequent.booleanValue() == false) continue ;

     goalClauseStack.push(goalClause) ;

     Rule goalRule = goalClause.getRule();
     Boolean ruleTruth = goalRule.backChain() ; // trouve la valeur de vérité de la règle
     if (ruleTruth == null) {
        textArea1.appendText("\nRegle " + goalRule.name +
                             " est nulle, je ne peux determiner sa valeur de verite.");
      } else if (ruleTruth.booleanValue() == true) {
       // la règle est OK, on donne la valeur conséquente à la variable
       goalVar.setValue(goalClause.rhs) ;
       goalVar.setRuleName(goalRule.name) ;
       goalClauseStack.pop() ;  // on retire l'objet de la pile des sous-buts
       textArea1.appendText("\nRegle " + goalRule.name + " est vraie, j'assigne " + goalVar.name + ": = " + goalVar.value);
       if (goalClauseStack.empty() == true) {
         textArea1.appendText("\n +++ J'ai trouve une solution pour le but: " + goalVar.name);
         break ; // pour l'instant, on ne cherche que la première solution et on s'arrête
       }
     } else {
       goalClauseStack.pop() ; // on retire l'objet de la pile des sous-buts
       textArea1.appendText("\nRegle " + goalRule.name + " est fausse, je ne peux affecter " + goalVar.name);
     }

     // displayVariables("Chaînage arrière") ;  // affiche les liens des variables
   } // endwhile

   if (goalVar.value == null) {
      textArea1.appendText("\n +++ Je ne peut pas trouver une solution pour le but: " + goalVar.name);
   }
 }

 // utilisé pour le chaînage avant seulement
 // détermine quelle règle peut être lancée, renvoie un Vector
 public Vector match(boolean test) {
    Vector matchList = new Vector() ;
    Enumeration enum = ruleList.elements() ;
    while (enum.hasMoreElements()) {
        Rule testRule = (Rule)enum.nextElement() ;
        if (test) testRule.check() ; // teste l'antécédent de la règle
        if (testRule.truth == null) continue ;
        // lance la règle une seule fois pour l'instant
        if ((testRule.truth.booleanValue() == true) &&
            (testRule.fired == false)) matchList.addElement(testRule) ;
    }
    displayConflictSet(matchList) ;
    return matchList ;
 }

 // utilisé seulement pour le chaînage avant
 // choisit une règle basé sur la spécificité
 public Rule selectRule(Vector ruleSet) {
    Enumeration enum = ruleSet.elements() ;
    long numClauses ;
    Rule nextRule ;

    Rule bestRule = (Rule)enum.nextElement() ;
    long max = bestRule.numAntecedents() ;
    while (enum.hasMoreElements()) {
        nextRule = (Rule)enum.nextElement() ;
        if ((numClauses = nextRule.numAntecedents()) > max) {
            max = numClauses ;
            bestRule = nextRule ;
        }
    }
    return bestRule ;
 }

 public void forwardChain() {
    Vector conflictRuleSet = new Vector() ;

    // teste d'abord les règles, basé sur les règles initiales
    conflictRuleSet = match(true); // on cherches quelles peuvent être déclanchées

    while(conflictRuleSet.size() > 0) {

      Rule selected = selectRule(conflictRuleSet); // sélectionne la "meilleur" règle 
      selected.fire() ; // déclanche le règle
			// fait l'action/assignement déduit
                        // met à jour toutes les clauses et règles

      conflictRuleSet = match(false); // cherche quelle règle lancer

    // displayVariables("Chainage Avant") ; // affiche l'assignement des variables
    }
 }


}




