package semorg.gui.util;

import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Vector;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

import semorg.gui.ClientBookingWindow;
import semorg.gui.ClientWindow;
import semorg.gui.CompanyBookingWindow;
import semorg.gui.CompanyInternalPresentationWindow;
import semorg.gui.CompanyWindow;
import semorg.gui.LecturerWindow;
import semorg.gui.MainWindow;
import semorg.gui.PublicPresentationWindow;
import semorg.gui.SeminarTypeWindow;
import semorg.gui.list.ClientBookingListWindow;
import semorg.gui.list.ClientListWindow;
import semorg.gui.list.CompanyBookingListWindow;
import semorg.gui.list.LecturerListWindow;
import semorg.gui.list.PresentationListWindow;
import semorg.gui.list.SeminarTypeListWindow;
import semorg.gui.provider.ClientBookingTableProvider;
import semorg.gui.provider.ClientTableProvider;
import semorg.gui.provider.CompanyBookingTableProvider;
import semorg.gui.provider.LecturerTableProvider;
import semorg.gui.provider.PresentationTableProvider;
import semorg.gui.provider.SeminarTypeTableProvider;
import semorg.sql.tables.AbstractTable;
import semorg.sql.tables.Client;
import semorg.sql.tables.ClientBooking;
import semorg.sql.tables.Company;
import semorg.sql.tables.CompanyBooking;
import semorg.sql.tables.CompanyInternalPresentation;
import semorg.sql.tables.Conduct;
import semorg.sql.tables.Instructor;
import semorg.sql.tables.Lecturer;
import semorg.sql.tables.Presentation;
import semorg.sql.tables.PublicPresentation;
import semorg.sql.tables.SeminarType;
import semorg.sql.tables.SimpleIDKey;
import semorg.sql.tables.Supervisor;
import semorg.sql.util.DBColumn;
import semorg.sql.util.DistinctVector;
import semorg.sql.util.Utility;

/**
 * This class provides a SWT composite which allows the user to manage several
 * associations.
 */
public class AssociationTabControl extends Composite {

    /**
     * Instances from this type allow to manage the association between the
     * classes {@link Client} and {@link Company} in the {@link CompanyWindow}.
     */
    public static final int TYPE_EMPLOYEE = 1;

    /**
     * Instances from this type allow to manage the association between the
     * classes {@link Client} and {@link ClientBooking} in the
     * {@link ClientWindow}.
     */
    public static final int TYPE_CLIENTBOOKING_CLIENT = 2;

    /**
     * Instances from this type allow to manage the association between classes
     * {@link Company} and {@link CompanyBooking} in the {@link CompanyWindow}.
     */
    public static final int TYPE_COMPANYBOOKING_COMPANY = 3;

    /**
     * Instances from this type allow to manage the association Supervisor in
     * the {@link LecturerWindow}.
     */
    public static final int TYPE_PRESENTATION_SUPERVISOR = 4;

    /**
     * Instances from this type allow to manage the association Instructor in
     * the {@link LecturerWindow}.
     */
    public static final int TYPE_PRESENTATION_INSTRUCTOR = 5;

    /**
     * Instances from this type allow to manage the association Conduct in the
     * {@link LecturerWindow}.
     */
    public static final int TYPE_SEMINARTYPE_CONDUCT = 6;

    /**
     * Instances from this type allow to manage association between the classes
     * {@link CompanyBooking} and {@link CompanyInternalPresentation} in the
     * {@link CompanyInternalPresentationWindow}.
     */
    public static final int TYPE_COMPANYBOOKING_PRESENTATION = 7;

    /**
     * Instances from this type allow to manage the association Instructor in
     * the {@link PublicPresentationWindow} and
     * {@link CompanyInternalPresentationWindow}.
     */
    public static final int TYPE_LECTURER_INSTRUCTOR = 8;

    /**
     * Instances from this type allow to manage the association Supervisor in
     * the {@link PublicPresentationWindow} and
     * {@link CompanyInternalPresentationWindow}.
     */
    public static final int TYPE_LECTURER_SUPERVISOR = 9;

    /**
     * Instances from this type allow to manage the association between classes
     * {@link Presentation} and {@link SeminarType} in {@link SeminarTypeWindow}.
     */
    public static final int TYPE_PRESENTATION_SEMTYPE = 10;

    /**
     * Instances from this type allow to manage the association Conduct in the
     * {@link SeminarTypeWindow}.
     */
    public static final int TYPE_LECTURER_CONDUCT = 11;

    /**
     * Instances from this type allow to manage the association between the
     * classes {@link ClientBooking} and {@link PublicPresentation} in the
     * {@link PublicPresentationWindow}.
     */
    public static final int TYPE_CLIENTBOOKING_PRESENTATION = 12;

    /**
     * Used to display the several {@link DelayedPaymentItem} objects as items
     * of a GUI table.
     */
    private TableViewer mainTableViewer;

    /**
     * Indicates which type of association is managed by the instance of this
     * class.
     */
    private int style;

    /** The id of the actual data record for which the associations get managed. */
    private int referencedFK;

    /**
     * Indicates whether the control is enabled or not. <tt>true</tt> if the
     * control is enabled, <tt>false</tt> otherwise.
     */
    private boolean enabled;

    /** The columns of the GUI table. */
    private Vector<DBColumn> columns;

    /** A set containing the listeners of the control. */
    private Set<ItemListener> itemListeners = new HashSet<ItemListener>();

    /**
     * These listeners react on changes in the database tables by updating the
     * GUI table.
     */
    private DistinctVector<DBTableChangedListener> updateListeners;

    /** The item "disconnect" in the toolbar. */
    private ToolItem disconnectItem;

    /** The item "delete" in the toolbar. */
    private ToolItem deleteItem;

    /** The item "configure" in the toolbar. */
    private ToolItem configureItem;

    /** The item "choose" in the toolbar. */
    private ToolItem chooseItem;

    /** The item "edit" in the toolbar. */
    private ToolItem editItem;

    /** The item "new" in the toolbar. */
    private ToolItem newItem;

    /**
     * Contains the ids of the previously selected items. <br>
     * <br>
     * This vector is a clone of the {@link #mainTableViewer} input. If the user
     * disconnects an associated item from the current item, it disappears from
     * the GUI table, but in the db it is still connected to the current object.
     * Thus we've got to hold the ids of the formerly connected items such that
     * we can disconnect them in the db when the user confirm his/her changes.
     */
    private DistinctVector<SimpleIDKey> previouslySelectedIds = new DistinctVector<SimpleIDKey>();

    /** Contains the ids of the items which should be deleted. */
    private DistinctVector<SimpleIDKey> idsToDelete = new DistinctVector<SimpleIDKey>();

