package sensicamJNI.fake;

import java.io.IOException;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Random;

import sensicamJNI.CamTypes;
import sensicamJNI.SenbufDev;
import sensicamJNI.SencamDef;

/** Fake version of JNI calls to linux sensicam SDK
 *  Generates random data. 
 */

public class Sensicam {
	private static int imgWidth = -1, imgHeight= -1;
	private static final int ccdwidth = 1376, ccdHeight = 1040;
	private static int exposureMS;
	private static int delayMS;
	private static int counter = 0;
	private static boolean selectCalled = false;
	
	/*********** sencaml.h **************/
	
	public static long[] sen_initboard(int board){ return new long[]{ 0, 0 }; }
	public static int sen_closeboard(long hdriver){ return 0; }
	public static void sen_enable_message_log(int msg_lev, String fileName){ }
	public static void sen_set_syslog_facility(int msg_lev) { }
	public static int sen_setup_camera(long hdriver){ return 0; }
	public static int sen_get_cam_param(long hdriver, SencamDef.cam_param param){
		param.ccdwidth = ccdwidth; param.ccdheight = ccdHeight;
		param.cam_typ = CamTypes.TESTCAM;
		return 0;
	};
	
	public static int sen_set_coc(long hdriver,
			int mode,    int trig,
            int roixmin, int roixmax,
            int roiymin, int roiymax,
            int hbin,    int vbin,
            String timevalues){
		int x0 = (roixmin-1) * 32;
		int y0 = (roiymin-1) * 32;
		int x1 = (roixmax-1) * 32 + 31;
		int y1 = (roixmax-1) * 32 + 31;
		if(x1 >= ccdwidth) x1 = ccdwidth - 1;
		if(y1 >= ccdHeight) y1 = ccdHeight - 1;
		imgWidth = (x1 - x0 + 1) / hbin;
		imgHeight = (y1 - y0 + 1) / vbin;
		String parts[] = timevalues.split(",");
		delayMS = Integer.parseInt(parts[0]);
		exposureMS = Integer.parseInt(parts[1]);
		return 0;
	}
	
	public static int[] sen_getsizes(long hdriver){ return new int[]{ 0, ccdwidth, ccdHeight, imgWidth, imgHeight, 12 }; }
	public static int[] sen_allocate_buffer(long hdriver, int bufnr, int size){ return new int[]{ 0, 0, size }; }

	public static int sen_free_buffer(long hdriver, int bufnr){ return 0; }

	public static int sen_run_coc(long hdriver,int mode){ return 0; }
	public static int sen_stop_coc(long hdriver,int mode){ return 0; }
	public static int sen_get_cam_values(long hdriver, SencamDef.cam_values val){ 
		val.exptime = exposureMS;
		val.deltime = delayMS;
		return 0;
	}
	
	public static int sen_get_buffer_status(long hdriver, int bufnr, int mode, SenbufDev.DEVBUF stat, int len){
		//we simply pretend the data was put in the first buffer they ask for after a select is called
		if(selectCalled){
			selectCalled = false;
			 stat.status = 1 << SenbufDev.WRITE_DONE_B;
		}else{
			 stat.status = 0;			
		}
		return 0;
	}
	
	public static int sen_copy_buffer(long hdriver, int bufnr, ByteBuffer data, int size, int offset){
		ByteBuffer buff = data.duplicate();
		buff.order(ByteOrder.LITTLE_ENDIAN);
		
		int nx = imgWidth / 10 - 1;
		int iy = counter / nx;
		int ix = counter - iy * nx;
		int bx = ix * 10;
		int by = iy * 10;
		
		//data.rewind();
		//data.position(offset);
		Random r = new Random();		
		//for(int i=0; i < (size / 2); i++){
		for(int x=0; x < imgWidth; x++){
			for(int y=0; y < imgHeight; y++){
				short val = (short)(r.nextInt(4096) * exposureMS / 100);
				if(val >= 4096)
					val = 4095;
			
				if(x >= bx && x < bx+50 && y >=by && y < by+50){
					val = (short)(counter % 4096);
				}
				
				buff.putShort((y*imgWidth+x)*2, val);	
			}
		}	
		
		counter++;
		return 0;
	}
	public static int sen_add_buffer_to_list(long hdriver, int bufnr, int size, int offset, int data){ return 0; }
	public static int sen_remove_buffer_from_list(long hdriver, int bufnr){ return 0; }
	public static int sen_set_buffer_event(long hdriver, int bufnr, int mode){ return 0; }
	
	public static int select_with_timeout(long hDriver, double timeout){ 
		try {
			Thread.sleep(delayMS + exposureMS);
		} catch (InterruptedException e){ }
		selectCalled = true;
		return 1;
	}

	/*SEN_BUF_STAT_WRITE_DONE
	SEN_BUF_STAT_ERROR
	SEN_BUF_STAT_QUEUED
	*/
}
