package UltimaDemo;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.SpinnerNumberModel;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import net.miginfocom.swing.MigLayout;
import SDK.SDKlib;
import SDK.SDKlib.Action;
import SDK.SDKlib.Area;
import SDK.SDKlib.Correction;
import SDK.SDKlib.GUIControl;
import SDK.SDKlib.PowerLevel;
import SDK.SDKlib.Return;
import SDK.SDKlib.Side;

import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.ByteByReference;

import static UltimaDemo.Utils.*;
import static UltimaDemo.Main.tabbedPane;

//====================================================================================

public class Driver1 {
	static final int MAX_POWER     = 99;
	static final int MAX_SHARPNESS = 2;
	static final int MIN_SHARPNESS = -2;

	private final String RADIOGET   = "RADIOGET";
	private final String RADIOSET   = "RADIOSET";
	private final String CLEAR      = "CLEAR";
	private final String GUICONTROL = "GUICONTROL";
	private final String SHARPNESS  = "SHARPNESS";
	private final String COLOUR     = "COLOUR";
	private final String POWERLEVEL = "POWERLEVEL";
	private final String RESINAREA  = "RESINAREA";
	private final String RASIDE     = "RASIDE";

	private final ActionHandler ah = new ActionHandler();

	public static final JPanel panelDriver1 = new JPanel();

	private final JPanel panelGeneral = new JPanel();
	private final JPanel panelAction = new JPanel();
	private final JLabel labelAction = new JLabel("Action:");
	private final JRadioButton rdbtnGet = new JRadioButton("Get");
	private final JRadioButton rdbtnSet = new JRadioButton("Set");
	private final ButtonGroup buttonGroup = new ButtonGroup();
	private final JCheckBox checkUser = new JCheckBox("User");
	private final JCheckBox checkPrinter = new JCheckBox("Printer");
	private final JButton btnGUIControl = new JButton("GUI Control");
	private final JSpinner spinnerSharpness = new JSpinner(new SpinnerNumberModel(0, MIN_SHARPNESS, MAX_SHARPNESS, 1));
	private final JButton btnSharpness = new JButton("Sharpness");
	private final JComboBox<ComboItem> comboCorrection = new JComboBox<ComboItem>();
	private final JButton btnColour = new JButton("Colour Corr.");

	private final JPanel panelPowerLevel = new JPanel();
	private final JLabel labelYMC      = new JLabel("YMC");
	private final JLabel labelResin    = new JLabel("Resin");
	private final JLabel labelOvercoat = new JLabel("Overcoat");
	private final JSpinner spinnerYMCPower      = new JSpinner(new SpinnerNumberModel(0, 0, MAX_POWER, 1));
	private final JSpinner spinnerResinPower    = new JSpinner(new SpinnerNumberModel(0, 0, MAX_POWER, 1));
	private final JSpinner spinnerOvercoatPower = new JSpinner(new SpinnerNumberModel(0, 0, MAX_POWER, 1));
	private final JButton btnPowerLevel = new JButton("Power Level");

	private final JPanel panelResinArea = new JPanel();
	private final JLabel labelResinSide = new JLabel("Side");
	private final JComboBox<ComboItem> comboResinAreaSide = new JComboBox<ComboItem>();
	private final JLabel labelResinAreaNo = new JLabel("No.");
	private final JSpinner spinnerResinAreaNo = new JSpinner(new SpinnerNumberModel(new Byte("1"), 
																					new Byte("1"), 
																					new Byte("5"), 
																					new Byte("1")));
	private final JLabel labelResinL = new JLabel("L");
	private final JLabel labelResinW = new JLabel("W");
	private final JLabel labelResinB = new JLabel("B");
	private final JLabel labelResinH = new JLabel("H");
	private final JSpinner spinnerResinL = new JSpinner(new SpinnerNumberModel(0, 0, MAX_X_COORD, 1));
	private final JSpinner spinnerResinW = new JSpinner(new SpinnerNumberModel(0, 0, MAX_CARD_LENGTH, 1));
	private final JSpinner spinnerResinB = new JSpinner(new SpinnerNumberModel(0, 0, MAX_Y_COORD, 1));
	private final JSpinner spinnerResinH = new JSpinner(new SpinnerNumberModel(0, 0, MAX_CARD_HEIGHT, 1));
	private final JButton btnResinArea = new JButton("Resin Area");

