package semorg.sql.tables;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import semorg.gui.util.DBTableChangedListener;
import semorg.gui.util.Messages;
import semorg.sql.access.DBAccess;
import semorg.sql.util.DBColumn;
import semorg.sql.util.DBConstraint;
import semorg.sql.util.DistinctVector;
import semorg.sql.util.Utility;

/**
 * The super class for all presentation classes. It encapsulates all common
 * properties and methods of this classes.
 */
public class Presentation extends AbstractTable implements SimpleIDKey {

    /**
     * A list of the ids of locked records. This list is meant to avoid the
     * deletion or changing of records, which are currently edited.
     */
    public static List<Integer> lockedIds = new ArrayList<Integer>();

    /** The DB-ID. */
    protected int id;

    // TODO: maxEntrants ???

    /** The id of the corresponding seminartype. Has to be not null. */
    protected int seminarTypeId; // NOT NULL

    /** The duration of the presentation. */
    protected Integer duration;

    /** The day when the presentation begins. */
    protected Date beginningDay;

    /** The last day of the presentation. */
    protected Date endingDay;

    /** The time when the presentation begins. */
    protected Time startingTime;

    /** The time when the presentation ends. */
    protected Time endingTime;

    /** The time when the presentation starts at the beginning day. */
    protected Time firstStartingTime;

    /** The time when the presentation ends at the ending day. */
    protected Time lastEndingTime;

    /** The location of the presentation (such as the room). */
    protected String location;

    /** The street. */
    protected String street;

    /** The zip code. */
    protected String zipCode;

    /** The city. */
    protected String city;

    /** The country. */
    protected String country;

    /** The annex. */
    protected String annex;

    /**
     * <tt>true</tt> if the presentation is canceled, <tt>false</tt>
     * otherwise.
     */
    protected boolean cancelled;

    /** The name of the corresponding table in the db. */
    private static String tableName = "presentation";

    /** SQL query to get all presentations supervised by a certain lecturer. */
    private static String superviseQueryString = "SELECT pr.id_pk, pr.seminartype_fk, "
	    + "pr.duration, pr.beginningday, pr.endingday, pr.startingtime, pr.endingtime, "
	    + "pr.firststartingtime, pr.lastendingtime, pr.location, pr.street, pr.zipcode, "
	    + "pr.city, pr.country, pr.annex, pr.cancelled, "
	    + "pr.creationdate, pr.modificationdate FROM presentation pr, supervisor s "
	    + "WHERE pr.id_pk=s.presentationid AND s.lecturerid=?";

    /**
     * SQL query to get all presentations which are instructed by certain
     * lecturer.
     */
    private static String instructQueryString = "SELECT pr.id_pk, pr.seminartype_fk, "
	    + "pr.duration, pr.beginningday, pr.endingday, pr.startingtime, pr.endingtime, "
	    + "pr.firststartingtime, pr.lastendingtime, pr.location, pr.street, pr.zipcode, "
	    + "pr.city, pr.country, pr.annex, pr.cancelled, "
	    + "pr.creationdate, pr.modificationdate FROM presentation pr, instructor i "
	    + "WHERE pr.id_pk=i.presentationid AND i.lecturerid=?";

    /** SQL query to get all presentations of a certain seminartype. */
    private static String presentationQueryString = "SELECT pr.id_pk, pr.seminartype_fk, "
	    + "pr.duration, pr.beginningday, pr.endingday, pr.startingtime, pr.endingtime, "
	    + "pr.firststartingtime, pr.lastendingtime, pr.location, pr.street, pr.zipcode, "
	    + "pr.city, pr.country, pr.annex, pr.cancelled, "
	    + "pr.creationdate, pr.modificationdate FROM presentation pr, seminartype s "
	    + "WHERE pr.seminartype_fk=? AND s.id_pk=pr.seminartype_fk";

    /** SQL query to get all presentation records from the database. */
    private static String queryString = "SELECT pr.id_pk, pr.seminartype_fk, "
	    + "pr.duration, pr.beginningday, pr.endingday, pr.startingtime, pr.endingtime, "
	    + "pr.firststartingtime, pr.lastendingtime, pr.location, pr.street, pr.zipcode, "
	    + "pr.city, pr.country, pr.annex, pr.cancelled, "
	    + "pr.creationdate, pr.modificationdate FROM presentation pr "
	    + "WHERE true";

