package version10_2_2_1.agnosticMemory;

import version10_2_2_1.Interface.InteractionList;
import version10_2_2_1.Interface.PrimitiveInteraction;
import version10_2_2_1.platform.Agent;

/**
 * Decision system.
 * This class selects the intended interactions
 * @author simon
 */
public class Decision {

	private Agent agent;
	
	private PrimitiveInteraction intention;
	
	
	private Thread[] t_utility;
	
	private float[] learn_utilities;
	private float[] instance_utilities;
	private float[] construction_utilities;
	private float[] utilities;
	
	private boolean[] jump;
	
	int[] nb;
	
	///////////////////////////////////////////////////////////
	public Decision(Agent a){
		agent=a;
		
		t_utility=new Thread[6];
		
		learn_utilities=new float[6];
		instance_utilities=new float[6];
		construction_utilities=new float[6];
		utilities=new float[6];
		
		jump=new boolean[6];
		nb=new int[6];
	}
	
	/**
	 * decision of the next interaction
	 * @return the intended interaction
	 */
	public PrimitiveInteraction decision(){
		System.out.println();System.out.println();
		
		// reset utility values
		for (int i=0;i<6;i++){
			learn_utilities[i]=0;
			instance_utilities[i]=0;
			construction_utilities[i]=0;
			utilities[i]=0;
			nb[i]=0;
		}
		
		// groups of opposite interactions: a unique interaction must be enactable per group (and to save cpu ressources)
		for (short i=0;i<4;i++){
			if (agent.signatureList.get(i+InteractionList.nbDF).getPrediction()>0){
				for (int j=0;j<4;j++) nb[j]++;
			}
		}
		nb[4]=1;
		nb[5]=1;
		
		jump[0]=(nb[0]==1);
		jump[1]=(nb[1]==1);
		jump[2]=(nb[2]==1);
		jump[3]=(nb[3]==1);
		jump[4]=(agent.signatureList.get(4+InteractionList.nbDF).getPrediction()>0);
		jump[5]=(agent.signatureList.get(5+InteractionList.nbDF).getPrediction()>0);
		
		
		// compute learning utility values
		/*for (short i=0;i<6;i++) t_utility[i]=new UtilityThread(i);
		for (short i=0;i<6;i++) t_utility[i].start();
		try {
			for (short i=0;i<6;i++) t_utility[i].join();
		} catch (InterruptedException e){e.printStackTrace();}
		*/

		// compute utility related to valence of interactions
		instance_utilities=agent.signatureList.getInstanceUtility();
		
		// compute utility related to construction of affordances
		construction_utilities=agent.signatureList.getConstructionUtility();
		
		for (int i=0;i<6;i++){
			float valence=0;
			if (agent.signatureList.get(i+InteractionList.nbDF).getPrediction()>0)
				valence=agent.signatureList.get(i+InteractionList.nbDF).interaction.valence();

			utilities[i]=valence + 1*learn_utilities[i] + 1*instance_utilities[i] + 1*construction_utilities[i];
		}
		
		System.out.println("---- learning utility -----");
		for (int i=0;i<6;i++){
			float valence=0;
			if (agent.signatureList.get(i+InteractionList.nbDF).getPrediction()>0)
				valence=agent.signatureList.get(i+InteractionList.nbDF).interaction.valence();

			System.out.println(" -- "+i+" -> "+utilities[i]+" = "+valence+" + "
					                                             +1*learn_utilities[i]+" + "
					                                             +1*instance_utilities[i]+" + "
					                                             +1*construction_utilities[i]);
		}
		System.out.println("----");

		
		//////////////////////////////////////////////////////////////////
		// select interaction with the highest utility
		float max=-1000000;
		int imax=-1;
		System.out.println(" nb = "+nb[0]);
		for (int i=0;i<6;i++){
			System.out.println(" -- "+i+" -> "+utilities[i]);
			if ( (agent.signatureList.get(i+InteractionList.nbDF).getPrediction()>=0 || nb[i]!=1) && utilities[i]>max){  // an interaction per group must be enactable
				max=utilities[i];
				imax=i;
			}
		}

		System.out.println("Select interaction "+imax+" : "+agent.signatureList.get(InteractionList.nbDF+imax).interaction().getName()+", utility : "+max);
		intention=agent.signatureList.get(InteractionList.nbDF+imax).interaction();

		return intention;
	}


	/**
	 * Get the last intended interaction
	 * @return the last selected intended interaction
	 */
	public PrimitiveInteraction getIntention(){
		return intention;
	}
	
	
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	
	private class UtilityThread extends Thread {
		
		private short id;
		
		public UtilityThread(short i){
			super();
			id=i;
		}
		public void run(){
			
			// learning utility : learn unreliable interactions
			learn_utilities[id]+=agent.signatureList.getLearningUtility(id,jump[id], nb[id]==1);
		}
	}
	
}
