package org.kne.opencl64;

import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout.OfByte;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import club.doki7.ffm.library.ILibraryLoader;
import club.doki7.ffm.library.JavaSystemLibrary;
import club.doki7.ffm.library.WindowsLibrary;
import club.doki7.ffm.ptr.IntPtr;
import club.doki7.opencl.CL;
import club.doki7.opencl.CLConstants;
import club.doki7.opencl.handle.CLDeviceId;
import club.doki7.opencl.handle.CLPlatformId;

public class OpenCLPlatform {
	static CL opencl=new CL(ILibraryLoader.platformLoader().loadLibrary("OpenCL"));
	static CLUtils openclUtils=new CLUtils(opencl);
	
	private CLPlatformId cl_platform_id;
	
	protected CLPlatformId getCl_platform_id() {
		return cl_platform_id;
	}

	protected OpenCLPlatform(CLPlatformId cl_platform_id) {
		this.cl_platform_id=cl_platform_id;
	}

	public static List<OpenCLPlatform> getOpenCLPlatforms() {
		// int numPlatforms[] = new int[1];
		 IntPtr iptr=IntPtr.allocate(Arena.ofAuto());
		 int errcode =opencl. getPlatformIDs(0, null, iptr);
		 CLUtils.checkResult(errcode);
	        //System.out.println("Number of platforms: "+numPlatforms[0]);

	        // Obtain the platform IDs
	        CLPlatformId.Ptr platforms = CLPlatformId.Ptr.allocate(Arena.ofAuto(), iptr.read());
	      errcode=  opencl.getPlatformIDs(iptr.read(), platforms, iptr);
			 CLUtils.checkResult(errcode);
		List<OpenCLPlatform> plats=new ArrayList<>(iptr.read());
	        for (int i=0;i<iptr.read();i++) {
	        	plats.add(new OpenCLPlatform(platforms.read(i)));
			}
	      return Collections.unmodifiableList( plats);
	}
	
	public String getName() {
		String platformName = openclUtils.getString(cl_platform_id, CLConstants. PLATFORM_NAME);
		return platformName;
	}
	
	public String getVersion() {
		 String platformVersion = openclUtils.getString(cl_platform_id, CLConstants.PLATFORM_VERSION);
		 return platformVersion;
	}
	
	public List<OpenCLDevice> getOpenCLDevices() {
		 IntPtr numDevices = IntPtr.allocate(Arena.ofAuto());
         int errcode=opencl.getDeviceIDs(cl_platform_id, CLConstants.DEVICE_TYPE_ALL, 0, null, numDevices);
         if(errcode==CLConstants. DEVICE_NOT_FOUND) {
        	 return Collections.unmodifiableList( new ArrayList<>());
         }
		 CLUtils.checkResult(errcode);
         CLDeviceId.Ptr devicesArray = CLDeviceId.Ptr.allocate(Arena.ofAuto(),numDevices.read());
         errcode=opencl.getDeviceIDs(cl_platform_id, CLConstants.DEVICE_TYPE_ALL, numDevices.read(), devicesArray, null);
		 CLUtils.checkResult(errcode);
		List<OpenCLDevice> devs=new ArrayList<>(numDevices.read());
         for (int i = 0; i < numDevices.read(); i++) {
        	 devs.add(new OpenCLDevice(this, devicesArray.read(i)));
		}
		return Collections.unmodifiableList(devs);
	}
	
	

	@Override
	public String toString() {
		return "OpenCLPlatform [getName()=" + getName() + ", getVersion()=" + getVersion() + "]";
	}

	
}