    /** SQL query to insert a presentation record. */
    protected static String presentationInsertString = "INSERT INTO "
	    + tableName + " VALUES(?, ?, ?, ?, ?, "
	    + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

    /** SQL statement for creating the table "presentation" (if not exists). */
    private static String createTableSQLString = "CREATE TABLE IF NOT EXISTS `"
	    + tableName
	    + "` ("
	    + "`id_pk` integer NOT NULL auto_increment,"
	    + "`seminartype_fk` integer NOT NULL,"
	    + "`duration` integer,"
	    + "`beginningday` date,"
	    + "`endingday` date,"
	    + "`startingtime` time,"
	    + "`endingtime` time,"
	    + "`firststartingtime` time,"
	    + "`lastendingtime` time,"
	    + "`location` varchar(50),"
	    + "`street` varchar(50),"
	    + "`zipcode` varchar(5),"
	    + "`city` varchar(30),"
	    + "`country` varchar(13),"
	    + "`annex` varchar(13),"
	    + "`cancelled` boolean,"
	    + "`creationdate` timestamp NOT NULL default '0000-00-00 00:00:00',"
	    + "`modificationdate` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,"
	    + "PRIMARY KEY  (`id_pk`),"
	    + "CONSTRAINT `presentation_fk` FOREIGN KEY (`seminartype_fk`) REFERENCES `seminartype` (`id_pk`) ON DELETE CASCADE)";

    /** SQL query to update a presentation record. */
    protected static String presentationUpdateString = "UPDATE "
	    + tableName
	    + " SET seminartype_fk=?, duration=?, beginningday=?, endingday=?, startingtime=?, endingtime=?, "
	    + "firststartingtime=?, lastendingtime=?, location=?, street=?, zipCode=?, city=?, country=?, annex=?, cancelled=?, "
	    + "modificationdate=? WHERE id_pk=?";

    /**
     * Initializes the common properties of all presentations with the given
     * parameters.
     */
    protected Presentation(int id, int seminarTypeId, Integer duration,
	    Date beginningDay, Date endingDay, Time startingTime,
	    Time endingTime, Time firstStartingTime, Time lastEndingTime,
	    String location, String street, String zipCode, String city,
	    String country, String annex, boolean cancelled,
	    Timestamp creationDate, Timestamp modificationDate)
	    throws SQLException {

	super(creationDate, modificationDate);

	this.id = id;
	this.seminarTypeId = seminarTypeId;
	this.duration = duration;
	this.beginningDay = beginningDay;
	this.endingDay = endingDay;
	this.startingTime = startingTime;
	this.endingTime = endingTime;
	this.firstStartingTime = firstStartingTime;
	this.lastEndingTime = lastEndingTime;
	this.location = location;
	this.street = street;
	this.zipCode = zipCode;
	this.city = city;
	this.country = country;
	this.annex = annex;
	this.cancelled = cancelled;

	this.creationDate = creationDate;
	this.modificationDate = modificationDate;
    }

    /**
     * Returns the shortened title of the seminartype corresponding to the
     * current {@link Presentation} object.
     * 
     * @return shortened title of the seminartype of this presentation.
     */
    public String getSeminarTypeDescription() {
	Vector<DBConstraint> keyConstraint = new Vector<DBConstraint>();
	keyConstraint.add(new DBConstraint(SeminarType.getColumns().get(0)
		.getInternalColumnName(), DBConstraint.REL_EQ, new Integer(
		seminarTypeId), DBConstraint.CONJ_END));
	DistinctVector<SeminarType> semTypes;
	try {
	    semTypes = SeminarType.getVectorFromDB(keyConstraint, null);
	} catch (SQLException e) {
	    return "";
	}
	if (semTypes.size() > 0)
	    return semTypes.iterator().next().getShortTitle();
	else
	    return "";

    }

    /**
     * Checks if the according DB table exists.
     * 
     * @see semorg.sql.tables.AbstractTable#tableOK(String)
     * @return <code>true</code>, if the table is ok, <code>false</code>
     *         otherwise.
     */
    public static boolean tableOK() {
	return AbstractTable.tableOK(tableName);
    }

    /**
     * Creates the table "presentation" if it does not exist.
     * 
     * @param statement
     *                instance of the class Statement, which is used for
     *                executing the SQL statement {@link #createTableSQLString}.
     * @throws SQLException
     *                 If the execution of the given statement with the query
     *                 {@link #createTableSQLString} or its closing fails.
     */
    public static void createPresentationTable(Statement statement)
	    throws SQLException {
	statement.execute(createTableSQLString);
	statement.close();
    }

