com.ciphertool.zodiacengine.gui.view.SwingUserInterface.java Source code

Java tutorial

Introduction

Here is the source code for com.ciphertool.zodiacengine.gui.view.SwingUserInterface.java

Source

/**
 * Copyright 2012 George Belden
 * 
 * This file is part of ZodiacEngine.
 * 
 * ZodiacEngine is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * ZodiacEngine is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * ZodiacEngine. If not, see <http://www.gnu.org/licenses/>.
 */

package com.ciphertool.zodiacengine.gui.view;

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Required;

import com.ciphertool.genetics.GeneticAlgorithmStrategy;
import com.ciphertool.genetics.algorithms.crossover.CrossoverAlgorithmType;
import com.ciphertool.genetics.algorithms.mutation.MutationAlgorithmType;
import com.ciphertool.genetics.algorithms.selection.SelectionAlgorithmType;
import com.ciphertool.genetics.algorithms.selection.modes.SelectorType;
import com.ciphertool.zodiacengine.dao.CipherDao;
import com.ciphertool.zodiacengine.entities.Cipher;
import com.ciphertool.zodiacengine.genetic.util.FitnessEvaluatorType;
import com.ciphertool.zodiacengine.gui.common.ParameterConstants;
import com.ciphertool.zodiacengine.gui.common.StrategyBuilder;
import com.ciphertool.zodiacengine.gui.controller.CipherSolutionController;

public class SwingUserInterface extends JFrame implements UserInterface {
    private static final long serialVersionUID = -7682403631152076457L;

    private Logger log = Logger.getLogger(getClass());
    private static final int PROGRAM_EXIT_SLEEP_MILLIS = 1000;
    private static final double LAYOUT_LABEL_WEIGHT = 1.0;
    private static final double LAYOUT_INPUT_WEIGHT = 2.0;

    private static boolean inDebugMode;

    private String windowTitle;
    private int windowWidth;
    private int windowHeight;
    private String cipherNameText = "Cipher: ";
    private String startButtonText = "Start";
    private String debugButtonText = "Debug";
    private String continueButtonText = "Continue";
    private String stopButtonText = "Stop";
    private String generationsText = "Generations: ";
    private String populationText = "Population Size: ";
    private String lifespanText = "Individual Lifespan: ";
    private String survivalRateText = "Survival Rate: ";
    private String mutationRateText = "Mutation Rate: ";
    private String maxMutationsPerIndividualText = "Max Mutations Each: ";
    private String crossoverRateText = "Crossover Rate: ";
    private String mutateDuringCrossoverText = "Mutate during crossover";
    private String continuousText = "Run until user stops";
    private String fitnessEvaluatorNameText = "Fitness Evaluator: ";
    private String crossoverAlgorithmNameText = "Crossover Algorithm: ";
    private String mutationAlgorithmNameText = "Mutation Algorithm: ";
    private String selectionAlgorithmNameText = "Selection Algorithm: ";
    private String selectorNameText = "Selector Method: ";
    private String statusRunning = "Running.";
    private String statusNotRunning = "Not running.";
    private String compareToKnownSolutionText = "Compare to known solution";
    private int lifespanInitial;
    private static final int LIFESPAN_MIN = -1;
    private static final int LIFESPAN_MAX = 1000;
    private static final int LIFESPAN_STEP = 1;
    private int generationsInitial;
    private static final int GENERATIONS_MIN = 1;
    private static final int GENERATIONS_MAX = 100000;
    private static final int GENERATIONS_STEP = 50;
    private int populationInitial;
    private static final int POPULATION_MIN = 1;
    private static final int POPULATION_MAX = 100000;
    private static final int POPULATION_STEP = 100;
    private double survivalInitial;
    private static final double SURVIVAL_MIN = 0.0;
    private static final double SURVIVAL_MAX = 1.0;
    private static final double SURVIVAL_STEP = 0.01;
    private double mutationInitial;
    private static final double MUTATION_MIN = 0.0;
    private static final double MUTATION_MAX = 1;
    private static final double MUTATION_STEP = 0.001;
    private int maxMutationsPerIndividualInitial;
    private static final int MAX_MUTATION_MIN = 1;
    private static final int MAX_MUTATION_MAX = 100;
    private static final int MAX_MUTATION_STEP = 1;
    private double crossoverInitial;
    private static final double CROSSOVER_MIN = 0.0;
    private static final double CROSSOVER_MAX = 1.0;
    private static final double CROSSOVER_STEP = 0.01;

