/*
 * $Id: VKCProjectDAO.java,v 1.15 2007/07/27 11:14:32 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
 * THIS SOFTWARE OR ITS DERIVATIVES.
 *
 * $Log: VKCProjectDAO.java,v $
 * Revision 1.15  2007/07/27 11:14:32  marbobo
 * + Ungenutzte Anweisungen entfernt
 *
 * Revision 1.14  2007/02/13 12:28:38  lawern
 * Delegator-Konstruktor-Methoden nur noch friendly oder private.
 *
 * Revision 1.13  2007/02/06 08:54:33  lawern
 * Dynamische Attribute zu Delegator-Objekten gemacht + getDynaAttributes()-Methoden implementiert.
 *
 * Revision 1.12  2007/01/09 11:56:27  korowa
 * VKCExternalException wird nicht mehr abgefangen sondern weitergereicht
 *
 * Revision 1.11  2007/01/02 11:08:43  jonyp
 * delete unnecessary ";"
 *
 * Revision 1.10  2006/10/04 03:14:53  marbobo
 * + Vollständige Unterstützung für Templates implementiert
 * + Alles von Virtoweb auf ProCoBa umgestellt
 *
 * Revision 1.9  2006/09/15 09:03:31  lawern
 * Javadoc-Anpassungen
 *
 * Revision 1.8  2006/09/14 09:04:32  lawern
 * DB-Persistenz nur noch nach .save-Aufruf
 *
 * Revision 1.7  2006/09/13 09:32:45  lawern
 * allgemeine Überarbeitung
 *
 * Revision 1.6  2006/09/08 11:31:50  korowa
 * Die vorher definierte ProjectMessageFunktionen sind ausimplementiert
 *
 * Revision 1.5  2006/09/01 11:08:17  korowa
 * ProjektNachrichten und damit verbundene Funktionen hinzugefügt
 *
 * Revision 1.4  2006/08/24 22:19:42  marbobo
 * + Behandlung von Projektschritten implementiert
 *
 * Revision 1.3  2006/08/24 14:52:33  marbobo
 * + Überarbeitet und mit Funktionalität gefüllt
 *
 * Revision 1.2  2006/08/23 18:37:15  marbobo
 * + kleine Anpassung
 *
 * Revision 1.1  2006/08/17 13:01:13  lawern
 * Erster unvollständiger Schnellschuss für die Externe API.
 *
 */
package vkc.external;

import java.io.InputStream;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpSession;
import javax.swing.text.BadLocationException;

import vkc.db.entities.VKCAclType;
import vkc.db.entities.VKCCatProjectStep;
import vkc.db.entities.VKCCategory;
import vkc.db.entities.VKCUser;
import vkc.db.serializer.VKCAclSerializer;
import vkc.db.serializer.VKCCategorySerializer;
import vkc.db.serializer.VKCSysParameterSerializer;
import vkc.exception.DBException;
import vkc.procoba.project.entities.VKCProject;
import vkc.procoba.project.entities.VKCProjectMessage;
import vkc.security.PermissionManager;
import vkc.security.VKCAcl;
import vkc.util.ProjectUtils;
import vkc.util.VKCStringUtils;
import vkc.view.WebShare;
import vkc.view.bean.ProjectInfo;

/**
 * Diese Klasse kapselt ein im VKC-System liegendes Projekt. Mit Hilfe der
 * Methoden dieser Klasse können vorhandene Projekte geholt und bestimmte
 * Metadaten verändert werden. Ebenso können auch neue Projekte angelegt werden.
 * 
 * @author marbobo
 */
public class VKCProjectDAO {
	VKCCategoryDAO internalCategoryDAO = new VKCCategoryDAO();

