/*
 * Liberu.java
 *
 * Created on 6 of December 2006, 1:34
 */

/**
 *
 * @author Eng. Paulo Roque Silva
 */
import icommand.nxt.Motor;
import icommand.nxt.Battery;
import icommand.nxt.LightSensor;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.swing.*;
import javax.sound.sampled.Clip;

public class Liberu { // Total of used Threads = NNEURONP * (NTRAIL+1) + NNEURONT + NTRAIL (RunId) +
	                  // + RunEmotionalUnit + PlayLiberu + SimLiberu + JavaQueueEvents + Java???internal
// Brain Constants
    // ATENTION ->    NNEURON > NSignalIN + NSignalOUT
    static final int  RNDelay = 3;  	// Random delay, step delay = NEURONT / RNDelay
    static final int  NNEURONT = 250; 	/* C. elegans = 302 neurons e 5000 connections
                                           39 sensitive neurons
                                           21 principal classes of motion neurons */
    static final int  NNEURONPTaste = 25;    /* N Neurons Of IDs modules 50 */
    static final int  NNEURONPSmell = 25;    /* N Neurons Of IDs modules 50 */
    static final int  NNEURONPVision= 25;    /* N Neurons Of IDs modules 150 */
    static final int  NNEURONPTact  = 5;    /* N Neurons Of IDs modules 5 */
    static final int  NNEURONPSound = 25;    /* N Neurons Of IDs modules 100 */
    static final int  NNEURONPProSelf= 25;    /* N Neurons Of IDs modules 50 */
	static final int  NTRAIL = 6;       // # of Senses (including Proprioception) recorded in the Past
    static final int  ACTRND = 5;       // # of Acts of Liberu - BODY
    static final int  ACTMOVES = 6;     // # of Acts of Liberu - BODY + EMOTIONS
    static final int  MOVES = 12;        // # of motion Acts of Liberu - Genetic evoluctive, got number
    static final int  PerTime = 50;  	// Percentage of good, in time, actions
// Body Constants    
    static final float MaxInSense = 255.0F;	// Max power for sensing (higher goes pain) and acting
    static final float MinSense = 0.0F; // Minimal differential of sensations or input differential
    static final int  NanalogTaste = 3, // Taste (3 Sherin of 3 possible variables)
                      NanalogSmell = 9, // Smell (9 Sherin of 9 possible variables)
                      NanalogVision= 3*5,// Vision (10 Sherin of 10 possible variables)
                      NanalogTact  = 1, // Tact (1 Sherin of 2 value possible)
                      NanalogSound = PlayLiberu.BANDS,// Sound (
                      NanalogProSelf=MOVES;// ProSelf (7 Sherins of 5 moves + 2 motivations)3Dez2011 15:18
    static final int  DRINK     = 0,    // The robot drinks water
    				  EAT       = 1,    // The robot eats food
    				  NECK_LEFT = 1,    // The robot moves neck to left
    				  WALK      = 2,    // The robot moves forward
    				  TURN_LEFT = 3,    // The robot turns him self to the left - Manter ordem, antes do Right
    				  TURN_RIGHT= 4,    // The robot turns him self to the right
    				  //  FIM DOS ACTRND
//    				  NECK_RIGHT= 5,    // The robot moves neck to right
    				  CHORA     = 5,    // The robot chora
    				  //  FIM DOS ACTMOVES
    				  PAIN      = 6,    // Touch sense in the wall with pain %ACETILCOLINA STOP
    				  New       = 7,    // Emotion, New expression &SERETONINA ID
    				  Happy     = 8,    // Emotion, happy expression $DOPAMINA aceleracao (a)
    				  Sad       = 9,    // Emotion, Sad expression #ADRENALINA ataca-foge Parasimp-simpati (v)
    				  MDrink    =10,    // drinking MOTIVATION
    				  MEat      =11,    // eating MOTIVATION
    				  //  FIM DOS MOVES
 /* Homeostase */	  Belo      =12,    // Emotion, Wonderful expression
    				  NThirsty  =40,    // Threshold to be thirsty (in steps)
    				  NHungry   =100,   // Threshold to be hungry (in steps)
                      // Sense Variables - se tacto em baixo necessita festas... tacto vai sempre decrescer com step
    				  NO_TACT   = 0,    // fell no tact
    				  TACT 		= 1;    // fell tact - the wall

// Brain Variables
    static int 	      perTime;          // Accumulated in time %of if id(T+1) > id(T)
    static boolean 	  ratVSemo;		    // TRUE If Liberu is rational vs False If is Emotional (after %Time)
    Net			      past;             // Memory network of Liberu
    RunEmotionalUnit  reu;              // Cerebellum - RunEmotionalUnit variable
    ConcurrentLinkedQueue<Signal>       // because, credit is given by who's listening, not who's talking...
    				  busInTaste,       // Bus data in to the Past - taste
    				  busInSmell,       // Bus data in to the Past - smell
    				  busInVision,      // Bus data in to the Past - vision
					  busInTact,        // Bus data in to the Past - touch
					  busInSound,       // Bus data in to the Past - sound      - FUTURAS APLICACOES
    				  busInProSelf,     // Bus data out to the Past - proprioception
    				  busOutTaste,      // Bus data out to the Past - taste
    				  busOutSmell,      // Bus data out to the Past - smell
    				  busOutVision,     // Bus data out to the Past - vision
					  busOutTact,       // Bus data out to the Past - touch
					  busOutSound,      // Bus data out to the Past - sound      - FUTURAS APLICACOES
    				  busOutProSelf,    // Bus data out to the Past - proprioception
    				  busInTTaste,      // Bus data in to the Time - taste
    				  busInTSmell,      // Bus data in to the Time - smell
    				  busInTVision,     // Bus data in to the Time - vision
					  busInTTact,       // Bus data in to the Time - touch
					  busInTSound,      // Bus data in to the Time - sound      - FUTURAS APLICACOES
    				  busInTProSelf,    // Bus data out to the Time - proprioception
					  busTimeOut,       // Bus data from the Past time
					  busInAct;         // Bus data from the REU to Act nodes

// Body Variables
    Signal            []bodyAction;     // Actions of the body of the robot
    int               cycleThirsty;     // Update the thirsty cycle
    int               cycleHungry;      // Update the hungry cycle
    boolean 		  thirsty, hungry;  // If robot feels thirsty or hungry
    int               power;            // Strong of sensitive signal

// Simulator variables
    CyclicBarrier     stepBarrierTaste; // Waiting step barrier past neurons
    CyclicBarrier     stepBarrier2Taste;// Waiting step barrier past neurons
    CyclicBarrier     stepBarrierSmell; // Waiting step barrier past neurons
    CyclicBarrier     stepBarrier2Smell;// Waiting step barrier past neurons
    CyclicBarrier     stepBarrierVision;// Waiting step barrier past neurons
    CyclicBarrier     stepBarrier2Vision;// Waiting step barrier past neurons
    CyclicBarrier     stepBarrierTact;  // Waiting step barrier past neurons
    CyclicBarrier     stepBarrier2Tact; // Waiting step barrier past neurons
    CyclicBarrier     stepBarrierSound; // Waiting step barrier past neurons
    CyclicBarrier     stepBarrier2Sound;// Waiting step barrier past neurons
    CyclicBarrier     stepBarrierProSelf;// Waiting step barrier past neurons
    CyclicBarrier     stepBarrier2ProSelf;// Waiting step barrier past neurons
    CyclicBarrier     stepId;   		// Waiting step barrier IDs
    CyclicBarrier     stepId2;   		// Waiting step barrier IDs
    CyclicBarrier     stepActBarrier;   // Waiting step act barrier
    CyclicBarrier     stepREUBarrier;   // Waiting step RunEmotionalUnit barrier
    CyclicBarrier     stepTimeBarrier;  // Waiting step Time Present barrier
    Interface         visor;			// screen
    JTextField        texto;            // pressed key
    
