//NNGeneString.cpp

#include "NNGeneString.h"

NNGeneString::NNGeneString(int numInputs, int numOutputs, int numHiddenLayers, 
						   int* hLayerSizes, Neuron*** listOfLayers)
{
	numberOfInputs = numInputs;
	numberOfOutputs = numOutputs;
	numberOfHiddenLayers = numHiddenLayers;

	hiddenLayerSizes = new int[numHiddenLayers];
	for (int i=0; i<numHiddenLayers; i++)
		hiddenLayerSizes[i] = hLayerSizes[i];
	
	weights = new float**[numHiddenLayers+1]; //no weights for the input layer

	//creating weights for hidden layers
	for (int i=0; i<numHiddenLayers; i++)
	{
		weights[i] = new float*[hiddenLayerSizes[i]]; //creating arrays that point to weight arrays
		for (int j=0; j<hiddenLayerSizes[i]; j++)
		{
			if (i==0) //first hidden layer
			{
				weights[i][j] = new float[numberOfInputs];
				for (int k=0; k<numberOfInputs; k++)
				{
					//mutation
					float chance = (FRAND+1)/2; //get a number between 0.0 and 1.0
					if (chance <= MUTATION_CHANCE)
					{
						float chance2 = FRAND; //continuous number between -1.0 and 1.0

						if (chance2 > 0)
						{
							weights[i][j][k] = 
								listOfLayers[i+1][j]->GetInputWeights()[k] + MUTATION_AMOUNT;

							if (weights[i][j][k] > 1.0)
							{
								weights[i][j][k] = 1.0;
							}
						}
						else
						{
							weights[i][j][k] = 
								listOfLayers[i+1][j]->GetInputWeights()[k] - MUTATION_AMOUNT;

							if (weights[i][j][k] < -1.0)
							{
								weights[i][j][k] = -1.0;
							}
						}

						//if (CONTINUOUS_WEIGHT_VALUES)
						//{
						//	//weights[i][j][k] = FRAND; //continuous number between -1.0 and 1.0
						//}
						//else
						//{
						//	//weights[i][j][k] = DISCRETE_FRAND; //discrete number between -1.0 and 1.0
						//}

						//std::cout << "Mutation Occurred." << std::endl;
					}
					else
					{
						weights[i][j][k] = listOfLayers[i+1][j]->GetInputWeights()[k];
					}
				}
			}
			else //other hidden layers
			{
				weights[i][j] = new float[hiddenLayerSizes[i-1]];
				for (int k=0; k<hiddenLayerSizes[i-1]; k++)
				{
					//mutation
					float chance = (FRAND+1)/2; //get a number between 0.0 and 1.0
					if (chance <= MUTATION_CHANCE)
					{
						float chance2 = FRAND; //continuous number between -1.0 and 1.0

						if (chance2 > 0)
						{
							weights[i][j][k] = 
								listOfLayers[i+1][j]->GetInputWeights()[k] + MUTATION_AMOUNT;

							if (weights[i][j][k] > 1.0)
							{
								weights[i][j][k] = 1.0;
							}
						}
						else
						{
							weights[i][j][k] = 
								listOfLayers[i+1][j]->GetInputWeights()[k] - MUTATION_AMOUNT;

							if (weights[i][j][k] < -1.0)
							{
								weights[i][j][k] = -1.0;
							}
						}

						//if (CONTINUOUS_WEIGHT_VALUES)
						//{
						//	weights[i][j][k] = FRAND; //continuous number between -1.0 and 1.0
						//}
						//else
						//{
						//	weights[i][j][k] = DISCRETE_FRAND; //discrete number between -1.0 and 1.0
						//}

						//std::cout << "Mutation Occurred." << std::endl;
					}
					else
					{
						weights[i][j][k] = listOfLayers[i+1][j]->GetInputWeights()[k];
					}
				}
			}


		}
	}

	//creating weights for output layer
	weights[numHiddenLayers] = new float*[numberOfOutputs];
	for (int i=0; i<numberOfOutputs; i++)
	{
		weights[numHiddenLayers][i] = new float[hiddenLayerSizes[numHiddenLayers-1]];
		for (int k=0; k<hiddenLayerSizes[numHiddenLayers-1]; k++)
		{
			//mutation
			float chance = (FRAND+1)/2; //get a number between 0.0 and 1.0
			if (chance <= MUTATION_CHANCE)
			{
				float chance2 = FRAND; //continuous number between -1.0 and 1.0

				if (chance2 > 0)
				{
					weights[numHiddenLayers][i][k] = 
						listOfLayers[numHiddenLayers+1][i]->GetInputWeights()[k] + MUTATION_AMOUNT;

					if (weights[numHiddenLayers][i][k] > 1.0)
					{
						weights[numHiddenLayers][i][k] = 1.0;
					}
				}
				else
				{
					weights[numHiddenLayers][i][k] = 
						listOfLayers[numHiddenLayers+1][i]->GetInputWeights()[k] - MUTATION_AMOUNT;

					if (weights[numHiddenLayers][i][k] < -1.0)
					{
						weights[numHiddenLayers][i][k] = -1.0;
					}
				}

				//if (CONTINUOUS_WEIGHT_VALUES)
				//{
				//	weights[numHiddenLayers][i][k] = FRAND; //continuous number between -1.0 and 1.0
				//}
				//else
				//{
				//	weights[numHiddenLayers][i][k] = DISCRETE_FRAND; //discrete number between -1.0 and 1.0
				//}

				//std::cout << "Mutation Occurred." << std::endl;
			}
			else
			{
				weights[numHiddenLayers][i][k] = listOfLayers[numHiddenLayers+1][i]->GetInputWeights()[k];
			}
		}
	}
}

NNGeneString::~NNGeneString()
{
	//deleting hidden layers
	for (int i=0; i<numberOfHiddenLayers; i++)
	{
		for (int j=0; j<hiddenLayerSizes[i]; j++)
		{
			delete [] weights[i][j];
		}
		delete [] weights[i];
	}

	//deleting output layer
	for (int k=0; k<numberOfOutputs; k++)
	{
		delete [] weights[numberOfHiddenLayers][k];
	}

	delete [] weights;
	delete [] hiddenLayerSizes;
}
