package mcmas.core;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import mcmas.api.MCMASException;
import mcmas.utils.Objects7;

import org.jocl.CL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



public class MCMUtils {
	
	private final static Logger logger = LoggerFactory.getLogger(MCMUtils.class);
	
	public static String readFileAsString(String filePath) {
		filePath = Objects7.requireNonNull(filePath, "Can't open a null path");
	    byte[] buffer = new byte[(int) new File(filePath).length()];
	    FileInputStream f = null;
	    
	    try {
	    	f = new FileInputStream(filePath);
	    	f.read(buffer);
	    } catch(IOException e) {
	    	throw new MCMASException("Invalid program: " + filePath, e);
	    } finally {
	    	try {
	    		if (f != null) {
	    			f.close();
	    		}
	    	} catch (IOException e) {
	    		// Really nothing to do here...
	    	}
	    }
	    
	    return new String(buffer);
	}
	
	public static void printEventStats(String title, MCMEvent e) {
		logger.info("waited[{}] time[{}] tag[{}]", new Object[] {
				e.getWaitDuration() / 1000000,
				e.getExecutionDuration() / 1000000,
				title
		});
	}
	
	public static String formatEventStats(String tag, MCMEvent e) {
		return String.format("tag[%s] waited[%d] time[%d]",
				tag, e.getWaitDuration() / 1000000, e.getExecutionDuration() / 1000000);
	}
	
	public static MCMProgram compileFile(MCMContext context, String sourceFile, Object... options) {
		MCMProgram program = null;
		StringBuilder optionsString = new StringBuilder();
		
		for (Object option : options) {
			optionsString.append(option);
		}
		
		
		program = context.createProgram(MCMUtils.readFileAsString(sourceFile), optionsString.toString());
		return program;
	}
	
	public static long binaryOr(MCMFlag... flags) {
		long value = 0;
		
		for (MCMFlag flag : flags) {
			value |= flag.getValue();
		}
		
		return value;
	}
	
	public static long binaryOr(long... flags) {
		long value = 0;
		
		for (long flag : flags) {
			value |= flag;
		}
		
		return value;
	}
	
	public static void printInfos() {
		MCMPlatform[] platforms = MCMPlatform.getPlatforms();
		
		if (platforms.length == 0) {
			System.out.println("No device detected");
		}
		
		for (MCMPlatform platform : platforms) {
			MCMDevice[] devices = platform.getDevices(CL.CL_DEVICE_TYPE_ALL);
			
			for (int j = 0; j < devices.length; j++) {
				MCMDevice device = devices[j];
				
				int k = 1;
				
				String name = device.getInfoString(CL.CL_DEVICE_NAME);
				System.out.println(String.format("%d. Device: %s", j + 1, name));
				
				String device_version = device.getInfoString(CL.CL_DEVICE_VERSION);
				System.out.println(String.format(" %d.%d Hardware version: %s", j + 1, k++, device_version));
				
				String driver_version = device.getInfoString(CL.CL_DRIVER_VERSION);
				System.out.println(String.format(" %d.%d Driver version: %s", j + 1, k++, driver_version));
				
				int compute_units = device.getInfoInt(CL.CL_DEVICE_MAX_COMPUTE_UNITS);
				System.out.println(String.format(" %d.%d Parallel compute units: %d", j + 1, k++, compute_units));
				
				long global_memory = device.getInfoLong(CL.CL_DEVICE_GLOBAL_MEM_SIZE);
				System.out.println(String.format(" %d.%d Global memory size: %d", j + 1, k++, global_memory));
			}
		}
	}
	
	public static void main(String[] args) {
		printInfos();
	}
	
}