	VKCProjectDAO() {
		try {
			internalCategoryDAO.internalCategory = new VKCProject();
			internalCategoryDAO.internalCategory.setName("");
			internalCategoryDAO.internalCategory.setDescription("");
			((VKCProject) internalCategoryDAO.internalCategory)
					.setExternalContacts("");
			internalCategoryDAO.internalCategory
					.setParentCategoryId(new Integer(VKCSysParameterSerializer
							.getProjectsRootCategoryId()));
			VKCAcl acl = VKCAclSerializer
					.getAclByCategoryId(internalCategoryDAO.internalCategory
							.getParentCategoryId());
			acl.setAclId(null);
			internalCategoryDAO.internalCategory.setAcl(acl);
		} catch (DBException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Konstruktor zum Anlegen eines neuen Projektes im Projektroot von VKC
	 * 
	 * @param name
	 *            Name des Projektes
	 * @param description
	 *            Beschreibung des Projektes
	 * @param externalContacts
	 *            Externe Kontakte des Projektes
	 */
	public VKCProjectDAO(String name, String description,
			String externalContacts) {
		try {
			internalCategoryDAO.internalCategory = new VKCProject();

			if (name != null) {
				internalCategoryDAO.internalCategory.setName(VKCStringUtils
						.filterUnicodeChars(name));
			} else {
				internalCategoryDAO.internalCategory.setName("");
			}

			if (description != null) {
				description = VKCStringUtils.filterUnicodeChars(description);
				description = VKCStringUtils.decodeXmlEntities(description);
				description = VKCStringUtils
						.encodeNamedXmlEntities(description);
				internalCategoryDAO.internalCategory
						.setDescription(description);
			} else {
				internalCategoryDAO.internalCategory.setDescription("");
			}

			if (externalContacts != null) {
				externalContacts = VKCStringUtils
						.filterUnicodeChars(externalContacts);
				externalContacts = VKCStringUtils
						.decodeXmlEntities(externalContacts);
				externalContacts = VKCStringUtils
						.encodeNamedXmlEntities(externalContacts);
				((VKCProject) internalCategoryDAO.internalCategory)
						.setExternalContacts(externalContacts);
			} else {
				((VKCProject) internalCategoryDAO.internalCategory)
						.setExternalContacts("");
			}

			internalCategoryDAO.internalCategory
					.setParentCategoryId(new Integer(VKCSysParameterSerializer
							.getProjectsRootCategoryId()));
			VKCAcl acl = VKCAclSerializer
					.getAclByCategoryId(internalCategoryDAO.internalCategory
							.getParentCategoryId());
			acl.setAclId(null);
			internalCategoryDAO.internalCategory.setAcl(acl);
		} catch (DBException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Konstruktor zum Anlegen eines neuen Projektes aus einem regulären VKC
	 * Projekt-Objekt
	 * 
	 * @param project
	 *            Regulärer VKC Projekt
	 */
	VKCProjectDAO(VKCProject project) {
		internalCategoryDAO.internalCategory = project;
	}

	/**
	 * Liefert für eine Projekt-ID und einen Benutzer das Projekt-Objekt zurück
	 * 
	 * @param projectId
	 *            ID des Projektes, das geholt werden soll
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @return Das gewünschte Projekt-Objekt, falls der Benutzer die
	 *         entsprechenden Rechte hat, null sonst
	 * @throws VKCExternalException 
	 */
	public static VKCProjectDAO retrieveVKCProjectDAO(Integer projectId,
			HttpSession session) throws VKCExternalException {
		return retrieveVKCProjectDAO(projectId, (VKCUser) session
				.getAttribute(WebShare.USER_KEY));
	}

	/**
	 * Liefert für eine Projekt-ID und einen Benutzer das Projekt-Objekt zurück
	 * 
	 * @param projectId
	 *            ID des Projektes, das geholt werden soll
	 * @param user
	 *            Der aktuelle Benutzer
	 * @return Das gewünschte Projekt-Objekt, falls der Benutzer die
	 *         entsprechenden Rechte hat, null sonst
	 * @throws VKCExternalException 
	 */
	public static VKCProjectDAO retrieveVKCProjectDAO(Integer projectId,
			VKCUserDAO user) throws VKCExternalException {
		if (user.isAuthorized()) {
			return retrieveVKCProjectDAO(projectId, user.getIntUser());
		}

		return null;
	}

	/**
	 * Liefert für eine Projekt-ID und einen Benutzer das Projekt-Objekt zurück
	 * 
	 * @param projectId
	 *            ID des Projektes, das geholt werden soll
	 * @param user
	 *            Der aktuelle Benutzer
	 * @return Das gewünschte Projekt-Objekt, falls der Benutzer die
	 *         entsprechenden Rechte hat, null sonst
	 * @throws VKCExternalException 
	 */
	private static VKCProjectDAO retrieveVKCProjectDAO(Integer projectId,
			VKCUser user) throws VKCExternalException {
		if (user == null) {
			return null;
		}

		VKCProject project = null;

		try {
			if (PermissionManager.hasPermission(VKCAclSerializer
					.getAclByCategoryId(projectId), user, 'r')) {
				VKCCategory category = VKCCategorySerializer
						.retrieveCategory(projectId);

				if (category instanceof VKCProject) {
					project = (VKCProject) category;
				}

				if (project != null) {
					return new VKCProjectDAO(project);
				}

				throw new VKCExternalException(VKCExternalException.UNKNOWN);
			}

			throw new VKCExternalException(
					VKCExternalException.READ_PERMISSION_FAILED);
		} catch (DBException e) {
			e.printStackTrace();

			return null;
		}
	}

	/**
	 * Gibt ein <code>Set</code> mit Projekt-IDs aller vom einem Benutzer
	 * lesbaren Projekte zurück
	 * 
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @return <code>Set</code> mit Projekt-IDs aller vom einem Benutzer
	 *         lesbaren Projekte
	 */
	public static Set retrieveProjectIds(HttpSession session) {
		return retrieveProjectIds((VKCUser) session
				.getAttribute(WebShare.USER_KEY));
	}

	/**
	 * Gibt ein <code>Set</code> mit Projekt-IDs aller vom einem Benutzer
	 * lesbaren Projekte zurück
	 * 
	 * @param user
	 *            Der aktuelle Benutzer
	 * @return <code>Set</code> mit Projekt-IDs aller vom einem Benutzer
	 *         lesbaren Projekte
	 */
	public static Set retrieveProjectIds(VKCUserDAO user) {
		if (user.isAuthorized()) {
			return retrieveProjectIds(user.getIntUser());
		}

		return new HashSet();
	}

	/**
	 * Gibt ein <code>Set</code> mit Projekt-IDs aller vom einem Benutzer
	 * lesbaren Projekte zurück
	 * 
	 * @param user
	 *            Der aktuelle Benutzer
	 * @return <code>Set</code> mit Projekt-IDs aller vom einem Benutzer
	 *         lesbaren Projekte
	 */
	private static Set retrieveProjectIds(VKCUser user) {
		try {
			HashSet ids = new HashSet();
			List projectInfos = ProjectUtils.getProjectInfos(user);

			for (Iterator iter = projectInfos.iterator(); iter.hasNext();) {
				ProjectInfo projectInfo = (ProjectInfo) iter.next();
				ids.add(projectInfo.getId());
			}

			return ids;
		} catch (DBException e) {
			return new HashSet();
		}
	}

	/**
	 * Fügt diesem Projekt ein Dokument hinzu
	 * 
	 * @param document
	 *            Hinzufügendes Dokument
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @throws VKCExternalException 
	 * @see vkc.external.VKCCategoryDAO#addDocument(vkc.external.VKCDocumentDAO,
	 *      javax.servlet.http.HttpSession)
	 */
	public void addDocument(VKCDocumentDAO document, HttpSession session) throws VKCExternalException {
		internalCategoryDAO.addDocument(document, session);
	}

	/**
	 * Fügt diesem Projekt ein Dokument mit dem angegebenem InputStream hinzu
	 * 
	 * @param document
	 *            Hinzufügendes Dokument
	 * @param docStream
	 *            InputStream des Dokuments
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @throws VKCExternalException 
	 * @see vkc.external.VKCCategoryDAO#addDocument(vkc.external.VKCDocumentDAO,
	 *      java.io.InputStream, javax.servlet.http.HttpSession)
	 */
	public void addDocument(VKCDocumentDAO document, InputStream docStream,
			HttpSession session) throws VKCExternalException {
		internalCategoryDAO.addDocument(document, docStream, session);
	}

	/**
	 * Fügt diesem Projekt ein Dokument mit dem angegebenem InputStream hinzu
	 * 
	 * @param document
	 *            Hinzufügendes Dokument
	 * @param docStream
	 *            InputStream des Dokuments
	 * @param user
	 *            Benutzer-Objekt
	 * @throws VKCExternalException 
	 * @see vkc.external.VKCCategoryDAO#addDocument(vkc.external.VKCDocumentDAO,
	 *      java.io.InputStream, vkc.external.VKCUserDAO)
	 */
	public void addDocument(VKCDocumentDAO document, InputStream docStream,
			VKCUserDAO user) throws VKCExternalException {
		internalCategoryDAO.addDocument(document, docStream, user);
	}

	/**
	 * Fügt diesem Projekt ein Dokument hinzu
	 * 
	 * @param document
	 *            Hinzufügendes Dokument
	 * @param user
	 *            Benutzer-Objekt
	 * @throws VKCExternalException 
	 * @see vkc.external.VKCCategoryDAO#addDocument(vkc.external.VKCDocumentDAO,
	 *      vkc.external.VKCUserDAO)
	 */
	public void addDocument(VKCDocumentDAO document, VKCUserDAO user) throws VKCExternalException {
		internalCategoryDAO.addDocument(document, user);
	}

	/**
	 * Fügt diesem Projekt ein dynamisches Attribut hinzu
	 * 
	 * @param dynaAttribute
	 *            Hinzufügendes Attribute
	 * @see vkc.external.VKCCategoryDAO#addDynaAttribute(vkc.external.VKCDynaAttributeDAO)
	 */
	public void addDynaAttribute(VKCDynaAttributeDAO dynaAttribute) {
		internalCategoryDAO.addDynaAttribute(dynaAttribute);
	}

	/**
	 * Fügt diesem Projekt eine Unterkategorie hinzu
	 * 
	 * @param subCategory
	 *            Hinzuzufügende Unterkategorie
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @throws VKCExternalException 
	 */
	public void addSubCategory(VKCProjectSubfolderDAO subCategory,
			HttpSession session) throws VKCExternalException {
		addSubCategory(subCategory, (VKCUser) session
				.getAttribute(WebShare.USER_KEY));
	}

	/**
	 * Fügt diesem Projekt eine Unterkategorie hinzu
	 * 
	 * @param subCategory
	 *            Hinzuzufügende Unterkategorie
	 * @param user
	 *            Benutzer-Objekt
	 * @throws VKCExternalException 
	 */
	public void addSubCategory(VKCProjectSubfolderDAO subCategory,
			VKCUserDAO user) throws VKCExternalException {
		addSubCategory(subCategory, user.getIntUser());
	}

	/**
	 * Fügt diesem Projekt eine Unterkategorie hinzu
	 * 
	 * @param subCategory
	 *            Hinzuzufügende Unterkategorie
	 * @param user
	 *            Benutzer-Objekt
	 * @throws VKCExternalException 
	 */
	private void addSubCategory(VKCProjectSubfolderDAO subCategory, VKCUser user) throws VKCExternalException {
		if (subCategory == null) {
			return;
		}

		if (internalCategoryDAO.internalCategory.getCategoryId() != null) {
			try {
				if (PermissionManager.hasPermission(
						internalCategoryDAO.internalCategory.getAcl(), user,
						'C')) {
					VKCAcl acl = internalCategoryDAO.internalCategory.getAcl();

					try {
						PermissionManager.setCategoryOwnerPermissions(
								new Integer(VKCAclType.USER_TYPE), user
										.getUserId(), user.getUserId(), acl);
					} catch (Exception ex) {
					}

					acl.setAclId(null);

					VKCCategory newCategory = subCategory.internalCategoryDAO.internalCategory;
					newCategory.setAcl(acl);
					newCategory
							.setParentCategoryId(internalCategoryDAO.internalCategory
									.getCategoryId());
					newCategory.setCreated(new Timestamp(System
							.currentTimeMillis()));
					newCategory.setCreatorId(user.getUserId());
					// Fügt die Kategorie ein
					VKCCategorySerializer.saveCategory(newCategory);
				} else {
					throw new VKCExternalException(
							VKCExternalException.CREATE_CATEGORY_PERMISSION_FAILED);
				}
			} catch (DBException e) {
				e.printStackTrace();
			} 
		} else {
			throw new VKCExternalException(VKCExternalException.ID_MISSED);
		}
	}

	/**
	 * Löscht dieses Projekt
	 * 
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @throws VKCExternalException 
	 * @see vkc.external.VKCCategoryDAO#delete(javax.servlet.http.HttpSession)
	 */
	public void delete(HttpSession session) throws VKCExternalException {
		internalCategoryDAO.delete(session);
	}

	/**
	 * Löscht dieses Projekt
	 * 
	 * @param user
	 *            Benutzer-Objekt
	 * @throws VKCExternalException 
	 * @see vkc.external.VKCCategoryDAO#delete(vkc.external.VKCUserDAO)
	 */
	public void delete(VKCUserDAO user) throws VKCExternalException {
		internalCategoryDAO.delete(user);
	}

	/**
	 * Löscht das dynamische Attribute mit dem angegebenen Namen
	 * 
	 * @param name
	 *            Der Name des Attributes
	 * @see vkc.external.VKCCategoryDAO#deleteDynaAttribute(java.lang.String)
	 */
	public void deleteDynaAttribute(String name) {
		internalCategoryDAO.deleteDynaAttribute(name);
	}

	/**
	 * Liefert für das aktuelle Projekt alle vom Benutzer lesbaren direkten
	 * Unterkategorie IDs zurück
	 * 
	 * @param user
	 *            Der aktuelle Benutzer
	 * @return <code>Set</code> der Unterkategorie IDs
	 * @see vkc.external.VKCCategoryDAO#getAccessibleSubCategoryIds(vkc.external.VKCUserDAO)
	 */
	public Set getAccessibleSubCategoryIds(VKCUserDAO user) {
		return internalCategoryDAO.getAccessibleSubCategoryIds(user);
	}

	/**
	 * Liefert die ID dieses Projektes
	 * 
	 * @return Die Projekt ID
	 * @see vkc.external.VKCCategoryDAO#getCategoryId()
	 */
	public Integer getCategoryId() {
		return internalCategoryDAO.getCategoryId();
	}

	/**
	 * Liefert die ID dieses Projektes
	 * 
	 * @return Die Projekt ID
	 */
	public Integer getProjectId() {
		return internalCategoryDAO.getCategoryId();
	}

	/**
	 * Liefert die Beschreibung dieses Projektes (in Unicode) zurück
	 * 
	 * @return Die Beschreibung dieses Projektes (in Unicode)
	 * @see vkc.external.VKCCategoryDAO#getDescription()
	 */
	public String getDescription() {
		return internalCategoryDAO.getDescription();
	}

	/**
	 * Liefert für das aktuelle Projekt alle Dokument IDs zurück
	 * 
	 * @return <code>Set</code> der Dokument IDs
	 * @see vkc.external.VKCCategoryDAO#getDocumentIds()
	 */
	public Set getDocumentIds() {
		return internalCategoryDAO.getDocumentIds();
	}

	/**
	 * Gibt das dynamische Attribute zurück
	 * 
	 * @param name
	 *            Der Name des Attributes
	 * @return Falls vorhanden das dynamische Attribut, sonst null
	 * @see vkc.external.VKCCategoryDAO#getDynaAttribute(java.lang.String)
	 */
	public VKCDynaAttributeDAO getDynaAttribute(String name) {
		return internalCategoryDAO.getDynaAttribute(name);
	}
    
    /**
     * Gibt eine Liste der dynamischen Attribute zurück
     * 
     * @return Falls vorhanden eine Collection mit dynamischen Attributen
     *         (VKCDynaAttributeDAO), sonst null.
     */
    public Collection getDynaAttributes() {
        return internalCategoryDAO.getDynaAttributes();
    }

	/**
	 * Liefert die externen Kontakte dieses Projektes (in Unicode) zurück
	 * 
	 * @return Die externen Kontakte dieses Projektes (in Unicode)
	 */
	public String getExternalContacts() {
		if (internalCategoryDAO.internalCategory != null) {
			String s = VKCStringUtils
					.filterUnicodeChars(((VKCProject) internalCategoryDAO.internalCategory)
							.getExternalContacts());
			s = VKCStringUtils.htmlFormatedText(s);
			s = VKCStringUtils.decodeXmlEntities(s);
			s = VKCStringUtils.decodeNamedXmlEntitiesNotInSwing(s);

			try {
				s = VKCStringUtils.removeHtmlTags(s);
			} catch (BadLocationException e) {
				e.printStackTrace();
			}

			return s;
		}

		return "";
	}

	/**
	 * Liefert den Namen dieses Projektes (in Unicode) zurück
	 * 
	 * @return Der Name dieses Projektes (in Unicode)
	 * @see vkc.external.VKCCategoryDAO#getName()
	 */
	public String getName() {
		return internalCategoryDAO.getName();
	}

	/**
	 * Liefert die Eltern-Kategorie ID
	 * 
	 * @return Die Eltern-Kategorie ID
	 * @see vkc.external.VKCCategoryDAO#getParentCategoryId()
	 */
	public Integer getParentCategoryId() {
		return internalCategoryDAO.getParentCategoryId();
	}

	/**
	 * Liefert für das aktuelle Projekt alle direkten Unterkategorie IDs zurück
	 * 
	 * @return <code>Set</code> der Unterkategorie IDs
	 * @see vkc.external.VKCCategoryDAO#getSubCategoryIds()
	 */
	public Set getSubCategoryIds() {
		return internalCategoryDAO.getSubCategoryIds();
	}

	/**
	 * Liefert für das aktuelle Projekt rekursiv alle Unterkategorie IDs zurück
	 * 
	 * @return <code>Set</code> der Unterkategorie IDs
	 * @throws DBException
	 * @see vkc.external.VKCCategoryDAO#getSubCategoryIdsRecursiv()
	 */
	public Set getSubCategoryIdsRecursiv() throws DBException {
		return internalCategoryDAO.getSubCategoryIdsRecursiv();
	}

	/**
	 * Speichert das aktuelle Projekt
	 * 
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @throws VKCExternalException 
	 * @see vkc.external.VKCCategoryDAO#save(javax.servlet.http.HttpSession)
	 */
	public void save(HttpSession session) throws VKCExternalException {
		internalCategoryDAO.save(session);
	}

	/**
	 * Speichert das aktuelle Projekt
	 * 
	 * @param user
	 *            Der aktuelle Benutzer
	 * @throws VKCExternalException 
	 * @see vkc.external.VKCCategoryDAO#save(vkc.external.VKCUserDAO)
	 */
	public void save(VKCUserDAO user) throws VKCExternalException {
		internalCategoryDAO.save(user);
	}

	/**
	 * Ändert den Wert des angegebenen dynamischen Attributes in diesem Projekt
	 * 
	 * @param name
	 *            Zu änderndes Attribute
	 * @param newValue
	 *            Der neue Wert
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @throws VKCExternalException 
	 * @see vkc.external.VKCCategoryDAO#setDynaAttribute(java.lang.String,
	 *      java.lang.String, javax.servlet.http.HttpSession)
	 */
	public void setDynaAttribute(String name, String newValue,
			HttpSession session) throws VKCExternalException {
		internalCategoryDAO.setDynaAttribute(name, newValue, session);
	}

	/**
	 * Ändert den Wert des angegebenen dynamischen Attributes in diesem Projekt
	 * 
	 * @param name
	 *            Zu änderndes Attribute
	 * @param newValue
	 *            Der neue Wert
	 * @param user
	 *            Der aktuelle Benutzer
	 * @throws VKCExternalException 
	 * @see vkc.external.VKCCategoryDAO#setDynaAttribute(java.lang.String,
	 *      java.lang.String, vkc.external.VKCUserDAO)
	 */
	public void setDynaAttribute(String name, String newValue, VKCUserDAO user) throws VKCExternalException {
		internalCategoryDAO.setDynaAttribute(name, newValue, user);
	}

	/**
	 * Fügt diesem Projekt ein neues Projektschritt hinzu. Dabei wird die
	 * Einfügeposition in Abhängigkeit der Ordnung des Projektschrittes
	 * bestimmt. Ist die Ordnung des Projektschrittes <= 0 wird es an die erste
	 * Position eingefügt. Ist die Ordnung des Projektschrittes >= als die
	 * höchste Position, so wird es an die letzte Position eingefügt. Ist die
	 * Ordnung des Projektschrittes im Bereich der vorhandenen Position, so wird
	 * es genau an der Postion der Ordnung des Projektschrittes eingefügt und
	 * alle Positionen rechts davon um eins erhöht.
	 * 
	 * @param projectStep
	 *            Hinzufügendes Projektschritt
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @throws VKCExternalException 
	 */
	public void addProjectStep(VKCProjectStepDAO projectStep,
			HttpSession session) throws VKCExternalException {
		addProjectStep(projectStep, (VKCUser) session
				.getAttribute(WebShare.USER_KEY));
	}

	/**
	 * Fügt diesem Projekt ein neues Projektschritt hinzu. Dabei wird die
	 * Einfügeposition in Abhängigkeit der Ordnung des Projektschrittes
	 * bestimmt. Ist die Ordnung des Projektschrittes <= 0 wird es an die erste
	 * Position eingefügt. Ist die Ordnung des Projektschrittes >= als die
	 * höchste Position, so wird es an die letzte Position eingefügt. Ist die
	 * Ordnung des Projektschrittes im Bereich der vorhandenen Position, so wird
	 * es genau an der Postion der Ordnung des Projektschrittes eingefügt und
	 * alle Positionen rechts davon um eins erhöht.
	 * 
	 * @param projectStep
	 *            Hinzufügendes Projektschritt
	 * @param user
	 *            Der aktuelle Benutzer
	 * @throws VKCExternalException 
	 */
	public void addProjectStep(VKCProjectStepDAO projectStep, VKCUserDAO user) throws VKCExternalException {
		if (user.isAuthorized()) {
			addProjectStep(projectStep, user.getIntUser());
		}
	}

	/**
	 * Fügt diesem Projekt ein neues Projektschritt hinzu. Dabei wird die
	 * Einfügeposition in Abhängigkeit der Ordnung des Projektschrittes
	 * bestimmt. Ist die Ordnung des Projektschrittes <= 0 wird es an die erste
	 * Position eingefügt. Ist die Ordnung des Projektschrittes >= als die
	 * höchste Position, so wird es an die letzte Position eingefügt. Ist die
	 * Ordnung des Projektschrittes im Bereich der vorhandenen Position, so wird
	 * es genau an der Postion der Ordnung des Projektschrittes eingefügt und
	 * alle Positionen rechts davon um eins erhöht.
	 * 
	 * @param projectStep
	 *            Hinzufügendes Projektschritt
	 * @param user
	 *            Der aktuelle Benutzer
	 * @throws VKCExternalException 
	 */
	private void addProjectStep(VKCProjectStepDAO projectStep, VKCUser user) throws VKCExternalException {
		if (internalCategoryDAO.internalCategory.getCategoryId() != null) {
			if (PermissionManager.hasPermission(
					internalCategoryDAO.internalCategory.getAcl(), user, 'w')) {
				try {
					VKCProject project = (VKCProject) internalCategoryDAO.internalCategory;
					VKCCatProjectStep catProjectStep = projectStep.projectStep;
					catProjectStep.setActivity(VKCStringUtils
							.filterUnicodeChars(projectStep.getActivity()));
					catProjectStep.setCategoryId(project.getCategoryId());
					List leftSteps = new ArrayList();
					List rightSteps = new ArrayList();
					List steps = new ArrayList();
					int maxStep = 0;

					for (Iterator iter = project.getProjectSteps().iterator(); iter
							.hasNext();) {
						VKCCatProjectStep step = (VKCCatProjectStep) iter
								.next();

						if (step.getStep().intValue() < catProjectStep
								.getStep().intValue()) {
							if (step.getStep().intValue() > maxStep) {
								maxStep = step.getStep().intValue();
							}

							leftSteps.add(step);
						} else {
							rightSteps.add(step);
						}
					}

					if (leftSteps.isEmpty() && rightSteps.isEmpty()) {
						catProjectStep.setStep(new Integer(1));
						steps.add(catProjectStep);
					} else if (leftSteps.isEmpty() && !rightSteps.isEmpty()) {
						catProjectStep.setStep(new Integer(1));
						steps.add(catProjectStep);

						for (Iterator iter = rightSteps.iterator(); iter
								.hasNext();) {
							VKCCatProjectStep ps = (VKCCatProjectStep) iter
									.next();
							ps
									.setStep(new Integer(ps.getStep()
											.intValue() + 1));
							steps.add(ps);
						}
					} else if (!leftSteps.isEmpty() && rightSteps.isEmpty()) {
						catProjectStep.setStep(new Integer(maxStep + 1));
						steps.add(catProjectStep);
						steps.addAll(leftSteps);
					} else {
						steps.addAll(leftSteps);
						catProjectStep.setStep(new Integer(maxStep + 1));
						steps.add(catProjectStep);

						for (Iterator iter = rightSteps.iterator(); iter
								.hasNext();) {
							VKCCatProjectStep ps = (VKCCatProjectStep) iter
									.next();
							ps
									.setStep(new Integer(ps.getStep()
											.intValue() + 1));
							steps.add(ps);
						}
					}

					project.setProjectSteps(steps);
					project
							.setLastChanged(new Date(System.currentTimeMillis()));
					project.setLastChangerId(user.getUserId());
					VKCCategorySerializer.saveCategory(project);
				} catch (DBException e) {
					e.printStackTrace();
				}
			} else {				
				throw new VKCExternalException(
							VKCExternalException.WRITE_PERMISSION_FAILED);
			}
		}
	}

	/**
	 * Gibt das Projektschritt zurück
	 * 
	 * @param step
	 *            Die Ordnung/Reihenfolge/Position des Projektschrittes
	 * @return Falls vorhanden das Projektschritt, sonst <code>null</code>
	 */
	public VKCProjectStepDAO getProjectStep(Integer step) {
		VKCProject project = (VKCProject) internalCategoryDAO.internalCategory;

		for (Iterator iter = project.getProjectSteps().iterator(); iter
				.hasNext();) {
			VKCCatProjectStep ps = (VKCCatProjectStep) iter.next();

			if (ps.getStep().intValue() == step.intValue()) {
				return new VKCProjectStepDAO(ps);
			}
		}

		return null;
	}

	/**
	 * Gibt das Projektschritt zurück
	 * 
	 * @param stepId
	 *            Die ID des Projektschrittes
	 * @return Falls vorhanden das Projektschritt, sonst <code>null</code>
	 */
	public VKCProjectStepDAO getProjectStepById(Integer stepId) {
		VKCProject project = (VKCProject) internalCategoryDAO.internalCategory;

		for (Iterator iter = project.getProjectSteps().iterator(); iter
				.hasNext();) {
			VKCCatProjectStep ps = (VKCCatProjectStep) iter.next();

			if (ps.getCatProjStepId().equals(stepId)) {
				return new VKCProjectStepDAO(ps);
			}
		}

		return null;
	}

	/**
	 * Gibt alle IDs aller Projektschritte dieses Prrojektes zurück
	 * 
	 * @return IDs aller Projektschritte
	 */
	public Set getProjectStepIds() {
		VKCProject project = (VKCProject) internalCategoryDAO.internalCategory;
		HashSet ids = new HashSet();

		for (Iterator iter = project.getProjectSteps().iterator(); iter
				.hasNext();) {
			VKCCatProjectStep ps = (VKCCatProjectStep) iter.next();
			ids.add(ps.getCatProjStepId());
		}

		return ids;
	}

	/**
	 * Löscht das Projektschritt anhand seiner Position
	 * 
	 * @param step
	 *            Ordnung/Reihefolge/Position des Projektschrittes
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @throws VKCExternalException 
	 */
	public void deleteProjectStep(Integer step, HttpSession session) throws VKCExternalException {
		deleteProjectStep(step, (VKCUser) session
				.getAttribute(WebShare.USER_KEY));
	}

	/**
	 * Löscht das Projektschritt anhand seiner Position
	 * 
	 * @param step
	 *            Ordnung/Reihefolge/Position des Projektschrittes
	 * @param user
	 *            Der aktuelle Benutzer
	 * @throws VKCExternalException 
	 */
	public void deleteProjectStep(Integer step, VKCUserDAO user) throws VKCExternalException {
		if (user.isAuthorized()) {
			deleteProjectStep(step, user.getIntUser());
		}
	}

	/**
	 * Löscht das Projektschritt anhand seiner Position
	 * 
	 * @param step
	 *            Ordnung/Reihefolge/Position des Projektschrittes
	 * @param user
	 *            Der aktuelle Benutzer
	 * @throws VKCExternalException 
	 */
	private void deleteProjectStep(Integer step, VKCUser user) throws VKCExternalException {
		if (internalCategoryDAO.internalCategory.getCategoryId() != null) {
			if (PermissionManager.hasPermission(
					internalCategoryDAO.internalCategory.getAcl(), user, 'w')) {
				try {
					VKCProject project = (VKCProject) internalCategoryDAO.internalCategory;
					List leftSteps = new ArrayList();
					List rightSteps = new ArrayList();
					List steps = new ArrayList();

					for (Iterator iter = project.getProjectSteps().iterator(); iter
							.hasNext();) {
						VKCCatProjectStep ps = (VKCCatProjectStep) iter.next();

						if (ps.getStep().intValue() < step.intValue()) {
							leftSteps.add(ps);
						} else if (ps.getStep().intValue() > step.intValue()) {
							rightSteps.add(ps);
						}
					}

					if (leftSteps.isEmpty() && !rightSteps.isEmpty()) {
						for (Iterator iter = rightSteps.iterator(); iter
								.hasNext();) {
							VKCCatProjectStep ps = (VKCCatProjectStep) iter
									.next();
							ps
									.setStep(new Integer(ps.getStep()
											.intValue() - 1));
							steps.add(ps);
						}
					} else if (!leftSteps.isEmpty() && rightSteps.isEmpty()) {
						steps.addAll(leftSteps);
					} else if (!leftSteps.isEmpty() && !rightSteps.isEmpty()) {
						steps.addAll(leftSteps);

						for (Iterator iter = rightSteps.iterator(); iter
								.hasNext();) {
							VKCCatProjectStep ps = (VKCCatProjectStep) iter
									.next();
							ps
									.setStep(new Integer(ps.getStep()
											.intValue() - 1));
							steps.add(ps);
						}
					}

					project.setProjectSteps(steps);
					project
							.setLastChanged(new Date(System.currentTimeMillis()));
					project.setLastChangerId(user.getUserId());
					VKCCategorySerializer.saveCategory(project);
				} catch (DBException e) {
					e.printStackTrace();
				}
			} else {				
				throw new VKCExternalException(
							VKCExternalException.WRITE_PERMISSION_FAILED);
			}
		}
	}

	/**
	 * Löscht das Projektschritt anhand seiner ID
	 * 
	 * @param stepId
	 *            ID des Projektschrittes
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @throws VKCExternalException 
	 */
	public void deleteProjectStepById(Integer stepId, HttpSession session) throws VKCExternalException {
		deleteProjectStepById(stepId, (VKCUser) session
				.getAttribute(WebShare.USER_KEY));
	}

	/**
	 * Löscht das Projektschritt anhand seiner ID
	 * 
	 * @param stepId
	 *            ID des Projektschrittes
	 * @param user
	 *            Der aktuelle Benutzer
	 * @throws VKCExternalException 
	 */
	public void deleteProjectStepById(Integer stepId, VKCUserDAO user) throws VKCExternalException {
		if (user.isAuthorized()) {
			deleteProjectStepById(stepId, user.getIntUser());
		}
	}

	/**
	 * Löscht das Projektschritt anhand seiner ID
	 * 
	 * @param stepId
	 *            ID des Projektschrittes
	 * @param user
	 *            Der aktuelle Benutzer
	 * @throws VKCExternalException 
	 */
	private void deleteProjectStepById(Integer stepId, VKCUser user) throws VKCExternalException {
		if (internalCategoryDAO.internalCategory.getCategoryId() != null) {
			if (PermissionManager.hasPermission(
					internalCategoryDAO.internalCategory.getAcl(), user, 'w')) {
				try {
					VKCProject project = (VKCProject) internalCategoryDAO.internalCategory;
					List steps = new ArrayList();

					for (Iterator iter = project.getProjectSteps().iterator(); iter
							.hasNext();) {
						VKCCatProjectStep ps = (VKCCatProjectStep) iter.next();

						if (!ps.getCatProjStepId().equals(stepId)) {
							steps.add(ps);
						}
					}

					project.setProjectSteps(steps);
					project
							.setLastChanged(new Date(System.currentTimeMillis()));
					project.setLastChangerId(user.getUserId());
					VKCCategorySerializer.saveCategory(project);
				} catch (DBException e) {
					e.printStackTrace();
				}
			} else {				
					throw new VKCExternalException(
							VKCExternalException.WRITE_PERMISSION_FAILED);
			}
		}
	}

	/**
	 * Fügt diesem Projekt eine neue Projektnachricht hinzu.
	 * 
	 * @param projectMessage
	 *            Hinzufügende Projektnachricht
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 */
	public void addProjectMessage(VKCProjectMessageDAO projectMessage,
			HttpSession session) {
		addProjectMessage(projectMessage, (VKCUser) session
				.getAttribute(WebShare.USER_KEY));
	}

	/**
	 * Fügt diesem Projekt eine neue Projektnachricht hinzu.
	 * 
	 * @param projectMessage
	 *            Hinzufügende Projektnachricht
	 * @param user
	 *            Der aktuelle Benutzer
	 */
	public void addProjectMessage(VKCProjectMessageDAO projectMessage,
			VKCUserDAO user) {
		if (user.isAuthorized()) {
			addProjectMessage(projectMessage, user.getIntUser());
		}
	}

	/**
	 * Fügt diesem Projekt eine neue Projektnachricht hinzu.
	 * 
	 * @param projectMessage
	 *            Hinzufügende Projektnachricht
	 * @param user
	 *            Der aktuelle Benutzer
	 */
	private void addProjectMessage(VKCProjectMessageDAO projectMessage,
			VKCUser user) {
		try {
			VKCProject project = (VKCProject) internalCategoryDAO.internalCategory;
			List recepientIds = project.getMembers();
			for (Iterator iter = recepientIds.iterator(); iter.hasNext();) {
				Integer recepientId = (Integer) iter.next();
				VKCProjectMessage message = projectMessage.projectMessage;
				message.setProjectId(project.getCategoryId());
				message.setCreatorId(user.getUserId());
				message.setCreationDate(new Date(System.currentTimeMillis()));
				message.setText(VKCStringUtils
						.filterUnicodeChars(projectMessage.getText()));
				message.setRecepientId(recepientId);
				ProjectUtils.saveProjectMessage(message);
			}
		} catch (DBException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Löscht die Projektnachricht anhand ihrer ID
	 * 
	 * @param messageId
	 *            ID der Projektnachricht
	 * @param session
	 *            Session-Objekt in dem der aktuelle Benutzer hinterlegt ist
	 * @throws VKCExternalException 
	 */
	public void deleteProjectMessageById(Integer messageId, HttpSession session) throws VKCExternalException {
		deleteProjectMessageById(messageId, (VKCUser) session
				.getAttribute(WebShare.USER_KEY));
	}

	/**
	 * Löscht die Projektnachricht anhand ihrer ID
	 * 
	 * @param messageId
	 *            ID der Projektnachricht
	 * @param user
	 *            Der aktuelle Benutzer
	 * @throws VKCExternalException 
	 */
	public void deleteProjectMessageById(Integer messageId, VKCUserDAO user) throws VKCExternalException {
		if (user.isAuthorized()) {
			deleteProjectMessageById(messageId, user.getIntUser());
		}
	}

	/**
	 * Löscht die Projektnachricht anhand ihrer ID
	 * 
	 * @param messageId
	 *            ID der Projektnachricht
	 * @param user
	 *            Der aktuelle Benutzer
	 * @throws VKCExternalException 
	 */
	private void deleteProjectMessageById(Integer messageId, VKCUser user) throws VKCExternalException {
		if (internalCategoryDAO.internalCategory.getCategoryId() != null) {
			if (PermissionManager.hasPermission(
					internalCategoryDAO.internalCategory.getAcl(), user, 'w')) {
				try {
					ProjectUtils.deleteProjectMessage(messageId);
				} catch (DBException e) {
					e.printStackTrace();
				}
			} else {
				throw new VKCExternalException(
							VKCExternalException.WRITE_PERMISSION_FAILED);
			}
		}
	}

	/**
	 * Gibt eine Liste von Projektnachrichten, die für einen Mitglieder dieses Projects bestimmt sind
	 *  
	 * @param userId
	 *            Empfänger dieser Nachrichten
	 * @return Falls vorhanden Liste von Projectnachrichten, sonst <code>null</code>
	 */
	public List getProjectMessage(Integer userId) {
		if (internalCategoryDAO.internalCategory.getCategoryId() != null) {
			try {

				List msgs = ProjectUtils.retrieveProjectMessages(
						internalCategoryDAO.internalCategory.getCategoryId(),
						userId);
				List messages = new ArrayList();
				for (Iterator iter = msgs.iterator(); iter.hasNext();) {
					VKCProjectMessage msg = (VKCProjectMessage) iter.next();
					VKCProjectMessageDAO message = new VKCProjectMessageDAO(msg);
					messages.add(message);
				}

				return messages;
			} catch (DBException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

}