//the neural net we used
import java.util.*;

public class NeuralNet
{
	public int numInputs;
	public Perceptron[] internal;
	public Perceptron output;
	
	//constructors
	public NeuralNet(int numI, int sizeInt)
	{
		numInputs = numI;
		internal = new Perceptron[sizeInt]; 
	}

	public NeuralNet(int numI, int sizeInt, double[][] weights1, double[] weights2)
	{
		numInputs = numI;
		internal = new Perceptron[sizeInt]; 
		double[] temp = new double[numI];
		for(int i = 0; i < sizeInt; i++)
		{
			temp = new double[numI];
			for(int j = 0; j < numI; j++)
			{
				temp[j] = weights1[j][i];
			}
			internal[i] = new Perceptron(numI, temp, 1);
		}
		output = new Perceptron(weights1[0].length, weights2, 1);
	}
	
	//gets the values
	public double getVal(double[] input)
	{
		double[] input2 = getVals(input);
		return (output.getValue(input2));
	}
	
	public double[] getVals(double[] input)
	{
		double[] vals = new double[internal.length];
		for(int i = 0; i < internal.length; i++)
		{
			vals[i] = internal[i].getValue(input); //do we want to do getValue or fire?
		}
		return vals;
	}
	
	public void printWeights(Perceptron p)
	{
		for(int i = 0; i < p.weights.length; i++)
			System.out.println(p.weights[i]);
	}
	
	public void storeInFile(FileOut file)
	{
		for(int i = 0; i < internal.length; i++)
		{
			internal[i].storeInFile(file);
			file.print("\n");
		}
		output.storeInFile(file);
	}
	
	public void mutate()
	{
		Random rn = new Random();
		int num = abs(rn.nextInt()) % (internal.length + 1);
		if (num < internal.length)
			internal[num].mutate();
		else
			output.mutate();
	}
	
	public int abs(int num)
	{
		if (num < 0) return -num;
		return num;
	}

	//the breeding of two neural nets
	public NeuralNet breed(NeuralNet p1, NeuralNet p2, boolean[][] pb, boolean[] bot)
	{
		Perceptron[] p = new Perceptron[internal.length];
		double[][] w = new double[numInputs][internal.length];
		double[] w2 = new double[internal.length];
		boolean[] pb2 = new boolean[numInputs];
		for(int i = 0; i < internal.length; i++)
		{
			for(int j = 0; j < numInputs; j++)
			{
				if(pb[j][i])
				{
					w[j][i] = p1.internal[i].weights[j];
				}
				else
				{
					w[j][i] = p2.internal[i].weights[j];
				}
			}			
		}
		for(int i = 0; i < internal.length; i++)
		{
			if (bot[i])
			{
				w2[i] = p1.output.weights[i];
			}
			else
			{
				w2[i] = p2.output.weights[i];
			}
		}
		return new NeuralNet(numInputs, internal.length, w, w2);
	}
}