package imseProc.aqui;


import imseProc.aqui.proc.ImageStepSyncController;
import imseProc.core.IMSEProc;
import imseProc.core.ImagePipeController;
import imseProc.core.ImgPipe;
import imseProc.graph.JFreeChartGraph;
import oneLiners.OneLiners;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Text;

import comedi.ComediDataView;
import comedi.ComediRawDataStore;
import comedi.DataViewChangedNotification;
import comediJNI.ComediDef;

import simpleScope.DoubleBufferDataset;

public class AquisitionSWTController implements DataViewChangedNotification, ImagePipeController {
	
	
	public static final String inputSubDeviceNames[] = new String[]{ "Analogue In", "Digital IO" };	
	public static final int inputSubDeviceVals[] = new int[]{ 0, 2 };
	
	public static final int MAX_CHANS = 4;
	public static final String chanColorNames[] = new String[]{ "Blk", "Grn", "Blu", "Red" };

	private Group swtGroup;
	
	private Label statusLabel;
	
	private Button startButton;
	private Button stopButton;
	
	private Spinner chanSpinners[];
	
	private Spinner nScansSpinner;
	private Spinner bufferLenSpinner;
	private Spinner graphUpdateSpinner;
	private Text freqTextbox;
	
	private Button fixYCheckbox;
	private Spinner xMin;
	private Spinner xMax;
	private Spinner xStep;
	private Spinner xCount;
	
	private Combo subdeviceCombo;

	private String bufferStatus;
	
	private Button saveDataButton;
	
	private JFreeChartGraph graph;
	private DoubleBufferDataset dataset;
	private ComediDataView dataView;
	
	private AquisitionHanger proc;
	
	private ImageStepSyncController stepProcCtrl;
	
