package comedi;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;

import comediJNI.Comedi;
import comediJNI.ComediDef;

/** Data storage of raw Comedi data.
 * 
 * This is supposed to handle both package digital and scanned analogue 
 * data and provide appropriate conversions to physical units.
 * 
 * {@link ComediRawReadBuffer} and {@link ComediRawWriteBuffer} extend this 
 * to implement the specifics for the two cases.
 * 
 *  Particularly, the {@link ComediRawReadBuffer} provides a ring 
 *  buffer for continuous reading and overwriting.
 * 
 * @author cisadmin
 *
 */
public abstract class ComediRawDataStore {
	public ByteBuffer buff;
	
	/** Size of buffer (in scans) */
	public int buffLength = 0;
	
	/** Number of channels in data */
	public int nChans;
	
	/** Number of times the buffer has completely overflowed (or been repeated for writing)*/
	public int nOverflows = 0;
	
	/** Scan number of the next new scan that will be read, or next to be written*/
	public int nextScanNum = 0;
	
	/** Location into buffer that next scan location will be read to, or written from  */
	public int nextScanLoc = 0;	
	
	/** Physical range and maximum data value for each channel */
	public ComediDef.Range range[];
	public int maxRaw[];
	
	/** 1 for digital, 16 or 32 for analogue */
	public int bitsPerSample;
	
	public int periodNS;
	public int chans[];

	protected ByteBuffer oneByteBuff = ByteBuffer.allocate(1);
	
	protected RawStoreChangedNotification notify;
	
	protected abstract int getScanLoc(int scan);
	
	/** Things should sync on the ComediRawDataStore object before calling this */ 
	public double getPhysDouble(int scan, int chan){
		double ret;
			
		int entry = getScanLoc(scan);
		if(entry < 0)
			return Double.NaN;
		
		int raw;
		if(bitsPerSample == 1) {
			raw = buff.getInt(entry*4);
			return ((raw & (1 << chan)) != 0) ? 1 : 0;
			
		}else{
			
			if(bitsPerSample == 16){
				raw = buff.getShort((entry * nChans + chan)*2);
				if(raw < 0)
					raw += 65536;
			}else{
				raw = buff.getInt((entry * nChans + chan)*4);
			}
			
			ret = Comedi.to_phys(raw, range[chan], maxRaw[chan]);
			
			return ret;
		}		
	}
	
	
	public void setNotify(RawStoreChangedNotification notify){
		this.notify = notify;
	}
	
	public void dump() {
		try {
			FileOutputStream fout = new FileOutputStream("/tmp/rawADCDump");
			FileChannel fc = fout.getChannel();
			
			ByteBuffer vBuf = buff.asReadOnlyBuffer();
			vBuf.position(0);
			vBuf.limit(vBuf.capacity()-1);
			fc.write(vBuf);
			fc.close();
			
			
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		

	}

	
}
