package imseProc.platesGen;



import imseProc.core.IMSEProc;
import imseProc.core.ImgPipe;
import imseProc.core.ImgSource;
import imseProc.core.ImagePipeController;
import oneLiners.OneLiners;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

import seed.minerva.optics.OpticApprox;
import seed.minerva.optics.Util;
import seed.minerva.optics.materials.IsotropicFixedIndexGlass;
import seed.minerva.optics.materials.UniaxialFixedIndexGlass;


/** SWT Composite for controlling a PlatesGenSource */
public class PlatesGenSWTControl implements ImagePipeController {
	private final static String itemNames1[] = new String[]{ 
			"nImg",
			"width / px",
			"height / px",
			"pixel size / μm", 
			"focalLength / mm",
			"polariser angle / °",
			"Cmpt.1", "Cmpt.2", "Cmpt.3",
	};
	
	private final static String colNames2[] = new String[]{ 
		"Plate", "L/mm", "no", "ne", "axis ang", "axis tilt", "plate tilt ∥", "plate tilt ⟂", "scan θmax" };
	
	
	private final static String colNames1[] = new String[]{ 
		"Property", "Value / Amp",	"Wavelen / nm",	"Pol. Ang. °",	"Ellipt." };			
	private int nPlates = 8;
	
	private final double initProps[][] = new double[][]{
				{ 30 },  
				{ 320 }, { 240 }, 
				{ 19.8 },
				{ 50 },
				{ 45 },
				{ 0.00, 652.5, 	45,	0 },
				{ 1.00, 653.5,	45,	0 },
				{ 0.00, 654.5,	45,	0 }
			};
	
	
	/** Tilted LiNb */
	/*private final double initPlates[][] = new double[][]{
			{ 20, 2.282, 2.199, +45, 0, +45, 0 },
			
			{ 20, 2.282, 2.199, -45, 0, +45, 0 },
			{ 7.5, 2.282, 2.199, 0, 0, +45, 0 },
			//{ 0, 2.282, 2.199, 0, 0, 0 },
			//{ 0, 2.282, 2.199, 0, 0, 0 },
			
			{ 0, 2.282, 2.199, 0, 0, 0 ,0 },
			{ 0, 2.282, 2.199, 0, 0, 0 ,0},		
			
			//LiNbO3 No(650nm) = 2.28198458906231
			//LiNbO3 Ne(650nm) = 2.19901659008769
	};//*/
	
	private final static double fWave = Util.calcWaveplateFullWaveThickness(new UniaxialFixedIndexGlass(1.666, 1.549), 653e-9);
	
	/**Proper system */
	private final double initPlates[][] = new double[][]{
			{ 0, 1.666, 1.549, 0, 0, 0, 0, 0 },
			{ 0, 1.666, 1.549, 0, 0, 0, 0, 0 },
			{ fWave/2*1e3, 
				1.666, 1.549, 0, 0, 0, 0, 360 },
			
			{ fWave/4*1e3, 
				1.666, 1.549, +45, 0, 0, 0, 0 },
			
			{ 3.8, 1.666, 1.549, +45, +45, 0, 0, 0 },
			{ 3.8, 1.666, 1.549, -45, +45, 0, 0, 0 },
			
			{ 5.4, 1.666, 1.549, 0, +45, 0, 0, 0 },
			{ 1.2, 1.666, 1.549, 0, +45, 0, 0, 0 },

			{ 0, 1.666, 1.549, 0, 0, 0, 0, 0 },
			{ 0, 1.666, 1.549, 0, 0, 0, 0, 0 },
			
			// αBBO 1.666 1.549
	};
	
	
	private PlatesGenSource source;
	
