/*
 * $Id: VKCDocument.java,v 1.107 2008/04/17 10:01:01 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: VKCDocument.java,v $
 * Revision 1.107  2008/04/17 10:01:01  marbobo
 * + Velocity-Templates angepasst
 *
 * Revision 1.106  2006/08/17 07:55:53  lawern
 * getAcl gelöscht, weil sie nicht vollständig implementiert ist.
 *
 * Revision 1.105  2005/09/15 13:40:13  marbobo
 * + Cachen von Publisher-, LastChanger- und LastAccessorName
 *
 * Revision 1.104  2005/09/13 00:11:38  marbobo
 * + getCategoryId() wieder auf alte form gebracht da unnötig/fehleranfällig
 *
 * Revision 1.103  2005/09/12 15:28:26  jonyp
 * added "isInTrash"-method
 * increase performance in getCategory(), getCategoryId() methods
 *
 * Revision 1.102  2005/09/09 12:18:55  marbobo
 * + Bugfix
 *
 * Revision 1.101  2005/09/04 17:57:40  marbobo
 * + Neues Metadaten-Attribute (Erstellungsdatum) für Dokumente hinzugefügt
 *
 * Revision 1.100  2005/09/01 08:32:00  korowa
 * Es werden mehrere URL angeboten, welche direkten Zugriff auf Dateien
 *  und automatisches Anmelden als Gast erlauben.
 *
 * Revision 1.99  2005/08/30 14:24:41  jonyp
 * aded setFlag method and change STATUS_/FLAG constants to Integer
 *
 * Revision 1.98  2005/08/18 14:03:09  korowa
 * + Bugfix beim Iconansichten
 *
 * Revision 1.97  2005/08/18 11:10:41  korowa
 * Das Aussehen von Icons kann jetzt auf die frühere Version umgestellt werden
 *
 * Revision 1.96  2005/08/16 10:54:39  korowa
 * Das Aussehen von Icons kann jetzt auf die frühere Version umgestellt werden
 *
 * Revision 1.95  2005/08/09 19:03:21  jonyp
 * added methods to display lastChnage/lastAccessor as User.Info.Lastname format
 *
 * Revision 1.94  2005/07/19 12:14:30  marbobo
 * + kleine Anpassung
 *
 * Revision 1.93  2005/07/16 23:55:14  marbobo
 * + Bugfix in DokumentIcon-Methoden bei versionierten Dokumenten
 *
 * Revision 1.92  2005/07/14 12:50:41  korowa
 * +3 neue dateitypen sind in Datenbank reingekommen(odt,fh11,fh8)
 * +neue Eigenschaft(editable) von Dokumenttype, die Editierbarkeit eines Dokumentes in VKC anzeigt
 *
 * Revision 1.91  2005/06/23 22:28:11  marbobo
 * + Fehlende Icon-Bilder hinmzugefügt
 * + Alle Icon-Pfade korrigiert
 * + Alle Icon-Methoden korrigiert und optimiert
 *
 * Revision 1.90  2005/06/23 11:42:34  korowa
 * Image-Path für Icons wird jetzt aus Datenbank geholt
 *
 * Revision 1.89  2005/05/24 12:59:55  korowa
 * Die ausgeschnietene Dokumente werden jetzt markiert(getDocumentIconShaded())
 * +Die Icons für Dokumente werden jetzt aus Datenbank geholt
 *
 * Revision 1.88  2005/05/20 09:07:51  korowa
 * Die ausgeschnietene Dokumente werden jetzt markiert(getDocumentIconShaded())
 * +Die Icons für Dokumente werden jetzt aus Datenbank geholt
 *
 * Revision 1.87  2005/03/23 19:45:35  marbobo
 * + Lokalisierung der Größenanzeige
 *
 * Revision 1.86  2005/03/21 20:21:08  marbobo
 * + DocSize auf Type Long umgestellt
 *
 * Revision 1.85  2005/02/15 09:26:47  bigmac
 * Refactorings
 *
 * Revision 1.84  2005/02/14 21:26:36  jonyp
 * added getLastChangerName
 *
 * Revision 1.83  2005/02/02 22:58:08  marbobo
 * Neue filterMethode (Unicode-Sensitive) wird bei der Beschreibung verwendet
 *
 * Revision 1.82  2005/01/20 15:25:50  marbobo
 * + Anpassungen an den Methoden getRootURL() und getContextName()
 *
 * Revision 1.81  2004/12/22 00:34:29  marbobo
 * + Bugfixes in den Methoden die versionierte Dokumente betreffen
 *
 * Revision 1.80  2004/12/20 11:43:31  jonyp
 * + getSuccessor/PredecessorVersionDocId
 *
 * Revision 1.79  2004/11/24 09:26:02  lawern
 * Hibernate ist VKC-Geschichte!
 *
 * Revision 1.78  2004/11/09 14:35:40  marbobo
 * + Umstellung von authorId auf publisherId
 * + Hinzufügen von AuthorName für Dokumente
 * + Nötwendige Änderungen betreffend AuthorName und PublisherId
 *
 * Revision 1.77  2004/10/26 14:59:31  jonyp
 * added lastAccessor-method
 *
 * Revision 1.76  2004/10/25 13:24:43  koppy
 * Änderungen bzgl. Rauswurf von CONVERSION_STATUS_ID
 * aus DOCUMENTS-Tabelle. Stattdessen entsprechende
 * DOCUMENTID in der CONVERSIONSTATI-Tabelle
 *
 * Revision 1.75  2004/10/17 20:01:28  marbobo
 * + Neues Flag (TOBEPUBLISHED) hinzugefügt
 *
 * Revision 1.74  2004/10/14 10:33:13  jonyp
 * prepared documentIcon for a document which is to be published
 *
 * Revision 1.73  2004/08/27 16:37:28  koppy
 * +getDisplayURI(): URL-codierter String
 * zur Verlinkung des Dokumentes in Webseiten
 *
 * Revision 1.72  2004/07/30 13:18:35  jonyp
 * *** empty log message ***
 *
 * Revision 1.71  2004/07/30 13:10:50  jonyp
 * added new return for document-deleted if flag is set
 *
 * Revision 1.70  2004/07/06 14:24:43  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.69  2004/06/27 17:16:55  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.68  2004/06/02 09:16:47  jonyp
 * format things
 *
 * Revision 1.67  2004/05/24 16:46:26  jonyp
 * +hasPermission method
 *
 * Revision 1.66  2004/05/21 16:43:02  jonyp
 * added method "getAllowEditProperties"
 *
 * Revision 1.65  2004/05/07 10:15:08  jonyp
 * minor bug fixes
 *
 * Revision 1.64  2004/05/04 12:28:29  jonyp
 * getFolderImage: added image for null-document
 *
 * Revision 1.63  2004/04/26 08:56:07  jonyp
 * - changed methods "documentTypeIcon" to "documentIcon"
 * - added new method "documentTypeIcon"
 *
 * Revision 1.62  2004/04/23 13:27:24  jonyp
 * getDocumentTypeIcon: return icon if document is versioned
 *
 * Revision 1.61  2004/04/23 07:57:01  jonyp
 * + getFirstVersionDocId/getTopVersionDocId
 *
 * Revision 1.60  2004/04/16 14:07:16  jonyp
 * *** empty log message ***
 *
 * Revision 1.59  2004/04/07 15:19:32  jonyp
 * isVirtualDocument/isRealDocument
 *
 * Revision 1.58  2004/03/24 13:08:36  bigmac
 * -AclAble
 *
 * Revision 1.57  2004/03/15 13:40:03  bigmac
 * Anpassungen an PermissionManager und weitere Refactorings
 *
 * Revision 1.56  2004/03/12 15:44:16  bigmac
 * Methoden für (lokale) zusätzliche Attribute aus VKCDynAttributeSerializer 
 * nach VKCAddAttributeSerializer verschoben
 * 
 * Unbenutze private Methoden projektweit entsorgt
 *
 * Revision 1.55  2004/03/12 12:56:58  bigmac
 * Anpassungen an VKCKeywordSerializer und VKCDynaAttributeSerializer
 * und generelle Refactorings durchgeführt
 *
 * Revision 1.54  2004/03/08 16:12:24  jonyp
 * getVirtualDocumentTypeIcon
 *
 * Revision 1.53  2004/03/07 20:05:57  bigmac
 * einige Methoden aus der VKCDataBase in die entsprechenden 
 * Serializer verschoben, ein paar Refactorings durchgeführt und 
 * tote Code-Teile entfernt
 *
 * Revision 1.52  2004/03/07 13:45:46  bigmac
 * Anpassungen an VKCDocumentTypeSerializer, VKCDocumentClassSerializer, VKCDocumentStatusSerializer
 *
 * Revision 1.51  2004/03/03 08:38:59  bigmac
 * Indizierung von Dokumenten wird innerhalb einer Session durchgeführt
 *
 * Revision 1.50  2004/03/02 23:05:45  bigmac
 * Anpassungen an VKCDocumentSerializer und VKCCategorySerializer
 *
 * Revision 1.49  2004/02/26 14:54:30  koppy
 * +getDisplayName()
 *
 * Revision 1.48  2004/02/20 16:36:07  bigmac
 * +getDocumentStatus()
 *
 * Revision 1.47  2004/02/18 15:00:11  marbobo
 * + getDocumentSysLinkNoSlash() (ohne führende Slash)
 *
 * Revision 1.46  2004/02/18 14:48:01  marbobo
 * /sysLink.do anpassung
 *
 * Revision 1.45  2004/02/18 01:15:56  marbobo
 * + getDocumentLink() und getDocumentSysLink
 *
 * Revision 1.44  2004/02/16 10:14:52  bigmac
 * Parametermethoden für Struts hinzugefügt
 *
 * Revision 1.43  2004/02/15 15:36:42  bigmac
 * +getHeader()
 *
 * Revision 1.42  2004/02/09 13:14:56  bigmac
 * +getCategory()
 *
 * Revision 1.41  2004/01/16 14:24:08  koppy
 * Kleine Erweiterungen bzgl. der Konvertierung
 *
 * Revision 1.40  2004/01/05 14:53:47  lawern
 * saveDocument hat zusätzlich noch den Parameter updateStatistic bekommen.
 *
 * Revision 1.39  2003/12/17 15:44:47  bigmac
 * einige Komfortmethoden für logic-Tags hinzugefügt
 *
 * Revision 1.38  2003/12/10 14:42:59  koppy
 * Typ von archiveId geändert (Integer -->String)
 *
 * Revision 1.37  2003/11/28 17:15:55  koppy
 * saveAdditionalDocuments flag rausgenommen
 *
 * Revision 1.36  2003/10/16 07:52:53  lawern
 * Umstellung von VKCUser auf UserInfo + Code aufräumen.
 *
 * Revision 1.35  2003/09/14 20:25:22  marbobo
 * +cloneDocument() - Damit kann man das aktuelle Dokument klonen
 *
 * Revision 1.34  2003/09/09 00:33:06  marbobo
 * ungenutzte Imports entfernt und Bugfixes
 *
 * Revision 1.33  2003/09/05 12:09:07  jonyp
 * versionsbeschreibung
 *
 * Revision 1.31  2003/09/01 16:32:32  jonyp
 * *** empty log message ***
 *
 * Revision 1.30  2003/08/30 11:40:50  jonyp
 * additional attributes
 *
 * Revision 1.29  2003/08/02 16:57:12  bigmac
 * *** empty log message ***
 *
 * Revision 1.28  2003/07/31 01:20:11  koppy
 * + cutOut: boolean
 *
 * Revision 1.27  2003/07/30 12:02:55  jonyp
 * docClassId
 *
 * Revision 1.25  2003/06/17 16:03:20  koppy
 * + zipped flag
 *
 * Revision 1.24  2003/06/06 23:24:22  koppy
 * + getNl2BrDescpription()
 *
 * Revision 1.23  2003/06/03 13:22:10  jonyp
 * getKeyword(boolean withWeight)
 *
 * Revision 1.22  2003/04/25 13:46:25  koppy
 * + get/set Analyser
 *
 * Revision 1.21  2003/04/14 13:21:14  koppy
 * +hasExpired()
 *
 * Revision 1.20  2003/03/31 13:56:10  koppy
 * +getAuthorRepresentation()
 *
 * Revision 1.19  2003/03/12 11:45:11  jonyp
 * getAbsoultePath modification
 *
 * Revision 1.18  2003/03/11 14:36:46  jonyp
 * deleted getExtensionString
 *
 * Revision 1.17  2003/03/11 09:55:43  jonyp
 * getExtensionString
 *
 * Revision 1.16  2003/03/10 01:27:00  koppy
 * Anzeige/Speicherung zusätzlicher Formate eines Dokumentes
 *
 * Revision 1.15  2003/03/06 13:11:50  jonyp
 * getCategoryPath
 *
 * Revision 1.14  2003/03/03 22:53:45  koppy
 * Kleinigkeiten, bugfixes
 *
 * Revision 1.13  2003/02/27 15:28:05  jonyp
 * version_no bei documents
 *
 * Revision 1.12  2003/02/23 13:26:21  koppy
 * *** empty log message ***
 *
 * Revision 1.11  2003/02/20 16:31:54  jonyp
 * docSize bei tabelle "documents" und "additionaldocformats" neu
 *
 * Revision 1.10  2003/02/04 22:22:28  koppy
 * Bestseller feature
 *
 * Revision 1.9  2003/01/31 03:58:18  koppy
 * accessCounter bei Dokumenten + checkPermissionTag abstrahiert
 *
 * Revision 1.8  2003/01/29 03:23:40  koppy
 * ACLs + Versionierung
 *
 * Revision 1.7  2003/01/24 03:49:26  koppy
 * document version feature
 *
 * Revision 1.6  2002/12/16 20:23:15  koppy
 * Documents delete feature
 *
 * Revision 1.5  2002/11/25 11:04:47  jonyp
 * changes due to midification of table keywords: term/termdescription
 *
 * Revision 1.4  2002/11/12 15:38:16  koppy
 * +mimetype
 *
 * Revision 1.3  2002/11/10 19:27:55  koppy
 * <No Comment Entered>
 *
 * Revision 1.2  2002/11/04 02:04:31  koppy
 * long --> Integer
 *
 * Revision 1.1  2002/10/21 14:35:38  bigmac
 * *** empty log message ***
 *
 * Revision 1.2  2002/10/21 13:34:59  koppy
 * +setCategoryId()
 *
 * Revision 1.1  2002/09/16 12:13:54  koppy
 * Initial version
 *
 */

