package semorg.gui;

import java.sql.SQLException;
import java.sql.Timestamp;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
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.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;

import semorg.gui.list.SeminarTypeListWindow;
import semorg.gui.util.AssociationTabControl;
import semorg.gui.util.ForeignKeyConstraintSelector;
import semorg.gui.util.ItemListener;
import semorg.gui.util.Messages;
import semorg.gui.util.CalendarControl.SWTCalendarEvent;
import semorg.gui.util.CalendarControl.SWTCalendarListener;
import semorg.sql.tables.AbstractTable;
import semorg.sql.tables.Client;
import semorg.sql.tables.CompanyInternalPresentation;
import semorg.sql.tables.SeminarType;
import semorg.sql.tables.SimpleIDKey;
import semorg.sql.util.Utility;

/** The window for editing new or existing {@link SeminarType} records. */
public class SeminarTypeWindow {

    /**
     * Inner class which provides a listener reacting on changes of the input in
     * the {@link SeminarTypeWindow} window.
     */
    class InputChangedListener implements ModifyListener, SelectionListener,
	    SWTCalendarListener, ItemListener {

	/**
	 * Appends to the title of the window an asterisk (*) if the input has
	 * changed. Furthermore it sets the flag {@link #inputChanged} to
	 * <tt>true</tt>.
	 */
	private void inputChanged() {
	    if (!settingInput && !inputChanged) {
		inputChanged = true;
		shell.setText(shell.getText() + "*");
	    }
	}

	/** Invokes {@link #inputChanged()} if a text has been changed. */
	public void modifyText(ModifyEvent e) {
	    inputChanged();
	}

	/** Invokes {@link #inputChanged()} if a widget has been selected. */
	public void widgetSelected(SelectionEvent e) {
	    inputChanged();
	}

	/** Invokes {@link #inputChanged()} if a doubleclick has occurred. */
	public void widgetDefaultSelected(SelectionEvent e) {
	    inputChanged();
	}

	/** Invokes {@link #inputChanged()} if a date has been changed. */
	public void dateChanged(SWTCalendarEvent event) {
	    inputChanged();
	}

	/**
	 * Invokes {@link #inputChanged()} if a item in the
	 * AssociationTabControl has changed.
	 */
	public void itemChanged() {
	    inputChanged();
	}

    }

    /**
     * Holds the data of the actual displayed data record. If a new record is
     * entered it is set to <tt>null</tt> until the changes have been
     * committed.
     */
    private SeminarType input;

    /**
     * Is set to <tt>true</tt> if the data from the database (or corresponding
     * from {@link #input}) is to be set into the window form, otherwise
     * <tt>false</tt>. <br>
     * <br>
     * 
     * That is needed to prevent the {@link ModifyListener} from firing when the
     * data is load into the window form by using the .setText() methods of the
     * GUI elements.
     */
    private boolean settingInput = false;

    /**
     * Is set to <tt>true</tt> if the input has been changed and not committed
     * yet, otherwise it is set to <tt>false</tt>.
     */
    private boolean inputChanged;

    /**
     * <tt>true</tt> if the editing of the input (i.e. the elements of the
     * form) has been enabled, otherwise it is <tt>false</tt>. <br>
     * <br>
     * 
     * This flag indicates whether the actual displayed record has been locked
     * by the actual editing window or not. This avoids the releasing of records
     * which are locked by other editing windows.
     */
    private boolean inputEditingEnabled;

    /** Listener instance added to the most elements of the window. */
    private InputChangedListener inputChangedListener = new InputChangedListener();

    /* ********** GUI PROPERTIES ********* */
    /** The editing window. */
    private Shell shell;

    /* Text- and Combofields, CalendarControls and Buttons */
    private final Label numberLabel;
    private final Text numberText;
    private final Text shortTitleText;
    private final Text titleText;
    private final Text objectiveText;
    private final Text methodologyText;
    private final Text topicText;
    private final Text routineText;
    private final Text durationText;
    private final Text documentsText;
    private final Text audienceText;
    private final Text requirementsText;
    private final Text chargeText;
    private final Text maxEntrantsText;
    private final Text minEntrantsText;

    private AssociationTabControl presentationControl;
    private AssociationTabControl lecturerControl;

    private final Button okButton;
    private final Button applyButton;
    private final Button newButton;
    private final Button abortButton;

    /** The triangle-button with the apex to the left. */
    private final Button prevButton;

    /** The triangle-button with the apex to the right. */
    private final Button nextButton;

    /**
     * Creates a {@link SeminarTypeWindow} instance with the given shell as the
     * parent shell. <br>
     * <br>
     * 
     * It also adds a listener which reacts on closing events. It checks if
     * changes have been made and if so it opens a dialog which informs the user
     * and asks for a decision (confirm/discard). Finally it releases the locked
     * record (if one is displayed and it is locked by this editing window).
     * 
     * @param parent
     *                Shell instance used the as parent shell of the window.
     */

