package mcmas.core;

//import java.util.Arrays;

import mcmas.utils.Objects7;

import org.jocl.CL;
import org.jocl.Pointer;
import org.jocl.Sizeof;
import org.jocl.cl_device_id;
import org.jocl.cl_platform_id;


public class MCMPlatform implements MCMRequestable {
	
	public final static int PROFILE    = CL.CL_PLATFORM_PROFILE;
	public final static int VERSION    = CL.CL_PLATFORM_VERSION;
	public final static int NAME       = CL.CL_PLATFORM_NAME;
	public final static int VENDOR     = CL.CL_PLATFORM_VENDOR;
	public final static int EXTENSIONS = CL.CL_PLATFORM_EXTENSIONS;
	
	public static MCMPlatform[] getPlatforms() {
		cl_platform_id[] rawPlaforms = MCMHelpers.getPlatforms();
		MCMPlatform[] plaforms = new MCMPlatform[rawPlaforms.length];
		
		for (int i = 0; i < rawPlaforms.length; i++) {
			plaforms[i] = new MCMPlatform(rawPlaforms[i]);
		}
		
		return plaforms;
	}
	
	private cl_platform_id id;
	private MCMProperties properties;
	
	public MCMPlatform(cl_platform_id id) {
		id = Objects7.requireNonNull(id, "Can't create a null platform");
		this.id = id;
		this.properties = new MCMProperties(this);
	}
	
	public cl_platform_id getId() {
		return id;
	}
	
	public MCMDevice[] getDevices(long deviceType) {
		cl_device_id[] rawDevices = MCMHelpers.getDevices(id, deviceType);
		MCMDevice[] devices = new MCMDevice[rawDevices.length];
		
		for (int i = 0; i < rawDevices.length; i++) {
			devices[i] = new MCMDevice(rawDevices[i]);
		}
		
		return devices;
	}
	
	public int[] getSupportedCLVersion() {
		return MCMHelpers.getSupportedOpenCLVersion(id);
	}
	
	public int getSupportedVersionInt() {
		return MCMHelpers.getSupportedOpenCLVersionAsInt(id);
	}
	
	private void getPlatformInfo(int param, int size, Pointer value) {
		CL.clGetPlatformInfo(id, param, size, value, null);
	}
	
	public int getInfo(int param, long size, Pointer value, long[] returnSize) {
		return CL.clGetPlatformInfo(id, param, size, value, returnSize);
	}
	
	public int getInfoInt(int param) {
		int[] result = new int[1];
		getPlatformInfo(param ,Sizeof.cl_int, Pointer.to(result));
		return result[0];
	}
	
	public long getInfoLong(int param) {
		long[] result = new long[1];
		getPlatformInfo(param ,Sizeof.cl_long, Pointer.to(result));
		return result[0];
	}
	
	public String getInfoString(int param) {
		long [] size = new long[1];
		CL.clGetPlatformInfo(id, param, 0, null, size);
		
		byte [] value = new byte[(int) (size[0])];
		CL.clGetPlatformInfo(id, param, size[0], Pointer.to(value), size);
		
		// Skip the final NULL character (value is a C string)
		return new String(value, 0, Math.max(0, (int) size[0] - 1));
	}
	
	public MCMProperties getProperties() {
		return properties;
	}
	
	public String toString() {
		StringBuilder b = new StringBuilder();
		
		b.append(super.toString() + "\n");
		b.append("  name:       " + getInfoString(CL.CL_PLATFORM_NAME) + "\n");
		b.append("  vendor:     " + getInfoString(CL.CL_PLATFORM_VENDOR) + "\n");
		b.append("  version:    " + getInfoString(CL.CL_PLATFORM_VERSION) + "\n");
		b.append("  extensions: " + getInfoString(CL.CL_PLATFORM_EXTENSIONS) + "\n"); 
		
		return b.toString();
	}
	
}