package vkc.db.entities;

import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;

import vkc.db.helper.DBHelper;
import vkc.db.serializer.VKCAclSerializer;
import vkc.db.serializer.VKCCategorySerializer;
import vkc.db.serializer.VKCDocumentSerializer;
import vkc.db.serializer.VKCDocumentStatusSerializer;
import vkc.db.serializer.VKCSysParameterSerializer;
import vkc.db.serializer.VKCUserSerializer;
import vkc.exception.DBException;
import vkc.security.PermissionManager;
import vkc.security.VKCAcl;
import vkc.server.archive.DataStoreException;
import vkc.util.CategoryUtils;
import vkc.util.HttpUtils;
import vkc.util.ObjectCloner;
import vkc.util.StringUtils;
import vkc.util.VKCCategoryAbsPath;
import vkc.util.VKCStringUtils;
import vkc.view.WebShare;
import vkc.view.bean.UserInfo;
import vkc.view.form.SysLinkForm;
import java.sql.Connection;


/**
 * Stellt ein Dokument im VKC-System dar
 *
 * @author koppy
 */
public class VKCDocument extends VKCEntity implements Serializable {
	public static final Integer STATUS_DELETED = new Integer(4);
	public static final Integer STATUS_CREATED = new Integer(0);

	public static final Integer FLAG_PUBLISHED = new Integer(0);
	public static final Integer FLAG_EXPIRED = new Integer(1);
	public static final Integer FLAG_DELETED = new Integer(2);
	public static final Integer FLAG_TOBEPUBLISHED = new Integer(3);