    /** Creates a new instance of Liberu */
    public Liberu(Interface panelG, JTextField txt) {
    	
        visor        = panelG;
        texto        = txt;
    	ratVSemo     = true;	// if at Xanos years, % in of good in time > PerTime (%Time), goes true
    	perTime      = 0;
    	power        = PlayLiberu.Power;   // ALTERAR COM CORPO - HARDWARE
    	past         = new Net(NTRAIL, NNEURONPTaste, NNEURONPSmell, NNEURONPVision, NNEURONPTact,
    			NNEURONPSound, NNEURONPProSelf, NNEURONT);
        bodyAction   = new Signal[MOVES];
        for (int i=0; i<bodyAction.length; i++)
        	bodyAction[i] = new Signal(i, power);
        setThirsty(false);
        setHungry(false);
        cycleThirsty = 6;  		// Starts earlier then Hungry
        cycleHungry  = 0;
        busInTaste   = new ConcurrentLinkedQueue<Signal>();
        busInSmell   = new ConcurrentLinkedQueue<Signal>();
        busInVision  = new ConcurrentLinkedQueue<Signal>();
        busInTact    = new ConcurrentLinkedQueue<Signal>();
        busInSound   = new ConcurrentLinkedQueue<Signal>();
        busInProSelf = new ConcurrentLinkedQueue<Signal>();
        // Chora is simpatic-parasimpatic system
//        busInProSelf.add(new Signal(CHORA, power));   // recent == 0

        busOutTaste  = new ConcurrentLinkedQueue<Signal>();
        busOutSmell  = new ConcurrentLinkedQueue<Signal>();
        busOutVision = new ConcurrentLinkedQueue<Signal>();
        busOutTact   = new ConcurrentLinkedQueue<Signal>();
        busOutSound  = new ConcurrentLinkedQueue<Signal>();
        busOutProSelf= new ConcurrentLinkedQueue<Signal>();
        
        busInTTaste   = new ConcurrentLinkedQueue<Signal>();
        busInTSmell   = new ConcurrentLinkedQueue<Signal>();
        busInTVision  = new ConcurrentLinkedQueue<Signal>();
        busInTTact    = new ConcurrentLinkedQueue<Signal>();
        busInTSound   = new ConcurrentLinkedQueue<Signal>();
        busInTProSelf = new ConcurrentLinkedQueue<Signal>();

        busTimeOut      = new ConcurrentLinkedQueue<Signal>();

        busInAct        = new ConcurrentLinkedQueue<Signal>();
    }
    