	private Group swtGroup;
	private Table propsTable, platesTable;
	private TableEditor tableEditor1, tableEditor2;
	private Button swtGenerateButton;
	
	
	public PlatesGenSWTControl(Composite parent, int style, PlatesGenSource source) {
		swtGroup = new Group(parent, style);
		
		this.source = source;
		
		swtGroup.setLayout(new GridLayout(2, false));
		swtGroup.setText("PlatesGen Control");
		
		propsTable = new Table(swtGroup, SWT.BORDER);				
		propsTable.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, true, 2, 0));
		propsTable.setHeaderVisible(true);
		propsTable.setLinesVisible(true);	
		
		TableColumn cols[] = new TableColumn[colNames1.length];
		for(int i=0; i < colNames1.length; i++){
			cols[i] = new TableColumn(propsTable, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
			cols[i].setText(colNames1[i]); 
			cols[i].pack();
		}
		
		TableItem items[] = new TableItem[itemNames1.length];
		for(int i=0; i < itemNames1.length; i++){
			items[i] = new TableItem(propsTable, SWT.NONE);
			items[i].setText(0, itemNames1[i]);
			
			for(int j=0; j < initProps[i].length; j++){
				items[i].setText(j+1, Double.toString(initProps[i][j]));
			}
				
			
		}
		
		tableEditor1 = new TableEditor(propsTable);
		tableEditor1.horizontalAlignment = SWT.LEFT;
		tableEditor1.grabHorizontal = true;
		propsTable.addListener(SWT.MouseDown, new Listener() { @Override public void handleEvent(Event event) { tableMouseDownEvent1(event); } });
		
		
		platesTable = new Table(swtGroup, SWT.BORDER);				
		platesTable.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, true, 2, 0));
		platesTable.setHeaderVisible(true);
		platesTable.setLinesVisible(true);
		cols = new TableColumn[colNames2.length];
		for(int i=0; i < colNames2.length; i++){
			cols[i] = new TableColumn(platesTable, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
			cols[i].setText(colNames2[i]); 
			cols[i].pack();
		}
		
		
		items = new TableItem[nPlates];
		for(int i=0; i < nPlates; i++){
			items[i] = new TableItem(platesTable, SWT.NONE);
			items[i].setText(0, Integer.toString(i));
			for(int j=0; j < (colNames2.length-1); j++)
				items[i].setText(j+1, Double.toString(initPlates[i][j]));
		}
		
		tableEditor2 = new TableEditor(platesTable);
		tableEditor2.horizontalAlignment = SWT.LEFT;
		tableEditor2.grabHorizontal = true;
		platesTable.addListener(SWT.MouseDown, new Listener() { @Override public void handleEvent(Event event) { tableMouseDownEvent2(event); } });
		
		swtGenerateButton = new Button(swtGroup, SWT.PUSH);
		swtGenerateButton.setText("Generate");
		swtGenerateButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event event) { generateButtonEvent(event); }});
		swtGenerateButton.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false, 2, 1));
		
		swtGroup.pack();
	}
	
	
	private void generateButtonEvent(Event event) {
		if(source == null)
			return;
		
		
		
		int nImages = (int)OneLiners.mustParseDouble(propsTable.getItem(0).getText(1));
		int width = (int)OneLiners.mustParseDouble(propsTable.getItem(1).getText(1));
		int height = (int)OneLiners.mustParseDouble(propsTable.getItem(2).getText(1));

		double pixelSize = OneLiners.mustParseDouble(propsTable.getItem(3).getText(1)) * 1e-6;
		double focalLength = OneLiners.mustParseDouble(propsTable.getItem(4).getText(1)) * 1e-3;
		double polAng = OneLiners.mustParseDouble(propsTable.getItem(5).getText(1)) * Math.PI/180;
		
		int nCmpts=0;
		for(int i=0; i < 3; i++) 
			if(OneLiners.mustParseDouble(propsTable.getItem(6+i).getText(1)) > 0)
				nCmpts++;
		double inputAmp[] = new double[nCmpts];
		double inputWavelen[] = new double[nCmpts];
		double inputPolAng[] = new double[nCmpts];
		double inputEllip[] = new double[nCmpts];
		int k=0;
		for(int i=0; i < 3; i++){
			double amp = OneLiners.mustParseDouble(propsTable.getItem(6+i).getText(1));
			if(amp > 0){
				inputAmp[k] = amp;
				inputWavelen[k] = OneLiners.mustParseDouble(propsTable.getItem(6+i).getText(2)) * 1e-9;
				inputPolAng[k] = OneLiners.mustParseDouble(propsTable.getItem(6+i).getText(3)) * Math.PI/180;
				inputEllip[k] = OneLiners.mustParseDouble(propsTable.getItem(6+i).getText(4));
				k++;
			}
		}
		
		double plateInfo[][] = new double[nPlates][colNames2.length-1];
		
		for(int i=0; i < nPlates; i++){
			TableItem tableItem = platesTable.getItem(i);
						
			for(int j=0; j < (colNames2.length-1); j++)
				plateInfo[i][j] = OneLiners.mustParseDouble(tableItem.getText(j+1));
			
			plateInfo[i][0] *= 1e-3; //in mm
			plateInfo[i][3] *= Math.PI / 180;
			plateInfo[i][4] *= Math.PI / 180;
			plateInfo[i][5] *= Math.PI / 180;		
			plateInfo[i][6] *= Math.PI / 180;
			plateInfo[i][7] *= Math.PI / 180;
		};
		
		source.setAll(nImages, width, height, focalLength, pixelSize, polAng, plateInfo,
				inputAmp, inputWavelen, inputPolAng, inputEllip);
		
	}
	
	private void tableMouseDownEvent1(Event event){ tableMouseDownEvent(event, propsTable, tableEditor1);	}
	
	private void tableMouseDownEvent2(Event event){ tableMouseDownEvent(event, platesTable, tableEditor2); }
	/** Copied from 'Snippet123'  Copyright (c) 2000, 2004 IBM Corporation and others. 
	 * [ org/eclipse/swt/snippets/Snippet124.java ] */
	private void tableMouseDownEvent(Event event, Table table, TableEditor tableEditor){
		
		Rectangle clientArea = table.getClientArea ();
		Point pt = new Point (event.x, event.y);
		int index = table.getTopIndex ();
		while (index < table.getItemCount ()) {
			boolean visible = false;
			final TableItem item = table.getItem (index);
			for (int i=0; i<table.getColumnCount (); i++) {
				Rectangle rect = item.getBounds (i);
				if (rect.contains (pt)) {
					final int column = i;
					
					if(table == propsTable && index < 6 && column != 1)
						break;
					
					final Text text = new Text(table, SWT.NONE);
					Listener textListener = new Listener () {
						public void handleEvent (final Event e) {
							switch (e.type) {
							case SWT.FocusOut:
								item.setText(column, Double.toString(OneLiners.mustParseDouble(text.getText())));
								//checkTable();
								text.dispose ();
								break;
							case SWT.Traverse:
								switch (e.detail) {
								case SWT.TRAVERSE_RETURN:
									item.setText(column, Double.toString(OneLiners.mustParseDouble(text.getText())));
									//checkTable();
									//FALL THROUGH
								case SWT.TRAVERSE_ESCAPE:
									text.dispose ();
									e.doit = false;
								}
								break;
							}
						}
					};
					text.addListener (SWT.FocusOut, textListener);
					text.addListener (SWT.Traverse, textListener);
					tableEditor.setEditor (text, item, i);
					text.setText (item.getText (i));
					text.selectAll ();
					text.setFocus ();
					return;
				}
				if (!visible && rect.intersects (clientArea)) {
					visible = true;
				}
			}
			if (!visible) return;
			index++;
		}
	}

	public ImgSource getSource() { return source; }
	
	@Override
	public void generalControllerUpdate(){
		if(!swtGroup.isDisposed()){
			IMSEProc.ensureFinalSWTUpdate(swtGroup.getDisplay(), this, new Runnable() {
				@Override
				public void run() {
					if(!swtGroup.isDisposed()){
						
					}
						
				}
			});		
		}
	}

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

	@Override
	public void destroy() {
		
		swtGroup.dispose();		
	}

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