	private boolean cutOut = false;	

	private int ranking = 1;

	private Collection additionalDocumentFormats = new ArrayList();

	private Date creationDate = null;
	private Date expires = null;
	private Date lastAccessed;
	private Date lastChanged;
	private Date published = new Date(System.currentTimeMillis());

	private Integer accessCount = new Integer(0);
	private Integer aclId = new Integer(1);
	private Integer categoryId = null;
	private Integer docClassId = new Integer(0);
	private Integer docTypeId = new Integer(0);
	private Integer documentId = new Integer(-1);
	private Integer flag = VKCDocument.FLAG_PUBLISHED;
	private Integer langPackId = new Integer(0);
	private Integer lastAccessorId = new Integer(1);
	private Integer lastChangerId = new Integer(1);
	private Integer lockUserId = null;
	private Integer preDocId = null;
	private Integer publisherId = new Integer(1);
	private Integer status = STATUS_CREATED;
	private Integer versionNo = new Integer(1);
	private Integer versionLow = new Integer(0);
	private Integer versionHigh = new Integer(1);
	// !=null, wenn Datei mit dem ZIP-Algorithmus komprimiert, ansonsten: null
	private Integer zipped = null;

	private Long docSize = null;

	private String archiveId;
	private String authorName = "";
	private String description;
	private String name;
	private String summary;
	private String title = "";
	private String versionDescr = "";
	private String lastAccessorName = null;
	private String lastChangerName = null;
	private String publisherName = null;