    /**
     * Converts the actual Presentation object into a database record and
     * inserts it into the table presentation. Furthermore this method queries
     * the auto-generated id, sets the appropriate property {@link #id} and
     * returns the id. If a country or annex has been inserted into the form,
     * this method also inserts the concerning properties into the table
     * "enumeration" for later use. Finally it fires a
     * TableChanged-EventListener to update the UI.
     * 
     * @return the auto-generated id of the inserted tupel.
     * @throws SQLException
     *                 If the auto-generated id can't resolved from the db, i.e.
     *                 it hasn't been generated, or the PreparedStatement
     *                 instance can't be created or executed etc.
     */
    public int insertIntoDB() throws SQLException {
	PreparedStatement insertStmt = DBAccess.dbAccess
		.getPreparedStatement(Presentation.presentationInsertString);

	// PK MIT AUTO_INCREMENT
	insertStmt.setNull(1, Types.INTEGER);
	// NOT NULL
	insertStmt.setInt(2, seminarTypeId);

	if (duration != null)
	    insertStmt.setInt(3, duration);
	else
	    insertStmt.setNull(3, Types.INTEGER);

	if (beginningDay != null)
	    insertStmt.setDate(4, Utility.convertToSQLDate(beginningDay));
	else
	    insertStmt.setNull(4, Types.DATE);

	if (endingDay != null)
	    insertStmt.setDate(5, Utility.convertToSQLDate(endingDay));
	else
	    insertStmt.setNull(5, Types.DATE);

	if (startingTime != null)
	    insertStmt.setTime(6, startingTime);
	else
	    insertStmt.setNull(6, Types.TIME);

	if (endingTime != null)
	    insertStmt.setTime(7, endingTime);
	else
	    insertStmt.setNull(7, Types.TIME);

	if (firstStartingTime != null)
	    insertStmt.setTime(8, firstStartingTime);
	else
	    insertStmt.setNull(8, Types.TIME);

	if (lastEndingTime != null)
	    insertStmt.setTime(9, lastEndingTime);
	else
	    insertStmt.setNull(9, Types.TIME);

	insertStmt.setString(10, location);
	insertStmt.setString(11, street);
	insertStmt.setString(12, zipCode);
	insertStmt.setString(13, city);
	insertStmt.setString(14, country);
	insertStmt.setString(15, annex);
	insertStmt.setBoolean(16, cancelled);

	insertStmt.setTimestamp(17, Utility.convertToTimestamp(creationDate));
	insertStmt.setTimestamp(18, Utility
		.convertToTimestamp(modificationDate));

	insertStmt.executeUpdate();

	ResultSet rs = insertStmt.getGeneratedKeys();
	if (rs.next()) {
	    this.id = rs.getInt(1);
	} else {
	    // TODO: throw correct exceptions
	    throw new SQLException();
	}

	rs.close();
	insertStmt.close();

	if (country.length() > 0)
	    Enumeration.insertcountryStringInDB(country);
	if (annex.length() > 0)
	    Enumeration.insertAnnexStringInDB(annex);

	AbstractTable
		.fireTableChangedEvent(DBTableChangedListener.TYPE_PRESENTATION);

	return this.id;

    }