    public CyclicBarrier initiateTaste() {

    	// Create Past running threads
    	stepBarrierTaste  = new CyclicBarrier(NNEURONPTaste + 1 //,
    			 /* Process that runs between steps */
    			 /* new MoveQueue(busInTouch, busInSmell, busInVision) */ );
    	stepBarrier2Taste  = new CyclicBarrier(NNEURONPTaste + 1);
    	for (int i=0; i < past.nNeuronsPTaste; i++)
    		new Thread(new RunNeuronPast(stepBarrierTaste, stepBarrier2Taste, past.nodeTaste[i],
                                           busInTaste, busOutTaste, NNEURONPTaste)).start();
           
        return stepBarrierTaste;
    }
    
    public CyclicBarrier initiate2Taste() {

        return stepBarrier2Taste;
    }
    
    public CyclicBarrier initiateSmell() {

    	// Create Past running threads
    	stepBarrierSmell  = new CyclicBarrier(NNEURONPSmell + 1 //,
    			 /* Process that runs between steps */
    			 /* new MoveQueue(busInTouch, busInSmell, busInVision) */ );
    	stepBarrier2Smell  = new CyclicBarrier(NNEURONPSmell + 1);
    	for (int i=0; i < past.nNeuronsPSmell; i++)
    		new Thread(new RunNeuronPast(stepBarrierSmell, stepBarrier2Smell, past.nodeSmell[i],
                                           busInSmell, busOutSmell, NNEURONPSmell)).start();
           
        return stepBarrierSmell;
    }
    
    public CyclicBarrier initiate2Smell() {

        return stepBarrier2Smell;
    }
    
    public CyclicBarrier initiateVision() {

    	// Create Past running threads
    	stepBarrierVision  = new CyclicBarrier(NNEURONPVision + 1 //,
    			 /* Process that runs between steps */
    			 /* new MoveQueue(busInTouch, busInSmell, busInVision) */ );
    	stepBarrier2Vision  = new CyclicBarrier(NNEURONPVision + 1);
    	for (int i=0; i < past.nNeuronsPVision; i++)
    		new Thread(new RunNeuronPast(stepBarrierVision, stepBarrier2Vision, past.nodeVision[i],
                                           busInVision, busOutVision, NNEURONPVision)).start();
           
        return stepBarrierVision;
    }
    
    public CyclicBarrier initiate2Vision() {

        return stepBarrier2Vision;
    }
    