	private VKCCategory category = null;

	private VKCDocumentClass documentClass = new VKCDocumentClass();
	private VKCDocumentType documentType = new VKCDocumentType();
	
	/**
	 * Konstruktor
	 */
	public VKCDocument() {
	    //Leer
	}

	public Integer getDocumentId() {
		return documentId;
	}

	public void setDocumentId(Integer i) {
		documentId = i;		
	}

	public void setCategoryId(Integer i) {
		categoryId = i;
	}

	public Integer getCategoryId() {
	    return categoryId;
	}

	public VKCCategory getCategory() throws DBException {
		if (category == null) {
		    category = VKCCategorySerializer.retrieveCategory(getCategoryId());
		}
	    
		return category;
	}

	public void setArchiveId(String s) {
		archiveId = s;
	}

	public String getArchiveId() {
		return archiveId;
	}

	public void setAuthorName(String s) {
		authorName = s;
	}

	public String getAuthorName() {
	    if (StringUtils.isEmpty(authorName)) {
			try {
                UserInfo ui = VKCUserSerializer.retrieveUserInfo(getPublisherId());
                
                if (ui != null) {
                    return ui.getFirstname() + " " + ui.getLastname();
                } else {
                    return "";
                }
			} catch (Exception e) {
				return "";
			}
	    }
	    
	    return authorName;
	}

