#define POSITIVE_ETA 1.2f
#define NEGATIVE_ETA 0.5f
#define DELTA_MIN 0.00001f
#define MAX_STEP 50.0f	

#define PARRAY_INPUT_COUNT 0
#define PARRAY_OUTPUT_COUNT 1
#define PARRAY_LAYER_COUNT 2
#define PARRAY_LEARN 3 
#define PARRAY_START 4
#define PARRAY_ITEMS_PER 5
#define ITERATIONS 6

kernel void NetworkCalc(
    global read_only int *params,
    global write_only float *errors,
    global read_only int *layerIndex,
    global read_only int *layerCounts,
    global read_only int *layerFeedCounts,
    global read_only int *weightIndex,
    global read_only float* input,
    global read_only float* ideal,
    global read_only float* weightsIn,
    global write_only float* layerOutputOut
    )
{
	int taskIndex = get_global_id(0);
	
	int inputSize = params[PARRAY_INPUT_COUNT];
    int outputSize = params[PARRAY_OUTPUT_COUNT];
    int layerCount = params[PARRAY_LAYER_COUNT];
	
	// forward pass
	int taskInputIndex = taskIndex * inputSize;
	int taskIdealIndex = taskIndex * outputSize;
	
	int sourceIndex = NEURON_COUNT - layerCounts[layerCount-1];
	
	global float* layerOutput = layerOutputOut + (taskIndex*NEURON_COUNT);
		
	for(int i=0;i<NEURON_COUNT;i++)
		layerOutput[i] = 1;
		
	// load the input into the layer output array, this feeds the first layer.
	for(int i=0;i<inputSize;i++)
		layerOutput[sourceIndex+i] = input[taskInputIndex+i];
				
	for (int currentLayer = layerCount - 1; currentLayer > 0; currentLayer--)
	{
		int inputIndex = layerIndex[currentLayer];
		int outputIndex = layerIndex[currentLayer - 1];
		int inputSize = layerCounts[currentLayer];
		int outputSize = layerFeedCounts[currentLayer - 1];
		int index = weightIndex[currentLayer - 1];

		global float *wptr = weightsIn+index;
		for (int x = 0; x < outputSize; x++)
		{
			float sum = 0;
			global float *outputPtr = layerOutput+inputIndex;
			for (int y = 0; y < inputSize; y++)
			{
				sum += *(wptr++) * layerOutput[inputIndex + y];
			}
       
			layerOutput[outputIndex + x] = ACTIVATION(sum, 1.0);
		}
	}	
	
	// Calculate the errors 
	float e = 0;
   
	for(int i=0;i<outputSize;i++)
	{
		float diff = ideal[taskIdealIndex+i] - layerOutput[i];
		e+=diff*diff;
	}				

	errors[taskIndex] = e;
}