/* Rule class

        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 Rule {
  RuleBase rb ;
  String name ;
  Clause antecedents[] ;  // jusqu'à 5 antécédents
  Clause consequent ;     // seulement une conséquence autorisée
  Boolean truth;          // état = (null=unknown, true, ou false)
  boolean fired=false;
  Rule(RuleBase Rb, String Name, Clause lhs, Clause rhs) {
    rb = Rb ;
    name = Name ;
    antecedents = new Clause[1] ;
    antecedents[0] = lhs ;
    lhs.addRuleRef(this) ;
    consequent = rhs ;
    rhs.addRuleRef(this) ;
    rhs.isConsequent() ;
    rb.ruleList.addElement(this) ;  // s'auto-ajoute à la liste
    truth = null ;
  }
 Rule(RuleBase Rb, String Name, Clause lhs1, Clause lhs2, Clause rhs) {
    rb = Rb ;
    name = Name ;
    antecedents = new Clause[2] ;
    antecedents[0] = lhs1 ;
    lhs1.addRuleRef(this) ;
    antecedents[1] = lhs2 ;
    lhs2.addRuleRef(this) ;
    consequent = rhs ;
    rhs.addRuleRef(this) ;
    rhs.isConsequent() ;
    rb.ruleList.addElement(this) ;  // s'auto-ajoute à la liste
    truth = null ;
  }
 Rule(RuleBase Rb, String Name, Clause lhs1, Clause lhs2,
                                Clause lhs3, Clause rhs) {
    rb = Rb ;
    name = Name ;
    antecedents = new Clause[3] ;
    antecedents[0] = lhs1 ;
    lhs1.addRuleRef(this) ;
    antecedents[1] = lhs2 ;
    lhs2.addRuleRef(this) ;
    antecedents[2] = lhs3 ;
    lhs3.addRuleRef(this) ;
    consequent = rhs ;
    rhs.addRuleRef(this) ;
    rhs.isConsequent() ;
    rb.ruleList.addElement(this) ;  // s'auto-ajoute à la liste
    truth = null ;
  }
Rule(RuleBase Rb, String Name, Clause lhs1, Clause lhs2,
                               Clause lhs3, Clause lhs4,
                               Clause rhs) {
    rb = Rb ;
    name = Name ;
    antecedents = new Clause[4] ;
    antecedents[0] = lhs1 ;
    lhs1.addRuleRef(this) ;
    antecedents[1] = lhs2 ;
    lhs2.addRuleRef(this) ;
    antecedents[2] = lhs3 ;
    lhs3.addRuleRef(this) ;
    antecedents[3] = lhs4 ;
    lhs4.addRuleRef(this) ;
    consequent = rhs ;
    rhs.addRuleRef(this) ;
    rhs.isConsequent() ;
    rb.ruleList.addElement(this) ;  // s'auto-ajoute à la liste
    truth = null ;
  }
Rule(RuleBase Rb, String Name, Clause lhs1, Clause lhs2,
                               Clause lhs3, Clause lhs4,
			       Clause lhs5,
                               Clause rhs) {
    rb = Rb ;
    name = Name ;
    antecedents = new Clause[5] ;
    antecedents[0] = lhs1 ;
    lhs1.addRuleRef(this) ;
    antecedents[1] = lhs2 ;
    lhs2.addRuleRef(this) ;
    antecedents[2] = lhs3 ;
    lhs3.addRuleRef(this) ;
    antecedents[3] = lhs4 ;
    lhs4.addRuleRef(this) ;
    antecedents[4] = lhs5 ;
    lhs5.addRuleRef(this) ;
    consequent = rhs ;
    rhs.addRuleRef(this) ;
    rhs.isConsequent() ;
    rb.ruleList.addElement(this) ;  // s'auto-ajoute à la liste
    truth = null ;
  }
Rule(RuleBase Rb, String Name, Clause lhs1, Clause lhs2,
                               Clause lhs3, Clause lhs4,
			       Clause lhs5, Clause lhs6,
                               Clause rhs) {
    rb = Rb ;
    name = Name ;
    antecedents = new Clause[6] ;
    antecedents[0] = lhs1 ;
    lhs1.addRuleRef(this) ;
    antecedents[1] = lhs2 ;
    lhs2.addRuleRef(this) ;
    antecedents[2] = lhs3 ;
    lhs3.addRuleRef(this) ;
    antecedents[3] = lhs4 ;
    lhs4.addRuleRef(this) ;
    antecedents[4] = lhs5 ;
    lhs5.addRuleRef(this) ;
    antecedents[5] = lhs6 ;
    lhs6.addRuleRef(this) ;
    consequent = rhs ;
    rhs.addRuleRef(this) ;
    rhs.isConsequent() ;
    rb.ruleList.addElement(this) ;  // s'auto-ajoute à la liste
    truth = null ;
  }


  long numAntecedents() { return antecedents.length; }

  // utilisé par le chaînage avant
  // une variable a été trouvée, on reteste donc toutes les clauses
  // qui font référence à la variable, et après toutes les règles qui
  // référencent ces clauses
  public static void checkRules(Vector clauseRefs) {
   Enumeration enum = clauseRefs.elements();
  while(enum.hasMoreElements()) {
    Clause temp = (Clause)enum.nextElement();
    Enumeration enum2 = temp.ruleRefs.elements() ;
    while(enum2.hasMoreElements()) {
        ((Rule)enum2.nextElement()).check() ; // reteste la règle
    }
  }
}

   // utilisé par le chaînage avant seulement
  Boolean check() {  // si l'antécédent est vrai et que la règle n'a pas été déclanchée
   RuleBase.appendText("\nJe teste la regle " + name ) ;
   for (int i=0 ; i < antecedents.length ; i++ ) {
    if (antecedents[i].truth == null) return null ;
    if (antecedents[i].truth.booleanValue() == true) {
        continue ;
    } else {
        return truth = new Boolean(false) ; // ne pas lancer cette règle
    }
   } // endfor
   return truth = new Boolean(true) ;  // on peut lancer cette règle
  }

  // utilisé seulement par le chaînage avant
  // lance cette règle et met en oeuvre la clause de conséquence.
  // si une variable est changée, met à jour toutes les clauses où 
  // elle est référencée, met à jour toutes les clauses
  // qu'il référence, et après toutes les règles qui contiennent 
  // ces clauses
  void fire() {
    RuleBase.appendText("\nLancement de la regle " + name ) ;
    truth = new Boolean(true) ;
    fired = true ;
    // assigne la valeur à la variable et met à jour les clauses
    consequent.lhs.setValue(consequent.rhs) ;
    // now retest any rules whose clauses just changed
    // reteste maintenant les règles dont les clauses viennent de changer 
    checkRules(consequent.lhs.clauseRefs) ;
  }

  // détermine si une règle est vraie ou fausse (true or false)
  // en essayant de prouver récursivement que les clauses antécédentes 
  // sont vraies, s'il y en a de fausses, la règle est fausse
  Boolean backChain()
  {
    RuleBase.appendText("\nEvaluation de la regle " + name) ;
    for (int i=0 ; i < antecedents.length ; i++) { // teste chaque clause
     if (antecedents[i].truth == null) rb.backwardChain(antecedents[i].lhs.name);
     if (antecedents[i].truth == null) {  // n'a pu prouver la vérité
         antecedents[i].lhs.askUser() ;   // donc demande à l'utilisateur de l'aide
         truth = antecedents[i].check() ; // redondant ?
     } // endif
     if (antecedents[i].truth.booleanValue() == true) {
         continue ;    // teste l'antécédent suivant (s'il y en a)
     } else {
         return truth = new Boolean(false) ; // sortie, si ils sont faux
     }
    } // endfor
    return truth = new Boolean(true) ; // tous les antécédents sont vrais
  }

  // affiche la règle au format texte
  void display(TextArea textArea) {
    textArea.appendText(name +": IF ") ;
    for(int i=0 ; i < antecedents.length ; i++) {
      Clause nextClause = antecedents[i] ;
      textArea.appendText(nextClause.lhs.name +
                          nextClause.cond.asString() +
                          nextClause.rhs + " ") ;
      if ((i+1) < antecedents.length) textArea.appendText("\n     AND ") ;
    }
    textArea.appendText("\n     THEN ") ;
       textArea.appendText(consequent.lhs.name +
                          consequent.cond.asString() +
                          consequent.rhs + "\n") ;
  }
};