	public void setVersionNo(Integer i) {
		versionNo = i;
	}

	public Integer getVersionNo() {
		return versionNo;
	}

	public void setVersionLow(Integer i) {
		versionLow = i;
	}

	public Integer getVersionLow() {
		return versionLow;
	}

	public void setVersionHigh(Integer i) {
		versionHigh = i;
	}

	public Integer getVersionHigh() {
		return versionHigh;
	}

	public void setStatus(Integer i) {
		status = i;
	}

	public Integer getStatus() {
		return status;
	}

	public void setFlag(Integer i) {
		flag = i;
	}

	public Integer getFlag() {
		return flag;
	}

	public String getName() {
		return name;
	}

	public void setName(String s) {
		name = s;
	}
	public String getTitle() {
		return title;
	}

	public void setTitle(String s) {
		title = StringUtils.normalize(s);
	}

	public Integer getAclId() {
		return aclId;
	}

	public void setAclId(Integer i) {
		aclId = i;
	}

//	public VKCAcl getAcl() {
//		return null;
//	}

	public void setPublisherId(Integer i) {
		publisherId = i;
	}
	
	public Integer getPublisherId() {
		return publisherId;
	}

	public String getLastAccessorName() {
    	try {
    		if (lastAccessorName == null) {
        		UserInfo ui = VKCUserSerializer.retrieveUserInfo(getLastAccessorId());
        		
        		if (ui != null) {
        			lastAccessorName = ui.getLastnameLabel();
        		} else {
        			lastAccessorName = "";
        		}
    		}
    		
    		return lastAccessorName;
    	} catch (DBException ex) {
    		return "";
    	}
	}

	public String getLastChangerName() {
    	try {
    		if (lastChangerName == null) {
        		UserInfo ui = VKCUserSerializer.retrieveUserInfo(getLastChangerId());
        		
        		if (ui != null) {
        			lastChangerName = ui.getLastnameLabel();
        		} else {
        			lastChangerName = "";
        		}
    		}
    		
    		return lastChangerName;
    	} catch (DBException ex) {
    		return "";
    	}
	}
	
	public String getPublisherName()  {
    	try {
    		if (publisherName == null) {
        		UserInfo ui = VKCUserSerializer.retrieveUserInfo(getPublisherId());
        		
        		if (ui != null) {
        		    publisherName = ui.getLastnameLabel();
        		} else {
           			publisherName = "";
        		}
    		}
    		
    		return publisherName;
    	} catch (DBException ex) {
    		return "";
    	}
	}	
	
    public VKCDocumentClass getDocumentClass() {
		return documentClass;    	
    }

	public void setDocumentClass(VKCDocumentClass dc) {
		documentClass = dc;
		docClassId = dc.getDocClassId();
	}

	public VKCDocumentType getDocumentType() {
		return documentType;
	}

	public void setDocumentType(VKCDocumentType dt) {
		documentType = dt;
		docTypeId = dt.getDocTypeId();
	}

	public Integer getLastAccessorId() {
		return lastAccessorId;
	}

	public void setLastAccessorId(Integer i) {
		lastAccessorId = i;
	}
	
	public Date getExpires() {
		return expires;
	}

	public void setExpires(Date d) {
		expires = d;
	}
	
	public Date getPublished() {
		return published;
	}

	public void setPublished(Date d) {
		published = d;
	}

	public Integer getLastChangerId() {
		return lastChangerId;
	}

	public void setLastChangerId(Integer i) {
		lastChangerId = i;
	}
	
	public Date getLastChanged() {
		return lastChanged;
	}

	public void setLastChanged(Date d) {
		lastChanged = d;
	}
	
	public Date getLastAccessed() {
		return lastAccessed;
	}

	public void setLastAccessed(Date d) {
		lastAccessed = d;
	}
	
	public String getDescription() {
		return description;
	}

	public String getNl2BrDescription(){
	    return VKCStringUtils.filterUnicodeChars(getDescription());
	}

	public void setDescription(String s) {
		description = s;
	}

	public void setDocSize(Long l) {
		docSize = l;
	}

	public Long getDocSize() {
		return docSize;
	}

	public String getFormattedDocSize(String languageId) {
		return VKCStringUtils.formatBytes(getDocSize().longValue(), languageId);
	}

	public String getSummary() {
		return summary;
	}

	public void setSummary(String s) {
		summary = s;
	}

	public Integer getAccessCount() {
		return accessCount;
	}

	public void setAccessCount(Integer i) {
		accessCount = i;
	}

	/**
	 * Liefert den InputStream des Dokumentes
	 */
	public InputStream getInputStream() throws DataStoreException {
		return WebShare.archive.getInputStream(getArchiveId().toString());
	}