    /**
     * Converts the actual {@link Presentation} object into a database record
     * and updates a existing record to the changes made. If a country or annex
     * has been inserted into the form, this method also inserts the concerning
     * properties into the table "enumeration" for later use. Finally it fires a
     * TableChanged-EventListener to update the UI.
     * 
     * @throws SQLException
     *                 If the PreparedStatement instance can't be created or
     *                 executed, this exception is thrown.
     */
    public void updateDB() throws SQLException {
	PreparedStatement updateStmt = DBAccess.dbAccess
		.getPreparedStatement(presentationUpdateString);

	updateStmt.setInt(1, seminarTypeId);

	if (duration != null)
	    updateStmt.setInt(2, duration);
	else
	    updateStmt.setNull(2, Types.INTEGER);

	if (beginningDay != null)
	    updateStmt.setDate(3, Utility.convertToSQLDate(beginningDay));
	else
	    updateStmt.setNull(3, Types.DATE);

	if (endingDay != null)
	    updateStmt.setDate(4, Utility.convertToSQLDate(endingDay));
	else
	    updateStmt.setNull(4, Types.DATE);

	if (startingTime != null)
	    updateStmt.setTime(5, startingTime);
	else
	    updateStmt.setNull(5, Types.TIME);

	if (endingTime != null)
	    updateStmt.setTime(6, endingTime);
	else
	    updateStmt.setNull(6, Types.TIME);

	if (firstStartingTime != null)
	    updateStmt.setTime(7, firstStartingTime);
	else
	    updateStmt.setNull(7, Types.TIME);

	if (lastEndingTime != null)
	    updateStmt.setTime(8, lastEndingTime);
	else
	    updateStmt.setNull(8, Types.TIME);

	updateStmt.setString(9, location);
	updateStmt.setString(10, street);
	updateStmt.setString(11, zipCode);
	updateStmt.setString(12, city);
	updateStmt.setString(13, country);
	updateStmt.setString(14, annex);
	updateStmt.setBoolean(15, cancelled);

	updateStmt.setTimestamp(16, new Timestamp(System.currentTimeMillis()));

	// WHERE - part
	updateStmt.setInt(17, id);

	updateStmt.executeUpdate();

	updateStmt.close();

	if (country.length() > 0)
	    Enumeration.insertcountryStringInDB(country);
	if (annex.length() > 0)
	    Enumeration.insertAnnexStringInDB(annex);

	AbstractTable
		.fireTableChangedEvent(DBTableChangedListener.TYPE_PRESENTATION);
    }

    /**
     * Removes the given elements from the table "presentation".
     * <p>
     * <i>Hint:</i> The given elements should be ONLY deleted from the table
     * "presentation", i.e. NOT in the extending classes/tables, because the
     * rest is done by the dbms in order to fulfill a FK-constraint with an
     * ON-DELETE-cascade.
     * </p>
     * Due to the FK connections (with an ON-DELETE-cascade) this method fires
     * several TableChanged-Events to update the UI.
     * 
     * @param selectedElements
     *                the elements, which should be deleted from the database.
     * @throws SQLException
     *                 Throws a SQL exception if the Statement instance can't be
     *                 created or executed.
     */
    public static void removeFromDB(Iterable selectedElements)
	    throws SQLException {
	// delete only in table person (also in subclasses),
	// because we use Foreign Key with ON DELETE CASCADE

	String deleteString = "DELETE FROM " + tableName + " WHERE ";
	Iterator<Presentation> it = selectedElements.iterator();

	// add first element
	int idToDelete = it.next().getId();
	deleteString += "id_pk=" + idToDelete + " ";

	// add the remaining elements
	while (it.hasNext()) {
	    idToDelete = it.next().getId();
	    deleteString += "OR id_pk=" + idToDelete + " ";
	}
	Statement stmt = DBAccess.dbAccess.getStatement();
	stmt.executeUpdate(deleteString);
	stmt.close();

	AbstractTable
		.fireTableChangedEvent(DBTableChangedListener.TYPE_PRESENTATION);
	// because of FK-association (on delete cascade)
	AbstractTable
		.fireTableChangedEvent(DBTableChangedListener.TYPE_PUBLICPRESENTATION);
	AbstractTable
		.fireTableChangedEvent(DBTableChangedListener.TYPE_COMPANYINTERNALPRESENTATION);
	AbstractTable
		.fireTableChangedEvent(DBTableChangedListener.TYPE_COMPANYBOOKING);
	AbstractTable
		.fireTableChangedEvent(DBTableChangedListener.TYPE_CLIENTBOOKING);

    }