    /**
     * Creates an instance of this class by initializing the gui elements and
     * adding some listeners to the elements.
     * 
     * @param parent
     *                the parent composite of this AssociationTabControl
     * @param style
     *                the style of the AssociationTabControl (see {@link #style})
     */
    public AssociationTabControl(Composite parent, int style, Shell parentShell) {
	super(parent, SWT.NULL);
	this.style = style;

	FormLayout mainLayout = new FormLayout();
	this.setLayout(mainLayout);

	/* Creating the ToolBar */
	ToolBar buttonToolBar = new ToolBar(this, SWT.FLAT);
	buttonToolBar.setLayoutData(Utility.getFormData(0, 0, null, 0, null, 0,
		100, 0));

	newItem = new ToolItem(buttonToolBar, SWT.NULL);
	newItem.setImage(Utility.getImage("new.png"));
	newItem.setToolTipText(Messages
		.getString("GUIText.AddNewItemButtonToolTip"));
	newItem.setEnabled(true);
	newItem.addSelectionListener(new SelectionListener() {
	    public void widgetSelected(SelectionEvent event) {
		openNewItemWindow();
	    }

	    public void widgetDefaultSelected(SelectionEvent event) {
		widgetSelected(event);
	    }
	});

	editItem = new ToolItem(buttonToolBar, SWT.NULL);
	editItem.setImage(Utility.getImage("edit.png"));
	editItem.setToolTipText(Messages
		.getString("GUIText.EditItemButtonToolTip"));
	editItem.setEnabled(false);
	editItem.addSelectionListener(new SelectionListener() {
	    public void widgetSelected(SelectionEvent event) {
		openEditItemWindow();
	    }

	    public void widgetDefaultSelected(SelectionEvent event) {
		widgetSelected(event);
	    }
	});

	chooseItem = new ToolItem(buttonToolBar, SWT.NULL);
	chooseItem.setImage(Utility.getImage("choose.png"));
	chooseItem.setToolTipText(Messages
		.getString("GUIText.ChooseItemButtonToolTip"));
	chooseItem.addSelectionListener(new SelectionAdapter() {
	    public void widgetSelected(SelectionEvent evt) {
		openListWindow();
	    }
	});

	disconnectItem = new ToolItem(buttonToolBar, SWT.NULL);
	disconnectItem.setImage(Utility.getImage("disconnect.png"));
	disconnectItem.setToolTipText(Messages
		.getString("GUIText.DisconnectItemButtonToolTip"));
	disconnectItem.setEnabled(false);
	disconnectItem.addSelectionListener(new SelectionAdapter() {
	    public void widgetSelected(SelectionEvent evt) {
		onDisconnect();
	    }
	});

	deleteItem = new ToolItem(buttonToolBar, SWT.PUSH);
	deleteItem.setImage(Utility.getImage("delete.png"));
	deleteItem.setToolTipText(Messages
		.getString("GUIText.DeleteItemButtonToolTip"));
	deleteItem.setEnabled(false);
	deleteItem.addSelectionListener(new SelectionListener() {
	    public void widgetSelected(SelectionEvent event) {
		onDelete();
	    }

	    public void widgetDefaultSelected(SelectionEvent event) {
		widgetSelected(event);
	    }
	});

	configureItem = new ToolItem(buttonToolBar, SWT.PUSH);
	configureItem.setImage(Utility.getImage("configure.png"));
	configureItem.setToolTipText(Messages
		.getString("GUIText.ConfigureListItemButtonToolTip"));
	configureItem.setEnabled(true);
	configureItem.addSelectionListener(new SelectionAdapter() {

	    public void widgetSelected(SelectionEvent arg0) {

		ConfigureListDlg dlg = new ConfigureListDlg(Display
			.getCurrent().getActiveShell(), mainTableViewer
			.getTable().getColumns(), mainTableViewer.getTable()
			.getColumnOrder());

		if (dlg.open() == IDialogConstants.OK_ID) {
		    copyColumnProperties(dlg.getColumnProperties());
		}
	    }

	    private void copyColumnProperties(
		    TableColumnProperty[] dlgColumnProperties) {
		TableColumn[] tableColumns = mainTableViewer.getTable()
			.getColumns();
		int[] columnOrder = new int[tableColumns.length];
		for (int i = 0; i < tableColumns.length; i++) {
		    tableColumns[i].setWidth(dlgColumnProperties[i].getWidth());
		    tableColumns[i].setResizable(dlgColumnProperties[i]
			    .getResizable());
		    tableColumns[i].setAlignment(dlgColumnProperties[i]
			    .getAlignment());
		    columnOrder[dlgColumnProperties[i].getColumnNumber()] = dlgColumnProperties[i]
			    .getIndex();
		}
		mainTableViewer.getTable().setColumnOrder(columnOrder);
	    }
	});

	/*
	 * viewer has a border, it is allowed to select mutiple lines and all
	 * columns are selected
	 */
	mainTableViewer = new TableViewer(this, SWT.BORDER | SWT.MULTI
		| SWT.FULL_SELECTION);
	mainTableViewer.getTable().setLayoutData(
		Utility.getFormData(buttonToolBar, 2, 100, 0, 0, 0, 100, 0));

	mainTableViewer.setContentProvider(new ArrayContentProvider());

	mainTableViewer
		.addSelectionChangedListener(new ISelectionChangedListener() {
		    // if an item gets selected enable the following buttons
		    public void selectionChanged(SelectionChangedEvent event) {
			disconnectItem.setEnabled(!mainTableViewer
				.getSelection().isEmpty()
				&& enabled);

			editItem.setEnabled(!mainTableViewer.getSelection()
				.isEmpty()
				&& enabled);
			deleteItem.setEnabled(!mainTableViewer.getSelection()
				.isEmpty()
				&& enabled);
		    }
		});

	configureClassSpecificViewerParts();
	Table mainTable = mainTableViewer.getTable();

	final TableColumn[] tc = new TableColumn[columns.size()];

	mainTable.setHeaderVisible(true);
	for (int i = 0; i < tc.length; i++) {
	    tc[i] = new TableColumn(mainTable, SWT.LEFT);
	    tc[i].setWidth(100);
	    tc[i].setText(columns.get(i).getPublicColumnName());
	}

	// add listeners which react on changes to the db tables
	updateListeners = new DistinctVector<DBTableChangedListener>();
	addUpdateListener();
	// remove the listeners when the containing window is closed
	parentShell.addListener(SWT.Close, new Listener() {
	    public void handleEvent(Event event) {
		for (int i = 0; i < updateListeners.size(); i++) {
		    AbstractTable.removeDBTableChangedListener(updateListeners
			    .elementAt(i));
		}
	    }
	});
	/* TODO: make list items sortable, but the db functions are not usable */
    }