	/**
	 * Gibt alle Versionen dieses Dokumentes als Vektor zurück
	 *
	 * @return alle Versionen zu diesem Dokument
	 * @throws DBException
	 */
	public Collection getAllVersions() throws DBException {
		Collection allVersions = new ArrayList();

		// Dieses Dokument selbst
		allVersions.add(this);

		if (getPreDocId() != null) {
			// Weitere Versionnen, falls vorhanden
			Integer currentPreDocId = getPreDocId();
			
			while (currentPreDocId != null) {
				VKCDocument preDoc = VKCDocumentSerializer.retrieveDocument(currentPreDocId);
				allVersions.add(preDoc);
				currentPreDocId = preDoc.getPreDocId();
			}
		}

		return allVersions;
	}

	/**
	 * find out currently first document of the version chain (id of the top document)
	 * @return: docId of the currently first document of the version chain
	 */
	public Integer getTopVersionDocumentId() throws DBException {
		if (!isTopVersion()) {
			// call method with documentId, so that method starts looking up preDocId of the documents!
			return VKCDocumentSerializer.getTopVersionDocId(getDocumentId());
		}
		
        return getDocumentId();
	}

	/**
	 * find out currently first document of the version chain (id of the top document)
	 * @return: docId of the currently first document of the version chain
	 */
	public Integer getPredecessorVersionDocumentId() {
        return getPreDocId();
	}
	
	/**
	 * find out currently first document of the version chain (id of the top document)
	 * @return: docId of the currently first document of the version chain
	 */
	public Integer getSuccessorVersionDocumentId() throws DBException {
	    if (!isTopVersion()) {
	        return VKCDocumentSerializer.getSuccessorVersionDocId(getDocumentId());
	    }
	    
	    // no successor
	    return null;
	}
	
	/**
	 * find out currently top document of the version chain (id of the top document)
	 * @return: docId of the currently first document of the version chain
	 */
	public Integer getFirstVersionDocumentId() throws DBException {
		if (!isFirstVersion()) {
            // call method with documentId, so that method starts looking up preDocId of the documents!
			return VKCDocumentSerializer.getFirstVersionDocId(getDocumentId());
		}
	
		return getDocumentId();
	}
	
	/**
	 * checks wether this document is currently top of the version chain (top)
	 * @return: true:  yes
	 *          false: no
	 */
	public boolean isTopVersion() throws DBException {
		if (getDocumentId().equals(VKCDocumentSerializer.getTopVersionDocId(getDocumentId()))) {
			return true;		
		}
	    
		return false;
	}

	/**
	 * checks wether this document is currently first of the version chain
	 * @return: true:  yes
	 *          false: no
	 */
	public boolean isFirstVersion() {
		if (getPreDocId() == null || getPreDocId().intValue() == 0) {
			return true;		
		}
	    
		return false;
	}

	public String toString() {
		return getName() + ", " + getPublished() + ", PublisherId=" + getPublisherId();
	}

	public Integer getDocTypeId() {
		return docTypeId;
	}
	
	public void setDocTypeId(Integer i) {
		docTypeId = i;
	}

	public Integer getDocClassId() {
		return docClassId;
	}
	
	public void setDocClassId(Integer i) {
		docClassId = i;
	}

	public void debug() {
		System.out.println("documentId=" + getDocumentId());
		System.out.println("archiveId=" + getArchiveId());
		System.out.println("publisherId=" + getPublisherId());
		System.out.println("docTypeId=" + getDocTypeId());
		System.out.println("published=" + getPublished());
		System.out.println("expires=" + getExpires());
	}
	
	public Integer getPreDocId() {
		return preDocId;
	}
	
	public void setPreDocId(Integer i) {
		preDocId = i;
	}
	
	public int getRanking() {
		return ranking;
	}
	
	public void setRanking(int i) {
		ranking = i;
	}

	public Collection getAdditionalDocumentFormats() {
		return additionalDocumentFormats;
	}

	public boolean addAdditionalDocumentFormat(VKCAdditionalDocumentFormat df) {
		return additionalDocumentFormats.add( df );
	}
	public void setAdditionalDocumentFormats(Collection adf) {
		additionalDocumentFormats = adf;
	}

	public VKCCategoryAbsPath getCategoryPath() throws DBException {
		Connection conn = null;
		
		try {
			conn = WebShare.database.getConnection();
			
			return getCategoryPath(conn);
		} finally {
			DBHelper.close(conn);
		}
	}
	
	public VKCCategoryAbsPath getCategoryPath(Connection conn) throws DBException {
		return VKCCategorySerializer.getCategoryAbsPath(getCategoryId(), conn);
	}

