#ifndef __CL_KERNEL_CLASS_H__
#define __CL_KERNEL_CLASS_H__

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

#include "clErrorClass.h"
#include <vector>
#include <sstream>

//! OpenCLのカーネルを扱うクラス.
/*!  */
class clKernelClass
{
private:
    std::vector<cl_kernel>   kernel;          //!< OpenCLのカーネル
    std::vector<std::string> kernel_name;     //!< カーネルの名前
protected:
public:

//関数とか
private:
protected:
public:
    clKernelClass();              // 変数の初期化など
    clKernelClass(cl_program program, std::string kernel_name);
    ~clKernelClass();             // カーネルの開放
	
    const       void            createKernel(cl_program program, std::string kernel_name);
    const       cl_kernel       getKernel(std::string string);
	const       unsigned int    getKernelIndex(std::string name);
	const		void			runKernel();


// -------------------------------------------------------
//! \brief  カーネルの参照を取得.
//! \param  カーネルの名前.
//! \return カーネルの参照を返却する.

// ---------------エラー処理---------------//
#define EXCEPT \
if(status != CL_SUCCESS){\
	std::ostringstream s; \
	s << "set kernel arguments failed." << std::endl \
	<< "Argument " << arg << "set failed." << std::endl; \
	throw clErrorClass(status, s.str(), __FUNCTION__); \
}

// ---------------反復記述用---------------//
#define SET_KERNEL_ARG(X) \
status = clSetKernelArg(kernel[getKernelIndex(kernel_name)], arg++, s##X, a##X);EXCEPT; if(num_args == arg)return;


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)
{try{

	cl_uint status;
	cl_uint arg=0;
	if(!num_args)return;
	
	SET_KERNEL_ARG(1);
	SET_KERNEL_ARG(2);
	SET_KERNEL_ARG(3);
	SET_KERNEL_ARG(4);
	SET_KERNEL_ARG(5);
	SET_KERNEL_ARG(6);
	SET_KERNEL_ARG(7);
	SET_KERNEL_ARG(8);
	SET_KERNEL_ARG(9);
	SET_KERNEL_ARG(10);
	SET_KERNEL_ARG(11);
	SET_KERNEL_ARG(12);
	SET_KERNEL_ARG(13);
	SET_KERNEL_ARG(14);
	SET_KERNEL_ARG(15);

}catch(clErrorClass &err){err.showErrMsg();}catch(...){std::cerr << "unknown error." << std::endl;}}

			    void            setKernelArgs(std::string kernel_name, cl_mem *memory, unsigned int arg_index, size_t memory_size);
				void            setKernelArgs(std::string kernel_name, void   *memory, unsigned int arg_index, size_t memory_size);
};
#endif //__CL_KERNEL_CLASS_H__