    /**
     * Checks if the id of the given element is locked.
     * 
     * @param element
     *                the element to be checked for a locked id
     * @return <tt>true</tt> if the id is locked (i.e. element is edited
     *         anywhere else) and <tt>false</tt> otherwise.
     */
    private boolean hasLockedId(SimpleIDKey element) {
	switch (style) {
	case TYPE_EMPLOYEE:
	    return Client.lockedIds.contains(new Integer(element.getId()));
	case TYPE_CLIENTBOOKING_CLIENT: // like Presentation
	case TYPE_CLIENTBOOKING_PRESENTATION:
	    return ClientBooking.lockedIds
		    .contains(new Integer(element.getId()));
	case TYPE_COMPANYBOOKING_PRESENTATION: // like im Company
	case TYPE_COMPANYBOOKING_COMPANY:
	    return CompanyBooking.lockedIds.contains(new Integer(element
		    .getId()));
	case TYPE_LECTURER_CONDUCT:// like Supervisor
	case TYPE_LECTURER_INSTRUCTOR:// like Supervisor
	case TYPE_LECTURER_SUPERVISOR:
	    return Lecturer.lockedIds.contains(new Integer(element.getId()));
	case TYPE_SEMINARTYPE_CONDUCT:
	    return SeminarType.lockedIds.contains(new Integer(element.getId()));
	case TYPE_PRESENTATION_SEMTYPE:// like Supervisor
	case TYPE_PRESENTATION_INSTRUCTOR:// like Supervisor
	case TYPE_PRESENTATION_SUPERVISOR:
	    return Presentation.lockedIds
		    .contains(new Integer(element.getId()));
	}
	return true; // should not reach this point
    }

    /**
     * This method implements the functionality of the deletion button, i.e. it
     * deletes the selected elements if they're not locked. <br>
     * <br>
     * It just adds the element ids to the {@link #idsToDelete} vector and calls
     * the function {@link #deleteFromDB()}.
     */
    protected void onDelete() {
	IStructuredSelection selection = (IStructuredSelection) mainTableViewer
		.getSelection();

	// reference to the input of the table
	DistinctVector tableContent = (DistinctVector) mainTableViewer
		.getInput();
	// the selected elements as a vector
	DistinctVector<SimpleIDKey> selectedElements = new DistinctVector<SimpleIDKey>(
		(List<SimpleIDKey>) selection.toList());

	/* Dialog-Strings */
	String question = determineDeleteMessage(selectedElements);

	String hint = (selectedElements.size() > 1) ? Messages
		.getString("GUIText.DeleteErrorDialogText") : Messages
		.getString("GUIText.DeleteErrorDialogSingularText");

	MessageDialog dlg = new MessageDialog(
		MainWindow.getInstance().getShell(),
		Messages.getString("GUIText.DeleteItemMessageDialogTitle"),
		null,
		question,
		MessageDialog.QUESTION,
		new String[] {
			Messages
				.getString("GUIText.DeleteItemMessageDialogYesButtonText"),
			Messages
				.getString("GUIText.DeleteItemMessageDialogNoButtonText") },
		0);

	/* yes selected --> try to delete */
	if (dlg.open() == 0) {

	    /*
	     * if one of the selected elements is locked --> no deletion -->
	     * return
	     */
	    for (int i = 0; i < selectedElements.size(); i++) {

		if (hasLockedId(selectedElements.elementAt(i))) {
		    MessageDialog.openInformation(MainWindow.getInstance()
			    .getShell(), Messages
			    .getString("GUIText.DeleteErrorDialogTitle"), hint);
		    return;
		}
	    }

	    for (int i = 0; i < selectedElements.size(); i++) {
		// add id only if it is in the input of the table
		if ((tableContent.remove(selectedElements.elementAt(i)))) {
		    idsToDelete.add(selectedElements.elementAt(i));
		}
	    }

	    try {
		deleteFromDB();
	    } catch (SQLException e) {
		e.printStackTrace();
	    }

	    if (selectedElements.size() > 0) {
		fireItemChanged();
		mainTableViewer.refresh(); // updating the GUI
	    }
	}
	/* no selected or dialog closed --> no deleting */
    }

    /**
     * This method determines the right deletion dialog hint text against the
     * type of the association managed by this control.
     * 
     * @return String containing the right deletion dialog hint text.
     */
    private String determineDeleteMessage(
	    DistinctVector<SimpleIDKey> selectedElements) {
	String question = "";
	int numberOfElements = selectedElements.size();

	switch (style) {
	case TYPE_EMPLOYEE:
	    question = numberOfElements > 1 ? Messages
		    .getString("GUIText.DeleteClientItemsMessageDialogText")
		    : Messages
			    .getString("GUIText.DeleteClientItemMessageDialogText");
	    break;
	case TYPE_CLIENTBOOKING_CLIENT: // like Presentation
	case TYPE_CLIENTBOOKING_PRESENTATION:
	    question = numberOfElements > 1 ? Messages
		    .getString("GUIText.DeleteClientBookingItemsMessageDialogText")
		    : Messages
			    .getString("GUIText.DeleteClientBookingItemMessageDialogText");
	    break;
	case TYPE_COMPANYBOOKING_PRESENTATION: // like in the Company
	case TYPE_COMPANYBOOKING_COMPANY:
	    question = numberOfElements > 1 ? Messages
		    .getString("GUIText.DeleteCompanyBookingItemsMessageDialogText")
		    : Messages
			    .getString("GUIText.DeleteCompanyBookingItemMessageDialogText");
	    break;
	case TYPE_LECTURER_CONDUCT:// like Supervisor
	case TYPE_LECTURER_INSTRUCTOR:// like Supervisor
	case TYPE_LECTURER_SUPERVISOR:
	    question = numberOfElements > 1 ? Messages
		    .getString("GUIText.DeleteLecturerItemsMessageDialogText")
		    : Messages
			    .getString("GUIText.DeleteLecturerItemMessageDialogText");
	    break;
	case TYPE_SEMINARTYPE_CONDUCT:
	    question = numberOfElements > 1 ? Messages
		    .getString("GUIText.DeleteSeminarTypeItemsMessageDialogText")
		    : Messages
			    .getString("GUIText.DeleteSeminarTypeItemMessageDialogText");
	    break;
	case TYPE_PRESENTATION_SEMTYPE:// like Supervisor
	case TYPE_PRESENTATION_INSTRUCTOR:// like Supervisor
	case TYPE_PRESENTATION_SUPERVISOR:
	    PublicPresentation pubPres = null;
	    CompanyInternalPresentation ciPres = null;

	    for (SimpleIDKey item : selectedElements) {
		Presentation selectedItem = (Presentation) item;
		/* test if the selection is a public presentation */
		try {
		    try {
			pubPres = PublicPresentation
				.getPublicPresentation(selectedItem.getId());
		    } catch (SQLException e) {
			e.printStackTrace();
		    }
		} catch (NoSuchElementException e1) {
		    /*
		     * if the selection is no public presentation, test if it is
		     * a company internal presentation
		     */
		    try {
			try {
			    ciPres = CompanyInternalPresentation
				    .getCompanyInternalPresentation(selectedItem
					    .getId());
			} catch (SQLException e) {
			    e.printStackTrace();
			}
		    } catch (NoSuchElementException e2) {
			// both queries retrieved no result --> no such
			// Presentation
		    }
		}

	    }

	    if (pubPres != null && ciPres != null) {
		// mixed set
		question = Messages
			.getString("GUIText.DeleteMixedPresentationItemsMessageDialogText");
	    } else if (pubPres != null) {
		// only public presentations
		question = numberOfElements > 1 ? Messages
			.getString("GUIText.DeletePublicPresentationItemsMessageDialogText")
			: Messages
				.getString("GUIText.DeletePublicPresentationItemMessageDialogText");
	    } else {
		// only company internal presentation
		question = numberOfElements > 1 ? Messages
			.getString("GUIText.DeleteCompanyInternalPresentationItemsMessageDialogText")
			: Messages
				.getString("GUIText.DeleteCompanyInternalPresentationItemMessageDialogText");
	    }
	    break;
	}
	return question;
    }