	/**
	 * Checks whether this document has expired or not
	 *
	 * @return true if document has expired, otherwise false
	 */
	public boolean hasExpired() {
		//Assert.notNull( flag );
		if (getExpires() == null) {
			return false;
		}
		
		if (VKCDocument.FLAG_EXPIRED.equals(getFlag())) {
			return true;
		}
		
		return getExpires().before(new Date(System.currentTimeMillis()));
	}

	public boolean equals(Object o){
		if (!(o instanceof VKCDocument)) {
			return false;
		}
		
		if (getDocumentId() == null) {
			return false;
		}
		
		return getDocumentId().equals(((VKCDocument)o).getDocumentId());
	}

	public int hashCode(){
		if (getDocumentId() == null) {
			return new Integer(-1).hashCode();
		}

		return getDocumentId().hashCode();
	}

	public void setZipped(Integer i) {
        zipped = i;
    }

    public Integer getZipped() {
	    return zipped;
    }
    
    public void setLangPackId(Integer i) {
    	langPackId = i;
    }
    
    public Integer getLangPackId() {
        return langPackId;	
    }
    
	public Integer getLockUserId() {
		return lockUserId;
	}

	public void setLockUserId(Integer i) {
		lockUserId = i;
	}
	
	public boolean getCutOut() {
		return cutOut;
	}

	public void setCutOut(boolean b) {
		cutOut = b;
	}	

	public String getVersionDescr() {
		return versionDescr;
	}

	public void setVersionDescr(String s) {
		versionDescr = s;
	}

	public VKCDocument cloneDocument() throws Exception {
		VKCDocument doc = (VKCDocument) ObjectCloner.deepCopy(this);

		return doc;
	}

	public final boolean isLink() {
		return "LINK".equals(getDocumentType().getExtension());
	}

	public final boolean isNote() {
		return "NOTE".equals(getDocumentType().getExtension());
	}

	public final boolean isFile() {
		return !isNote() && !isLink();
	}
	
	public boolean isTitleEmpty() {
		return StringUtils.isEmpty(getTitle());		
	}

	public VKCDocumentStatus getDocumentStatus() {
		return VKCDocumentStatusSerializer.getDocumentStatus(getStatus());
	}

    /**
     * Methode liefert die "Überschrift" für einen Dokumenteintrag
     * auf den JSP-Seiten
     * @return
     */
    public String getHeader() {
        if (isTitleEmpty()) {
            return getName();
        } 

        return getTitle();
    }
    
    public boolean isEditable(){
        if (getDocumentType() != null && getDocumentType().isEditable()) {
        	return true;
        }
        
        return false;
    }
    
    
	public String getDocumentIcon() throws NumberFormatException, DBException {
        if (VKCDocument.FLAG_TOBEPUBLISHED.equals(getFlag())) {
            return "/gfx/document-tobepublished.gif";
        }
        
        if (Integer.parseInt(VKCSysParameterSerializer.retrieveValue("DOCUMENT", "EnableMultiIcon", "0")) != 0) {
	        if (getDocumentType() != null) {
	            String imgPath = getDocumentType().getImgPath();
	            
	            if (getPreDocId() != null && getPreDocId().intValue() > 0) {
	                imgPath += VKCDocumentType.DELIMITER + VKCDocumentType.VERSION;
	            }
	            
	            imgPath += VKCDocumentType.POINT + getDocumentType().getIconExtension();
	            
	            return imgPath;
	        }
        }
        
        if (getPreDocId() != null && getPreDocId().intValue() > 0) {
            return "/gfx/documents.gif";
        }
        
        return "/gfx/document.gif";
    }
	
	public String getDocumentIconShaded() throws NumberFormatException, DBException {
        if (VKCDocument.FLAG_TOBEPUBLISHED.equals(getFlag())) {
            return "/gfx/document-tobepublished-shaded.gif";
        }
        
        if (Integer.parseInt(VKCSysParameterSerializer.retrieveValue("DOCUMENT", "EnableMultiIcon", "0")) != 0){
	        if (getDocumentType() != null) {
	            String imgPath = getDocumentType().getImgPath();
	            
	            if (getPreDocId() != null && getPreDocId().intValue() > 0) {
	                imgPath += VKCDocumentType.DELIMITER + VKCDocumentType.VERSION;
	            }
	            
	            imgPath += VKCDocumentType.DELIMITER + VKCDocumentType.SHADED;
	            imgPath += VKCDocumentType.POINT + getDocumentType().getIconExtension();
	            
	            return imgPath;
	        }
        }

        if (getPreDocId() != null && getPreDocId().intValue() > 0) {
            return "/gfx/documents-shaded.gif";
        }
        
        return "/gfx/document-shaded.gif";
    }
		
