package sentest;

import java.nio.ByteBuffer;

import sensicamJNI.CamTypes;
import sensicamJNI.SenbufDev;
import sensicamJNI.SencamDef;
import sensicamJNI.Sensicam;
import sensicamJNI.SensicamException;

/** This is basically a direct copy of the sengrab.c proted through to Java.
 * 
 * It seems to work, although PCCIS crashes occasionally when debugging it in eclipse
 * over X forwarding.
 *  
 * @author oliford
 */
public class SensicamGrab {
	public static final int nImages = 10;
	
	public static void main(String[] args) {
		int boardNo = 0;
		int nBuffs = 4;
		int bufferNo[] = new int[nBuffs];
		for(int i=0; i < nBuffs; i++)
			bufferNo[i] = -1;
		
		Sensicam.sen_enable_message_log(0xffff, "/tmp/sencam.log");
		Sensicam.sen_set_syslog_facility(0xffff);
		
		long retL[] = Sensicam.sen_initboard(boardNo);
		long hDriver = retL[1];
		System.out.println("initboard: " + retL[0] +"\t"+hDriver);

		try{
			int ret = Sensicam.sen_setup_camera(hDriver);
			if(ret < 0)			  
				throw new SensicamException("sen_setup_camera", ret);
			System.out.println("sen_setup_camera: " + ret);

			SencamDef.cam_param params = new SencamDef.cam_param();

			Sensicam.sen_get_cam_param(hDriver, params);


			/*set typical COC-parameters of camera 1 */
			if((params.cam_typ == CamTypes.LONGEXP) || (params.cam_typ == CamTypes.OEM))
				ret = Sensicam.sen_set_coc(hDriver, CamTypes.M_LONG, 0,1, params.ccdwidth/32,1, params.ccdheight/32,1,1,"0,10,-1,-1");
			else if(params.cam_typ == CamTypes.FASTEXP)
				ret = Sensicam.sen_set_coc(hDriver, CamTypes.M_FAST, 0,1, params.ccdwidth/32,1, params.ccdheight/32,1,1,"0,1000000,0,1000000,-1,-1");
			else if(params.cam_typ == CamTypes.LONGEXPI)
				ret = Sensicam.sen_set_coc(hDriver, CamTypes.M_LONG, 0,1, params.ccdwidth/32,1, params.ccdheight/32,1,1,"0,10,-1,-1");
			else if(params.cam_typ == CamTypes.LONGEXPQE)
				ret = Sensicam.sen_set_coc(hDriver, CamTypes.M_LONG, 0,1, params.ccdwidth/32,1, params.ccdheight/32+1,1,1,"0,10,-1,-1");
			else if(params.cam_typ == CamTypes.FASTEXPQE)
				ret = Sensicam.sen_set_coc(hDriver, CamTypes.M_LONG, 0,1, params.ccdwidth/32,1, params.ccdheight/32+1,1,1,"0,10,-1,-1");
			else if(params.cam_typ == CamTypes.DICAM)
				ret = Sensicam.sen_set_coc(hDriver, CamTypes.M_DICAM, 0,1, params.ccdwidth/32,1, params.ccdheight/32,1,1,"2,990,0,1,0,0,1,0,-1,-1");
			else 
				throw new SensicamException("Unknown camera "+params.cam_typ);
			
			if(ret < 0)
				throw new SensicamException("sen_set_coc", ret);			    
			System.out.println("sen_set_coc: " + ret);


			/* allocate and map 4 device-buffers with ccdsize */
			int retI[] = Sensicam.sen_getsizes(hDriver);
			ret = retI[0]; int ccdx=retI[1], ccdy=retI[2], actx=retI[3], acty=retI[4], bit_pix=retI[5];

			if(ret < 0)
				throw new SensicamException("sen_getsizes", ret);
			
			for(int i=0;i<nBuffs;i++)
			{
				bufferNo[i] = -1;
				
				int size=ccdx*ccdy*2;				
				retI = Sensicam.sen_allocate_buffer(hDriver, bufferNo[i], size);
				ret = retI[0]; bufferNo[i] = retI[1]; size = retI[2];
				
				if(ret < 0)
					throw new SensicamException("sen_allocate_buffer", ret);
			}
			
			int imgSize = acty*actx*(bit_pix==12 ? 2 : 1);
			ByteBuffer imageData[] = new ByteBuffer[nImages];
			for(int i=0; i < imageData.length; i++){
				//imageData[i] = ByteBuffer.allocate(imgSize);
				imageData[i] = ByteBuffer.allocateDirect(imgSize);
			}

			grabPictures(hDriver, imageData, imgSize, bufferNo);

		}catch(Exception e){
			e.printStackTrace();
			
		}finally{
			for(int i=0; i < nBuffs; i++){
				if(bufferNo[i] >= 0){
					int ret = Sensicam.sen_free_buffer(hDriver, bufferNo[i]);
					if(ret < 0)
						System.err.println("WARNING: sen_free_buffer returned error: "+ret);
				}
			}
			
			int ret2 = Sensicam.sen_closeboard(hDriver);
			System.out.println("closeboard: " + ret2);	
		}
	}
	
		
	public static int grabPictures(long hDriver, ByteBuffer images[], int imgDataSize, int bufferNo[]){
	
		int count = images.length;

		int ret;
		
		SenbufDev.DEVBUF stat = new SenbufDev.DEVBUF();
		SencamDef.cam_values values = new SencamDef.cam_values();

		ret = Sensicam.sen_run_coc(hDriver, SencamDef.CAM_CONT); //SencamDef.CAM_SINGLE);
		if(ret < 0)
			throw new SensicamException("sen_run_coc", ret);
		
		for(int x=0;x<4;x++)
		{
			ret = Sensicam.sen_add_buffer_to_list(hDriver, bufferNo[x], imgDataSize, 0, 0);
			if(ret < 0)
				throw new SensicamException("sen_add_buffer_to_list", ret);

			ret = Sensicam.sen_set_buffer_event(hDriver, bufferNo[x], 1);
			if(ret < 0)
				throw new SensicamException("sen_set_buffer_event", ret);
		}
		int actbuf = 0;
		
		Sensicam.sen_get_cam_values(hDriver, values);

		System.out.println("coctime="+values.coctime+", beltime="+values.beltime+", readtime="+values.readtime);

		System.out.println("\n");

		for(int imgIdx=0;imgIdx<count;)
		{
			double timeout = values.readtime / 1000.0; //t in ms
			
			timeout += 0.100; //add 100ms
			
			System.out.println("timeout " + timeout);

			ret = Sensicam.select_with_timeout(hDriver, timeout);
			if(ret < 0)
				throw new SensicamException("error in select: " + ret);
			
			if(ret == 0)			
				throw new SensicamException("Select timed out. If using HW-trigger mode, check if trigger-signal is connected");
		
			//search for last written buffer
			int b = actbuf;
			for(int z=0; z < 4; z++) {
				Sensicam.sen_get_buffer_status(hDriver, bufferNo[b], 0, stat, 4);
				System.out.println(z + ": buf " + b + ", stat = " + stat);
				if(stat.SEN_BUF_STAT_WRITE_DONE() != 0) {
					System.out.println("picdone in buffer "+b+" stat "+stat);					
					actbuf = b;
				}
				b++;
				if(b >= bufferNo.length)
					b=0;
			}
			Sensicam.sen_get_buffer_status(hDriver, bufferNo[actbuf], 0, stat, 4);			
			System.out.println("actual buffer is " + actbuf + " status " + stat);
			
			if(stat.SEN_BUF_STAT_ERROR() != 0)
				System.err.println("Bufferstatus Error-Flags set " + stat);
			else
			{
				ret = Sensicam.sen_copy_buffer(hDriver, bufferNo[actbuf], images[imgIdx], imgDataSize, 0);
				if(ret <0)
					throw new SensicamException("sen_copy_buffer", ret);

				int sum = 0;
				for(int y=0; y < imgDataSize; y++)
					sum += images[imgIdx].get(y);
				
				System.out.println("Image sum = " + sum);
			
				System.out.println("sen_copy_buffer(p:images["+imgIdx+"][],"+imgDataSize+")");					
				imgIdx++;
			}
			//set device buffer(s) again in list
			for(int z=0; z < 4; z++)
			{
				Sensicam.sen_get_buffer_status(hDriver, bufferNo[z], 0, stat, 4);
				if(stat.SEN_BUF_STAT_QUEUED() == 0)
				{
					System.out.println("add buffer "+z+" stat "+stat);
					
					ret = Sensicam.sen_add_buffer_to_list(hDriver, bufferNo[z], imgDataSize, 0, 0);
					if(ret < 0)
						throw new SensicamException("sen_add_buffer_to_list", ret);
				}
			}
			System.out.println("pic "+imgIdx+" done and copied\r");
			
		}
		System.out.println();

		System.out.println("out of loop, taste to stop\n");
		
		ret = Sensicam.sen_stop_coc(hDriver, 0);
		if(ret < 0)
			throw new SensicamException("en_stop_camera", ret);		

		//remove device buffers from working list
		
		System.out.println("after stop\n");
		
		for(int z=0; z < 4; z++)
		{
			Sensicam.sen_get_buffer_status(hDriver, bufferNo[z], 0, stat, 4);
			//if(SEN_BUF_STAT_QUEUED(&stat))
			{
				System.out.println("remove buffer "+z+" stat "+stat);
				
				ret = Sensicam.sen_remove_buffer_from_list(hDriver, bufferNo[z]);
				if(ret < 0)
					throw new SensicamException("sen_remove_buffer_from_list", ret);
			}
			//disable select for device buffers
			ret = Sensicam.sen_set_buffer_event(hDriver, bufferNo[z], 0);

			if(ret < 0)
				throw new SensicamException("sen_set_buffer_event", ret);
			
			Sensicam.sen_get_buffer_status(hDriver, bufferNo[z], 0, stat, 4);
			
			System.out.println("Done stat "+stat);
			

		}
		
		return 0;
	}

}