    /**
     * This methode implements the functionality of the edit button, i.e. it
     * opens a window for editing the chosen data record.
     */
    protected void openEditItemWindow() {
	IStructuredSelection selection = (IStructuredSelection) mainTableViewer
		.getSelection();

	switch (style) {
	case TYPE_EMPLOYEE:
	    new ClientWindow(MainWindow.getInstance().getShell(),
		    (Client) selection.getFirstElement(), this);
	    break;
	case TYPE_CLIENTBOOKING_CLIENT: // like Presentation
	case TYPE_CLIENTBOOKING_PRESENTATION:
	    new ClientBookingWindow(MainWindow.getInstance().getShell(),
		    (ClientBooking) selection.getFirstElement(), this);
	    break;
	case TYPE_COMPANYBOOKING_PRESENTATION: // like in the Company
	case TYPE_COMPANYBOOKING_COMPANY:
	    new CompanyBookingWindow(MainWindow.getInstance().getShell(),
		    (CompanyBooking) selection.getFirstElement(), this);
	    break;
	case TYPE_LECTURER_CONDUCT:// like Supervisor
	case TYPE_LECTURER_INSTRUCTOR:// like Supervisor
	case TYPE_LECTURER_SUPERVISOR:
	    new LecturerWindow(MainWindow.getInstance().getShell(),
		    (Lecturer) selection.getFirstElement(), this);
	    break;
	case TYPE_SEMINARTYPE_CONDUCT:
	    new SeminarTypeWindow(MainWindow.getInstance().getShell(),
		    (SeminarType) selection.getFirstElement(), this);
	    break;
	case TYPE_PRESENTATION_SEMTYPE:// like Supervisor
	case TYPE_PRESENTATION_INSTRUCTOR:// like Supervisor
	case TYPE_PRESENTATION_SUPERVISOR:

	    Presentation selectedItem = (Presentation) selection
		    .getFirstElement();

	    PublicPresentation pubPres = null;
	    CompanyInternalPresentation ciPres = null;

	    /* test if the selection is a public presentation */
	    try {
		try {
		    pubPres = PublicPresentation
			    .getPublicPresentation(selectedItem.getId());
		} catch (SQLException e) {
		    e.printStackTrace();
		}

		if (pubPres != null) {
		    new PublicPresentationWindow(MainWindow.getInstance()
			    .getShell(), pubPres, this);
		}

	    } catch (NoSuchElementException e1) {
		/*
		 * if the selection is no public presentation, test if it is a
		 * company internal presentation
		 */
		try {
		    try {
			ciPres = CompanyInternalPresentation
				.getCompanyInternalPresentation(selectedItem
					.getId());
		    } catch (SQLException e) {
			e.printStackTrace();
		    }

		    if (ciPres != null) {
			new CompanyInternalPresentationWindow(MainWindow
				.getInstance().getShell(), ciPres, this);
		    }

		} catch (NoSuchElementException e2) {
		    /*
		     * both queries retrieved no result --> no such Presentation
		     */
		}
	    }
	    break;
	}
    }

    /**
     * This methode implements the functionality of the new button, i.e. it
     * opens a window for editing the chosen data record.
     */
    protected void openNewItemWindow() {

	switch (style) {
	case TYPE_EMPLOYEE:
	    new ClientWindow(MainWindow.getInstance().getShell(), null, this);
	    break;
	case TYPE_CLIENTBOOKING_CLIENT: // like Presentation
	case TYPE_CLIENTBOOKING_PRESENTATION:
	    new ClientBookingWindow(MainWindow.getInstance().getShell(), null,
		    this);
	    break;
	case TYPE_COMPANYBOOKING_PRESENTATION: // like in Company
	case TYPE_COMPANYBOOKING_COMPANY:
	    new CompanyBookingWindow(MainWindow.getInstance().getShell(), null,
		    this);
	    break;
	case TYPE_LECTURER_CONDUCT:// like Supervisor
	case TYPE_LECTURER_INSTRUCTOR:// like Supervisor
	case TYPE_LECTURER_SUPERVISOR:
	    new LecturerWindow(MainWindow.getInstance().getShell(), null, this);
	    break;
	case TYPE_SEMINARTYPE_CONDUCT:
	    new SeminarTypeWindow(MainWindow.getInstance().getShell(), null,
		    this);
	    break;
	case TYPE_PRESENTATION_SEMTYPE:// like Supervisor
	case TYPE_PRESENTATION_INSTRUCTOR:// like Supervisor
	case TYPE_PRESENTATION_SUPERVISOR:
	    // open dialog
	    MessageDialog dlg = new MessageDialog(
		    MainWindow.getInstance().getShell(),
		    Messages
			    .getString("GUIText.ChoosePresentationTypeDialogWindowTitle"),
		    null,
		    Messages
			    .getString("GUIText.ChoosePresentationTypeDialogQuestionText"),
		    MessageDialog.QUESTION,
		    new String[] {
			    Messages
				    .getString("GUIText.ChoosePresentationTypeDialogButtonPublicText"),
			    Messages
				    .getString("GUIText.ChoosePresentationTypeDialogButtonCompanyInternalText"),
			    Messages
				    .getString("GUIText.ChoosePresentationTypeDialogButtonAbortText") },
		    0);

	    switch (dlg.open()) {
	    case 0:
		new PublicPresentationWindow(MainWindow.getInstance()
			.getShell(), null, this);
		break;
	    case 1:
		new CompanyInternalPresentationWindow(MainWindow.getInstance()
			.getShell(), null, this);
		break;
	    default:
		// nothing to do
	    }
	    break;
	}
    }