    /**
     * Returns a vector of {@link semorg.sql.util.DBColumn} instances according to
     * the properties of the table "presentation". Note that this function maps
     * the names of the database columns to the names of the GUI tables.
     * 
     * @return the vector of DBColumn instances.
     * @see semorg.sql.tables.AbstractTable#getColumns(String tableAbbreviation)
     */
    public static Vector<DBColumn> getColumns() {
	Vector<DBColumn> columns = new Vector<DBColumn>();
	columns.add(new DBColumn("pr.id_pk", Messages
		.getString("MAP.Presentation.IdPK"), Integer.class));
	columns.add(new DBColumn("pr.seminartype_fk", Messages
		.getString("MAP.Presentation.SeminarTypeFK"), Integer.class));
	columns.add(new DBColumn("pr.duration", Messages
		.getString("MAP.Presentation.Duration"), Integer.class));
	columns.add(new DBColumn("pr.beginningday", Messages
		.getString("MAP.Presentation.BeginningDay"), Date.class));
	columns.add(new DBColumn("pr.endingday", Messages
		.getString("MAP.Presentation.EndingDay"), Date.class));
	columns.add(new DBColumn("pr.startingtime", Messages
		.getString("MAP.Presentation.StartingTime"), Time.class));
	columns.add(new DBColumn("pr.endingtime", Messages
		.getString("MAP.Presentation.EndingTime"), Time.class));
	columns.add(new DBColumn("pr.firststartingtime", Messages
		.getString("MAP.Presentation.FirstStartingTime"), Time.class));
	columns.add(new DBColumn("pr.lastendingtime", Messages
		.getString("MAP.Presentation.LastEndingTime"), Time.class));
	columns.add(new DBColumn("pr.location", Messages
		.getString("MAP.Presentation.Location"), String.class));
	columns.add(new DBColumn("pr.street", Messages
		.getString("MAP.Presentation.Street"), String.class));
	columns.add(new DBColumn("pr.street", Messages
		.getString("MAP.Presentation.ZipCode"), String.class));
	columns.add(new DBColumn("pr.zipcode", Messages
		.getString("MAP.Presentation.City"), String.class));
	columns.add(new DBColumn("pr.country", Messages
		.getString("MAP.Presentation.Country"), String.class));
	columns.add(new DBColumn("pr.annex", Messages
		.getString("MAP.Presentation.Annex"), String.class));
	columns.add(new DBColumn("pr.cancelled", Messages
		.getString("MAP.Presentation.Cancelled"), Boolean.class));
	columns.addAll(AbstractTable.getColumns("pr."));
	return columns;

    }

    /**
     * Creates for each element in a given ResultSet instance an instance of
     * this class and returns a vector with the resulting class objects.
     * 
     * @param resultSet
     *                given ResultSet instance.
     * @return a DistinctVector instance filled with the created
     *         {@link Presentation} instances.
     */
    private static DistinctVector<Presentation> getVector(ResultSet resultSet) {
	DistinctVector<Presentation> set = new DistinctVector<Presentation>();
	try {
	    while (resultSet.next()) {
		int id = resultSet.getInt("id_pk");
		int seminarTypeId = resultSet.getInt("seminartype_fk");
		Integer duration = resultSet.getInt("duration");
		if (resultSet.wasNull())
		    duration = null;
		Date beginningDay = resultSet.getDate("beginningday");
		Date endingDay = resultSet.getDate("endingday");
		Time startingTime = resultSet.getTime("startingtime");
		Time endingTime = resultSet.getTime("endingtime");
		Time firstStartingTime = resultSet.getTime("firststartingtime");
		Time lastEndingTime = resultSet.getTime("lastendingtime");
		String location = resultSet.getString("location");
		String street = resultSet.getString("street");
		String zipCode = resultSet.getString("zipcode");
		String city = resultSet.getString("city");
		String country = resultSet.getString("country");
		String annex = resultSet.getString("annex");
		boolean cancelled = resultSet.getBoolean("cancelled");
		Timestamp creationDate = resultSet.getTimestamp("creationdate");
		Timestamp modificationDate = resultSet
			.getTimestamp("modificationdate");

		set.add(new Presentation(id, seminarTypeId, duration,
			beginningDay, endingDay, startingTime, endingTime,
			firstStartingTime, lastEndingTime, location, street,
			zipCode, city, country, annex, cancelled, creationDate,
			modificationDate));
	    }
	} catch (SQLException e) {
	    e.printStackTrace();
	}
	return set;
    }

    /**
     * Returns all presentations which are supervised by a lecturer
     * corresponding to the given id.
     * 
     * @param lecturerId
     *                id of the supervising lecturer
     * @return {@link DistinctVector} instance filled with all presentations
     *         which are supervised by the given lecturer.
     * @throws SQLException
     *                 Throws a SQL exception if the Statement instance can't be
     *                 created or executed.
     */
    public static DistinctVector<Presentation> getPresSupervisedBy(
	    int lecturerId) throws SQLException {

	PreparedStatement stmt = DBAccess.dbAccess
		.getPreparedStatement(superviseQueryString);

	stmt.setInt(1, lecturerId);

	ResultSet rs = stmt.executeQuery();
	DistinctVector<Presentation> returnValue = Presentation.getVector(rs);
	rs.close();
	stmt.close();
	return returnValue;
    }

