package mcmas.core;

import mcmas.utils.Objects7;

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


public class MCMDevice {
	
	public static final int ADDRESS_BYTES      = CL.CL_DEVICE_ADDRESS_BITS;
	public static final int AVAILABLE          = CL.CL_DEVICE_ADDRESS_BITS;
	public static final int COMPILER_AVAILABLE = CL.CL_DEVICE_COMPILER_AVAILABLE;
	
	private final cl_device_id id;
	
	public MCMDevice(cl_device_id id) {
		id = Objects7.requireNonNull(id, "Can't create a device using a null id");
		this.id = id;
	}
	
	public cl_device_id getId() {
		return id;
	}
	
	public String getDeviceName() {
		return getInfoString(CL.CL_DEVICE_NAME);
	}
	
	private void getDeviceInfo(int param, int size, Pointer value) {
		CL.clGetDeviceInfo(id, param, size, value, null);
	}
	
	public int getInfoInt(int param) {
		int[] result = new int[1];
		getDeviceInfo(param ,Sizeof.cl_int, Pointer.to(result));
		return result[0];
	}
	
	public long getInfoLong(int param) {
		long[] result = new long[1];
		getDeviceInfo(param ,Sizeof.cl_long, Pointer.to(result));
		return result[0];
	}
	
	public String getInfoString(int param) {
		long [] size = new long[1];
		CL.clGetDeviceInfo(id, param, 0, null, size);
		
		byte [] value = new byte[(int) (size[0])];
		CL.clGetDeviceInfo(id, param, size[0], Pointer.to(value), null);
		
		// Skip the final NULL character (value is a C string)
		return new String(value, 0, Math.max(0, (int) size[0] - 1));
	}
	
	public String toString() {
		StringBuilder b = new StringBuilder();
		
		b.append(super.toString() + "\n");
		b.append("  name:               " + getInfoString(CL.CL_DEVICE_NAME) + "\n");
		b.append("  vendor:             " + getInfoString(CL.CL_DEVICE_VENDOR) + "\n");
		b.append("  version:            " + getInfoString(CL.CL_DEVICE_VERSION) + "\n");
		b.append("  cores:              " + getInfoInt(CL.CL_DEVICE_MAX_COMPUTE_UNITS) + "\n");
		b.append("  max workgroup size: " + getInfoLong(CL.CL_DEVICE_MAX_WORK_GROUP_SIZE) + "\n");
		b.append("  max dimensions:     " + getInfoInt(CL.CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS) + "\n");
		b.append("  global mem size:    " + getInfoLong(CL.CL_DEVICE_GLOBAL_MEM_SIZE) / 1048576 + " MB\n");
		b.append("  max alloc size:     " + getInfoLong(CL.CL_DEVICE_MAX_MEM_ALLOC_SIZE) / 1048576 + " MB\n");
		b.append("  max constant size:  " + getInfoLong(CL.CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE) / 1024 + " KB\n");
		b.append("  local mem size:     " + getInfoLong(CL.CL_DEVICE_LOCAL_MEM_SIZE) / 1024 + " KB\n");
		b.append("  global cache size:  " + getInfoLong(CL.CL_DEVICE_GLOBAL_MEM_CACHE_SIZE) / 1024 + " KB\n");
		
		return b.toString();
	}
	

}