    /**
     * Opens a ListWindow corresponding to the {@link #style} of the current
     * {@link AssociationTabControl} instance.
     */
    protected void openListWindow() {
	switch (style) {
	case TYPE_EMPLOYEE:
	    new ClientListWindow(this);
	    break;
	case TYPE_CLIENTBOOKING_CLIENT: // wie Presentation
	case TYPE_CLIENTBOOKING_PRESENTATION:
	    new ClientBookingListWindow(this);
	    break;
	case TYPE_COMPANYBOOKING_PRESENTATION: // wie im Company
	case TYPE_COMPANYBOOKING_COMPANY:
	    new CompanyBookingListWindow(this);
	    break;
	case TYPE_LECTURER_CONDUCT:// wie Supervisor
	case TYPE_LECTURER_INSTRUCTOR:// wie Supervisor
	case TYPE_LECTURER_SUPERVISOR:
	    new LecturerListWindow(this);
	    break;
	case TYPE_SEMINARTYPE_CONDUCT:
	    new SeminarTypeListWindow(this);
	    break;
	case TYPE_PRESENTATION_SEMTYPE:// wie Supervisor
	case TYPE_PRESENTATION_INSTRUCTOR:// wie Supervisor
	case TYPE_PRESENTATION_SUPERVISOR:
	    new PresentationListWindow(this);
	    break;
	}
    }

    /**
     * This methode implements the functionality of the disconnect button, i.e.
     * it deletes the connection between the actual data record (in the editing
     * window) and the selected one in the GUI table of this control.
     */
    protected void onDisconnect() {
	DistinctVector input = (DistinctVector) mainTableViewer.getInput();

	Object[] selectedItems = ((IStructuredSelection) mainTableViewer
		.getSelection()).toArray();

	for (int i = 0; i < selectedItems.length; i++)
	    input.remove(selectedItems[i]);

	if (selectedItems.length > 0) {
	    fireItemChanged();
	    mainTableViewer.refresh();
	}
    }

    /**
     * Sets the columns of the GUI table corresponding to type of the
     * association which actually managed by this control.
     */
    private void configureClassSpecificViewerParts() {
	switch (style) {
	case TYPE_EMPLOYEE:
	    mainTableViewer.setLabelProvider(new ClientTableProvider());
	    this.columns = Client.getColumns();
	    break;
	case TYPE_CLIENTBOOKING_CLIENT:
	case TYPE_CLIENTBOOKING_PRESENTATION:
	    mainTableViewer.setLabelProvider(new ClientBookingTableProvider());
	    this.columns = ClientBooking.getColumns();
	    break;
	case TYPE_COMPANYBOOKING_PRESENTATION: // like in CompanyWindow
	case TYPE_COMPANYBOOKING_COMPANY:
	    mainTableViewer.setLabelProvider(new CompanyBookingTableProvider());
	    this.columns = CompanyBooking.getColumns();
	    break;
	case TYPE_LECTURER_CONDUCT:// like Supervisor
	case TYPE_LECTURER_INSTRUCTOR:// like Supervisor
	case TYPE_LECTURER_SUPERVISOR:
	    mainTableViewer.setLabelProvider(new LecturerTableProvider());
	    this.columns = Lecturer.getColumns();
	    break;
	case TYPE_SEMINARTYPE_CONDUCT:
	    mainTableViewer.setLabelProvider(new SeminarTypeTableProvider());
	    this.columns = SeminarType.getColumns();
	    break;
	case TYPE_PRESENTATION_SEMTYPE:// like Supervisor
	case TYPE_PRESENTATION_INSTRUCTOR:// like Supervisor
	case TYPE_PRESENTATION_SUPERVISOR:
	    mainTableViewer.setLabelProvider(new PresentationTableProvider());
	    this.columns = Presentation.getColumns();
	    break;
	}
    }

    /**
     * Fills the GUI table with data records corresponding to type of managed
     * association and the actual data record of the editing window this control
     * is included in.
     */
    public void setInput(int referencedFK) throws SQLException {

	this.referencedFK = referencedFK;
	idsToDelete.clear();

	if (referencedFK == AbstractTable.NULL_ID) {
	    mainTableViewer.setInput(new DistinctVector<SimpleIDKey>());
	} else {
	    try {
		switch (style) {
		case TYPE_EMPLOYEE:
		    mainTableViewer.setInput(Client.getEmployees(referencedFK));
		    break;
		case TYPE_CLIENTBOOKING_CLIENT:
		    mainTableViewer.setInput(ClientBooking
			    .getBookingsOfClient(referencedFK));
		    break;
		case TYPE_CLIENTBOOKING_PRESENTATION:
		    mainTableViewer.setInput(ClientBooking
			    .getBookingsForPresentation(referencedFK));
		    break;
		case TYPE_COMPANYBOOKING_COMPANY:
		    mainTableViewer.setInput(CompanyBooking
			    .getBookingsOfCompany(referencedFK));
		    break;
		case TYPE_COMPANYBOOKING_PRESENTATION:
		    mainTableViewer.setInput(CompanyBooking
			    .getBookingsForPresentation(referencedFK));
		    break;
		case TYPE_PRESENTATION_SUPERVISOR:
		    mainTableViewer.setInput(Presentation
			    .getPresSupervisedBy(referencedFK));
		    break;
		case TYPE_PRESENTATION_INSTRUCTOR:
		    mainTableViewer.setInput(Presentation
			    .getPresInstructedBy(referencedFK));
		    break;
		case TYPE_PRESENTATION_SEMTYPE:
		    mainTableViewer.setInput(Presentation
			    .getPresForSemType(referencedFK));
		    break;
		case TYPE_SEMINARTYPE_CONDUCT:
		    mainTableViewer.setInput(SeminarType
			    .getSemTypeConductedBy(referencedFK));
		    break;
		case TYPE_LECTURER_INSTRUCTOR:
		    mainTableViewer.setInput(Lecturer
			    .getLectInstructing(referencedFK));
		    break;
		case TYPE_LECTURER_SUPERVISOR:
		    mainTableViewer.setInput(Lecturer
			    .getLectSupervising(referencedFK));
		    break;
		case TYPE_LECTURER_CONDUCT:
		    mainTableViewer.setInput(Lecturer
			    .getLectConducting(referencedFK));
		    break;
		}
	    } catch (SQLException e) {
		mainTableViewer.setInput(null);
		throw e;
	    }
	    if (mainTableViewer.getInput() == null) {
		previouslySelectedIds.clear();
	    } else {
		DistinctVector<SimpleIDKey> input = (DistinctVector<SimpleIDKey>) mainTableViewer
			.getInput();
		previouslySelectedIds = (DistinctVector<SimpleIDKey>) input
			.clone();
	    }

	}
	setEnabled(true);
    }