	public String getVirtualDocumentIcon() throws NumberFormatException, DBException {
        if (VKCDocument.FLAG_TOBEPUBLISHED.equals(getFlag())) {
            return "/gfx/document-tobepublished.gif";
        }
        
        if (Integer.parseInt(VKCSysParameterSerializer.retrieveValue("DOCUMENT", "EnableMultiIcon", "0")) != 0){
	        if (getDocumentType() != null) {
	            String imgPath = getDocumentType().getImgPath() + VKCDocumentType.DELIMITER + VKCDocumentType.VIRTUAL;
	            
	            if (getPreDocId() != null && getPreDocId().intValue() > 0) {
	                imgPath += VKCDocumentType.DELIMITER + VKCDocumentType.VERSION;
	            }
	            
	            imgPath += VKCDocumentType.POINT + getDocumentType().getIconExtension();
	            
	            return imgPath;
	        }
        }
        
        if (getPreDocId() != null && getPreDocId().intValue() > 0) {
            return "/gfx/documents-virtual.gif";
        }
        
        return "/gfx/document-virtual.gif";
    }
		
    public HashMap getEditLinkParams() {
		HashMap params = new HashMap();
		params.put("documentId", getDocumentId());
		params.put("docType", getDocumentType().getExtension());
		params.put("init", "true");

		return params;
    }

	public HashMap getNewVersionLinkParams() {
		HashMap params = new HashMap();
		params.put("newDocumentPreDocId", getDocumentId());
		params.put("categoryId", categoryId);

		return params;
	}
	
	public HashMap getDeleteLinkParams() {
		HashMap params = new HashMap();
		params.put("action.delete.document", "true");
		params.put("categoryId", getCategoryId());
		params.put("documentId", getDocumentId());

		return params;
	}
	
	public HashMap getRegisterLinkParams() {
		HashMap params = new HashMap();
		params.put("action.register.document", "true");
		params.put("categoryId", getCategoryId());
		params.put("documentId", getDocumentId());

		return params;
	}
	
	public HashMap getSearchRelatedLinkParams() {
		HashMap params = new HashMap();
		params.put("categoryId", getCategoryId());
		params.put("documentId", getDocumentId());

		return params;
	}

	public String getDocumentLink() {
		if (getDocumentId().intValue() != -1 && getCategoryId() != null) {
			return "/showCategory.do?categoryId=" + getCategoryId().intValue() + "&anchor=doc" + getDocumentId().intValue();
		} 

		return "";
	}
	
	public String getDocumentSysLink() {
		if (getDocumentId().intValue() != -1 && getCategoryId() != null) {
			return SysLinkForm.getDocumentSysLink(getDocumentId(), null);
		} 

		return "";
	}

	public String getDocumentSysLinkNoSlash() {
		if (getDocumentId().intValue() != -1 && getCategoryId() != null) {
			return SysLinkForm.getDocumentSysLinkNoSlash(getDocumentId(), null);
		} 

		return "";
	}
	
	public String getDocumentOpenSysLink() {
		if (getDocumentId().intValue() != -1 && getCategoryId() != null) {
			return SysLinkForm.getDocumentOpenSysLink(getDocumentId(), null);
		} 

		return "";
	}

	public String getDocumentOpenSysLinkNoSlash() {
		if (getDocumentId().intValue() != -1 && getCategoryId() != null) {
			return SysLinkForm.getDocumentOpenSysLinkNoSlash(getDocumentId(), null);
		} 

		return "";
	}

	public String getDisplayName() {
		if (!getName().startsWith("http://") && !getName().startsWith("https://") && !getName().startsWith("ftp://")) {
			return getName();
		}
			
		try {
			return HttpUtils.url2filename(new URL(getName()));
		} catch (MalformedURLException e) {
			return e.getMessage();
		}
	}
	
	public String getDisplayURI() throws UnsupportedEncodingException{
	    return StringUtils.replaceToken(
	            "/display/" + getDocumentId() + "/" + URLEncoder.encode(getDisplayName(), "ISO-8859-1"),
	            "%2F", "/");
	}
	
	public boolean hasPermission(VKCUser user, char permToken) throws DBException {
		if (getCategoryId() != null) {
			if (!user.hasAdminPrivileges()) {
				VKCAcl acl = VKCAclSerializer.getAclByCategoryId(getCategoryId());

				return PermissionManager.hasPermission(acl, user, permToken);
			}

			return true;
		}

		return false;
	}
	
	public boolean isVirtualDocument(Integer pageCategoryId) {
		if (getCategoryId().equals(pageCategoryId)) {
			return false;	
		} 

		return true;
	}
	
	public boolean isRealDocument(Integer pageCategoryId) {
	    return !isVirtualDocument(pageCategoryId);
	}

	public Date getCreationDate() {
		return creationDate;
	}

	public void setCreationDate(Date creationDate) {
		this.creationDate = creationDate;
	}

	public boolean isInTrash() {
	    try {
            return CategoryUtils.isInTrash(getCategoryId());
        } catch (DBException e) {
            return false;
        }
	}
}