	public AquisitionSWTController(AquisitionHanger proc, Composite parent, int style) {
		this.proc = proc;
		
		swtGroup = new Group(parent, style);
		swtGroup.setText("Data Aquisition");
        swtGroup.setLayout(new GridLayout(4, false));
       
        Label lS = new Label(swtGroup, SWT.NONE); lS.setText("Status:");
        statusLabel = new Label(swtGroup, SWT.NONE);
        statusLabel.setText("Init\nInit");
        statusLabel.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 3, 1));
        
        Label lSD = new Label(swtGroup, SWT.NONE); lSD.setText("Subdevice:");
        subdeviceCombo = new Combo(swtGroup, SWT.NONE);
        subdeviceCombo.setItems(inputSubDeviceNames);
        subdeviceCombo.select(0);
        subdeviceCombo.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 3, 1));
        
        chanSpinners = new Spinner[MAX_CHANS];
        
        for(int i=0; i < MAX_CHANS; i++){
        	Label lC0 = new Label(swtGroup, SWT.NONE); lC0.setText("Chan "+i+"("+chanColorNames[i]+"):");
        	chanSpinners[i] = new Spinner(swtGroup, SWT.NONE);
        	chanSpinners[i].setValues((i < 2) ? i : -1, -1, 100, 0, 1, 5);
        	chanSpinners[i].setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1));
        }
        
        
        Label lNS = new Label(swtGroup, SWT.NONE); lNS.setText("Scans:");
        nScansSpinner = new Spinner(swtGroup, SWT.NONE);
        nScansSpinner.setValues(10000000, 1, Integer.MAX_VALUE, 0, 100, 10000);
        nScansSpinner.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1));
        
        
        Label lF = new Label(swtGroup, SWT.NONE); lF.setText("Freq:");
        freqTextbox = new Text(swtGroup, SWT.SINGLE);
        freqTextbox.setText("50000");
        freqTextbox.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1));
               
        Label lBL = new Label(swtGroup, SWT.NONE); lBL.setText("Buffer Length:");
        bufferLenSpinner = new Spinner(swtGroup, SWT.NONE);
        bufferLenSpinner.setValues(10000000, 1, Integer.MAX_VALUE, 0, 100, 10000);
        bufferLenSpinner.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1));
       
        Label lGU = new Label(swtGroup, SWT.NONE); lGU.setText("Graph Update(ms):");
        graphUpdateSpinner = new Spinner(swtGroup, SWT.NONE);
        graphUpdateSpinner.setValues(1000, -1, Integer.MAX_VALUE, 0, 100, 10000);
        graphUpdateSpinner.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1));
        graphUpdateSpinner.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { graphUpdatePeriodChangeEvent(event); } });
        
      
        fixYCheckbox = new Button(swtGroup, SWT.CHECK);
        fixYCheckbox.setText("Rescale Inhibit");
        fixYCheckbox.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { paramChangeEvent(event); } });
        fixYCheckbox.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false, 4, 1));
        
        Label lXM = new Label(swtGroup, SWT.NONE); lXM.setText("X Min:");
        xMin = new Spinner(swtGroup, SWT.NONE);
        xMin.setValues(-1, -1, Integer.MAX_VALUE, 0, 1000, 10000);
        xMin.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1));
        xMin.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { paramChangeEvent(event); }});        
        
        Label lXS = new Label(swtGroup, SWT.NONE); lXS.setText("X Step:");
        xStep = new Spinner(swtGroup, SWT.NONE);
        xStep.setValues(1, 1, Integer.MAX_VALUE, 0, 1, 10);
        xStep.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1));
        xStep.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { paramChangeEvent(event); }});        
        
        Label lXX = new Label(swtGroup, SWT.NONE); lXX.setText("X Max:");
        xMax = new Spinner(swtGroup, SWT.NONE);
        xMax.setValues(-1, -1, Integer.MAX_VALUE, 0, 1000, 10000);
        xMax.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1));
        xMax.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { paramChangeEvent(event); }});
        
        Label lXC = new Label(swtGroup, SWT.NONE); lXC.setText("X Count:");
        xCount = new Spinner(swtGroup, SWT.NONE);
        xCount.setValues(5000, -1, Integer.MAX_VALUE, 0, 1000, 10000);
        xCount.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 1, 1));
        xCount.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { paramChangeEvent(event); }});
        
        Label lB = new Label(swtGroup, SWT.NONE); lB.setText("");
        
        startButton = new Button(swtGroup, SWT.PUSH);
        startButton.setText("Start");
        startButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { startButtonEvent(event); } });
        startButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false, 1, 1));
        
        stopButton = new Button(swtGroup, SWT.PUSH);
        stopButton.setText("Stop");
        stopButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { stopButtonEvent(event); } });
        stopButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false, 1, 1));

        saveDataButton = new Button(swtGroup, SWT.PUSH);
        saveDataButton.setText("Save Data");
        saveDataButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { saveButtonEvent(event); } });
        saveDataButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, false, false, 1, 1));

        dataset = new DoubleBufferDataset("ADCDataSet");
                
        graph = new JFreeChartGraph(swtGroup, SWT.NONE, dataset);
        //graph.setData(new double[0], new double[0]);
        graph.getComposite().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 8, 1));
        
        //graph.setData(new double[]{ 1, 2, 3}, new double[]{ 10, 20, 30 });
        
        stepProcCtrl = new ImageStepSyncController(swtGroup, SWT.BORDER, proc);
        stepProcCtrl.getComposite().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 8, 1));
		
        swtGroup.pack();
        
        paramChangeEvent(null); //push init settings to processor
    }

	private void graphUpdatePeriodChangeEvent(Event event) {
		dataView.setUpdatePeriod(graphUpdateSpinner.getSelection());
		dataView.forceUpdate();
	}
	
	private void paramChangeEvent(Event event) {

		
		int subDev = inputSubDeviceVals[subdeviceCombo.getSelectionIndex()];
		
		int nChans = 0;
		for(int i=0; i < 4; i++){
			int chan = chanSpinners[i].getSelection();
			if(chan >= 0)
				nChans++;
		}
		
		int chans[] = new int[nChans];
		int range[] = new int[nChans];
		int j=0;
		for(int i=0; i < 4; i++){
			int chan = chanSpinners[i].getSelection();
			if(chan >= 0){
				chans[j] = chan;
				range[j] = 0;
				j++;
			}
		}
		
					
		int nScans = nScansSpinner.getSelection();
		double freq = OneLiners.mustParseDouble(freqTextbox.getText());
		int aref = ComediDef.AREF_GROUND;
		
		int buffLen = bufferLenSpinner.getSelection();
		
		proc.setAquiParams(subDev, chans, range, aref, nScans, (int)(1e9 / freq), buffLen);

		if(dataView != null){
			
			dataView.setRestrictions(
					xMin.getSelection(),
					xMax.getSelection(),
					xCount.getSelection(),
					xStep.getSelection());
			
			dataView.forceUpdate();
			
			if(!proc.isActive())
				dataView.abort(false);
		}
	}
	
	private void startButtonEvent(Event event) {
		paramChangeEvent(event); //make sure settings are correct
		proc.start();
	}
	
	private void stopButtonEvent(Event event) {
		ComediRawDataStore store = proc.getStore();
		if(store != null){
			store.dump();
		}
		proc.abort();
		if(dataView != null)
			dataView.abort(false);
			
	}
	
	private void saveButtonEvent(Event event) {
		proc.storeData();		
	}
	
	private void startDataView() {
		dataView = new ComediDataView(proc.getStore(), this);
		dataView.setUpdatePeriod(graphUpdateSpinner.getSelection());
		dataView.setRestrictions(
				xMin.getSelection(),
				xMax.getSelection(),
				xCount.getSelection(),
				xStep.getSelection());
		
		graph.setDataset(dataset);
		dataView.startUpdateThread();
	}
	
	public void destroy() {
		if(dataView != null && dataView.isActive())
			dataView.abort(false);
		
		proc.destroy();
	}

	@Override
	public Object getInterfacingObject() { return swtGroup; }
	

	@Override
	public void dataViewChanged() {
		synchronized (dataView) {
			int nC = dataView.getNChans();
			int x0 = dataView.getX0();
			int x1 = dataView.getX1();
			int dx = dataView.getDX();
			
			dataset.setData(dataView.getBuffer(), nC, x0, x1, dx);
			
			bufferStatus = "View: " + nC + " chans. Scans " +
					x0 + " - " + x1 + " step "+dx+"\n";
		}
		
		generalControllerUpdate();
	}


	@Override
	public void generalControllerUpdate() {
		IMSEProc.ensureFinalSWTUpdate(swtGroup.getDisplay(), this, new Runnable() {
			@Override
			public void run() {
				dataset.updateGraph();
				statusLabel.setText(proc.getStatusText() + "\n" + bufferStatus);
			
				if(proc.isActive() && (dataView == null || !dataView.isActive())){
					startDataView();
				}
				
				if(dataView != null && dataView.isActive() && !proc.isActive() ){
					dataView.abort(false);
				}
			}
		});
	}

	@Override
	public ImgPipe getPipe() { return proc; }
}