    private CipherSolutionController cipherSolutionController;
    private CipherDao cipherDao;
    private String defaultCipher;

    private JButton startButton;
    private JButton debugButton;
    private JButton continueButton;
    private JButton stopButton;
    private JComboBox<String> cipherComboBox;
    private JComboBox<String> fitnessEvaluatorComboBox;
    private JComboBox<String> crossoverAlgorithmComboBox;
    private JComboBox<String> mutationAlgorithmComboBox;
    private JComboBox<String> selectionAlgorithmComboBox;
    private JComboBox<String> selectorComboBox;
    private JCheckBox runContinuouslyCheckBox;
    private JSpinner generationsSpinner;
    private JSpinner populationSpinner;
    private JSpinner lifespanSpinner;
    private JSpinner survivalRateSpinner;
    private JSpinner mutationRateSpinner;
    private JSpinner maxMutationsPerIndividualSpinner;
    private JSpinner crossoverRateSpinner;
    private JCheckBox mutateDuringCrossoverCheckBox;
    private JLabel statusLabel;
    private JCheckBox compareToKnownSolutionCheckBox;

    private Map<String, Cipher> cipherMap;

    private StrategyBuilder strategyBuilder;

    public SwingUserInterface() {
    }

    private WindowAdapter getWindowClosingListener() {
        return new WindowAdapter() {
            public void windowClosing(WindowEvent windowEvent) {
                /*
                 * Run in a separate thread so the window closes, but the
                 * process remains alive until we are finished handling the
                 * windowClosing event.
                 */
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        /*
                         * In case the program was terminated abruptly, try to
                         * stop the service as normal so that the post-execution
                         * tasks are performed.
                         */
                        if (cipherSolutionController.isServiceThreadActive()) {
                            cipherSolutionController.stopServiceThread(SwingUserInterface.inDebugMode);

                            /*
                             * Keep waiting for the program to finish
                             * post-execution tasks.
                             */
                            try {
                                while (cipherSolutionController.isServiceThreadActive()) {
                                    Thread.sleep(PROGRAM_EXIT_SLEEP_MILLIS);
                                }
                            } catch (InterruptedException e) {
                                log.error(
                                        "Caught InterruptedException while waiting for service thread to complete after window close event.  Unable to continue.",
                                        e);
                            }
                        }

                    }
                });
            }
        };
    }

    public void init() {
        this.addWindowListener(getWindowClosingListener());
        this.setTitle(windowTitle);
        this.setSize(windowWidth, windowHeight);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        JPanel containerPanel = new JPanel();
        getContentPane().add(containerPanel);

        /*
         * Use a BorderLayout for the main container so we can use the SOUTH
         * panel as a status bar and use the NORTH panel as a menu bar, etc.
         */
        containerPanel.setLayout(new BorderLayout());

        JPanel bottomPanel = new JPanel();
        containerPanel.add(bottomPanel, BorderLayout.SOUTH);
        bottomPanel.setLayout(new BorderLayout());

        JPanel buttonPanel = new JPanel();
        bottomPanel.add(buttonPanel, BorderLayout.CENTER);

        GridLayout gridLayout = new GridLayout(1, 2, 5, 5);
        buttonPanel.setLayout(gridLayout);
        buttonPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        startButton = new JButton(startButtonText);
        startButton.addActionListener(getStartButtonActionListener(false));

        buttonPanel.add(startButton);

        debugButton = new JButton(debugButtonText);
        debugButton.addActionListener(getStartButtonActionListener(true));

        buttonPanel.add(debugButton);

        continueButton = new JButton(continueButtonText);
        continueButton.addActionListener(getContinueButtonActionListener());

        buttonPanel.add(continueButton);
        continueButton.setEnabled(false);

        stopButton = new JButton(stopButtonText);
        stopButton.addActionListener(getStopButtonActionListener());

        buttonPanel.add(stopButton);
        stopButton.setEnabled(false);

        JPanel statusPanel = new JPanel();
        bottomPanel.add(statusPanel, BorderLayout.SOUTH);

        statusLabel = new JLabel(statusNotRunning);
        statusPanel.add(statusLabel);

        /*
         * Next make a grid bag for the thirteen input elements with labels on
         * the left and spinners on the right.
         */
        JPanel mainPanel = new JPanel();
        GridBagLayout gridBagLayout = new GridBagLayout();
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.BOTH;
        constraints.insets = new Insets(5, 5, 5, 5);
        constraints.anchor = GridBagConstraints.WEST;
        mainPanel.setLayout(gridBagLayout);
        mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        containerPanel.add(mainPanel, BorderLayout.CENTER);

        List<Cipher> ciphers = cipherDao.findAll();
        cipherMap = new HashMap<String, Cipher>();
        cipherComboBox = new JComboBox<String>();
        String cipherName;
        for (Cipher cipher : ciphers) {
            cipherName = cipher.getName();
            cipherMap.put(cipherName, cipher);

            cipherComboBox.addItem(cipherName);

            if (cipher.getName().equals(defaultCipher)) {
                cipherComboBox.setSelectedItem(cipherName);
            }
        }
        JLabel cipherNameLabel = new JLabel(cipherNameText);
        cipherComboBox.addActionListener(getCipherComboBoxActionListener());

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(cipherNameLabel, constraints);
        mainPanel.add(cipherNameLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(cipherComboBox, constraints);
        mainPanel.add(cipherComboBox);

        appendGenerationsSpinner(gridBagLayout, constraints, mainPanel);

        appendRunContinuouslyCheckBox(gridBagLayout, constraints, mainPanel);

        appendPopulationSpinner(gridBagLayout, constraints, mainPanel);

        appendLifespanSpinner(gridBagLayout, constraints, mainPanel);

        appendSurvivalRateSpinner(gridBagLayout, constraints, mainPanel);

        appendMutationRateSpinner(gridBagLayout, constraints, mainPanel);

        appendMaxMutationsPerIndividualSpinner(gridBagLayout, constraints, mainPanel);

        appendCrossoverRateSpinner(gridBagLayout, constraints, mainPanel);

        appendMutateDuringCrossoverCheckBox(gridBagLayout, constraints, mainPanel);

        appendFitnessEvaluatorComboBox(gridBagLayout, constraints, mainPanel);

        appendCrossoverAlgorithmComboBox(gridBagLayout, constraints, mainPanel);

        appendMutationAlgorithmComboBox(gridBagLayout, constraints, mainPanel);

        appendSelectionAlgorithmComboBox(gridBagLayout, constraints, mainPanel);

        appendSelectorComboBox(gridBagLayout, constraints, mainPanel);

        appendCompareToKnownSolutionCheckBox(gridBagLayout, constraints, mainPanel);

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                setVisible(true);
                toFront();
            }
        });
    }

    private void appendGenerationsSpinner(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        SpinnerModel generationsModel = new SpinnerNumberModel(generationsInitial, GENERATIONS_MIN, GENERATIONS_MAX,
                GENERATIONS_STEP);
        generationsSpinner = new JSpinner(generationsModel);
        generationsSpinner.setEnabled(false);
        JLabel generationsLabel = new JLabel(generationsText);
        generationsLabel.setLabelFor(generationsSpinner);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(generationsLabel, constraints);
        mainPanel.add(generationsLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(generationsSpinner, constraints);
        mainPanel.add(generationsSpinner);
    }

    private void appendRunContinuouslyCheckBox(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        runContinuouslyCheckBox = new JCheckBox(continuousText);
        runContinuouslyCheckBox.addActionListener(getRunContinuouslyCheckBoxActionListener());
        runContinuouslyCheckBox.setSelected(true);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        JLabel dummyJLabel = new JLabel();
        gridBagLayout.setConstraints(dummyJLabel, constraints);
        mainPanel.add(dummyJLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(runContinuouslyCheckBox, constraints);
        mainPanel.add(runContinuouslyCheckBox);
    }

    private void appendPopulationSpinner(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        SpinnerModel populationModel = new SpinnerNumberModel(populationInitial, POPULATION_MIN, POPULATION_MAX,
                POPULATION_STEP);
        populationSpinner = new JSpinner(populationModel);
        JLabel populationLabel = new JLabel(populationText);
        populationLabel.setLabelFor(populationSpinner);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(populationLabel, constraints);
        mainPanel.add(populationLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(populationSpinner, constraints);
        mainPanel.add(populationSpinner);
    }

    private void appendLifespanSpinner(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        SpinnerModel lifespanModel = new SpinnerNumberModel(lifespanInitial, LIFESPAN_MIN, LIFESPAN_MAX,
                LIFESPAN_STEP);
        lifespanSpinner = new JSpinner(lifespanModel);
        JLabel lifespanLabel = new JLabel(lifespanText);
        lifespanLabel.setLabelFor(lifespanSpinner);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(lifespanLabel, constraints);
        mainPanel.add(lifespanLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(lifespanSpinner, constraints);
        mainPanel.add(lifespanSpinner);
    }

    private void appendSurvivalRateSpinner(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        SpinnerModel survivalRateModel = new SpinnerNumberModel(survivalInitial, SURVIVAL_MIN, SURVIVAL_MAX,
                SURVIVAL_STEP);
        survivalRateSpinner = new JSpinner(survivalRateModel);
        JLabel survivalRateLabel = new JLabel(survivalRateText);
        survivalRateLabel.setLabelFor(survivalRateSpinner);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(survivalRateLabel, constraints);
        mainPanel.add(survivalRateLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(survivalRateSpinner, constraints);
        mainPanel.add(survivalRateSpinner);
    }

    private void appendMutationRateSpinner(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        SpinnerModel mutationRateModel = new SpinnerNumberModel(mutationInitial, MUTATION_MIN, MUTATION_MAX,
                MUTATION_STEP);
        mutationRateSpinner = new JSpinner(mutationRateModel);
        JLabel mutationRateLabel = new JLabel(mutationRateText);
        mutationRateLabel.setLabelFor(mutationRateSpinner);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(mutationRateLabel, constraints);
        mainPanel.add(mutationRateLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(mutationRateSpinner, constraints);
        mainPanel.add(mutationRateSpinner);
    }

    private void appendMaxMutationsPerIndividualSpinner(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        SpinnerModel maxMutationsPerIndividualModel = new SpinnerNumberModel(maxMutationsPerIndividualInitial,
                MAX_MUTATION_MIN, MAX_MUTATION_MAX, MAX_MUTATION_STEP);
        maxMutationsPerIndividualSpinner = new JSpinner(maxMutationsPerIndividualModel);
        JLabel maxMutationsPerIndividualLabel = new JLabel(maxMutationsPerIndividualText);
        maxMutationsPerIndividualLabel.setLabelFor(maxMutationsPerIndividualSpinner);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(maxMutationsPerIndividualLabel, constraints);
        mainPanel.add(maxMutationsPerIndividualLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(maxMutationsPerIndividualSpinner, constraints);
        mainPanel.add(maxMutationsPerIndividualSpinner);
    }

    private void appendCrossoverRateSpinner(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        SpinnerModel crossoverRateModel = new SpinnerNumberModel(crossoverInitial, CROSSOVER_MIN, CROSSOVER_MAX,
                CROSSOVER_STEP);
        crossoverRateSpinner = new JSpinner(crossoverRateModel);
        JLabel crossoverRateLabel = new JLabel(crossoverRateText);
        crossoverRateLabel.setLabelFor(crossoverRateSpinner);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(crossoverRateLabel, constraints);
        mainPanel.add(crossoverRateLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(crossoverRateSpinner, constraints);
        mainPanel.add(crossoverRateSpinner);
    }

    private void appendMutateDuringCrossoverCheckBox(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        mutateDuringCrossoverCheckBox = new JCheckBox(mutateDuringCrossoverText);
        mutateDuringCrossoverCheckBox.setSelected(true);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        JLabel dummyJLabel = new JLabel();
        gridBagLayout.setConstraints(dummyJLabel, constraints);
        mainPanel.add(dummyJLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(mutateDuringCrossoverCheckBox, constraints);
        mainPanel.add(mutateDuringCrossoverCheckBox);
    }

    private void appendFitnessEvaluatorComboBox(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        fitnessEvaluatorComboBox = new JComboBox<String>();
        for (FitnessEvaluatorType fitnessEvaluatorType : FitnessEvaluatorType.values()) {
            fitnessEvaluatorComboBox.addItem(fitnessEvaluatorType.name());
        }
        fitnessEvaluatorComboBox.setSelectedItem(FitnessEvaluatorType.CIPHER_SOLUTION_UNIQUE_WORD.name());
        JLabel fitnessEvaluatorNameLabel = new JLabel(fitnessEvaluatorNameText);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(fitnessEvaluatorNameLabel, constraints);
        mainPanel.add(fitnessEvaluatorNameLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(fitnessEvaluatorComboBox, constraints);
        mainPanel.add(fitnessEvaluatorComboBox);
    }

    private void appendCrossoverAlgorithmComboBox(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        crossoverAlgorithmComboBox = new JComboBox<String>();
        for (CrossoverAlgorithmType crossoverAlgorithmType : CrossoverAlgorithmType.values()) {
            crossoverAlgorithmComboBox.addItem(crossoverAlgorithmType.name());
        }
        crossoverAlgorithmComboBox.setSelectedItem(CrossoverAlgorithmType.LOWEST_COMMON_GROUP.name());
        JLabel crossoverAlgorithmNameLabel = new JLabel(crossoverAlgorithmNameText);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(crossoverAlgorithmNameLabel, constraints);
        mainPanel.add(crossoverAlgorithmNameLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(crossoverAlgorithmComboBox, constraints);
        mainPanel.add(crossoverAlgorithmComboBox);
    }

    private void appendMutationAlgorithmComboBox(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {

        mutationAlgorithmComboBox = new JComboBox<String>();
        for (MutationAlgorithmType mutationAlgorithmType : MutationAlgorithmType.values()) {
            mutationAlgorithmComboBox.addItem(mutationAlgorithmType.name());
        }
        mutationAlgorithmComboBox.setSelectedItem(MutationAlgorithmType.CONSERVATIVE.name());
        JLabel mutationAlgorithmNameLabel = new JLabel(mutationAlgorithmNameText);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(mutationAlgorithmNameLabel, constraints);
        mainPanel.add(mutationAlgorithmNameLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(mutationAlgorithmComboBox, constraints);
        mainPanel.add(mutationAlgorithmComboBox);
    }

    private void appendSelectionAlgorithmComboBox(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        selectionAlgorithmComboBox = new JComboBox<String>();
        for (SelectionAlgorithmType selectionAlgorithmType : SelectionAlgorithmType.values()) {
            selectionAlgorithmComboBox.addItem(selectionAlgorithmType.name());
        }
        selectionAlgorithmComboBox.setSelectedItem(SelectionAlgorithmType.PROBABILISTIC.name());
        JLabel selectionAlgorithmNameLabel = new JLabel(selectionAlgorithmNameText);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(selectionAlgorithmNameLabel, constraints);
        mainPanel.add(selectionAlgorithmNameLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(selectionAlgorithmComboBox, constraints);
        mainPanel.add(selectionAlgorithmComboBox);
    }

    private void appendSelectorComboBox(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        selectorComboBox = new JComboBox<String>();
        for (SelectorType selectorType : SelectorType.values()) {
            selectorComboBox.addItem(selectorType.name());
        }
        selectorComboBox.setSelectedItem(SelectorType.TOURNAMENT.name());
        JLabel selectorNameLabel = new JLabel(selectorNameText);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        gridBagLayout.setConstraints(selectorNameLabel, constraints);
        mainPanel.add(selectorNameLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(selectorComboBox, constraints);
        mainPanel.add(selectorComboBox);
    }

    private void appendCompareToKnownSolutionCheckBox(GridBagLayout gridBagLayout, GridBagConstraints constraints,
            JPanel mainPanel) {
        compareToKnownSolutionCheckBox = new JCheckBox(compareToKnownSolutionText);

        constraints.weightx = LAYOUT_LABEL_WEIGHT;
        constraints.gridwidth = GridBagConstraints.RELATIVE;
        JLabel dummyJLabel = new JLabel();
        gridBagLayout.setConstraints(dummyJLabel, constraints);
        mainPanel.add(dummyJLabel);
        constraints.weightx = LAYOUT_INPUT_WEIGHT;
        constraints.gridwidth = GridBagConstraints.REMAINDER;
        gridBagLayout.setConstraints(compareToKnownSolutionCheckBox, constraints);
        mainPanel.add(compareToKnownSolutionCheckBox);

        boolean isSolutionKnown = doesSelectedCipherHaveKnownSolution();
        compareToKnownSolutionCheckBox.setEnabled(isSolutionKnown);
        compareToKnownSolutionCheckBox.setSelected(isSolutionKnown);
    }

    public ActionListener getRunContinuouslyCheckBoxActionListener() {
        return new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                if (runContinuouslyCheckBox.isSelected()) {
                    generationsSpinner.setEnabled(false);
                } else {
                    generationsSpinner.setEnabled(true);
                }
            }
        };
    }

    public ActionListener getStartButtonActionListener(final boolean debugMode) {
        return new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                SwingUserInterface.inDebugMode = debugMode;

                statusLabel.setText(statusRunning);
                startButton.setEnabled(false);
                continueButton.setEnabled(debugMode);
                debugButton.setEnabled(false);
                stopButton.setEnabled(true);

                int generations = (Integer) generationsSpinner.getValue();

                if (runContinuouslyCheckBox.isSelected()) {
                    generations = -1;
                }

                Map<String, Object> parameters = new HashMap<String, Object>();

                parameters.put(ParameterConstants.CIPHER_NAME, cipherComboBox.getSelectedItem());
                parameters.put(ParameterConstants.POPULATION_SIZE, populationSpinner.getValue());
                parameters.put(ParameterConstants.LIFESPAN, lifespanSpinner.getValue());
                parameters.put(ParameterConstants.NUMBER_OF_GENERATIONS, generations);
                parameters.put(ParameterConstants.SURVIVAL_RATE, survivalRateSpinner.getValue());
                parameters.put(ParameterConstants.MUTATION_RATE, mutationRateSpinner.getValue());
                parameters.put(ParameterConstants.MAX_MUTATIONS_PER_INDIVIDUAL,
                        maxMutationsPerIndividualSpinner.getValue());
                parameters.put(ParameterConstants.CROSSOVER_RATE, crossoverRateSpinner.getValue());
                parameters.put(ParameterConstants.MUTATE_DURING_CROSSOVER,
                        mutateDuringCrossoverCheckBox.isSelected());
                parameters.put(ParameterConstants.FITNESS_EVALUATOR, fitnessEvaluatorComboBox.getSelectedItem());
                parameters.put(ParameterConstants.CROSSOVER_ALGORITHM,
                        crossoverAlgorithmComboBox.getSelectedItem());
                parameters.put(ParameterConstants.MUTATION_ALGORITHM, mutationAlgorithmComboBox.getSelectedItem());
                parameters.put(ParameterConstants.SELECTION_ALGORITHM,
                        selectionAlgorithmComboBox.getSelectedItem());
                parameters.put(ParameterConstants.SELECTOR_METHOD, selectorComboBox.getSelectedItem());
                parameters.put(ParameterConstants.COMPARE_TO_KNOWN_SOLUTION,
                        compareToKnownSolutionCheckBox.isSelected());

                GeneticAlgorithmStrategy geneticAlgorithmStrategy = strategyBuilder
                        .buildStrategy(Collections.unmodifiableMap(parameters));

                GenericCallback uiCallback = new GenericCallback() {

                    @Override
                    public void doCallback() {
                        statusLabel.setText(statusNotRunning);
                        stopButton.setEnabled(false);
                        continueButton.setEnabled(false);
                        startButton.setEnabled(true);
                        debugButton.setEnabled(true);
                    }
                };

                cipherSolutionController.startServiceThread(geneticAlgorithmStrategy, uiCallback, debugMode);
            }
        };
    }

    public ActionListener getContinueButtonActionListener() {
        return new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                cipherSolutionController.continueServiceThread();

                statusLabel.setText(statusRunning);
            }
        };
    }

    public ActionListener getStopButtonActionListener() {
        return new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                cipherSolutionController.stopServiceThread(SwingUserInterface.inDebugMode);

                statusLabel.setText(statusNotRunning);
                stopButton.setEnabled(false);
                continueButton.setEnabled(false);
                startButton.setEnabled(true);
                debugButton.setEnabled(true);
            }
        };
    }

    public ActionListener getCipherComboBoxActionListener() {
        return new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                boolean isSolutionKnown = doesSelectedCipherHaveKnownSolution();
                compareToKnownSolutionCheckBox.setEnabled(isSolutionKnown);
                compareToKnownSolutionCheckBox.setSelected(isSolutionKnown);
            }
        };
    }

    private boolean doesSelectedCipherHaveKnownSolution() {
        if (cipherMap.get(cipherComboBox.getSelectedItem()).hasKnownSolution()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @param windowTitle
     *            the windowTitle to set
     */
    public void setWindowTitle(String windowTitle) {
        this.windowTitle = windowTitle;
    }

    /**
     * @param windowWidth
     *            the windowWidth to set
     */
    public void setWindowWidth(int windowWidth) {
        this.windowWidth = windowWidth;
    }

    /**
     * @param windowHeight
     *            the windowHeight to set
     */
    public void setWindowHeight(int windowHeight) {
        this.windowHeight = windowHeight;
    }

    /**
     * @param startButtonText
     *            the startButtonText to set
     */
    public void setStartButtonText(String startButtonText) {
        this.startButtonText = startButtonText;
    }

    /**
     * @param stopButtonText
     *            the stopButtonText to set
     */
    public void setStopButtonText(String stopButtonText) {
        this.stopButtonText = stopButtonText;
    }

    /**
     * @param cipherSolutionController
     *            the cipherSolutionController to set
     */
    @Required
    public void setCipherSolutionController(CipherSolutionController cipherSolutionController) {
        this.cipherSolutionController = cipherSolutionController;
    }

    /**
     * @param cipherDao
     *            the cipherDao to set
     */
    @Required
    public void setCipherDao(CipherDao cipherDao) {
        this.cipherDao = cipherDao;
    }

    /**
     * @param generationsInitial
     *            the generationsInitial to set
     */
    @Required
    public void setGenerationsInitial(int generationsInitial) {
        this.generationsInitial = generationsInitial;
    }

    /**
     * @param populationInitial
     *            the populationInitial to set
     */
    @Required
    public void setPopulationInitial(int populationInitial) {
        if (populationInitial <= 0) {
            throw new IllegalArgumentException("Tried to set a populationInitial of " + populationInitial
                    + ", but SwingUserInterface requires a populationInitial greater than 0.");
        }

        this.populationInitial = populationInitial;
    }

    /**
     * @param lifespanInitial
     *            the lifespanInitial to set
     */
    @Required
    public void setLifespanInitial(int lifespanInitial) {
        this.lifespanInitial = lifespanInitial;
    }

    /**
     * @param survivalInitial
     *            the survivalInitial to set
     */
    @Required
    public void setSurvivalInitial(double survivalInitial) {
        if (survivalInitial < 0.0 || survivalInitial > 1.0) {
            throw new IllegalArgumentException("Tried to set a survivalInitial of " + survivalInitial
                    + ", but SwingUserInterface requires a survivalInitial between 0.0 and 1.0 inclusive.");
        }

        this.survivalInitial = survivalInitial;
    }

    /**
     * @param mutationInitial
     *            the mutationInitial to set
     */
    @Required
    public void setMutationInitial(double mutationInitial) {
        if (mutationInitial < 0.0 || mutationInitial > 1.0) {
            throw new IllegalArgumentException("Tried to set a mutationInitial of " + mutationInitial
                    + ", but SwingUserInterface requires a mutationInitial between 0.0 and 1.0 inclusive.");
        }

        this.mutationInitial = mutationInitial;
    }

    /**
     * @param maxMutationsPerIndividualInitial
     *            the maxMutationsPerIndividualInitial to set
     */
    public void setMaxMutationsPerIndividualInitial(int maxMutationsPerIndividualInitial) {
        if (maxMutationsPerIndividualInitial <= 0) {
            throw new IllegalArgumentException("Tried to set a maxMutationsPerIndividualInitial of "
                    + maxMutationsPerIndividualInitial
                    + ", but SwingUserInterface requires a maxMutationsPerIndividualInitial greater than 0.");
        }

        this.maxMutationsPerIndividualInitial = maxMutationsPerIndividualInitial;
    }

    /**
     * @param crossoverInitial
     *            the crossoverInitial to set
     */
    @Required
    public void setCrossoverInitial(double crossoverInitial) {
        if (crossoverInitial < 0.0 || crossoverInitial > 1.0) {
            throw new IllegalArgumentException("Tried to set a crossoverInitial of " + crossoverInitial
                    + ", but SwingUserInterface requires a crossoverInitial between 0.0 and 1.0 inclusive.");
        }

        this.crossoverInitial = crossoverInitial;
    }

    /**
     * @param defaultCipher
     *            the defaultCipher to set
     */
    @Required
    public void setDefaultCipher(String defaultCipher) {
        this.defaultCipher = defaultCipher;
    }

    /**
     * @param strategyBuilder
     *            the strategyBuilder to set
     */
    @Required
    public void setStrategyBuilder(StrategyBuilder strategyBuilder) {
        this.strategyBuilder = strategyBuilder;
    }
}