#ifndef __CL_CLASS_H__
#define __CL_CLASS_H__

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif //__APPLE__

#include <string>
#include <iostream>
#include "clErrorClass.h"
#include "clDeviceClass.h"
#include "clPlatformClass.h"
//#include "clContextClass.h"
//#include "clCommandQueueClass.h"
#include "clProgramClass.h"
#include "clKernelClass.h"
#include "clMemoryClass.h"


//! openclの関数をまとめたクラス.
/*! OpenCLで使用するデバイスなどを用意する. */
class clClass
{
//変数とか
private:
	cl_platform_id		platform_id;
	cl_device_id		device_id;
	cl_context			context;
	cl_command_queue	command_queue;

	clPlatformClass		*C_platform;		//!< プラットフォームの情報を扱うクラスを包含
	clDeviceClass		*C_device;          //!< デバイスの情報を扱うクラスを包含
//	clContextClass		*C_context;		    //!< コンテキストの情報を扱うクラスを包含
//	clCommandQueueClass *C_commandqueue;    //!< コマンドキューの情報を扱うクラスを包含
	clProgramClass		*C_program;		    //!< プログラムの情報を扱うクラスを包含
	clKernelClass		*C_kernel;	        //!< カーネルの情報を扱うクラスを包含
	clMemoryClass		*C_memory;	        //!< メモリの情報を扱うクラスを包含
protected:
public:

// 関数とか
private:
protected:
public:
	clClass();
	~clClass();
			void				set(cl_device_id device_id);
	const   void                setUseDevice(unsigned int device);
// プラットフォーム関連
	const	cl_platform_id		getPlatformId() const;
	const	char*				getPlatformInfo(cl_platform_info platform_info) const;
			void				showPlatformInfo(cl_platform_info platform_info) const;
			void				showPlatformInfoAll() const;
			
// デバイス関連
	const   cl_device_id        getDeviceId() const;
	const	char*				getDeviceInfo(cl_device_info device_info) const;
			void				showDeviceInfo(cl_device_info device_info) const;
			void				showDeviceInfoAll() const;
// コンテキスト関連
	const	cl_context			getContext() const;
// コマンドキュー関連
	const	cl_command_queue	getCommandQueue() const;
			void				runKernel(std::string kernel_name, cl_uint num_dimension, const size_t *offset, size_t *global_work_size,  size_t *local_work_size, cl_uint num_event, const cl_event	*event_list, cl_event *event_ ) const;
			void				runKernel(std::string kernel_name, cl_uint num_dimension, size_t *global_work_size, size_t *local_work_size, cl_uint num_event, const cl_event *event_list, cl_event *event_ ) const;
			void				runKernel(std::string kernel_name, cl_uint num_dimension, const size_t *offset,size_t *global_work_size, size_t *local_work_size) const;
			void				runKernel(std::string kernel_name, cl_uint num_dimension, size_t *global_work_size, size_t *local_work_size) const;

			void				getResult(std::string kernel_name, std::string src_memory_name, cl_bool block, size_t offset, size_t memory_size, void *dst_memory, cl_uint num_event, const cl_event *event_list, cl_event *event_ ) const;
			void				getResult(std::string kernel_name, std::string src_memory_name, cl_bool block, size_t memory_size, void *dst_memory, cl_uint num_event, const cl_event *event_list, cl_event *event_ ) const;
			void				getResult(std::string kernel_name, std::string src_memory_name, size_t memory_size, void *dst_memory, cl_uint num_event, const cl_event *event_list, cl_event *event_ ) const;
			void				getResult(std::string kernel_name, std::string src_memory_name, cl_bool block, size_t offset, size_t memory_size, void *dst_memory) const;
			void				getResult(std::string kernel_name, std::string src_memory_name, cl_bool block, size_t memory_size, void *dst_memory) const;
			void				getResult(std::string kernel_name, std::string src_memory_name, size_t memory_size, void *dst_memory) const;

// プログラム関連
			void				createProgramObject(const char *filename);
// カーネル関連
			void				createKernel(const char *file_name, const char *kernel_name);
	const	cl_kernel			getKernel(std::string kernel_name) const;
	const   void                setKernelArg(std::string kernel_name, unsigned int arg_index, size_t memory_size, std::string memroy_name);
	const   void                setKernelArg(std::string kernel_name, unsigned int arg_index, size_t memory_size, void *memory           );

template<class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class T11, class T12, class T13, class T14, class T15>
void setKernelArgs(std::string kernel_name, unsigned int num_args,
T1     *a1,  size_t  s1,
T2     *a2,  size_t  s2,
T3     *a3,  size_t  s3,
T4     *a4,  size_t  s4,
T5     *a5,  size_t  s5,
T6     *a6,  size_t  s6,
T7     *a7,  size_t  s7,
T8     *a8,  size_t  s8,
T9     *a9,  size_t  s9,
T10    *a10, size_t  s10,
T11    *a11, size_t  s11,
T12    *a12, size_t  s12,
T13    *a13, size_t  s13,
T14    *a14, size_t  s14,
T15    *a15, size_t  s15)
{
	this->C_kernel->setKernelArgs(kernel_name, num_args,
		a1, 	s1, 
		a2, 	s2, 
		a3, 	s3, 
		a4, 	s4,
		a5, 	s5, 
		a6, 	s6, 
		a7, 	s7, 
		a8, 	s8, 
		a9, 	s9, 
		a10, 	s10, 
		a11, 	s11, 
		a12, 	s12, 
		a13, 	s13, 
		a14, 	s14, 
		a15,	s15);
}



// メモリ関連
	const   void                createMemory(cl_mem_flags flag, size_t memroy_size, void *mem_pointer, std::string mem_name) const;
		    cl_mem              *getMemory(unsigned int index) const;
			cl_mem              *getMemory(std::string  name)  const;

};
#endif //__CL_CLASS_H__
