package de.ugoe.cs.quest.ui.swt;

import java.util.Arrays;

import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

import de.ugoe.cs.util.console.CommandExecuter;

public class TrainModelDialog extends Dialog {

    protected Shell shlTrainUsageModel;

    private Button btnFirstorderMarkovModel;
    private Button btnHighorderMarkovModel;
    private Button btnPredictionByPartial;
    private Button btnDeterministicFiniteAutomaton;

    private Spinner minOrderSpinner;
    private Spinner maxOrderSpinner;
    private Text modelnameText;

    private String[] sequenceNames;
    private Text probEscapeText;
    private Label lblEscapeProbability;

    /**
     * Create the dialog.
     * 
     * @param parent
     * @param style
     */
    public TrainModelDialog(Shell parent, int style) {
        super(parent, style);
        setText("SWT Dialog");
    }

    /**
     * Open the dialog.
     */
    public void open() {
        createContents();
        shlTrainUsageModel.open();
        shlTrainUsageModel.layout();
        Display display = getParent().getDisplay();
        while (!shlTrainUsageModel.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    /**
     * Create contents of the dialog.
     */
    private void createContents() {
        shlTrainUsageModel =
            new Shell(getParent(), SWT.DIALOG_TRIM | SWT.MIN | SWT.APPLICATION_MODAL);
        shlTrainUsageModel.setSize(219, 330);
        shlTrainUsageModel.setText("Train Usage Model");
        shlTrainUsageModel.setLayout(new GridLayout(2, false));

        Group grpGeneralInformation = new Group(shlTrainUsageModel, SWT.NONE);
        grpGeneralInformation.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
        grpGeneralInformation.setText("Name");
        grpGeneralInformation.setLayout(new GridLayout(1, false));

        modelnameText = new Text(grpGeneralInformation, SWT.BORDER);
        modelnameText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));

        Group grpType = new Group(shlTrainUsageModel, SWT.NONE);
        grpType.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, 2, 1));
        grpType.setText("Type");
        grpType.setLayout(new GridLayout(2, false));

        btnFirstorderMarkovModel = new Button(grpType, SWT.RADIO);
        btnFirstorderMarkovModel.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                minOrderSpinner.setEnabled(false);
                maxOrderSpinner.setEnabled(false);
                probEscapeText.setEnabled(false);
            }
        });
        btnFirstorderMarkovModel
            .setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false, 2, 1));
        btnFirstorderMarkovModel.setText("First-Order Markov Model");
        btnFirstorderMarkovModel.setSelection(true);

        btnHighorderMarkovModel = new Button(grpType, SWT.RADIO);
        btnHighorderMarkovModel.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                minOrderSpinner.setEnabled(false);
                maxOrderSpinner.setEnabled(true);
                probEscapeText.setEnabled(false);
            }
        });
        btnHighorderMarkovModel.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false, 2, 1));
        btnHighorderMarkovModel.setText("High-Order Markov Model");

        btnPredictionByPartial = new Button(grpType, SWT.RADIO);
        btnPredictionByPartial.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                minOrderSpinner.setEnabled(true);
                maxOrderSpinner.setEnabled(true);
                probEscapeText.setEnabled(true);
            }
        });
        btnPredictionByPartial.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, true, false, 2, 1));
        btnPredictionByPartial.setText("Prediction by Partial Match");

        lblEscapeProbability = new Label(grpType, SWT.NONE);
        lblEscapeProbability.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1));
        lblEscapeProbability.setText("Escape Probability:");

        probEscapeText = new Text(grpType, SWT.BORDER);
        probEscapeText.setText("0.1");
        probEscapeText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
        probEscapeText.setEnabled(false);

        btnDeterministicFiniteAutomaton = new Button(grpType, SWT.RADIO);
        btnDeterministicFiniteAutomaton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                minOrderSpinner.setEnabled(false);
                maxOrderSpinner.setEnabled(false);
                probEscapeText.setEnabled(false);
            }
        });
        btnDeterministicFiniteAutomaton.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false,
                                                                   false, 2, 1));
        btnDeterministicFiniteAutomaton.setText("Deterministic Finite Automaton");

        Group grpModelProperties = new Group(shlTrainUsageModel, SWT.NONE);
        grpModelProperties.setLayout(new GridLayout(4, false));
        grpModelProperties.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true, 2, 1));
        grpModelProperties.setText("Order");

        Label lblMin = new Label(grpModelProperties, SWT.NONE);
        lblMin.setText("Min.");

        minOrderSpinner = new Spinner(grpModelProperties, SWT.BORDER);
        minOrderSpinner.setEnabled(false);

        Label lblMax = new Label(grpModelProperties, SWT.NONE);
        lblMax.setText("Max.");

        maxOrderSpinner = new Spinner(grpModelProperties, SWT.BORDER);
        maxOrderSpinner.setEnabled(false);
        maxOrderSpinner.setMinimum(2);

        Button btnTrain = new Button(shlTrainUsageModel, SWT.NONE);
        btnTrain.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                String command = "";
                String modelname = modelnameText.getText();
                if (modelname.equals("")) {
                    MessageBox messageBox = new MessageBox(shlTrainUsageModel, SWT.ERROR);
                    messageBox.setText("Error");
                    messageBox.setMessage("No modelname defined!");
                    messageBox.open();
                    return;
                }
                if (btnFirstorderMarkovModel.getSelection()) {
                    command = "trainMarkovModel " + modelname + " " + sequenceNames[0];

                }
                else if (btnHighorderMarkovModel.getSelection()) {
                    int modelOrder = maxOrderSpinner.getSelection();
                    command =
                        "trainMarkovModel " + modelname + " " + sequenceNames[0] + " " + modelOrder;
                }
                else if (btnPredictionByPartial.getSelection()) {
                    int minOrder = minOrderSpinner.getSelection();
                    int maxOrder = maxOrderSpinner.getSelection();
                    if (minOrder > maxOrder) {
                        MessageBox messageBox = new MessageBox(shlTrainUsageModel, SWT.ERROR);
                        messageBox.setText("Error");
                        messageBox
                            .setMessage("Min. Order must be smaller than or equal to max. order!");
                        messageBox.open();
                        return;
                    }
                    double probEscape = Double.parseDouble(probEscapeText.getText());
                    if (probEscape < 0.0 || probEscape > 1.0) {
                        MessageBox messageBox = new MessageBox(shlTrainUsageModel, SWT.ERROR);
                        messageBox.setText("Error");
                        messageBox.setMessage("Escape probability must be in [0,1]!");
                        messageBox.open();
                        return;
                    }
                    command =
                        "trainPPM " + modelname + " " + sequenceNames[0] + " " + probEscape + " " +
                            maxOrder + " " + minOrder;
                }
                else if (btnDeterministicFiniteAutomaton.getSelection()) {
                    command = "trainDFA " + modelname + " " + sequenceNames[0];
                }
                CommandExecuter.getInstance().exec(command);
                for (int i = 1; i < sequenceNames.length; i++) {
                    command = "updateModel " + sequenceNames[i];
                    CommandExecuter.getInstance().exec(command);
                }
                shlTrainUsageModel.dispose();
            }
        });
        btnTrain.setText("Train!");

        Button btnAbort = new Button(shlTrainUsageModel, SWT.NONE);
        btnAbort.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                shlTrainUsageModel.dispose();
            }
        });
        btnAbort.setText("Abort");

    }

    public void setSequenceNames(String[] sequenceNames) {
        this.sequenceNames = Arrays.copyOf(sequenceNames, sequenceNames.length);
    }
}