	private final JTextArea textDriver1Msg = new JTextArea();
	private final JScrollPane scrollPane = new JScrollPane(textDriver1Msg);    
	private final JButton btnClear = new JButton("Clear");

	private HANDLE hSession;
	private SDKlib SDK;

	// ====================================================================================

	public Driver1() {
		panelDriver1.setLayout(new MigLayout("", "[pref!][grow]", "[][][][][110.00,grow][28.00]"));

		// ===== Action Radio Buttons =====
		panelDriver1.add(panelAction, "cell 0 0,alignx center");
		panelAction.setLayout(new MigLayout("insets 0", "[][][]", "[]"));
		panelAction.add(labelAction, "flowx,cell 0 0 3 0,alignx left");
		panelAction.add(rdbtnGet, "cell 0 0");
		rdbtnGet.setSelected(true);
		buttonGroup.add(rdbtnGet);
		rdbtnGet.setActionCommand(RADIOGET);
		buttonGroup.add(rdbtnSet);
		panelAction.add(rdbtnSet, "cell 0 0");
		buttonGroup.add(rdbtnSet);
		rdbtnSet.setActionCommand(RADIOSET);
		rdbtnSet.addActionListener(ah);
		rdbtnGet.addActionListener(ah);

		// ===== General Controls =====
		panelDriver1.add(panelGeneral, "cell 0 1,grow");
		panelGeneral.setLayout(new MigLayout("", "[100.00,grow][grow][grow]", "[][][]"));
		panelGeneral.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), 
							                    "", 
							                    TitledBorder.LEADING, 
							                    TitledBorder.TOP, 
							                    null, 
							                    new Color(0, 0, 0)));

		panelGeneral.add(btnGUIControl, "cell 0 0,growx");
		checkUser.setEnabled(false);
		panelGeneral.add(checkUser, "cell 1 0,alignx right");
		checkPrinter.setEnabled(false);
		panelGeneral.add(checkPrinter, "cell 2 0,alignx right");
		btnGUIControl.setActionCommand(GUICONTROL);
		btnGUIControl.addActionListener(ah);

		panelGeneral.add(btnSharpness, "cell 0 1,growx");
		spinnerSharpness.setEnabled(false);
		panelGeneral.add(spinnerSharpness, "cell 1 1 2 1,growx");
		btnSharpness.setActionCommand(SHARPNESS);
		btnSharpness.addActionListener(ah);

		panelGeneral.add(btnColour, "cell 0 2,growx");
		comboCorrection.setEnabled(false);
		panelGeneral.add(comboCorrection, "cell 1 2 2 1,growx");
		InitCorrectionCombo(comboCorrection);
		btnColour.setActionCommand(COLOUR);
		btnColour.addActionListener(ah);

		// ===== Power Level =====
		panelDriver1.add(panelPowerLevel, "cell 0 2,grow");
		panelPowerLevel.setLayout(new MigLayout("",
				"[grow 33,center][grow 33,center][grow 33,center]", "[][][]"));
		panelPowerLevel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), 
								                   "", 
								                   TitledBorder.LEADING,	
								                   TitledBorder.TOP, 
								                   null, 
								                   new Color(0, 0, 0)));
		panelPowerLevel.add(labelYMC, "cell 0 0");
		panelPowerLevel.add(labelResin, "cell 1 0");
		panelPowerLevel.add(labelOvercoat, "cell 2 0");
		spinnerYMCPower.setEnabled(false);
		panelPowerLevel.add(spinnerYMCPower, "cell 0 1,growx");
		spinnerResinPower.setEnabled(false);
		panelPowerLevel.add(spinnerResinPower, "cell 1 1,growx");
		spinnerOvercoatPower.setEnabled(false);
		panelPowerLevel.add(spinnerOvercoatPower, "cell 2 1,growx");

		panelPowerLevel.add(btnPowerLevel, "cell 0 2 3 1,alignx center");
		btnPowerLevel.setActionCommand(POWERLEVEL);
		btnPowerLevel.addActionListener(ah);

		// ===== Resin Area =====
		panelDriver1.add(panelResinArea, "cell 0 3,grow");
		panelResinArea.setLayout(new MigLayout("", "[grow][grow][grow][grow]", "[][][][]"));
		panelResinArea.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), 
								                  "", 
								                  TitledBorder.LEADING, 
								                  TitledBorder.TOP, 
								                  null, 
								                  new Color(0, 0, 0)));
		panelResinArea.add(labelResinSide, "flowx,cell 0 0 2 1,alignx left");
		panelResinArea.add(comboResinAreaSide, "cell 0 0 2 1,growx");
		comboResinAreaSide.addItem(new ComboItem("Front", Side.FRONT));
		comboResinAreaSide.addItem(new ComboItem("Back", Side.BACK));
		comboResinAreaSide.setActionCommand(RASIDE);
		comboResinAreaSide.addActionListener(ah); 
		
		panelResinArea.add(labelResinAreaNo, "cell 2 0,alignx right");
		panelResinArea.add(spinnerResinAreaNo, "cell 3 0,growx");
		spinnerResinAreaNo.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				ResinAreaChanged();
			}
	    });

		panelResinArea.add(labelResinL, "cell 0 1,alignx center");
		panelResinArea.add(labelResinW, "cell 1 1,alignx center");
		panelResinArea.add(labelResinB, "cell 2 1,alignx center");
		panelResinArea.add(labelResinH, "cell 3 1,alignx center");
		spinnerResinL.setEnabled(false);
		spinnerResinL.setEditor(new JSpinner.NumberEditor(spinnerResinL,"#"));
		panelResinArea.add(spinnerResinL, "cell 0 2,growx");
		spinnerResinW.setEnabled(false);
		spinnerResinW.setEditor(new JSpinner.NumberEditor(spinnerResinW,"#"));
		panelResinArea.add(spinnerResinW, "cell 1 2,growx");
		spinnerResinB.setEnabled(false);
		spinnerResinB.setEditor(new JSpinner.NumberEditor(spinnerResinB,"#"));
		panelResinArea.add(spinnerResinB, "cell 2 2,growx");
		spinnerResinH.setEnabled(false);
		spinnerResinH.setEditor(new JSpinner.NumberEditor(spinnerResinH,"#"));
		panelResinArea.add(spinnerResinH, "cell 3 2,growx");

		panelResinArea.add(btnResinArea, "cell 0 3 4 1,alignx center");
		btnResinArea.setActionCommand(RESINAREA);
		btnResinArea.addActionListener(ah);

		// ===== Text Area =====
		panelDriver1.add(scrollPane, "flowy,cell 1 0 1 5,grow");
		textDriver1Msg.setEditable(false);
		textDriver1Msg.setBorder(BorderFactory.createLineBorder(Color.black));

		// ===== Clear Button =====
		panelDriver1.add(btnClear, "cell 1 5,alignx center");
		btnClear.setActionCommand(CLEAR);
		btnClear.addActionListener(ah);
	}

	// ====================================================================================

	void Init(HANDLE handle, SDKlib sdk) {
		tabbedPane.addTab("Driver 1", null, panelDriver1, null);
		this.hSession = handle;
		this.SDK = sdk;

		GetGUIControl(new GUIControl());
		GetSharpness(new ByteByReference());
		GetCorrection(new ByteByReference());
		GetResinArea(Side.FRONT, (byte)1, new Area());
		GetPowerLevels(new PowerLevel());
	}
	
	// ------------------------------------------------------------------------------------

	static void InitCorrectionCombo(JComboBox<ComboItem> combo)	{
		combo.addItem(new ComboItem("None",              Correction.NONE));
		combo.addItem(new ComboItem("Gamma 1",           Correction.GAMMA1));
		combo.addItem(new ComboItem("Gamma 2",           Correction.GAMMA2));
		combo.addItem(new ComboItem("ICC Internal",      Correction.ICC_INTERNAL));
		combo.addItem(new ComboItem("ICC External",      Correction.ICC_EXTERNAL));
		combo.addItem(new ComboItem("Perceptual",        Correction.PERCEPTUAL));
		combo.addItem(new ComboItem("Saturation",        Correction.SATURATION));
		combo.addItem(new ComboItem("Rel. Colorimetric", Correction.REL_COLORIMETRIC));
		combo.addItem(new ComboItem("Abs. Colorimetric", Correction.ABS_COLORIMETRIC));
	}

	// ------------------------------------------------------------------------------------

	private void GetSetControls(Boolean State) {
		checkUser.setEnabled(State);
		checkPrinter.setEnabled(State);
		spinnerSharpness.setEnabled(State);
		comboCorrection.setEnabled(State);
		spinnerYMCPower.setEnabled(State);
		spinnerResinPower.setEnabled(State);
		spinnerOvercoatPower.setEnabled(State);
		spinnerResinL.setEnabled(State);
		spinnerResinW.setEnabled(State);
		spinnerResinB.setEnabled(State);
		spinnerResinH.setEnabled(State);
	}

	// ------------------------------------------------------------------------------------

	private void ClearMsg() {
		textDriver1Msg.setText(null);
	}

	// ====================================================================================

	private void GUIControlToMsgBox(byte action, GUIControl GUI) {
		String sep = Separator(action);
		textDriver1Msg.append("GUI User"    + sep + EnabledDisabledString(GUI.user) + "\n" 
							+ "GUI Printer" + sep + EnabledDisabledString(GUI.printer) + "\n\n");
	}

	// ------------------------------------------------------------------------------------

	private byte GetGUIControl(GUIControl GUI) {
		byte sdkReturn = SDK.ID_GUIControl(hSession, Action.READ, GUI);
		if (sdkReturn != Return.SUCCESS) {
			DisplayError("GetGUIControl", sdkReturn);
		} 
		else {
			checkUser.setSelected(GUI.user);
			checkPrinter.setSelected(GUI.printer);
		}
		return sdkReturn;
	}

	// ------------------------------------------------------------------------------------

	private void GUIControl() {
		GUIControl GUI = new GUIControl();
		if (rdbtnGet.isSelected()) {
			if (GetGUIControl(GUI) == Return.SUCCESS) {
				GUIControlToMsgBox(Action.READ, GUI);
			}
		}
		else {
			GUI.user    = checkUser.isSelected();
			GUI.printer = checkPrinter.isSelected();

			byte sdkReturn = SDK.ID_GUIControl(hSession, Action.WRITE, GUI);
			if (sdkReturn != Return.SUCCESS) {
				DisplayError("SetGUIControl", sdkReturn);
			} 
			else {
				GUIControlToMsgBox(Action.WRITE, GUI);
			}
		}
	}

	// ====================================================================================

	private void SharpnessToMsgBox(byte action, byte sharpness) {
		textDriver1Msg.append("Sharpness" + Separator(action) + sharpness + "\n\n");
	}

	// ------------------------------------------------------------------------------------

	private byte GetSharpness(ByteByReference sharpness) {
		byte sdkReturn = SDK.ID_Sharpness(hSession, Action.READ, sharpness);
		if (sdkReturn != Return.SUCCESS) {
			DisplayError("GetSharpness", sdkReturn);
		} 
		else {
			spinnerSharpness.setValue(sharpness.getValue());
		}
		return sdkReturn;
	}

	// ------------------------------------------------------------------------------------

	private void Sharpness() {
		ByteByReference sharpness = new ByteByReference();
		if (rdbtnGet.isSelected()) {
			if (GetSharpness(sharpness) == Return.SUCCESS) {
				SharpnessToMsgBox(Action.READ, sharpness.getValue());
			}
		}
		else {
			sharpness.setValue((byte)spinnerSharpness.getValue());
			byte sdkReturn = SDK.ID_Sharpness(hSession, Action.WRITE, sharpness);
			if (sdkReturn != Return.SUCCESS) {
				DisplayError("SetSharpness", sdkReturn);
			}
			else {
				SharpnessToMsgBox(Action.WRITE, sharpness.getValue());
			}
		}
	}

	// ====================================================================================

	private String CorrectionString(byte correction) {
		return ((ComboItem)comboCorrection.getSelectedItem()).toString();
	}

	// ------------------------------------------------------------------------------------

	private void CorrectionToMsgBox(byte action, byte correction) {
		textDriver1Msg.append("Correction" 
							  + Separator(action) 
							  + CorrectionString(correction) 
							  + "\n\n");
	}

	// ------------------------------------------------------------------------------------

	private byte GetCorrection(ByteByReference correction) {
		byte sdkReturn = SDK.ID_ColourCorrection(hSession, Action.READ, correction);
		if (sdkReturn != Return.SUCCESS) {
			DisplayError("GetColourCorrection", sdkReturn);
		} 
		else {
			comboCorrection.setSelectedIndex(correction.getValue());
		}
		return sdkReturn;
	}

	// ------------------------------------------------------------------------------------

	private void ColourCorrection() {
		ByteByReference correction = new ByteByReference(
				((ComboItem)comboCorrection.getSelectedItem()).getValue());
		if (rdbtnGet.isSelected()) {
			if (GetCorrection(correction) == Return.SUCCESS) {
				CorrectionToMsgBox(Action.READ, correction.getValue());
			}
		}
		else {
			byte sdkReturn = SDK.ID_ColourCorrection(hSession, Action.WRITE, correction);
			if (sdkReturn != Return.SUCCESS) {
				DisplayError("SetColourCorrection", sdkReturn);
			}
			else {
				CorrectionToMsgBox(Action.WRITE, correction.getValue());
			}
		}
	}

	// ====================================================================================

	private void PowerLevelToMsgBox(byte action, PowerLevel Power) {
		String sep = Separator(action);
		textDriver1Msg.append(  "Power Level YMC"      + sep + Power.ymc      + "\n"
							  + "Power Level Resin"    + sep + Power.resin    + "\n"
							  + "Power Level Overcoat" + sep + Power.overcoat + "\n\n");
	}

	// ------------------------------------------------------------------------------------

	private byte GetPowerLevels(PowerLevel Power) {
		byte sdkReturn = SDK.ID_PowerLevel(hSession, Action.READ, Power);
		if (sdkReturn != Return.SUCCESS) {
			DisplayError("GetPowerLevel", sdkReturn);
		} 
		else {
			spinnerYMCPower.setValue(Power.ymc);
			spinnerResinPower.setValue(Power.resin);
			spinnerOvercoatPower.setValue(Power.overcoat);
		}
		return sdkReturn;
	}

	// ------------------------------------------------------------------------------------

	private void PowerLevel() {
		PowerLevel Power = new PowerLevel();
		if (rdbtnGet.isSelected()) {
			if (GetPowerLevels(Power) == Return.SUCCESS) {
				PowerLevelToMsgBox(Action.READ, Power);
			}
		}
		else {
			Power.ymc      = (byte)spinnerYMCPower.getValue();
			Power.resin    = (byte)spinnerResinPower.getValue();
			Power.overcoat = (byte)spinnerOvercoatPower.getValue();

			byte sdkReturn = SDK.ID_PowerLevel(hSession, Action.WRITE, Power);
			if (sdkReturn != Return.SUCCESS) {
				DisplayError("SetPowerLevel", sdkReturn);
			} 
			else {
				PowerLevelToMsgBox(Action.WRITE, Power);
			}
		}
	}

	// ====================================================================================

	private void ResinAreaChanged() {
		Area RA = new Area();
		if (GetResinArea(((ComboItem)comboResinAreaSide.getSelectedItem()).getValue(), 
						 (byte)spinnerResinAreaNo.getValue(),
						 RA) == Return.SUCCESS) {
			ResinAreaDisplay(RA);
		}
	}

	// ------------------------------------------------------------------------------------

	private void ResinAreaDisplay(Area RA) {
		spinnerResinL.setValue(RA.left);
		spinnerResinW.setValue(RA.width);
		spinnerResinB.setValue(RA.bottom);
		spinnerResinH.setValue(RA.height);
	}

	//------------------------------------------------------------------------------------

	private void ResinAreaToMsgBox(byte action, byte areaNo, byte side, Area RA) {
		String sep = Separator(action);
		textDriver1Msg.append("Resin Area " + ((ComboItem)comboResinAreaSide.getSelectedItem()).toString()
							  + " " + areaNo + "\n"
							  + "Left"   + sep + RA.left   + "\n" 
							  + "Width"  + sep + RA.width  + "\n" 
							  + "Bottom" + sep + RA.bottom + "\n" 
							  + "Height" + sep + RA.height + "\n\n");
	}

	// ------------------------------------------------------------------------------------

	private byte GetResinArea(byte side, byte areaNo, Area RA) {
		byte sdkReturn = SDK.ID_ResinArea(hSession, Action.READ, side, areaNo, RA);
		if (sdkReturn != Return.SUCCESS) {
			DisplayError("GetResinArea", sdkReturn);
		} 
		else {
			ResinAreaDisplay(RA);
		}
		return sdkReturn;
	}

	// ------------------------------------------------------------------------------------

	private void ResinArea() {
		Area RA = new Area();
		byte side   = ((ComboItem)comboResinAreaSide.getSelectedItem()).getValue();
		byte areaNo = (byte)spinnerResinAreaNo.getValue();

		if (rdbtnGet.isSelected()) {
			if (GetResinArea(side, areaNo, RA) == Return.SUCCESS) {
				ResinAreaToMsgBox(Action.READ, areaNo, side, RA);
			}
		}
		else {
			RA.left   = (int)spinnerResinL.getValue();
			RA.width  = (int)spinnerResinW.getValue();
			RA.bottom = (int)spinnerResinB.getValue();
			RA.height = (int)spinnerResinH.getValue();

			byte sdkReturn = SDK.ID_ResinArea(hSession, Action.WRITE, side, areaNo, RA);
			if (sdkReturn != Return.SUCCESS) {
				DisplayError("SetResinArea", sdkReturn);
			} 
			else {
				ResinAreaToMsgBox(Action.WRITE, areaNo, side, RA);
			}
		}
	}

	// ====================================================================================

	class ActionHandler implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			switch (e.getActionCommand()) {
			case RADIOGET:   GetSetControls(false); break;
			case RADIOSET:   GetSetControls(true);  break;
			case CLEAR:      ClearMsg();            break;
			case GUICONTROL: GUIControl();          break;
			case SHARPNESS:  Sharpness();           break;
			case COLOUR:     ColourCorrection();    break;
			case POWERLEVEL: PowerLevel();          break;
			case RESINAREA:  ResinArea();           break;
			case RASIDE:     ResinAreaChanged();    break;
			}
		}
	}
}