    /**
     * Returns all presentations which are instructed by a lecturer
     * corresponding to the given id.
     * 
     * @param lecturerId
     *                id of the instructing lecturer
     * @return {@link DistinctVector} instance filled with all presentations
     *         which are instructed by the given lecturer.
     * @throws SQLException
     *                 Throws a SQL exception if the Statement instance can't be
     *                 created or executed.
     */
    public static DistinctVector<Presentation> getPresInstructedBy(
	    int lecturerId) throws SQLException {

	PreparedStatement stmt = DBAccess.dbAccess
		.getPreparedStatement(instructQueryString);

	stmt.setInt(1, lecturerId);

	ResultSet rs = stmt.executeQuery();
	DistinctVector<Presentation> returnValue = Presentation.getVector(rs);
	rs.close();
	stmt.close();
	return returnValue;
    }

    /**
     * Returns all presentations which possess the given seminartype.
     * 
     * @param semTypeId
     *                id of the seminartype
     * @return {@link DistinctVector} instance filled with all presentations
     *         which possess the given seminartype.
     * @throws SQLException
     *                 Throws a SQL exception if the Statement instance can't be
     *                 created or executed.
     */
    public static DistinctVector<Presentation> getPresForSemType(int semTypeId)
	    throws SQLException {
	PreparedStatement stmt = DBAccess.dbAccess
		.getPreparedStatement(presentationQueryString);

	stmt.setInt(1, semTypeId);

	ResultSet rs = stmt.executeQuery();
	DistinctVector<Presentation> returnValue = Presentation.getVector(rs);
	rs.close();
	stmt.close();
	return returnValue;
    }

    /**
     * Creates a PreparedStatement instance with the given parameters, executes
     * the query and returns a vector of Presentation instances corresponding to
     * the ResultSet of the query.
     * 
     * @param additionalConstraints
     *                additional conditions of the WHERE-clause
     * @param sortString
     *                sort string with the following structure
     *                <code>ORDER BY attribute [ASC|DSC]</code>
     * @return a DistinctVector instance filled with the created Lecturer
     *         instances.
     * @throws SQLException
     *                 If the PreparedStatement can't be created or the
     *                 execution of the query fails this exception is thrown.
     */
    public static DistinctVector<Presentation> getPresentationVectorFromDB(
	    Vector<DBConstraint> additionalConstraints, String sortString)
	    throws SQLException {

	PreparedStatement stmt = AbstractTable.createExtendedQueryString(
		queryString, additionalConstraints, sortString);

	ResultSet rs = stmt.executeQuery();
	DistinctVector<Presentation> returnValue = Presentation.getVector(rs);
	rs.close();
	stmt.close();
	return returnValue;
    }

    /**
     * Returns for given id the corresponding {@link Presentation} object.
     * 
     * @param presentationId
     *                id of the wanted {@link Presentation} instance.
     * @return {@link Presentation} object corresponding to the given id.
     * @throws SQLException
     *                 if the PreparedStatement can't be created or the
     *                 execution of the query fails.
     * @see #getPresentationVectorFromDB(Vector, String)
     */
    public static Presentation getPresentation(int presentationId)
	    throws SQLException {
	Vector<DBConstraint> keyConstraint = new Vector<DBConstraint>();
	keyConstraint.add(new DBConstraint(Presentation.getColumns().get(0)
		.getInternalColumnName(), DBConstraint.REL_EQ, new Integer(
		presentationId), DBConstraint.CONJ_END));

	DistinctVector<Presentation> pres = Presentation
		.getPresentationVectorFromDB(keyConstraint, null);

	return pres.iterator().next();
    }

    /**
     * Returns a {@link Vector} of {@link DBColumn} objects for the current
     * {@link Presentation} instance.<br>
     * <br>
     * Note that the second element in the vector gets replaced by a
     * {@link DBColumn} which contains the shortened title of the corresponding
     * {@link SeminarType}.
     */
    public static Vector<DBColumn> getColumnsWithSemtype() {
	Vector<DBColumn> columns = getColumns();
	columns.set(1, new DBColumn("s.shorttitle", Messages
		.getString("MAP.Presentation.SeminarTypeST"), String.class));
	return columns;
    }