    /**
     * Returns the items of the GUI table.
     * 
     * @return a {@link DistinctVector} instance containing the the items of the
     *         GUI table.
     */
    public DistinctVector<SimpleIDKey> getObjects() {
	return (DistinctVector<SimpleIDKey>) mainTableViewer.getInput();
    }

    /**
     * Enables / disables the {@link #chooseItem}, the {@link #disconnectItem},
     * the {@link #editItem} and the {@link #deleteItem}.
     * 
     * @param enabled
     *                if <tt>true</tt> the buttons above will be enabled, if
     *                <tt>false</tt> they disabled.
     */
    public void setEnabled(boolean enabled) {
	this.enabled = enabled;
	chooseItem.setEnabled(enabled);
	disconnectItem.setEnabled(!mainTableViewer.getSelection().isEmpty()
		&& enabled);
	editItem.setEnabled(!mainTableViewer.getSelection().isEmpty()
		&& enabled);
	deleteItem.setEnabled(!mainTableViewer.getSelection().isEmpty()
		&& enabled);

    }

    /**
     * This method is called by the editing windows whose are created by this
     * control to update the data of this GUI table.
     * 
     * @param selectedElements
     *                the elements selected or created the editing windows
     *                spawned by this control.
     * @param checkAlreadyAssigned
     *                if <tt>true</tt> this method creates a message dialog
     *                which informs the user that the selected item is already
     *                assigned and will not be inserted again. Otherwise (<tt>false</tt>)
     *                the dialog will not appear.
     */
    public void addSelectedIds(SimpleIDKey[] selectedElements,
	    boolean checkAlreadyAssigned) {
	// getting the reference of the input of the maintableViewer
	DistinctVector input = (DistinctVector) mainTableViewer.getInput();
	boolean alreadyAssigned = false;

	/*
	 * If the seminartype of the presentation is changed it vanishes from
	 * the input of the gui table. In this case we don't want to add the
	 * presentation again into the input. But if we choose the presentation
	 * in the list window, we want to add it. So we have to distinguish
	 * between these two situations. To do so, we use the parameter
	 * checkAlreadyAssigned, which is only set to true by list windows.
	 */
	if (style == TYPE_PRESENTATION_SEMTYPE) {
	    for (int i = 0; i < selectedElements.length; i++) {
		if (input.contains(selectedElements[i])) {
		    alreadyAssigned = true;
		}

		if (checkAlreadyAssigned) {
		    input.add(selectedElements[i]);
		}
	    }
	} else {
	    for (int i = 0; i < selectedElements.length; i++) {
		if (input.contains(selectedElements[i])) {
		    alreadyAssigned = true;
		}
		input.add(selectedElements[i]);
	    }
	}

	if (selectedElements.length > 0) {
	    fireItemChanged();
	    mainTableViewer.refresh();

	    try {
		connectInDB();
	    } catch (SQLException e) {
		e.printStackTrace();
	    }
	}

	if (checkAlreadyAssigned && alreadyAssigned) {
	    MessageDialog
		    .openInformation(
			    MainWindow.getInstance().getShell(),
			    Messages
				    .getString("GUIText.AlreadyAssignedDialogWindowTitle"),
			    Messages
				    .getString("GUIText.AlreadyAssignedDialogHintText"));
	}

    }

    /**
     * Commits all changes made to the item corresponding to the given id into
     * the database using the methods listed beneath.
     * 
     * @param generatedId
     *                the id of item which was changed.
     * @throws SQLException
     *                 If the creation, manipulation, execution or closing of a
     *                 PreparedStatement instance used for querying the database
     *                 fails.
     * 
     * @see #deleteFromDB()
     * @see #disconnectInDB()
     * @see #connectInDB()
     */
    public void commitIntoDB(int generatedId) throws SQLException {
	referencedFK = generatedId;

	deleteFromDB();
	idsToDelete.clear();
	disconnectInDB();
	connectInDB();
    }