    public CyclicBarrier initiateTact() {

    	// Create Past running threads
    	stepBarrierTact  = new CyclicBarrier(NNEURONPTact + 1 //,
    			 /* Process that runs between steps */
    			 /* new MoveQueue(busInTouch, busInSmell, busInVision) */ );
    	stepBarrier2Tact  = new CyclicBarrier(NNEURONPTact + 1);
    	for (int i=0; i < past.nNeuronsPTact; i++)
    		new Thread(new RunNeuronPast(stepBarrierTact, stepBarrier2Tact, past.nodeTact[i],
                                           busInTact, busOutTact, NNEURONPTact)).start();
           
        return stepBarrierTact;
    }
    
    public CyclicBarrier initiate2Tact() {

        return stepBarrier2Tact;
    }
    
    public CyclicBarrier initiateSound() {

    	// Create Past running threads
    	stepBarrierSound  = new CyclicBarrier(NNEURONPSound + 1 //,
    			 /* Process that runs between steps */
    			 /* new MoveQueue(busInTouch, busInSmell, busInVision) */ );
    	stepBarrier2Sound  = new CyclicBarrier(NNEURONPSound + 1);
    	for (int i=0; i < past.nNeuronsPSound; i++)
    		new Thread(new RunNeuronPast(stepBarrierSound, stepBarrier2Sound, past.nodeSound[i],
                                           busInSound, busOutSound, NNEURONPSound)).start();
           
        return stepBarrierSound;
    }
    
    public CyclicBarrier initiate2Sound() {

        return stepBarrier2Sound;
    }
    
    public CyclicBarrier initiateProSelf() {

    	// Create Past running threads
    	stepBarrierProSelf  = new CyclicBarrier(NNEURONPProSelf + 1 //,
    			 /* Process that runs between steps */
    			 /* new MoveQueue(busInTouch, busInSmell, busInVision) */ );
    	stepBarrier2ProSelf  = new CyclicBarrier(NNEURONPProSelf + 1);
    	for (int i=0; i < past.nNeuronsPProSelf; i++)
    		new Thread(new RunNeuronPast(stepBarrierProSelf, stepBarrier2ProSelf, past.nodeProSelf[i],
                                           busInProSelf, busOutProSelf, NNEURONPProSelf)).start();
           
        return stepBarrierProSelf;
    }
    
    public CyclicBarrier initiate2ProSelf() {

        return stepBarrier2ProSelf;
    }
    
    public CyclicBarrier initiateAct(Clip cp1, Clip cp2, Clip cp3) {

    	// Create Act running threads
        stepActBarrier  = new CyclicBarrier(NNEURONPProSelf + 1 //,
   			 /* Process that runs between steps */
   			 /* new MoveQueueOut(busInProSelf) */ );
    	for (int i=0; i<bodyAction.length; i++)         // #################### REVER #############
    		bodyAction[i] = new Signal(i, power);
	    for (int n=0; n < NNEURONPProSelf; n++)// ACTION THREADS (NActions)
        	new Thread(new RunNeuronAct(stepActBarrier, past.actNode[n],
        								busInAct, busInProSelf, busInTProSelf, bodyAction,
        								cp1, cp2, cp3)).start();

        return stepActBarrier;
    }
    
    public CyclicBarrier initiateREU() {

    	// Create RunEmotionalUnit thread
        stepREUBarrier  = new CyclicBarrier( 2 //,
      			 /* Process that runs between steps */
      			 /*new MoveQueueREU(busPastOut)*/ );
	    reu = new RunEmotionalUnit(stepREUBarrier, visor, texto, past, busTimeOut, busInAct,
	    		busInProSelf, bodyAction);
	    new Thread(reu).start();

        return stepREUBarrier;
    }
    