    /** Returns the id. */
    public int hashCode() {
	return id;
    }

    /**
     * If the given object is an instance of the Presentation class this method
     * compares the id of the given and the actual object, otherwise it calls
     * the equal-method of the AbstractTable class with the given object.
     * 
     * @param otherPresentation
     *                object to be compared with the actual object.
     * @return <code>true</code> if the id of the given object and the actual
     *         object are the same, <code>false</code> otherwise.
     */
    public boolean equals(Object otherPresentation) {
	if (otherPresentation instanceof Presentation)
	    return id == (((Presentation) otherPresentation).id);
	else
	    return super.equals(otherPresentation);
    }

    /**
     * Returns a String composed of the id of the current presentation and the
     * shortened title of the corresponding seminartype.
     */
    public String getShortDescription() {
	SeminarType semType = null;
	try {
	    semType = SeminarType.getSeminarTypeFromDB(seminarTypeId);
	} catch (SQLException e) {
	}
	String returnValue = "" + id;

	if (semType != null)
	    returnValue += ", "
		    + Messages.getString("MAP.Presentation.SeminarTypeST")
		    + ": " + semType.getShortTitle();

	return returnValue;
    }

    /**
     * Returns the seminartype for the given presentation id.
     * 
     * @param presId
     *                the id of the presentation
     * @return {@link SeminarType} instance corresponding to the presenation
     * @throws SQLException
     *                 SQLException if the PreparedStatement can't be created or
     *                 the execution of the query fails.
     * @see SeminarType#getSeminarTypeFromDB(int)
     */
    public static SeminarType getSeminarTypeForPresId(int presId)
	    throws SQLException {
	Presentation tmpPres = null;
	SeminarType tmpSemType = null;

	// Get presentation for the given presId and retrieve corresponding
	// seminartype
	tmpPres = getPresentation(presId);
	if (tmpPres != null) {
	    tmpSemType = SeminarType.getSeminarTypeFromDB(tmpPres
		    .getSeminarTypeId());
	}

	if (tmpSemType != null) {
	    return tmpSemType;
	}

	return null;
    }

    public String getAnnex() {
	return annex;
    }

    public void setAnnex(String annex) {
	this.annex = annex;
    }

    public Date getBeginningDay() {
	return beginningDay;
    }

    public void setBeginningDay(Date beginningDay) {
	this.beginningDay = beginningDay;
    }

    public boolean isCancelled() {
	return cancelled;
    }

    public void setCancelled(boolean cancelled) {
	this.cancelled = cancelled;
    }

    public String getCity() {
	return city;
    }

    public void setCity(String city) {
	this.city = city;
    }

    public String getCountry() {
	return country;
    }

    public void setCountry(String country) {
	this.country = country;
    }

    public Integer getDuration() {
	return duration;
    }

    public void setDuration(Integer duration) {
	this.duration = duration;
    }

    public Date getEndingDay() {
	return endingDay;
    }

    public void setEndingDay(Date endingDay) {
	this.endingDay = endingDay;
    }

    public Time getEndingTime() {
	return endingTime;
    }

    public void setEndingTime(Time endingTime) {
	this.endingTime = endingTime;
    }

    public Time getFirstStartingTime() {
	return firstStartingTime;
    }

    public void setFirstStartingTime(Time firstStartingTime) {
	this.firstStartingTime = firstStartingTime;
    }

    public Time getLastEndingTime() {
	return lastEndingTime;
    }

    public void setLastEndingTime(Time lastEndingTime) {
	this.lastEndingTime = lastEndingTime;
    }

    public String getLocation() {
	return location;
    }

    public void setLocation(String location) {
	this.location = location;
    }

    public int getSeminarTypeId() {
	return seminarTypeId;
    }

    public void setSeminarTypeId(int seminarTypeId) {
	this.seminarTypeId = seminarTypeId;
    }

    public Time getStartingTime() {
	return startingTime;
    }

    public void setStartingTime(Time startingTime) {
	this.startingTime = startingTime;
    }

    public String getStreet() {
	return street;
    }

    public void setStreet(String street) {
	this.street = street;
    }

    public String getZipCode() {
	return zipCode;
    }

    public void setZipCode(String zipCode) {
	this.zipCode = zipCode;
    }

    public int getId() {
	return id;
    }

}
