// Primitives.cpp : Defines the entry point for the console application.

#include <string>
#include <vector>
#include <iostream>
#include "Common.h"
#include "OpenCLHandler.h"
#include "Tests.h"

// OpenCL C API
#include <CL/opencl.h>

// OpenCL C++ API
#include "cl.hpp"

//const size_t dataSize = 4096;
//
void capi()
{
	// Get a platform ID
	cl_platform_id platformID;
	clGetPlatformIDs(1, &platformID, NULL);
	
	// Get a device ID
	cl_device_id deviceID;
	clGetDeviceIDs(platformID, CL_DEVICE_TYPE_GPU, 1, &deviceID, NULL);
	
	// Create a context
	cl_context context;
	cl_context_properties contextProperties[] =
	{ CL_CONTEXT_PLATFORM, (cl_context_properties)platformID, 0 };
	context = clCreateContext(contextProperties, 1, &deviceID, NULL, NULL, NULL);
	
	// Create a command queue
	cl_command_queue queue;
	queue = clCreateCommandQueue(context, deviceID, CL_QUEUE_PROFILING_ENABLE, NULL);
	
	// Create an OpenCL program
	std::string source = FileToString("../kernels/programs.cl");
	const char* csource = source.c_str();
	cl_program program = clCreateProgramWithSource(context, 1, &csource, NULL, NULL);
	cl_int err = clBuildProgram(program, 1, &deviceID, NULL, NULL, NULL);
	if (err != CL_SUCCESS)
	{
		cl_uint logLength;
		clGetProgramBuildInfo(program, deviceID, CL_PROGRAM_BUILD_LOG, 0, NULL, &logLength);
		char* log = new char[logLength];
		clGetProgramBuildInfo(program, deviceID, CL_PROGRAM_BUILD_LOG, logLength, log, 0);
		std::cout << log << std::endl;
		delete[] log;
		exit(-1);
	}
}

void add_tests(std::vector<TestCase*>* tests) {

}


int main()
{
	//capi();

	OpenCLHandler handler("../kernels/programs.cl");
	std::vector<TestCase*> tests;

	Square s;
	Histogram h1(true, 32, 4096);
	Histogram h2(false, 32, 4096);
	ReduceAdd r1(handler.get_max_size());
	Compact c(1024);
	ExclusiveScan e(handler.get_max_size());

	tests.push_back(&s);
	tests.push_back(&h1);
	tests.push_back(&h2);
	tests.push_back(&r1);
	tests.push_back(&e);
	tests.push_back(&c);
	

	for (size_t i = 0; i < tests.size(); i++) {
		std::cout << tests[i]->description() << std::endl;
		if (handler.run_test(tests[i])) {
			std::cout << "    Success" << std::endl << std::endl;
		}
		else {
			std::cout << "    Failure" << std::endl << std::endl;
		}
	}
    return 0;
}