    public CyclicBarrier initiateIds() {

    	// Create Past Time running threads
        stepId   = new CyclicBarrier(NTRAIL+1);
        stepId2  = new CyclicBarrier(NTRAIL+1);
        new Thread(new RunId(stepId, stepId2, past.nodeTaste, busOutTaste, busInTTaste, busInTaste,
        		past.nNeuronsPTact)).start();
        new Thread(new RunId(stepId, stepId2, past.nodeSmell, busOutSmell, busInTSmell, busInSmell,
        		past.nNeuronsPSmell)).start();
        new Thread(new RunId(stepId, stepId2, past.nodeVision, busOutVision, busInTVision, busInVision,
        		past.nNeuronsPVision)).start();
        new Thread(new RunId(stepId, stepId2, past.nodeTact, busOutTact, busInTTact, busInTact,
        		past.nNeuronsPTact)).start();
        new Thread(new RunId(stepId, stepId2, past.nodeSound, busOutSound, busInTSound, busInSound,
        		past.nNeuronsPSound)).start();
        new Thread(new RunId(stepId, stepId2, past.nodeProSelf, busOutProSelf, busInTProSelf,
				 busInProSelf, past.actNode, past.nNeuronsPProSelf)).start();

        return stepId;
    }
    
    public CyclicBarrier initiateIds2() {

        return stepId2;
    }
    
    public CyclicBarrier initiatePastTime() {

    	// Create Past Time running threads
        stepTimeBarrier   = new CyclicBarrier(NNEURONT+1);
	    for (int n=0; n < past.nNeuronsT; n++)// ACTION THREADS (NActions)
        	new Thread(new RunPastTime(stepTimeBarrier,
        		  past.time[n], busTimeOut,
  				  busInTTaste,
				  busInTSmell,
				  busInTVision,
				  busInTTact,
				  busInTSound,
				  busInTProSelf)).start();

        return stepTimeBarrier;
    }
    
    public void clearBuses() {

    	while (!busInTaste.isEmpty())
    		busInTaste.poll();
    	while (!busInSmell.isEmpty())
    		busInSmell.poll();
    	while (!busInVision.isEmpty())
    		busInVision.poll();
    	while (!busInTact.isEmpty())
    		busInTact.poll();
    	while (!busInSound.isEmpty())
    		busInSound.poll();
    	while (!busInProSelf.isEmpty())
    		busInProSelf.poll();
    	while (!busOutTaste.isEmpty())
    		busOutTaste.poll();
    	while (!busOutSmell.isEmpty())
    		busOutSmell.poll();
    	while (!busOutVision.isEmpty())
    		busOutVision.poll();
    	while (!busOutTact.isEmpty())
    		busOutTact.poll();
    	while (!busOutSound.isEmpty())
    		busOutSound.poll();
    	while (!busOutProSelf.isEmpty())
    		busOutProSelf.poll();
    }
// ######################### Actions
    public void andaFlag() {         // miro-acts and micro-contra-acts   - 5 types of micro and velocity
		
    	reu.anda();
    }
	
    public void recuaFlag() {
		
    	reu.recua();
    }
	
	public void andaEsquFlag() {
		
    	reu.andaEsqu();
	}
	
	public void andaDireFlag() {
		
    	reu.andaDire();
	}
	
	public void necklFlag() {
		
    	reu.neckLeft();
	}
	
	public void neckrFlag() {
		
    	reu.neckRight();
	}
	
// #################################
    public void clearBusTimeOut() {

    	while (!busTimeOut.isEmpty())
    		busTimeOut.poll();
    }

    public void setThirsty(boolean w) {

    	thirsty = w;
    }
    
    public void setHungry(boolean w) {

    	hungry = w;
    }
    
    public int addStep() {
    	
    	return past.addDataActual();
    }

    public void feelPAIN() {
    	
    	reu.emotionPAIN();
    }
    
    public void feelNew() {
    	
    	reu.emotionNew(true);
    }
    
    public void feelHappy() {
    	
    	reu.emotionHappy();
    }
    
    public void feelSad() {
    	
    	reu.emotionSad();
    }
    
    public void motivation(int []senseProSelf, int pw) {

        cycleThirsty += 1;
        if (cycleThirsty >= NThirsty) {
            setThirsty(true);
        	visor.saveValue(6, 1);             // value 6
            reu.ansiaFeel();
        	senseProSelf[MDrink] = pw; 				 // thirsty motivation
        }
        else
        	visor.saveValue(6, 0);             // value 6
        cycleHungry += 1;
        if (cycleHungry >= NHungry) {
            setHungry(true);
        	visor.saveValue(7, 1);             // value 7
            reu.ansiaFeel();
        	senseProSelf[MEat] = pw;  						 // hungry motivation
        }
        else
        	visor.saveValue(7, 0);             // value 7
    }
    