    private SeminarTypeWindow(Shell parent) {

	shell = new Shell(parent, SWT.CLOSE);

	shell.addListener(SWT.Close, new Listener() {
	    public void handleEvent(Event event) {
		if (inputChanged) {
		    if (confirmClose()) {
			if (inputEditingEnabled && input != null)
			    SeminarType.lockedIds.remove(new Integer(input
				    .getId()));
		    } else
			event.doit = false;
		} else if (input != null && inputEditingEnabled)
		    SeminarType.lockedIds.remove(new Integer(input.getId()));
	    }
	});

	shell.setLayout(new GridLayout(1, false));
	shell.setSize(550, 730);
	shell.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "SeminarTypeWindow");

	GridData mgd = new GridData();
	mgd.horizontalAlignment = GridData.FILL;
	mgd.verticalAlignment = GridData.FILL;
	mgd.grabExcessHorizontalSpace = true;
	mgd.grabExcessVerticalSpace = true;

	final Group mainForm = new Group(shell, SWT.NULL);
	mainForm.setLayoutData(mgd);
	GridLayout mgl = new GridLayout(2, false);
	mgl.marginHeight = 0;
	mainForm.setLayout(mgl);

	final TabFolder tabs = new TabFolder(shell, SWT.FLAT);
	tabs.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "Tabs");
	GridData tgd = new GridData();
	tgd.heightHint = 130;
	tgd.horizontalAlignment = GridData.FILL;
	tgd.grabExcessHorizontalSpace = true;
	tabs.setLayoutData(tgd);

	final Composite leftColumn = new Composite(mainForm, SWT.NULL);
	leftColumn.setLayout(new GridLayout(1, false));
	GridData lcgd = new GridData();
	lcgd.horizontalAlignment = GridData.FILL;
	lcgd.grabExcessHorizontalSpace = true;
	lcgd.verticalAlignment = GridData.BEGINNING;
	leftColumn.setLayoutData(lcgd);

	final Composite rightColumn = new Composite(mainForm, SWT.NULL);
	rightColumn.setLayout(new GridLayout(1, false));
	GridData rightColumnGridData = new GridData();
	rightColumnGridData.horizontalAlignment = GridData.FILL;
	rightColumnGridData.grabExcessHorizontalSpace = true;
	rightColumnGridData.verticalAlignment = GridData.BEGINNING;
	rightColumn.setLayoutData(rightColumnGridData);

	final Composite idComposite = new Composite(leftColumn, SWT.NULL);
	idComposite.setLayout(new GridLayout(2, false));

	numberLabel = new Label(idComposite, SWT.READ_ONLY);
	numberLabel.setText(Messages.getString("GUIText.NumberText"));

	numberText = new Text(idComposite, SWT.SINGLE | SWT.BORDER
		| SWT.READ_ONLY);
	numberText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "NumberText");
	Utility.setLength(numberText, 10);
	numberText.addModifyListener(inputChangedListener);
	numberText.setToolTipText(Messages.getString("GUIText.NumberToolTip"));

	final Label shortTitleLabel = new Label(idComposite, SWT.READ_ONLY);
	shortTitleLabel.setText(Messages.getString("GUIText.ShortTitleText"));

	shortTitleText = new Text(idComposite, SWT.SINGLE | SWT.BORDER);
	shortTitleText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY,
		"ShortTitleText");
	shortTitleText.addModifyListener(inputChangedListener);
	shortTitleText.setBackground(Utility.LIGHT_YELLOW);
	shortTitleText.addFocusListener(Utility.checkEmptyListener);
	shortTitleText.setToolTipText(Messages
		.getString("GUIText.ShortTitleToolTip"));
	Utility.setLength(shortTitleText, 10);

	final Label titleLabel = new Label(leftColumn, SWT.READ_ONLY);
	titleLabel.setText(Messages.getString("GUIText.TitelText"));

	titleText = new Text(leftColumn, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL
		| SWT.WRAP);
	titleText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "TitleText");
	titleText.addModifyListener(inputChangedListener);
	GridData textGridData = new GridData();
	textGridData.widthHint = 220;
	textGridData.heightHint = 60;
	titleText.setLayoutData(textGridData);
	titleText.setTextLimit(50);
	titleText.setToolTipText(Messages.getString("GUIText.TitleToolTip"));

	final Label objectiveLabel = new Label(leftColumn, SWT.READ_ONLY);
	objectiveLabel.setText(Messages.getString("GUIText.ObjectiveText"));

	objectiveText = new Text(leftColumn, SWT.MULTI | SWT.BORDER
		| SWT.V_SCROLL | SWT.WRAP);
	objectiveText
		.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "ObjectiveText");
	objectiveText.addModifyListener(inputChangedListener);
	objectiveText.setLayoutData(textGridData);
	objectiveText.setTextLimit(400);
	objectiveText.setToolTipText(Messages
		.getString("GUIText.ObjectiveToolTip"));

	final Label methodologyLabel = new Label(leftColumn, SWT.READ_ONLY);
	methodologyLabel.setText(Messages.getString("GUIText.MethodologyText"));

	methodologyText = new Text(leftColumn, SWT.MULTI | SWT.BORDER
		| SWT.V_SCROLL | SWT.WRAP);
	methodologyText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY,
		"MethodologyText");
	methodologyText.addModifyListener(inputChangedListener);
	methodologyText.setLayoutData(textGridData);
	methodologyText.setTextLimit(400);
	methodologyText.setToolTipText(Messages
		.getString("GUIText.MethodologyToolTip"));

	final Label topicLabel = new Label(leftColumn, SWT.READ_ONLY);
	topicLabel.setText(Messages.getString("GUIText.TopicText"));

	topicText = new Text(leftColumn, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL
		| SWT.WRAP);
	topicText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "TopicText");
	topicText.addModifyListener(inputChangedListener);
	topicText.setLayoutData(textGridData);
	topicText.setTextLimit(400);
	topicText.setToolTipText(Messages.getString("GUIText.TopicToolTip"));

	final Label routineLabel = new Label(rightColumn, SWT.READ_ONLY);
	routineLabel.setText(Messages.getString("GUIText.RoutineText"));

	routineText = new Text(rightColumn, SWT.MULTI | SWT.BORDER
		| SWT.V_SCROLL | SWT.WRAP);
	routineText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "RoutineText");
	routineText.addModifyListener(inputChangedListener);
	routineText.setLayoutData(textGridData);
	routineText.setTextLimit(200);
	routineText
		.setToolTipText(Messages.getString("GUIText.RoutineToolTip"));

	final Composite durationComp = new Composite(rightColumn, SWT.NULL);
	durationComp.setLayout(new GridLayout(2, false));

	final Label durationLabel = new Label(durationComp, SWT.READ_ONLY);
	durationLabel.setText(Messages.getString("GUIText.DurationText"));

	durationText = new Text(durationComp, SWT.SINGLE | SWT.BORDER);
	durationText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "DurationText");
	Utility.setLength(durationText, 10);
	durationText.addModifyListener(inputChangedListener);
	durationText.addFocusListener(Utility.checkCorrectIntListener);
	durationText.setToolTipText(Messages
		.getString("GUIText.DurationToolTip"));

	final Label documentsLabel = new Label(rightColumn, SWT.READ_ONLY);
	documentsLabel.setText(Messages.getString("GUIText.DocumentsText"));

	documentsText = new Text(rightColumn, SWT.MULTI | SWT.BORDER
		| SWT.V_SCROLL | SWT.WRAP);
	documentsText
		.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "DocumentsText");
	documentsText.addModifyListener(inputChangedListener);
	documentsText.setLayoutData(textGridData);
	documentsText.setTextLimit(200);
	documentsText.setToolTipText(Messages
		.getString("GUIText.DocumentsToolTip"));

	final Label audienceLabel = new Label(rightColumn, SWT.READ_ONLY);
	audienceLabel.setText(Messages.getString("GUIText.AudienceText"));

	audienceText = new Text(rightColumn, SWT.MULTI | SWT.BORDER
		| SWT.V_SCROLL | SWT.WRAP);
	audienceText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "AudienceText");
	audienceText.addModifyListener(inputChangedListener);
	audienceText.setLayoutData(textGridData);
	audienceText.setTextLimit(200);
	audienceText.setToolTipText(Messages
		.getString("GUIText.AudienceToolTip"));

	final Label requirementsLabel = new Label(rightColumn, SWT.READ_ONLY);
	requirementsLabel.setText(Messages
		.getString("GUIText.RequirementsText"));

	requirementsText = new Text(rightColumn, SWT.MULTI | SWT.BORDER
		| SWT.V_SCROLL | SWT.WRAP);
	requirementsText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY,
		"RequirementsText");
	requirementsText.addModifyListener(inputChangedListener);
	requirementsText.setLayoutData(textGridData);
	requirementsText.setTextLimit(200);
	requirementsText.setToolTipText(Messages
		.getString("GUIText.RequirementsToolTip"));

	final Composite additionalComponents = new Composite(rightColumn,
		SWT.NULL);
	additionalComponents.setLayout(new GridLayout(2, false));

	final Label chargeLabel = new Label(additionalComponents, SWT.READ_ONLY);
	chargeLabel.setText(Messages.getString("GUIText.ChargeText"));
	Utility.alignRight(chargeLabel);

	chargeText = new Text(additionalComponents, SWT.SINGLE | SWT.BORDER);
	chargeText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "ChargeText");
	Utility.setLength(chargeText, 10);
	chargeText.addModifyListener(inputChangedListener);
	chargeText.addFocusListener(Utility.checkCorrectFloatListener);
	chargeText.setToolTipText(Messages.getString("GUIText.ChargeToolTip"));

	final Label maxEntrantsLabel = new Label(additionalComponents,
		SWT.READ_ONLY);
	maxEntrantsLabel.setText(Messages.getString("GUIText.MaxEntrantsText"));
	Utility.alignRight(maxEntrantsLabel);

	maxEntrantsText = new Text(additionalComponents, SWT.SINGLE
		| SWT.BORDER);
	maxEntrantsText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY,
		"MaxEntrantsText");
	Utility.setLength(maxEntrantsText, 10);
	maxEntrantsText.addModifyListener(inputChangedListener);
	maxEntrantsText.addFocusListener(Utility.checkCorrectIntListener);
	maxEntrantsText.setToolTipText(Messages
		.getString("GUIText.MaxEntrantsToolTip"));

	final Label minEntrantsLabel = new Label(additionalComponents,
		SWT.READ_ONLY);
	minEntrantsLabel.setText(Messages.getString("GUIText.MinEntrantsText"));
	Utility.alignRight(minEntrantsLabel);

	minEntrantsText = new Text(additionalComponents, SWT.SINGLE
		| SWT.BORDER);
	minEntrantsText.setData(Utility.ATOSJ_COMPONENT_NAME_KEY,
		"MinEntrantsText");
	Utility.setLength(minEntrantsText, 10);
	minEntrantsText.addModifyListener(inputChangedListener);
	minEntrantsText.addFocusListener(Utility.checkCorrectIntListener);
	minEntrantsText.setToolTipText(Messages
		.getString("GUIText.MinEntrantsToolTip"));

	TabItem presentationItem = new TabItem(tabs, SWT.NULL);
	presentationItem.setText(Messages
		.getString("GUIText.PresentationsControlText"));
	presentationControl = new AssociationTabControl(tabs,
		AssociationTabControl.TYPE_PRESENTATION_SEMTYPE, shell);
	presentationControl.addItemListener(inputChangedListener);
	presentationControl.setData(Utility.ATOSJ_COMPONENT_NAME_KEY,
		"PresentationControl");
	presentationItem.setControl(presentationControl);

	TabItem lecturerItem = new TabItem(tabs, SWT.NULL);
	lecturerItem
		.setText(Messages.getString("GUIText.LecturersControlText"));
	lecturerControl = new AssociationTabControl(tabs,
		AssociationTabControl.TYPE_LECTURER_CONDUCT, shell);
	lecturerControl.addItemListener(inputChangedListener);
	lecturerControl.setData(Utility.ATOSJ_COMPONENT_NAME_KEY,
		"LecturerControl");
	lecturerItem.setControl(lecturerControl);

	final Composite buttons = new Composite(shell, shell.getStyle());
	buttons.setLayout(new GridLayout(7, false));

	okButton = new Button(buttons, SWT.PUSH);
	okButton.setText(Messages.getString("GUIText.OkButtonText"));
	okButton.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
		| GridData.GRAB_VERTICAL));

	applyButton = new Button(buttons, SWT.PUSH);
	applyButton.setText(Messages.getString("GUIText.ApplyButtonText"));
	applyButton.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
		| GridData.GRAB_VERTICAL));

	newButton = new Button(buttons, SWT.PUSH);
	newButton.setText(Messages.getString("GUIText.NewButtonText"));
	newButton.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
		| GridData.GRAB_VERTICAL));

	abortButton = new Button(buttons, SWT.PUSH);
	abortButton.setText(Messages.getString("GUIText.AbortButtonText"));
	abortButton.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_FILL
		| GridData.GRAB_VERTICAL));

	GridData arrowButtonGridData = new GridData();
	arrowButtonGridData.verticalAlignment = GridData.FILL;
	arrowButtonGridData.grabExcessVerticalSpace = true;
	arrowButtonGridData.widthHint = 23;

	prevButton = new Button(buttons, SWT.ARROW | SWT.LEFT);
	prevButton.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "Previous");
	prevButton.setLayoutData(arrowButtonGridData);

	nextButton = new Button(buttons, SWT.ARROW | SWT.RIGHT);
	nextButton.setData(Utility.ATOSJ_COMPONENT_NAME_KEY, "Next");
	nextButton.setLayoutData(arrowButtonGridData);
    }

    /**
     * Creates an instance of this class, sets the input and finally opens it.
     * 
     * @param parent
     *                the parent shell to which this window belongs
     * @param input
     *                the data object to be displayed in the window
     * @param caller
     *                the {@link AssociationTabControl} instance which calls the
     *                constructor.
     */
    public SeminarTypeWindow(Shell parent, SeminarType input,
	    final AssociationTabControl caller) {
	this(parent);

	createButtonListener(caller);
	setInput(input);

	shell.open();
    }

    /**
     * Creates an instance of this class, sets the input and finally opens it.
     * 
     * @param parent
     *                the parent shell to which this window belongs
     * @param input
     *                the data object to be displayed in the window
     * @param caller
     *                the {@link ForeignKeyConstraintSelector} instance which
     *                calls the constructor.
     */
    public SeminarTypeWindow(Shell parent, SeminarType input,
	    final ForeignKeyConstraintSelector caller) {
	this(parent);

	createButtonListener(caller);
	setInput(input);

	shell.open();
    }

    /**
     * Loads a given {@link CompanyInternalPresentation} record into the window
     * form of initialize the elements of the form the empty string/null if no
     * data is given.
     * 
     * @param seminarType
     *                {@link SeminarType} instance which contains the data to be
     *                displayed or <tt>null</tt> if a completely new record is
     *                to be edited.
     */
    private void setInput(SeminarType seminarType) {
	/* STEP 1: switch off the listeners */
	settingInput = true;

	/* STEP 2: unlock the actually displayed data record (if exists) */
	if (this.input != null && inputEditingEnabled)
	    SeminarType.lockedIds.remove(new Integer(this.input.getId()));

	/*
	 * STEP 3: loading the given (new) data instance into the window form
	 * (if not null else initialize the elements)
	 */
	if (seminarType != null) {
	    numberLabel.setEnabled(true);
	    numberText.setEnabled(true);
	    shortTitleText.setFocus();
	    numberText.setText(new Integer(seminarType.getId()).toString());
	    if (seminarType.getShortTitle() != null)
		shortTitleText.setText(seminarType.getShortTitle());
	    else
		shortTitleText.setText("");
	    if (seminarType.getTitle() != null)
		titleText.setText(seminarType.getTitle());
	    else
		titleText.setText("");
	    if (seminarType.getObjective() != null)
		objectiveText.setText(seminarType.getObjective());
	    else
		objectiveText.setText("");
	    if (seminarType.getMethodology() != null)
		methodologyText.setText(seminarType.getMethodology());
	    else
		methodologyText.setText("");
	    if (seminarType.getTopic() != null)
		topicText.setText(seminarType.getTopic());
	    else
		topicText.setText("");
	    if (seminarType.getRoutine() != null)
		routineText.setText(seminarType.getRoutine());
	    else
		routineText.setText("");
	    if (seminarType.getDuration() != null)
		durationText.setText(seminarType.getDuration().toString());
	    else
		durationText.setText("");

	    if (seminarType.getDocuments() != null)
		documentsText.setText(seminarType.getDocuments());
	    else
		documentsText.setText("");
	    if (seminarType.getAudience() != null)
		audienceText.setText(seminarType.getAudience());
	    else
		audienceText.setText("");
	    if (seminarType.getRequirements() != null)
		requirementsText.setText(seminarType.getRequirements());
	    else
		requirementsText.setText("");

	    if (seminarType.getCharge() != null)
		chargeText.setText(Utility.createFloatText(seminarType
			.getCharge()));
	    else
		chargeText.setText("");

	    if (seminarType.getMaxEntrants() != null)
		maxEntrantsText
			.setText(seminarType.getMaxEntrants().toString());
	    else
		maxEntrantsText.setText("");

	    if (seminarType.getMinEntrants() != null)
		minEntrantsText
			.setText(seminarType.getMinEntrants().toString());
	    else
		minEntrantsText.setText("");

	    try {
		presentationControl.setInput(seminarType.getId());
		lecturerControl.setInput(seminarType.getId());
	    } catch (SQLException e) {/* TODO */
	    }
	} else {
	    // no data given (client == null): initialize elements
	    shortTitleText.setFocus();
	    numberLabel.setEnabled(false);
	    numberText.setEnabled(false);
	    numberText.setText("");
	    shortTitleText.setText("");
	    titleText.setText("");
	    objectiveText.setText("");
	    methodologyText.setText("");
	    topicText.setText("");
	    routineText.setText("");
	    durationText.setText("");
	    documentsText.setText("");
	    audienceText.setText("");
	    requirementsText.setText("");
	    chargeText.setText("");
	    maxEntrantsText.setText("");
	    minEntrantsText.setText("");

	    try {
		presentationControl.setInput(AbstractTable.NULL_ID);
		lecturerControl.setInput(AbstractTable.NULL_ID);
	    } catch (SQLException e) {/* TODO */
	    }
	}

	/*
	 * STEP 4: Check if the given record is already locked, i.e. it is
	 * already edited (if data object is not null, else enable the
	 * elements). -> yes: disable the form elements -> no: enable them and
	 * lock the new record
	 */
	if (seminarType != null) {
	    boolean alreadyEditing = SeminarType.lockedIds
		    .contains(new Integer(seminarType.getId()));
	    setInputComponentsEnabled(!alreadyEditing);

	    // neuen Datensatz sperren
	    if (!alreadyEditing) {
		SeminarType.lockedIds.add(new Integer(seminarType.getId()));
	    }
	}
	// completely new data record
	else
	    setInputComponentsEnabled(true);

	/*
	 * STEP 5: set input to the new data object, inputChanged to true and
	 * enable next/prev buttons
	 */
	this.input = seminarType;
	inputChanged = (seminarType == null);

	prevButton.setEnabled(this.input != null);
	nextButton.setEnabled(this.input != null);

	/* STEP 6: set the window title */
	String shellText;
	if (input == null)
	    shellText = Messages.getString("GUIText.NewItemWindowTitleText");
	else
	    shellText = Integer.toString(input.getId());

	shellText += Messages.getString("GUIText.SeminarTypeWindowTitleText");
	if (input == null)
	    shellText += "*";
	shell.setText(shellText);

	/* STEP 7: switch on the listeners */
	settingInput = false;
    }

    /**
     * According to the value of the given parameter (<tt>true</tt>/<tt>false</tt>)
     * this method enables / disables the widgets of the window form.<br>
     * <br>
     * 
     * <i>Note:</i> It also sets the member {@link #inputEditingEnabled} to the
     * value of the parameter to signal that editing of the input has been
     * enabled or not.
     * 
     * @param enabled
     *                if equals <tt>true</tt> the widgets are enabled
     *                otherwise the widgets get disabled.
     */
    private void setInputComponentsEnabled(boolean enabled) {
	numberText.setEnabled(enabled);

	shortTitleText.setEnabled(enabled);
	titleText.setEnabled(enabled);
	objectiveText.setEnabled(enabled);
	methodologyText.setEnabled(enabled);
	topicText.setEnabled(enabled);
	routineText.setEnabled(enabled);
	durationText.setEnabled(enabled);
	documentsText.setEnabled(enabled);
	audienceText.setEnabled(enabled);
	requirementsText.setEnabled(enabled);
	chargeText.setEnabled(enabled);
	maxEntrantsText.setEnabled(enabled);
	minEntrantsText.setEnabled(enabled);

	presentationControl.setEnabled(enabled);
	lecturerControl.setEnabled(enabled);

	okButton.setEnabled(enabled);
	applyButton.setEnabled(enabled);
	newButton.setEnabled(enabled);
	abortButton.setEnabled(enabled);
	prevButton.setEnabled(enabled);
	nextButton.setEnabled(enabled);

	inputEditingEnabled = enabled;

    }

    /**
     * Adds a listener to several buttons of the window form.<br>
     * <br>
     * 
     * This involves at the moment the buttons {@link #okButton},
     * {@link #abortButton}, {@link #applyButton}, {@link #newButton},
     * {@link #prevButton}, {@link #nextButton}.
     * 
     * @param caller
     *                {@link AssociationTabControl} instance which called the
     *                constructor which itself calls this method.
     */
    private void createButtonListener(final AssociationTabControl caller) {

	if (caller == null) { // normal mode, no caller

	    okButton.addListener(SWT.Selection, new Listener() {
		public void handleEvent(Event event) {
		    if (onSave())
			shell.close();
		}
	    });
	    applyButton.addListener(SWT.Selection, new Listener() {
		public void handleEvent(Event arg0) {
		    onSave();
		}
	    });
	} else {// caller mode

	    okButton.addListener(SWT.Selection, new Listener() {
		public void handleEvent(Event event) {
		    if (onSave()) {
			caller.addSelectedIds(new SimpleIDKey[] { input },
				false);
			shell.close();
		    }
		}
	    });
	    applyButton.addListener(SWT.Selection, new Listener() {
		public void handleEvent(Event arg0) {
		    if (onSave()) {
			caller.addSelectedIds(new SimpleIDKey[] { input },
				false);
		    }
		}
	    });
	}

	newButton.addListener(SWT.Selection, new Listener() {
	    public void handleEvent(Event arg0) {
		if (onSave())
		    setInput(null);
	    }
	});

	abortButton.addListener(SWT.Selection, new Listener() {
	    public void handleEvent(Event arg0) {
		shell.close();
	    }
	});

	prevButton.addListener(SWT.Selection, new Listener() {
	    public void handleEvent(Event arg0) {
		if (inputChanged) {
		    if (confirmClose())
			setInput(SeminarType.getPrevious(input.getId()));
		} else
		    setInput(SeminarType.getPrevious(input.getId()));
	    }
	});

	nextButton.addListener(SWT.Selection, new Listener() {
	    public void handleEvent(Event arg0) {
		if (inputChanged) {
		    if (confirmClose())
			setInput(SeminarType.getNext(input.getId()));
		} else
		    setInput(SeminarType.getNext(input.getId()));
	    }
	});
    }

    /**
     * Adds a listener to several buttons of the window form.<br>
     * <br>
     * 
     * This involves at the moment the buttons {@link #okButton},
     * {@link #abortButton}, {@link #applyButton}, {@link #newButton},
     * {@link #prevButton}, {@link #nextButton}.
     * 
     * @param caller
     *                {@link ForeignKeyConstraintSelector} instance which called
     *                the constructor which itself calls this method.
     */
    private void createButtonListener(final ForeignKeyConstraintSelector caller) {

	if (caller == null) { // normal mode, no caller

	    okButton.addListener(SWT.Selection, new Listener() {
		public void handleEvent(Event event) {
		    if (onSave())
			shell.close();
		}
	    });
	    applyButton.addListener(SWT.Selection, new Listener() {
		public void handleEvent(Event arg0) {
		    onSave();
		}
	    });
	} else {// caller mode

	    okButton.addListener(SWT.Selection, new Listener() {
		public void handleEvent(Event event) {
		    if (onSave()) {
			caller.setSelectedId(input.getId());
			shell.close();
		    }
		}
	    });
	    applyButton.addListener(SWT.Selection, new Listener() {
		public void handleEvent(Event arg0) {
		    if (onSave()) {
			caller.setSelectedId(input.getId());
		    }
		}
	    });
	}

	newButton.addListener(SWT.Selection, new Listener() {
	    public void handleEvent(Event arg0) {
		if (onSave())
		    setInput(null);
	    }
	});

	abortButton.addListener(SWT.Selection, new Listener() {
	    public void handleEvent(Event arg0) {
		shell.close();
	    }
	});

	prevButton.addListener(SWT.Selection, new Listener() {
	    public void handleEvent(Event arg0) {
		if (inputChanged) {
		    if (confirmClose())
			setInput(SeminarType.getPrevious(input.getId()));
		} else
		    setInput(SeminarType.getPrevious(input.getId()));
	    }
	});

	nextButton.addListener(SWT.Selection, new Listener() {
	    public void handleEvent(Event arg0) {
		if (inputChanged) {
		    if (confirmClose())
			setInput(SeminarType.getNext(input.getId()));
		} else
		    setInput(SeminarType.getNext(input.getId()));
	    }
	});
    }

    /**
     * Checks if all obligatory attributes of a
     * {@link CompanyInternalPresentation} record are entered into the window
     * form and if the entered fees are correct float numbers.
     * 
     * @return <tt>true</tt> if all mandatory fields are set and the fee
     *         values are valid float numbers (if entered), otherwise
     *         <tt>false</tt>.
     * 
     * @see semorg.sql.util.Utility#isCorrectFloat(String)
     * @see semorg.sql.util.Utility#isCorrectInteger(String)
     */
    protected boolean checkInput() {
	boolean inputOK = true;
	String errorMessage = "";
	if (shortTitleText.getText().equals("")) {
	    errorMessage += Messages
		    .getString("GUIText.ErrorMessageDialogMandatoryFieldShortTitleText");
	    inputOK = false;
	}
	if (!Utility.isCorrectInteger(durationText.getText())) {
	    errorMessage += Messages
		    .getString("GUIText.ErrorMessageDialogIncorrectNumberDuration");
	    inputOK = false;
	}
	if (!Utility.isCorrectFloat(chargeText.getText())) {
	    errorMessage += Messages
		    .getString("GUIText.ErrorMessageDialogIncorrectFloatCharge");
	    inputOK = false;
	}
	if (!Utility.isCorrectInteger(minEntrantsText.getText())) {
	    errorMessage += Messages
		    .getString("GUIText.ErrorMessageDialogIncorrectNumberMinEntrants");
	    inputOK = false;
	}
	if (!Utility.isCorrectInteger(maxEntrantsText.getText())) {
	    errorMessage += Messages
		    .getString("GUIText.ErrorMessageDialogIncorrectNumberMaxEntrants");
	    inputOK = false;
	}
	if (Utility.isCorrectInteger(maxEntrantsText.getText())
		&& Utility.isCorrectInteger(minEntrantsText.getText())
		&& Utility.parseInteger(maxEntrantsText.getText()) != null
		&& Utility.parseInteger(minEntrantsText.getText()) != null
		&& Utility.parseInteger(minEntrantsText.getText()) > Utility
			.parseInteger(maxEntrantsText.getText())) {

	    errorMessage += Messages
		    .getString("GUIText.ErrorMessageDialogMaxEntrantsLessThanMinEntrants");
	    inputOK = false;
	}
	if (!inputOK) {
	    MessageDialog
		    .openInformation(
			    shell,
			    Messages
				    .getString("GUIText.ErrorMessageDialogMandatoryFieldWindowTitle"),
			    errorMessage);
	}

	return inputOK;
    }

    /**
     * Reads the data from the window form elements, sets the values to a
     * {@link SeminarType} instance and commits the changes / the new record
     * into the database.
     * 
     * Furthermore the member {@link #input} is set to the new values.
     * 
     */
    protected void commitInputToDB() {

	if (input == null) {
	    // new record into the db

	    SeminarType newInput = new SeminarType(SeminarType.NULL_ID,
		    shortTitleText.getText(), titleText.getText(),
		    objectiveText.getText(), methodologyText.getText(),
		    topicText.getText(), routineText.getText(), Utility
			    .parseInteger(durationText.getText()),
		    documentsText.getText(), audienceText.getText(),
		    requirementsText.getText(), Utility.parseFloat(chargeText
			    .getText()), Utility.parseInteger(maxEntrantsText
			    .getText()), Utility.parseInteger(minEntrantsText
			    .getText()), new Timestamp(System
			    .currentTimeMillis()), new Timestamp(System
			    .currentTimeMillis()));
	    input = newInput;
	    try {
		int id = input.insertIntoDB();
		numberText.setText(new Integer(id).toString());
	    } catch (SQLException e) {
		e.printStackTrace();
	    }
	} else {
	    // update an existing record

	    input.setShortTitle(shortTitleText.getText());
	    input.setTitle(titleText.getText());

	    input.setObjective(objectiveText.getText());
	    input.setMethodology(methodologyText.getText());
	    input.setTopic(topicText.getText());
	    input.setRoutine(routineText.getText());
	    input.setDuration(Utility.parseInteger(durationText.getText()));
	    input.setDocuments(documentsText.getText());
	    input.setAudience(audienceText.getText());
	    input.setRequirements(requirementsText.getText());
	    input.setCharge(Utility.parseFloat(chargeText.getText()));
	    input.setMaxEntrants(Utility
		    .parseInteger(maxEntrantsText.getText()));
	    input.setMinEntrants(Utility
		    .parseInteger(minEntrantsText.getText()));

	    try {
		input.updateDB();
	    } catch (SQLException e) {
		e.printStackTrace();
	    }
	}

	try {
	    presentationControl.commitIntoDB(input.getId());
	} catch (SQLException e) {
	    e.printStackTrace();
	}

	try {
	    lecturerControl.commitIntoDB(input.getId());
	} catch (SQLException e) {
	    e.printStackTrace();
	}

	SeminarTypeListWindow.instance.update();
    }

    /**
     * Creates a message dialog if the data in the window form has been changed
     * (or was entered newly) and these changes haven't been confirmed (e.g. by
     * clicking the ok button) or discarded so far. It also receives the
     * decision of the user (confirm/discard changes or abort the window
     * closing) and handles it.
     * 
     * In the positive case (confirmation of the changes) it invokes the method
     * {@link #onSave()}.
     * 
     * @return <tt>true</tt> if the shell can be closed and <tt>false</tt>
     *         otherwise.
     */
    private boolean confirmClose() {

	MessageDialog dlg;

	if (input == null) {
	    dlg = new MessageDialog(
		    shell,
		    Messages
			    .getString("GUIText.SaveNewItemMessageDialogWindowTitle"), //$NON-NLS-1$
		    null,
		    Messages
			    .getString("GUIText.SaveNewItemMessageDialogQuestionText"), //$NON-NLS-1$
		    MessageDialog.QUESTION,
		    new String[] {
			    Messages
				    .getString("GUIText.SaveNewItemMessageDialogYesButtonText"), Messages.getString("GUIText.SaveNewItemMessageDialogNoButtonText"), //$NON-NLS-1$ //$NON-NLS-2$
			    Messages
				    .getString("GUIText.SaveNewItemMessageDialogAbortButtonText") }, 0); //$NON-NLS-1$
	} else {
	    dlg = new MessageDialog(
		    shell,
		    Messages
			    .getString("GUIText.SaveChangesMessageDialogWindowTitle"), //$NON-NLS-1$
		    null,
		    Messages
			    .getString("GUIText.SaveChangesMessageDialogQuestionText"), //$NON-NLS-1$
		    MessageDialog.QUESTION,
		    new String[] {
			    Messages
				    .getString("GUIText.SaveChangesMessageDialogYesButtonText"), Messages.getString("GUIText.SaveChangesMessageDialogNoButtonText"), //$NON-NLS-1$ //$NON-NLS-2$
			    Messages
				    .getString("GUIText.SaveChangesMessageDialogAbortButtonText") }, 0); //$NON-NLS-1$
	}
	switch (dlg.open()) {
	case 0:
	    return onSave();
	case 1:
	    return true;
	case 2:
	    return false;
	default:
	    return true;
	}
    }

    /**
     * Checks whether the input has been changed (i.e. inputChanged equals
     * <tt>true</tt>) or not. If changes have been done, it firstly checks if
     * the changes are valid ({@link #checkInput()}), secondly invokes the
     * method {@link #commitInputToDB()} to commit the changes and thirdly
     * updates the GUI by invoking the method {@link #setInput(SeminarType)}.
     * 
     * @return <tt>true</tt> if nothing has changed or the commit of the
     *         changes to the database was successful, <tt>false</tt>
     *         otherwise.
     */
    private boolean onSave() {
	if (!inputChanged)
	    return true;
	if (checkInput()) {
	    commitInputToDB();
	    setInput(input);
	    return true;
	} else
	    return false;
    }
}
