package modelling;

import java.awt.Image;
import java.util.TreeMap;
import sema.Area;
import sema.World;
import sema.Agent;
import sema.Element;

/**
 * Agent able to communicate with other agents.
 */
public class CommunicatingAgent extends Agent implements Communicating {
    
    /*
     * Creates a new agent able to communicate, with the same parameters than agent.
     */
    public CommunicatingAgent(World world, Area area, float delay, Image image) {
        super(world, area, delay, image);
        
    }
    
    /**
     * The TreeMap opens the maximum range of possible reactions : potentially
     * just a string in answer, or an action, or an event.
     */
    TreeMap vocabulary = new TreeMap();
    
    
    /**
     * It computes the answer to give back from the 'question' of the speaker,
     *  if it decides no to answer it return false,
     * else it return true and preselect the answer to give the next time we open the mouth
     * ( action of the discussion )
     */
    protected boolean setNextAnswer(String question, Communicating speaker){
        try {
            String a = (String) (vocabulary.get(question));
            nextAnswer = a;
            return true;
        }catch (Exception e) {}
        try {
            Action a = (Action) vocabulary.get(question);
            a.start();
            return true;
        }catch (Exception e) {}
        if (Math.random () > 0.5) {
        nextAnswer = "What did you say?";
        return true;
        }
        return false;
    }
    
    
    private Discussion currentDiscussion;
    
    
    /**
     * Returns the current discussion.
     */
    public Communicating.Discussion getCurrentDiscussion(){
        return currentDiscussion;
    }
    
    /**
     * Allows to set the current discussion.
     */
    protected void setCurrentDiscussion(Discussion speech){
        this.currentDiscussion = speech;
    }
    
    /**
     * Action of discuting. The action is paused when the agent waits an answer.
     * The fonction <code>hear</code> resumes then the discussion.
     */
    public class Discussion extends Action implements Communicating.Discussion{
        
        /**
         * Corresponds to a discussion with one unique element.
         */
        public Discussion(Element partenar){
            this.partenar = partenar;
        }
        
        
        protected Element partenar;
        
        
        public float step(){
            if ( world.nature.getDistance(CommunicatingAgent.this, partenar) < 3){
                try {
                    Communicating friend = (Communicating) partenar;
                    boolean succes = false;
                    int i =0;
                    while(!succes && i<3) {
                        if( !(friend.hear(getNextAnswer() , CommunicatingAgent.this))  ) {
                            pause(6); // uses pause with maximum delay.
                            return 1;
                        }
                        i++;
                    }
                    return -1;
                } catch (Exception e) {this.stop();}
            }
            return -1;
        }
        
        /**
         * Delates the action of the time to answer.
         */
        public float resumeStep(){
            return 2;
        }
    }
    
    
    /**
     * Receipts the speaker's words. Calls <code>setNextAnswer</code> to determinate the answer.
     * Resumes eventually the current discussion.
     */
    public boolean hear(String speech, Communicating speaker) {
        if (setNextAnswer(speech, speaker)) { // we decide to answer
            Discussion discussion = (Discussion) speaker.getCurrentDiscussion();
            
            if (getCurrentDiscussion() == null)
                setCurrentDiscussion(new Discussion((Element) speaker));
            else {
                Discussion sp = (Discussion) getCurrentDiscussion();
                sp.resume();
            }
            return true;
        }
        return false;
    }
    
    
    
    
    /**
     * Called by the discussion.
     */
    private String getNextAnswer(){
        return nextAnswer;}
    
    
    private String nextAnswer;
    
    
    
    
    
}