    /**
     * Disconnects all items whose ids are contained in the
     * {@link #previouslySelectedIds} Vector, but not in the input of the
     * {@link #mainTableViewer}.
     * 
     * @throws SQLException
     *                 If the creation, manipulation, execution or closing of a
     *                 PreparedStatement instance used for querying the database
     *                 fails.
     */
    private void disconnectInDB() throws SQLException {
	// DISCONNECT: all from previouslySelectedIds, which are not in the
	// table viewer input
	try {
	    Iterator it = previouslySelectedIds.iterator();
	    DistinctVector<SimpleIDKey> input = (DistinctVector<SimpleIDKey>) mainTableViewer
		    .getInput();
	    switch (style) {
	    case TYPE_EMPLOYEE:
		while (it.hasNext()) {
		    Client employee = (Client) it.next();
		    if (!input.contains(employee)) {
			employee.setEmployerId(Company.NULL_ID);
			employee.updateDB();
		    }
		}
		break;
	    case TYPE_CLIENTBOOKING_CLIENT:
		// exactly like the handling of ClientBookings in the
		// PresentationWindow
	    case TYPE_CLIENTBOOKING_PRESENTATION:
		DistinctVector<ClientBooking> clientBookings = new DistinctVector<ClientBooking>();
		while (it.hasNext()) {
		    ClientBooking booking = (ClientBooking) it.next();
		    if (!input.contains(booking))
			clientBookings.add(booking);
		}
		ClientBooking.removeFromDB(clientBookings);
		break;
	    case TYPE_COMPANYBOOKING_COMPANY:
		// exactly like the handling of CompanyBookings in the
		// PresentationWindow
	    case TYPE_COMPANYBOOKING_PRESENTATION:
		DistinctVector<CompanyBooking> companyBookings = new DistinctVector<CompanyBooking>();
		while (it.hasNext()) {
		    CompanyBooking booking = (CompanyBooking) it.next();
		    if (!input.contains(booking))
			companyBookings.add(booking);
		}
		CompanyBooking.removeFromDB(companyBookings);
		break;
	    case TYPE_PRESENTATION_SUPERVISOR:
		while (it.hasNext()) {
		    Presentation presentation = (Presentation) it.next();
		    if (!input.contains(presentation)) {
			Supervisor supervisor = new Supervisor(referencedFK,
				presentation.getId(), new Timestamp(System
					.currentTimeMillis()), new Timestamp(
					System.currentTimeMillis()));
			supervisor.deleteFromDB();
		    }
		}
		break;
	    case TYPE_PRESENTATION_INSTRUCTOR:
		while (it.hasNext()) {
		    Presentation presentation = (Presentation) it.next();
		    if (!input.contains(presentation)) {
			Instructor instructor = new Instructor(referencedFK,
				presentation.getId(), new Timestamp(System
					.currentTimeMillis()), new Timestamp(
					System.currentTimeMillis()));
			instructor.deleteFromDB();
		    }
		}
		break;
	    case TYPE_PRESENTATION_SEMTYPE:
		DistinctVector<Presentation> presentations = new DistinctVector<Presentation>();
		while (it.hasNext()) {
		    Presentation presentation = (Presentation) it.next();
		    if (!input.contains(presentation)) {
			presentations.add(presentation);
		    }
		}
		Presentation.removeFromDB(presentations);
		break;
	    case TYPE_SEMINARTYPE_CONDUCT:
		while (it.hasNext()) {
		    SeminarType semType = (SeminarType) it.next();
		    if (!input.contains(semType)) {
			Conduct conduct = new Conduct(referencedFK, semType
				.getId(), new Timestamp(System
				.currentTimeMillis()), new Timestamp(System
				.currentTimeMillis()));
			conduct.deleteFromDB();
		    }
		}
		break;
	    case TYPE_LECTURER_INSTRUCTOR:
		while (it.hasNext()) {
		    Lecturer lecturer = (Lecturer) it.next();
		    if (!input.contains(lecturer)) {
			Instructor instructor = new Instructor(
				lecturer.getId(), referencedFK, new Timestamp(
					System.currentTimeMillis()),
				new Timestamp(System.currentTimeMillis()));
			instructor.deleteFromDB();
		    }
		}
		break;
	    case TYPE_LECTURER_SUPERVISOR:
		while (it.hasNext()) {
		    Lecturer lecturer = (Lecturer) it.next();
		    if (!input.contains(lecturer)) {
			Supervisor supervisor = new Supervisor(
				lecturer.getId(), referencedFK, new Timestamp(
					System.currentTimeMillis()),
				new Timestamp(System.currentTimeMillis()));
			supervisor.deleteFromDB();
		    }
		}
		break;
	    case TYPE_LECTURER_CONDUCT:
		while (it.hasNext()) {
		    Lecturer lecturer = (Lecturer) it.next();
		    if (!input.contains(lecturer)) {
			Conduct conduct = new Conduct(lecturer.getId(),
				referencedFK, new Timestamp(System
					.currentTimeMillis()), new Timestamp(
					System.currentTimeMillis()));
			conduct.deleteFromDB();
		    }
		}
	    }
	} catch (Exception e) {
	}

    }

    /**
     * Connects all items whose ids are contained in the
     * {@link #previouslySelectedIds} Vector, but not in the input of the
     * {@link #mainTableViewer}.
     * 
     * @throws SQLException
     *                 If the creation, manipulation, execution or closing of a
     *                 PreparedStatement instance used for querying the database
     *                 fails.
     */
    private void connectInDB() throws SQLException {
	// CONNECT: all in the TableViewer input, which are not contained in
	// previouslySelectedIds
	Iterator<SimpleIDKey> it = ((DistinctVector<SimpleIDKey>) mainTableViewer
		.getInput()).iterator();

	while (it.hasNext()) {
	    SimpleIDKey element = it.next();
	    if (!previouslySelectedIds.contains(element)) {
		switch (style) {
		case TYPE_EMPLOYEE:
		    Client employee = (Client) element;
		    employee.setEmployerId(referencedFK);
		    employee.updateDB();
		    break;
		case TYPE_CLIENTBOOKING_CLIENT:
		    ClientBooking booking = (ClientBooking) element;
		    booking.setClientId(referencedFK);
		    booking.updateDB();
		    break;
		case TYPE_CLIENTBOOKING_PRESENTATION:
		    ClientBooking booking2 = (ClientBooking) element;
		    booking2.setPresentationId(referencedFK);
		    booking2.updateDB();
		    break;
		case TYPE_COMPANYBOOKING_COMPANY:
		    CompanyBooking booking3 = (CompanyBooking) element;
		    booking3.setCompanyId(referencedFK);
		    booking3.updateDB();
		    break;
		case TYPE_COMPANYBOOKING_PRESENTATION:
		    CompanyBooking booking4 = (CompanyBooking) element;
		    booking4.setPresentationId(referencedFK);
		    booking4.updateDB();
		    break;
		case TYPE_PRESENTATION_SUPERVISOR:
		    Supervisor supervisor = new Supervisor(referencedFK,
			    element.getId(), new Timestamp(System
				    .currentTimeMillis()), new Timestamp(System
				    .currentTimeMillis()));
		    try {
			supervisor.insertIntoDB();
		    } catch (SQLException e) {
			// ignore, possibly double entry
		    }
		    break;
		case TYPE_PRESENTATION_INSTRUCTOR:
		    Instructor instructor = new Instructor(referencedFK,
			    element.getId(), new Timestamp(System
				    .currentTimeMillis()), new Timestamp(System
				    .currentTimeMillis()));
		    try {
			instructor.insertIntoDB();
		    } catch (SQLException e) {
			// ignore, possibly double entry
		    }
		    break;
		case TYPE_PRESENTATION_SEMTYPE:
		    Presentation presentation = (Presentation) element;
		    presentation.setSeminarTypeId(referencedFK);
		    presentation.updateDB();
		    break;
		case TYPE_SEMINARTYPE_CONDUCT:
		    Conduct conduct = new Conduct(referencedFK,
			    element.getId(), new Timestamp(System
				    .currentTimeMillis()), new Timestamp(System
				    .currentTimeMillis()));
		    try {
			conduct.insertIntoDB();
		    } catch (SQLException e) {
			// ignore, possibly double entry
		    }
		    break;
		case TYPE_LECTURER_INSTRUCTOR:
		    Instructor instructor2 = new Instructor(element.getId(),
			    referencedFK, new Timestamp(System
				    .currentTimeMillis()), new Timestamp(System
				    .currentTimeMillis()));
		    try {
			instructor2.insertIntoDB();
		    } catch (SQLException e) {
			// ignore, possibly double entry
		    }
		    break;
		case TYPE_LECTURER_SUPERVISOR:
		    Supervisor supervisor2 = new Supervisor(element.getId(),
			    referencedFK, new Timestamp(System
				    .currentTimeMillis()), new Timestamp(System
				    .currentTimeMillis()));
		    try {
			supervisor2.insertIntoDB();
		    } catch (SQLException e) {
			// ignore, possibly double entry
		    }
		    break;
		case TYPE_LECTURER_CONDUCT:
		    Conduct conduct2 = new Conduct(element.getId(),
			    referencedFK, new Timestamp(System
				    .currentTimeMillis()), new Timestamp(System
				    .currentTimeMillis()));
		    try {
			conduct2.insertIntoDB();
		    } catch (SQLException e) {
			// ignore, possibly double entry
		    }
		    break;
		}
	    }
	}

    }

