package DialML;

import alice.tuprolog.*;

import java.util.*;

/**
 * <p>Les Rôles fonctionnels </p>
 * <p>Ce sont tous les rôles fonctionnels à la disposition des agents</p>
 * @author Yousfi Monod Mehdi
 * @version 1.0
 */

public class RoleFctl {

  // l'agent qui utilise les rôles fonctionnels
  AgentCog moi;

  // l'interlocuteur
  AgentCog lui;

  private boolean btrace=true;

  public RoleFctl(AgentCog m, AgentCog l) {
    moi=m;
    lui=l;
  }
  public void processMessage(int rf, Object o) {
    switch (rf) {
      case 0: // donne-connaissance
        processGiftKnowledge((Struct[])o);
        break;
      case 1: // donne-explication
        break;
      case 2: // donne-exemple
        break;
      case 3: // donne-précision
        break;
      case 4: // donne-information
        // réponse à une demande d'information ?
        // 1 = information fausse
        // 2 = information juste
        // 3 = information inconnue
        processGiftInfo((Integer)o);
        break;

      case 5: // demande-connaissance
        break;
      case 6: // demande-explication
        break;
      case 7: // demande-exemple
        break;
      case 8: // demande-précision
        break;
      case 9: // demande-information
        processAskInfo((Struct[])o);
        break;
      case 10: // dit-satisfaction
        moi.strat.other_sat=true;
        break;
      case 11: // dit-insatisfaction
        processSayInsat((Struct[])o);
        break;
    }
  }

  // traitement d'un "donne-connaissance"
  private void processGiftKnowledge(Struct[] implic) {
    // si l'élève peut apprendre la nouvelle donnée
    if (canAddKnowledge(implic[0], implic[1])) {
      moi.vectTheory.addImplic(implic[0], implic[1]);
      trace("Donnée \""+moi.vectTheory.getLogicData(implic)+"\" apprise de "+lui.getNom()+".");
      moi.world.sendMsg(lui,10,new Struct[2]);
    }
    // s'il ne peut l'apprendre il la fournie au maître avec une insatisfaction
    else moi.world.sendMsg(lui,11,implic);
  }


  // traitement d'un "demmande-information"
  private void processAskInfo(Struct[] implic) {
    moi.world.sendMsg(lui, 4, getInfo(implic));
  }

  // traitement d'un "donne-information"
  private void processGiftInfo(Integer i) {
    moi.strat.addMessage(4,i);
  }

  // traitement d'une insatisfaction
  // nous traitons le cas d'une insatisfaction suite à un "donne-connaissance"
  private void processSayInsat(Struct[] implic) {
    // tentative d'explication de la prémisse
    if (!moi.strat.expliquePred(implic[0])) {
      // tentative d'explication de la conclusion, le cas échéant
      if (!moi.strat.expliquePred(implic[1])) {
        trace("Donnée \"" + moi.vectTheory.getLogicData(implic) +
              "\" innexplicable.");
        return;
      }
    }
    moi.strat.teachImplic(implic);
  }

  /** La donnée peut-elle être ajoutée à la BC ?
   *
   */
  public boolean canAddKnowledge(Struct prem, Struct concl) {

    // est-ce le créateur qui m'apprend une donnée ?
    boolean createur=moi.master.getNom().equals("Créateur");
    Struct[] implic=new Struct[2];
    implic[0]=prem;
    implic[1]=concl;
    // la nouvelle donnée est-elle réèllement nouvelle ?
    if (moi.strat.getPathImplic(implic).size()!=0) {
      trace("Donnée \""+moi.vectTheory.getLogicKnowledge(prem,concl)+"\" déjà connue de la BC.");
      return true;
    }

    // un des prédicats est-il connu ?
    if (!createur && !moi.vectTheory.contient(prem) && !moi.vectTheory.contient(concl)) {
      trace("Donnée \""+moi.vectTheory.getLogicKnowledge(prem,concl)+"\" incompréhensible.");
      return false;
    }

    // la nouvelle donnée est-elle contradictoire avec la BC ?
    // si oui, oter la contradiction
    moi.strat.gereContr(implic);

    return true;
  }

  // la connaissance o est-elle connue de la BC ?
  private Integer getInfo(Object o) {
    Struct[] implic=(Struct[])o,implic2;
    if (moi.strat.getPath(implic[0],implic[1]).size()!=0) return (new Integer(2));
    implic2=moi.strat.getContr(implic);
    if (moi.strat.getPath(implic2[0],implic2[1]).size()!=0) return (new Integer(1));
    else return (new Integer(3));
  }

  private void trace(String msg) {
    if (btrace) System.out.println(moi.getNom()+"> "+msg);
  }

  private void erreur(String msg) {
    System.out.println(moi.getNom()+" erreur> "+msg);
  }
}