    public void motivationNXT(int []senseProSelf, LightSensor light, int pw) {

        if (Battery.getVoltageMilliVolt() <= 8000 && (light.getLightPercent() > 48 ||
        										light.getLightPercent() < 40)) {  // 9 Volts full (9000mV)
            setThirsty(true);
        	visor.saveValue(6, 1);             // value 6
            reu.ansiaFeel();
        	senseProSelf[MDrink] = pw; 	 // thirsty motivation
        }
        else
        	visor.saveValue(6, 0);             // value 6
    }
    
    public void feelTaste(int []sense) {
    	int       m;
    	
    	for (m=0; m < sense.length; m++)          // send all signals of a sense (send a Sherin)
    		busInTaste.add(new Signal(m, sense[m]));
    }

    public void feelSmell(int []sense) {
    	int       m;
    	
    	for (m=0; m < sense.length; m++)          // send all signals of a sense (send a Sherin)
    		busInSmell.add(new Signal(m, sense[m]));
    }

    public void feelVision(int []sense) {
    	int       m;
    	
    	for (m=0; m < sense.length; m++)          // send all signals of a sense (send a Sherin)
    		busInVision.add(new Signal(m, sense[m]));
    }

    public void feelTact(int []sense) {
    	int       m;
    	
    	for (m=0; m < sense.length; m++)          // send all signals of a sense (send a Sherin)
    		busInTact.add(new Signal(m, sense[m]));
    }

    public void feelSound(int []sense) {
    	int       m;
    	
    	for (m=0; m < sense.length; m++)          // send all signals of a sense (send a Sherin)
    		busInSound.add(new Signal(m, sense[m]));
    }

    public void feelProSelf(int []sense) {
    	int       m;
    	
    	for (m=0; m < sense.length; m++)          // send all signals of a sense (send a Sherin)
    		busInProSelf.add(new Signal(m, sense[m]));
    }


    public void act(Signal result[]) {   // miro-acts and micro-contra-acts   - 5 types of micro and velocity

    	for (int i=0; i<bodyAction.length; i++)
    		result[i].setActive(bodyAction[i].active);
//    	if (bodyAction[TURN_RIGHT].active && bodyAction[TURN_LEFT].active)						// NXT
//    	   ;																					// NXT
//    	else {																					// NXT
//            if (bodyAction[TURN_LEFT].active)													// NXT
//    			andaEsquFlag();																	// NXT
//            if (bodyAction[TURN_RIGHT].active)													// NXT
//    			andaDireFlag();																	// NXT
//    	}																						NXT
//        if (bodyAction[WALK].active)														// NXT
//			andaFlag();																		// NXT
//        if (bodyAction[EAT].active)															// NXT
//			recuaFlag();																	// NXT
//    	if (bodyAction[NECK_RIGHT].active && bodyAction[NECK_LEFT].active)						// NXT
// 	   		;																					// NXT
// 		else {																					// NXT
//        if (bodyAction[NECK_LEFT].active)
//			necklFlag();
//        if (bodyAction[NECK_RIGHT].active)
//			neckrFlag();
//    	}																						NXT
    }

    public void proSelf(int []senseProSelf,int []senseTaste, int pw) {   // REVER - Só se o mundo o permitir
        
    	// Drinks when taste water and feels thirsty
        if (bodyAction[DRINK].active  && senseTaste[World.WATER-1] == pw /*&& thirsty*/ ||
        		// Utero body simulation - Ovulação
        		bodyAction[DRINK].active && past.time[0][0].step <= RunEmotionalUnit.ActRandom) {
        	setThirsty(false);
        	reu.emotionHappy();
        	senseProSelf[DRINK] = pw;  						 // sense drink(1)
            bodyAction[DRINK].setActive(false);
        	cycleThirsty = 0;
        	}
        else
        	if (bodyAction[DRINK].active)
            	feelPAIN();
        // Eat when feels hungry and taste food
        if (bodyAction[EAT].active  && senseTaste[World.FOOD-1] == pw /*&& hungry*/ ||
        		// Utero body simulation - Ovulação
        		bodyAction[EAT].active && past.time[0][0].step <= RunEmotionalUnit.ActRandom) {
        	setHungry(false);
        	reu.emotionHappy();
        	senseProSelf[EAT] = pw;  						 // sense eat(1)
            bodyAction[EAT].setActive(false);
        	cycleHungry = 0;
        	}
        else
        	if (bodyAction[EAT].active)
            	feelPAIN();

        for (int i=0; i<bodyAction.length; i++) {
            if (bodyAction[i].active)
            	senseProSelf[i] = pw;  						 // sense all
            bodyAction[i].setActive(false);
        }
    }