    /**
     * Deletes all item whose ids are contained in the {@link #idsToDelete}
     * Vector.
     * 
     * @throws SQLException
     *                 If the creation, manipulation, execution or closing of a
     *                 PreparedStatement instance used for querying the database
     *                 fails.
     */
    private void deleteFromDB() throws SQLException {
	// DELETE: all from idsToDelete

	if (!idsToDelete.isEmpty()) {

	    switch (style) {
	    case TYPE_EMPLOYEE:
		Client.removeFromDB(idsToDelete);
		break;
	    case TYPE_CLIENTBOOKING_CLIENT:
	    case TYPE_CLIENTBOOKING_PRESENTATION:
		ClientBooking.removeFromDB(idsToDelete);
		break;
	    case TYPE_COMPANYBOOKING_PRESENTATION: // like in the CompanyWindow
	    case TYPE_COMPANYBOOKING_COMPANY:
		CompanyBooking.removeFromDB(idsToDelete);
		break;
	    case TYPE_LECTURER_CONDUCT:// like Supervisor
	    case TYPE_LECTURER_INSTRUCTOR:// like Supervisor
	    case TYPE_LECTURER_SUPERVISOR:
		Lecturer.removeFromDB(idsToDelete);
		break;
	    case TYPE_SEMINARTYPE_CONDUCT:
		SeminarType.removeFromDB(idsToDelete);
		break;
	    case TYPE_PRESENTATION_SEMTYPE:// like Supervisor
	    case TYPE_PRESENTATION_INSTRUCTOR:// like Supervisor
	    case TYPE_PRESENTATION_SUPERVISOR:
		Presentation.removeFromDB(idsToDelete);
		break;
	    }

	}

    }

    /**
     * Sets a pair of key and value to this control needed for testing with
     * ATOSj.
     * 
     * @param key
     *                the key (type) of the value set
     * @param value
     *                the value set to the control
     */
    public void setData(String key, String value) {
	super.setData(key, value);
	if (key.equals(Utility.ATOSJ_COMPONENT_NAME_KEY)) {
	    mainTableViewer.getTable().setData(key, value + "_Table");
	    disconnectItem.setData(key, value + "_DisconnectItem");
	    deleteItem.setData(key, value + "_DeleteItem");
	    configureItem.setData(key, value + "_ConfigureItem");
	    chooseItem.setData(key, value + "_ChooseItem");
	    editItem.setData(key, value + "_EditItem");
	    newItem.setData(key, value + "_NewItem");
	}
    }

    /** Adds a listener to {@link #itemListeners}. */
    public void addItemListener(ItemListener listener) {
	itemListeners.add(listener);
    }

    /** Removes a listener from {@link #itemListeners}. */
    public void removeItemListener(ItemListener listener) {
	itemListeners.remove(listener);
    }

    /** Fires all listners in {@link #itemListeners}. */
    private void fireItemChanged() {
	for (Iterator<ItemListener> iter = itemListeners.iterator(); iter
		.hasNext();) {
	    ItemListener listener = iter.next();
	    listener.itemChanged();
	}
    }

    /**
     * Adds listener to the {@link #updateListeners} vector. The type of the
     * listener is determined by the type of the association managed by this
     * control.
     */
    private void addUpdateListener() {
	switch (style) {
	case TYPE_EMPLOYEE:
	    updateListeners.add(new DBTableChangedListener(
		    DBTableChangedListener.TYPE_CLIENT) {
		public void dBTableChanged() {
		    update();
		}
	    });
	    break;
	case TYPE_CLIENTBOOKING_CLIENT:
	case TYPE_CLIENTBOOKING_PRESENTATION:
	    updateListeners.add(new DBTableChangedListener(
		    DBTableChangedListener.TYPE_CLIENTBOOKING) {
		public void dBTableChanged() {
		    update();
		}
	    });
	    break;
	case TYPE_COMPANYBOOKING_PRESENTATION: // like in the CompanyWindow
	case TYPE_COMPANYBOOKING_COMPANY:
	    updateListeners.add(new DBTableChangedListener(
		    DBTableChangedListener.TYPE_COMPANYBOOKING) {
		public void dBTableChanged() {
		    update();
		}
	    });
	    break;
	case TYPE_LECTURER_CONDUCT:// like Supervisor
	case TYPE_LECTURER_INSTRUCTOR:// like Supervisor
	case TYPE_LECTURER_SUPERVISOR:
	    updateListeners.add(new DBTableChangedListener(
		    DBTableChangedListener.TYPE_LECTURER) {
		public void dBTableChanged() {
		    update();
		}
	    });
	    break;
	case TYPE_SEMINARTYPE_CONDUCT:
	    updateListeners.add(new DBTableChangedListener(
		    DBTableChangedListener.TYPE_SEMINARTYPE) {
		public void dBTableChanged() {
		    update();
		}
	    });
	    break;
	case TYPE_PRESENTATION_SEMTYPE:// like Supervisor
	case TYPE_PRESENTATION_INSTRUCTOR:// like Supervisor
	case TYPE_PRESENTATION_SUPERVISOR:
	    updateListeners.add(new DBTableChangedListener(
		    DBTableChangedListener.TYPE_PRESENTATION) {
		public void dBTableChanged() {
		    update();
		}
	    });
	    break;
	}

	AbstractTable.addDBTableChangedListener(updateListeners.lastElement());
    }

    /**
     * Updates the GUI table with the actual records from a database query. <br>
     * <br>
     * For example if the rows of the GUI table are sorted by a column or a
     * record has been deleted.
     */
    public void update() {
	try {
	    setInput(referencedFK);
	} catch (SQLException e) {
	    e.printStackTrace();
	}

    }
}
