/*
 * Neuron.java
 *
 * Created on 4 of August 2004, 21:54
 */

/**
 *
 * @author Paulo Roque Silva
 */
import java.util.*;
import java.io.*;

public class Neuron implements Serializable {
    public static final long serialVersionUID = 2015L; // Data version
    private static final int Nperceptions = 10; // perceptions memory allocated by default
    public static final float Habit = 0.99F; // habit
    static boolean			end; // if true, neuron thread is to finish
    int			        	pointer, // actual memory step
    						step; // # of interactions
    int			 			who, // Self Identification
    						value, // #times that neuron had fired
    						quality, // Good/Bad
    						finalQuality, // quality total
    						threshold; // Level to react (in percentage 0-100) (to Past nodes)
    boolean					fire, // Neuron is fired
    						home, // true if home
    						standby, // standby for surviving learn in Act nodes & Past nodes
    						standby2; // Neuron is in standby for Out-Wait-In (to Past nodes)
    ArrayList<Signal>		perception; // Signals that neuron is listening or act
    ArrayList<Signal>		learn; // Learn data - credit

    /** Creates a new instance of Neuron */
    public Neuron(int neuronId, int th) {

		pointer = 0;
        step = 0; // step that past neuron starts to record
        end = false; // the simulation doesn't end yet
        home = false;
        who = neuronId;
        threshold = th;
        value = 0; // never has fired
        quality = 0;
        finalQuality = 0;
        fire = false;
        standby = false; // waits for random fires
        standby2 = false; // waits for REU-Action fired
        perception = new ArrayList<Signal>(Nperceptions);
        learn = new ArrayList<Signal>(Nperceptions);
    }

    public void addStep() {
        
        step += 1;
    }

    public void addPointer() {
        
        pointer += 1;
    }

    public void setPointer(int i) {
        
        pointer = i;
    }
    
    public void setHome(boolean b) {
        
        home = b;
    }
    
    public void addFinalQuality(int q) {
        
    	finalQuality += q;
    }
    
    public void addQuality(int q) {
        
    	quality += q;
    }
    
    public Signal getPerception(int n) {

    	if (n < perception.size())
        	return (Signal)perception.get(n);
    	else
    		if (n == 0)
    			return new Signal(0, 0, 0);
		return new Signal(0, 0, 0);
    }

    private boolean newPerception(int e) {

        boolean isNew;
        int		i;
        
        isNew =true;
        for (i=0; i<perception.size(); i++)
            if (getPerception(i).emitter == e)
                isNew = false;
        return isNew;
    }
    
    // add a signal with a who <e>, a quantity <pw> and a quality <plsr>
    public void addPerception(int e, float pw, int plsr) {

        if (newPerception(e))
        	perception.add(new Signal(e, pw, plsr));
    }
    
    public void clearSignals() {
    	int i;

    	for (i=0; i<perception.size(); i++)
    		getPerception(i).setActive(false);
    }

    public void clearPerceptions() { // ArrayList to clear all: dendrites.clear();
    	
        perception.clear();
        perception = new ArrayList<Signal>(Nperceptions);
    }
    
    public void removePerceptions(int e) { // ArrayList to clear all: dendrites.clear();
    	
        perception.remove(e);
    }
    
    public Signal getLearn(int n) { // n starts at 0 - n is not the emitted, but an index

    	return (Signal)learn.get(n);
    }

    public boolean newLearn(int e) {

        boolean isNew;
        int		i;
        
        isNew =true;
        for (i=0; i<learn.size(); i++)
            if (Math.abs(getLearn(i).emitter) == e)
                isNew = false;
        return isNew;
    }
    
    // add a signal with a who <e>, a quantity <pw> and a quality <plsr>
    public void addLearn(int e, float pw, int plsr) {

        if (newLearn(e))
            learn.add(new Signal(e, pw, plsr));
    }
    
    public void clearLearn() { // ArrayList to clear all: dendrites.clear();
    	
        learn.clear();
        learn = new ArrayList<Signal>(Nperceptions);
    }

    public void removeLearn(int e) {
    	
        learn.remove(e);
    }
    
    public float powerOfFire(int sense) { // For Past Neurons only
        float	activeCredit, // Sum of all 1/(log(abs(recP-actP+1))+1) from active signal
        		nActives; // # of active perceptions or signals
    	int		i; // index
    	float   x; // Absolute difference between Powers whose
        
        nActives = 0;
    	activeCredit = 0;
        for (i=0; i<perception.size(); i++)
            if (getPerception(i).active || getPerception(i).recPower > Brain.MinSense) {
            	// Set activePercentCredit
               	nActives += 1;
                x = Math.abs(getPerception(i).recPower - getPerception(i).actPower);
                if (x > Brain.MaxInSense)
                	x = Brain.MaxInSense;
                // TI-86 graph 14
                activeCredit += (Brain.MaxInSense - x) * 100 / Brain.MaxInSense;
            }
    	fire = false;
    	if (nActives == 0) nActives = 1;
    	activeCredit = activeCredit / nActives;
        if (activeCredit >= threshold) {
        	fire = true;
//            finalQuality = (int)(Habit * finalQuality); // CHAVE
        }
        return activeCredit;
    }
    
    public int powerToAct() { // For Act Neurons only
        int		activeCredit, // Sum of all 1/(log(abs(recP-actP+1))+1) from active signal
        		totalCredit, // total of perceptions values
        		credit, // credit
    			i; // index
        
    	activeCredit = 0;
        totalCredit = 0;
        for (i=0; i<perception.size(); i++) {
            if (getPerception(i).active)
                activeCredit += getPerception(i).recPower; // Could use in actions continues (Tonus)
            totalCredit += getPerception(i).recPower;
        }
    	fire = false;
    	if (totalCredit == 0) totalCredit = 1; // redundant - just in case
    	credit = (int)(100 * activeCredit / totalCredit);
    	System.out.println(credit);
        if (credit >= threshold) { // percentage average of active
        	fire = true;
        	standby = true;
        }
        return credit;
    }
}