    public void proSelfNXT(int []senseProSelf,LightSensor light, int pw) {   // REVER - Só se o mundo o permitir
        
    	// Trocar 3 funcoes Playliberu(update e liberu.proself e liberu.motivation)
    	// alterar actrnd e constantes e moves e comentarios
    	// falta a fala
    	
    	// Drinks when taste water and feels thirsty
        if (bodyAction[DRINK].active  && Battery.getVoltageMilliVolt() <= 8500
        		&& light.getLightPercent() < 48 && light.getLightPercent() > 40 /*&& Na TOMADA */
        		// Utero body simulation - Ovulação
        		|| bodyAction[DRINK].active && past.time[0][0].step <= RunEmotionalUnit.ActRandom) {
        	setThirsty(false);
        	reu.emotionHappy();
        	senseProSelf[DRINK] = pw;  						 // sense drink(1)
            bodyAction[DRINK].setActive(false);
        	cycleThirsty = 0;
        	}
        else
        	if (bodyAction[DRINK].active && past.time[0][0].step > RunEmotionalUnit.ActRandom)
            	feelPAIN();

    	if (Motor.A.getTachoCount() > 90 && Motor.B.getTachoCount() < -90)      // em graus
        	senseProSelf[TURN_RIGHT] = pw;  						 // sense drink(1)
    	if (Motor.B.getTachoCount() > 90 && Motor.A.getTachoCount() < -90)
        	senseProSelf[TURN_LEFT] = pw;  						 // sense drink(1)
        if ((Motor.A.getTachoCount() > 90) && (Motor.B.getTachoCount() > 90))
        	senseProSelf[WALK] = pw;  						 // sense drink(1)
        if ((Motor.A.getTachoCount() < -90) && (Motor.B.getTachoCount() < -90))
        	senseProSelf[EAT] = pw;  						 // sense drink(1)
//    	if (Motor.C.getTachoCount() < -90)
//            busInProSelf.add(new Signal(Liberu.NECK_LEFT, power));  // Ligacoes ao contrario
//    	if (Motor.C.getTachoCount() > 90)
//            busInProSelf.add(new Signal(Liberu.NECK_RIGHT, power));  // Ligacoes ao contrario
        Motor.A.resetTachoCount();
        Motor.B.resetTachoCount();
//        Motor.C.resetTachoCount();

        for (int i=0; i<bodyAction.length; i++)
            bodyAction[i].setActive(false);
    }

    public void endLiberu(boolean endL) {
    	int t, i;
        
        for (i=0; i<past.nNeuronsPTaste; i++)
            past.nodeTaste[i].setEnd(endL);
        for (i=0; i<past.nNeuronsPSmell; i++)
            past.nodeSmell[i].setEnd(endL);
        for (i=0; i<past.nNeuronsPVision; i++)
            past.nodeVision[i].setEnd(endL);
        for (i=0; i<past.nNeuronsPTact; i++)
            past.nodeTact[i].setEnd(endL);
        for (i=0; i<past.nNeuronsPSound; i++)
            past.nodeSound[i].setEnd(endL);
        for (i=0; i<past.nNeuronsPProSelf; i++)
            past.nodeProSelf[i].setEnd(endL);
        for (t=0; t<past.nTrails; t++)
            for (i=0; i<past.nNeuronsT; i++)
                past.time[i][t].setEnd(endL);
        for (i=0; i<past.nNeuronsPProSelf; i++)
            past.actNode[i].setEnd(endL);
    }

    public void saveLiberu() {
        
        try {
            // Save the nodes to Disk file <Liberu.dat>
            ObjectOutputStream out = new ObjectOutputStream(new
                    FileOutputStream("Liberu.dat"));
            out.writeObject(past);
            out.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    public void loadRobot() {
        
            try {
                // Load the nodes from the Disk file <Liberu.dat>
                ObjectInputStream in = new ObjectInputStream(new
                        FileInputStream("Liberu.dat"));
                past = (Net)in.readObject();
                in.close();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
    }
}
