/*
 * $Id: WebShare.java,v 1.131 2007/10/23 07:53:33 korowa Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: WebShare.java,v $
 * Revision 1.131  2007/10/23 07:53:33  korowa
 * MigrationLog hinzugefügt
 *
 * Revision 1.130  2007/08/01 14:56:51  marbobo
 * + WebDav-Logging implementiert
 * - Sessionbegrenzung wird nicht mehr auf WebDav angewendet
 *
 * Revision 1.129  2007/02/06 13:04:25  korowa
 * Ein Job hinzugefügt der die Überfählige Sessions entfernt
 *
 * Revision 1.128  2006/12/22 11:05:45  lawern
 * Prioritäten der Mail-Threads auf Minimum gesetzt.
 *
 * Revision 1.127  2006/10/04 03:14:52  marbobo
 * + Vollständige Unterstützung für Templates implementiert
 * + Alles von Virtoweb auf ProCoBa umgestellt
 *
 * Revision 1.126  2006/09/14 11:09:22  lawern
 * Versionsnummer entfernt
 *
 * Revision 1.125  2006/09/07 01:54:03  marbobo
 * + TabIds überarbeitet
 *
 * Revision 1.124  2006/08/28 13:17:22  marlin
 * Shark / axis stuff disabled
 *
 * Revision 1.123  2006/07/28 12:24:51  lawern
 * WebDAV überarbeitet.
 *
 * Revision 1.122  2006/07/20 21:58:19  marbobo
 * + existCategory erweitert
 *
 * Revision 1.121  2006/07/17 13:04:03  lawern
 * Neuer typografiegewichteter Index und k-NN-Klassifikation aus meiner Diss.
 *
 * Revision 1.120  2006/06/13 01:51:15  marbobo
 * + Bugfix
 *
 * Revision 1.119  2006/02/27 16:16:10  marbobo
 * + Systemsichten hinzugefügt
 * + SysLinks angepasst
 * + Benutzer können falls gewünscht Dokumentqueries anlegen
 *
 * Revision 1.118  2006/01/20 12:45:18  korowa
 * *** empty log message ***
 *
 * Revision 1.117  2005/09/05 22:52:40  marbobo
 * + isTrashEnabled() liefert nur noch dann true wenn auch die TrashKategorie existiert
 *
 * Revision 1.116  2005/09/04 18:05:49  marbobo
 * + Neues Metadaten-Attribute (Erstellungsdatum) für Dokumente hinzugefügt
 *
 * Revision 1.115  2005/08/30 14:35:31  jonyp
 * added setTrashCategory method
 *
 * Revision 1.114  2005/08/26 15:00:56  jonyp
 * *** empty log message ***
 *
 * Revision 1.113  2005/08/25 01:45:24  marbobo
 * + Permanente Registerkarten hinzugefügt
 *
 * Revision 1.112  2005/08/24 13:42:31  marbobo
 * + Permanente Parameter hinzugefügt
 *
 * Revision 1.111  2005/08/19 15:11:28  jonyp
 * *** empty log message ***
 *
 * Revision 1.110  2005/08/18 11:10:40  korowa
 * Das Aussehen von Icons kann jetzt auf die frühere Version umgestellt werden
 *
 * Revision 1.109  2005/08/16 10:54:38  korowa
 * Das Aussehen von Icons kann jetzt auf die frühere Version umgestellt werden
 *
 * Revision 1.108  2005/06/29 21:15:50  marbobo
 * + Clustern ist nun aktivierbar/deaktivierbar
 *
 * Revision 1.107  2005/06/15 12:09:51  jonyp
 * + getTrashCategory
 *
 * Revision 1.106  2005/04/21 13:13:12  marbobo
 * + Kontextpfad angepasst
 *
 * Revision 1.105  2005/03/10 11:01:05  jonyp
 * added getDbPathInfo method
 *
 * Revision 1.104  2005/02/14 14:01:55  bigmac
 * Applikationsweites CSS konfigurierbar gemacht + Refactorings
 *
 * Revision 1.103  2005/02/10 12:30:19  marbobo
 * + Keywordstrenner auf "," umgestellt
 *
 * Revision 1.102  2005/02/10 01:09:38  marbobo
 * + Keywordstrenner geändert (sonst konflikte mit XML-Entities z.B. &#8364;)
 *
 * Revision 1.101  2005/01/20 15:25:53  marbobo
 * + Anpassungen an den Methoden getRootURL() und getContextName()
 *
 * Revision 1.100  2005/01/07 08:59:40  jonyp
 * deleted listtitles property of CategorySettings class
 *
 * Revision 1.99  2004/12/22 14:24:27  jonyp
 * added display of contextpath
 *
 * Revision 1.98  2004/11/24 09:53:39  lawern
 * Versehentliches einchecken mit HashStoreKeeper-Size von 1005 korrigiert.
 *
 * Revision 1.97  2004/11/24 09:25:59  lawern
 * Hibernate ist VKC-Geschichte!
 *
 * Revision 1.96  2004/11/23 13:07:10  jonyp
 * configureLogger: call VKCSysParameterSerializer with default values
 *
 * Revision 1.95  2004/11/23 12:58:16  jonyp
 * get/setSysParameterValue() ==> check if sysparameters != null
 *
 * Revision 1.94  2004/11/18 13:43:37  koppy
 * DB-Konnektivitätscheck bei der Initialisierung
 *
 * Revision 1.93  2004/11/15 16:04:01  jonyp
 * changed "file:/" to new File(...).toUrl.toString in configure datastore to get it independent of the OS
 *
 * Revision 1.92  2004/11/10 15:02:48  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.91  2004/10/28 19:40:37  marbobo
 * + getLoginPage() - Liefert die gewählte Loginseite
 *
 * Revision 1.90  2004/10/25 13:28:18  koppy
 * Priorität des Server-Threads geändert
 *
 * Revision 1.89  2004/10/18 10:18:17  marbobo
 * VKCPublisher-Thread zur init()-Methode hinzugefügt
 *
 * Revision 1.88  2004/10/13 11:32:50  marbobo
 * Datastorage-Verzeichnisanzahl auf 1000 gesetzt
 *
 * Revision 1.87  2004/10/08 14:54:38  jonyp
 * added support of MarkHiddencategories in "getCategorySettings"
 *
 * Revision 1.86  2004/09/05 19:13:51  marbobo
 * + getRootURLEndsWithNoSlash()
 *
 * Revision 1.85  2004/08/23 15:58:48  jonyp
 * initSearch/Classify move to public methods
 *
 * Revision 1.84  2004/08/23 10:51:06  bigmac
 * +Konfiguration SOAPMessageLogHandler
 *
 * Revision 1.83  2004/08/20 12:57:15  koppy
 * + Initialisierung des UserDocPopulators
 *
 * Revision 1.82  2004/07/22 22:15:28  marbobo
 * + TEMP_USER_KEY hinzugefügt (nötig für Newsanzeigen beim Einlogen)
 *
 * Revision 1.81  2004/07/15 12:38:44  jonyp
 * + hold a local (cached) copy of sysparameters
 * + get/set mothod to sysparameter cache
 *
 * Revision 1.80  2004/07/14 10:51:28  jonyp
 * *** empty log message ***
 *
 * Revision 1.79  2004/07/13 14:47:42  jonyp
 * added garbage collector functionality via thread
 *
 * Revision 1.78  2004/06/22 13:20:20  lawern
 * Classify auf das Interface Classifier umgestellt.
 *
 * Revision 1.77  2004/06/04 09:19:14  jonyp
 * added functionality for new parameter "DisplayEmptyFolderWithEmptyIcon"
 *
 * Revision 1.76  2004/05/28 11:09:14  jonyp
 * added display of vkc version during startup/shutdown
 *
 * Revision 1.75  2004/05/28 10:40:53  jonyp
 * added VKC404Serializer statements to track server avaliability
 *
 * Revision 1.74  2004/05/24 16:49:44  jonyp
 * added comment for code for availiabilities
 *
 * Revision 1.73  2004/05/12 14:31:03  jonyp
 * *** empty log message ***
 *
 * Revision 1.72  2004/05/11 15:54:22  jonyp
 * changes due to traceLogger things
 *
 * Revision 1.71  2004/05/10 16:03:03  jonyp
 * LOGIN_PAGE_KEY
 *
 * Revision 1.70  2004/04/29 18:55:31  marbobo
 * getDocumentViewSettings() wegen Serializer angepasst
 *
 * Revision 1.69  2004/04/27 11:43:06  koppy
 * Initialisierung nach WebShare verschoben
 *
 * Revision 1.68  2004/04/26 21:59:27  marbobo
 * + Dokumentsicht erweitert (mit/ohne Details)
 *
 * Revision 1.67  2004/04/01 09:39:53  jonyp
 * key for capture/restore Account
 *
 * Revision 1.66  2004/03/30 20:31:25  marbobo
 * Unbenutzte Variablen entsorgt
 *
 * Revision 1.65  2004/03/30 14:02:06  bigmac
 * *** empty log message ***
 *
 * Revision 1.64  2004/03/24 14:23:06  bigmac
 * Anpassungen an categorySettings
 *
 * Revision 1.63  2004/03/15 10:34:47  bigmac
 * VKCAclManager entfernt
 *
 * Revision 1.62  2004/03/12 15:44:18  bigmac
 * Methoden für (lokale) zusätzliche Attribute aus VKCDynAttributeSerializer 
 * nach VKCAddAttributeSerializer verschoben
 * 
 * Unbenutze private Methoden projektweit entsorgt
 *
 * Revision 1.61  2004/03/09 18:40:37  bigmac
 * Anpassungen an VKCSysParameterSerializer
 *
 * Revision 1.60  2004/03/07 13:45:49  bigmac
 * Anpassungen an VKCDocumentTypeSerializer, VKCDocumentClassSerializer, VKCDocumentStatusSerializer
 *
 * Revision 1.59  2004/03/05 14:52:04  teng
 * VKCDocExpireMail und VKCDocDeleteMail werden durch vkc.messenger.mail.DocExpiredNotification und DocDeleteNotification ersetzt
 *
 * Revision 1.58  2004/03/02 23:05:48  bigmac
 * Anpassungen an VKCDocumentSerializer und VKCCategorySerializer
 *
 * Revision 1.57  2004/02/25 08:37:29  bigmac
 * WebShare.properties -> WebShare.getProperties()
 *
 * Revision 1.56  2004/02/20 20:13:55  teng
 * VKCDocPublishMail wird durch vkc.messenger.mail.DocPublishNotification ersetzt
 *
 * Revision 1.55  2004/02/20 16:32:41  bigmac
 * Anpassungen bzgl. Dokumentstati und Dokumentklassen
 *
 * Revision 1.54  2004/02/18 14:50:24  marbobo
 * /sysLink.do anpassung
 *
 * Revision 1.53  2004/02/09 13:21:20  bigmac
 * +getCategoryInfo()
 * - CATEGORY_KEY
 *
 * Revision 1.52  2004/01/27 10:44:55  bigmac
 * + getWebApplicationDir(), setWebApplicationDir()
 *
 * Revision 1.51  2003/12/17 10:52:00  bigmac
 * TraceLogger eingefügt
 *
 * Revision 1.50  2003/12/16 12:55:05  bigmac
 * getRootURL() hinzugefügt
 *
 * Revision 1.49  2003/12/02 17:12:58  koppy
 * bugfix in retreiveSysparameter(...)
 *
 * Revision 1.48  2003/11/28 15:05:31  jonyp
 * changes due to new schema
 *
 * Revision 1.47  2003/11/27 17:07:37  teng
 * neue Funktionen:
 * registerSysParameterManager() und getSysParameterManager()
 *
 * Revision 1.46  2003/11/27 15:42:50  teng
 * auskommentierte vkcmail weg
 *
 * Revision 1.45  2003/11/21 14:19:46  bigmac
 * Usertracking erweitert
 *
 * Revision 1.44  2003/11/12 16:31:35  bigmac
 * Usertracking überarbeitet
 *
 * Revision 1.43  2003/11/01 00:38:25  marbobo
 * + für eingeloggte Benutzer Anmeldezeitpunkt speichern
 *
 * Revision 1.42  2003/10/31 17:53:47  marbobo
 * + Eingeloggte Benutzer speichern (modifiziert)
 *
 * Revision 1.41  2003/10/31 10:32:14  bigmac
 * *** empty log message ***
 *
 * Revision 1.40  2003/10/23 12:56:01  marbobo
 * +VKC_ROOT_PATH
 *
 * Revision 1.39  2003/10/19 18:20:12  teng
 * VKCMail, DocExpireMail aus, VKCDocPublishMail, VKCDocExpireMail, VKCDocDeleteMail ein
 *
 * Revision 1.38  2003/10/01 11:11:26  jonyp
 * default value function bei getSysParameterValue
 *
 * Revision 1.37  2003/09/18 07:55:41  jonyp
 * setSysParameterValue
 *
 * Revision 1.36  2003/09/17 12:57:37  marbobo
 * Key für Nachrichten ingefügt
 *
 * Revision 1.35  2003/09/17 08:26:25  jonyp
 * WebShare.getSysParemterValue mit neuer Signatur
 *
 * Revision 1.34  2003/09/11 10:00:41  jonyp
 * defensive programming: getSysParameterValue asks for ""
 *
 * Revision 1.33  2003/09/09 14:10:33  jonyp
 * datatype bei sysparameters
 *
 * Revision 1.32  2003/09/08 16:59:04  marbobo
 * *** empty log message ***
 *
 * Revision 1.31  2003/09/02 17:58:07  teng
 * neue statische Variable fuer DocExpireMail
 *
 * Revision 1.30  2003/08/17 23:46:51  marbobo
 * +EDIT_USERNAME_KEY
 *
 * Revision 1.29  2003/08/05 15:06:30  bigmac
 * *** empty log message ***
 *
 * Revision 1.28  2003/08/02 16:13:37  bigmac
 * *** empty log message ***
 *
 * Revision 1.27  2003/07/18 14:14:02  teng
 * Die Variable fuer OpenOffice ist weg.
 *
 * Revision 1.26  2003/07/18 13:36:42  teng
 * Variable sofficeProcess fuer den OpenOffice-Prozess
 *
 * Revision 1.25  2003/07/12 13:59:57  koppy
 * + CLIPBOARD_KEY
 *
 * Revision 1.24  2003/05/26 16:05:21  koppy
 * aufgeräumt
 *
 * Revision 1.23  2003/05/22 00:02:53  koppy
 * + ZIPTEMP
 *
 * Revision 1.22  2003/04/03 13:46:26  bigmac
 * *** empty log message ***
 *
 * Revision 1.21  2003/03/10 01:26:46  koppy
 * Anzeige/Speicherung zusätzlicher Formate eines Dokumentes
 *
 * Revision 1.20  2003/03/05 17:11:41  teng
 * package of VKCMail.java changed
 *
 * Revision 1.19  2003/03/03 22:53:40  koppy
 * Kleinigkeiten, bugfixes
 *
 * Revision 1.18  2003/03/03 14:10:00  koppy
 * Init. von VKCMail nach StartupServlet verlagert
 *
 */

package vkc.view;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;

import javax.servlet.http.HttpSession;

import org.apache.struts.util.MessageResources;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;

import vkc.analyse.Analyser;
import vkc.db.VKCDatabase;
import vkc.db.VKCDatabaseManager;
import vkc.db.entities.VKCSysParameter;
import vkc.db.entities.VKCCategory;
import vkc.db.helper.DBHelper;
import vkc.db.serializer.VKC404Serializer;
import vkc.db.serializer.VKCDocumentViewFieldSerializer;
import vkc.db.serializer.VKCSysParameterSerializer;
import vkc.db.serializer.VKCCategorySerializer;
import vkc.db.serializer.VKCTabViewSerializer;
import vkc.exception.DBException;
import vkc.messenger.mail.DocDeleteNotification;
import vkc.messenger.mail.DocExpiredNotification;
import vkc.messenger.mail.DocPublishNotification;
import vkc.messenger.mail.UserDocMailsPopulator;
import vkc.misc.VKCLogManager;
import vkc.search.Classifier;
import vkc.search.IndexInitializer;
import vkc.search.Search;
import vkc.server.VKCServer;
import vkc.server.archive.DataStore;
import vkc.server.archive.DataStoreException;
import vkc.server.archive.FileDataStore;
import vkc.server.archive.HashStoreKeeper;
import vkc.server.jobs.DatastoreCleaningJob;
import vkc.server.jobs.GarbageCollectionJob;
import vkc.server.jobs.PublishingJob;
import vkc.server.jobs.SessionCleaningJob;
import vkc.util.CategoryUtils;
import vkc.util.DateUtils;
import vkc.util.PropertyUtils;
import vkc.util.StringUtils;
import vkc.util.TraceLogger;
import vkc.util.treeview.TreeViewManager;
import vkc.view.bean.CategorySettings;
import vkc.view.bean.DocumentViewSettings;
import vkc.view.bean.TabInfo;
import vkc.view.bean.UserTrackingInfo;
//import vkc.ws.axis.handler.SOAPMessageLogHandler;

/**
 * Sammelklasse für die Konfiguration
 * der Webapplikation.
 * Sämtliche Initialisierungen finden in vkc.servlets.StartupServlet statt.
 *
 * @see vkc.servlets.StartupServlet
 * @koppy
 */
public class WebShare {
	// Referenz auf die VKCDatenbank
    public static VKCDatabase database = null;

	public static DocPublishNotification docPublishMail = null;
	public static DocExpiredNotification docExpireMail = null;
	public static DocDeleteNotification docDeleteMail = null;
	
	public static MessageResources resources = null;
	
    // Referenz auf das Archiv
    public static DataStore archive = null;
    
    // Referenz auf den Classifier
    public static Classifier classifier = null;

    public static Scheduler scheduler = null;
    
	public static String VKC_ROOT_PATH = "";

    public static final String LOGIN_PAGE       = "/common/Login.jsp";
	public static final String HOME_PAGE        = "/index.jsp";

    // Keys for Beans
	public static final String LOGIN_PAGE_KEY   = "loginPage";
    public static final String USER_KEY         = "bean.user";
	public static final String PREV_USER_KEY    = "bean.prev_user";
	public static final String TEMP_USER_KEY    = "bean.temp_user";
	public static final String USER_TRACKING_KEY = "bean.user.tracking";
    public static final String LOCALE_KEY       = org.apache.struts.Globals.LOCALE_KEY;
    public static final String REFERER_KEY      = "login.referer";
    public static final String TEMPLATE_KEY     = "template";
    public static final String INFO_KEY         = "vkcinfo";
	public static final String MESSAGE_KEY      = "vkcmessage";
    public static final String DOCTYPES_KEY     = "hashmap.docTypes";
	public static final String CLIPBOARD_KEY    = "clipboard";
	public static final String RELATED_DOCUMENTS_KEY = "related.documents";
	public static final String DOCUMENT_KEY     = "selected.document";
	public static final String SYSTEMVIEWTYPEID_KEY = "bean.systemViewTypeId";

    // contains all application relevant properties
    private static final Properties properties = new Properties();

    // Misc.
    public static final String KEYWORDS_DELIMITER = ",";
    public static final String GROUPS_DELIMITER = ";";
    public static final String DEFAULT_TEMPLATE = "default";
    public static final long DEFAULT_EXPIRATION_TIME = 3600*24*1000*28; // 4 Weeks

	// TemplateUrl typen
	public static final int TEMPLATEURL_MAIL 			= 0;
	public static final int TEMPLATEURL_EXPDOC 			= 1;
	public static final int TEMPLATEURL_DELDOC 			= 2;
	public static final int TEMPLATEURL_NEWUSER 		= 3;
	public static final int TEMPLATEURL_CHANGEPASSWORD	= 4;

	// HashSet enthält die UserTrackingInfos der z.Zt. angemeldeten User
	private static HashSet activeUsers = new HashSet();

	private static TraceLogger traceLogger = null;

	private static File webApplicationDir = null;
	
	private static VKCServer server = null;

	// contains permanent sysparameters
    private static HashMap permanentSystemParameters = null;
    
	// contains permanent tabViews
    private static HashMap permanentTabViews = null;
    
    // context path
    private static String contextPath = null;
    
    // Context-relative path of the applicarion-wide CSS
    private static String applicationCss = "/templates/${template.name}/vkc.css";
    
    // trash category 
    private static VKCCategory trashCategory = null;
    

   
	/**
	 * Method returns the (absolute) root URL (only Hostname without Contextname) 
	 * of the current web application. It is guaranteed that the returned URL ends
	 * without a slash.
	 * <p>
	 * @return webapplication root URL (only Hostname without Contextname)
	 */
	public final static String getRootURL() {
		return VKCSysParameterSerializer.getRootURL();
	}

	public static void addActiveUser(UserTrackingInfo bean) {
		synchronized(activeUsers) {
			if (!activeUsers.contains(bean)) {
				activeUsers.add(bean);
			}
		}
	}

	public static void removeActiveUser(UserTrackingInfo bean) {
		synchronized(activeUsers) {
			activeUsers.remove(bean);
		}
	}

	public static UserTrackingInfo[] getActiveUsers() {
		synchronized(activeUsers) {
			return (UserTrackingInfo[])activeUsers.toArray(new UserTrackingInfo[0]);
		}
	}

	public static HttpSession getSession(String id) {
		synchronized(activeUsers) {
			for (Iterator iter = activeUsers.iterator(); iter.hasNext();) {
				UserTrackingInfo info = (UserTrackingInfo)iter.next();
				
				if (info.getSessionId().equals(id)) {
					return info.getSession();
				}
			}
		}
		
		return null;
	}

	public static TraceLogger getTraceLogger() {
		return traceLogger;
	}

	public static void setTraceLogger(TraceLogger logger) {
		traceLogger = logger;
	}

	public static File getWebApplicationDir() {
		return webApplicationDir;
	}

	public static void setWebApplicationDir(File file) {
		webApplicationDir = file;
	}
	
	public static final CategorySettings getCategorySettings() {
		CategorySettings conf = new CategorySettings();

		try {
			conf.setCountCatDocsEnabled(VKCSysParameterSerializer.retrieveIntValue("CATEGORYVIEW", "EnableCountCatDocs", 0) != 0);
			conf.setListAccessibleCategoriesOnly(VKCSysParameterSerializer.getListAccessibleCategoriesOnly());
			conf.setShowClusterCategory(VKCSysParameterSerializer.retrieveIntValue("CATEGORYVIEW", "EnableClusterCategory", 0) != 0);
			conf.setShowDisplayAscii(VKCSysParameterSerializer.retrieveIntValue("CATEGORYVIEW", "ShowDisplayAscii", 1) != 0);
			conf.setDisplayEmptyFoldersWithEmptyIcon(VKCSysParameterSerializer.retrieveIntValue("CATEGORYVIEW", "DisplayEmptyFoldersWithEmptyIcon", 0) != 0);
			conf.setMarkForbiddenCategories(VKCSysParameterSerializer.retrieveIntValue("CATEGORYVIEW", "MarkForbiddenCategories", 0) != 0);
			conf.setShowDocumentStatus(VKCSysParameterSerializer.retrieveIntValue("DOCUMENT", "EnableDocumentStatusCoverage", 0) != 0);
			conf.setShowDocumentClass(VKCSysParameterSerializer.retrieveIntValue("DOCUMENT", "EnableDocumentClassCoverage", 0) != 0);
			conf.setShowArchiveCategory(VKCSysParameterSerializer.retrieveIntValue("ARCHIVECATEGORY", "EnableArchiveCategory", 0) != 0);
			conf.setFunctionalViewRootId(new Integer(VKCSysParameterSerializer.retrieveIntValue("FUNCTIONALVIEW", "FunctionalViewRootCategoryId", 0)));
			conf.setProjectManagementEnabled(VKCSysParameterSerializer.isProjectManagementEnabled());
			conf.setProjectManagementRootId(new Integer(VKCSysParameterSerializer.retrieveIntValue("PROJECTMANAGEMENT", "ProjectRootCategoryId", 0)));
			conf.setProjectManagementTemplateId(new Integer(VKCSysParameterSerializer.retrieveIntValue("PROJECTMANAGEMENT", "TemplatesRootCategoryId", 0)));
			conf.setShowCreationDate(VKCSysParameterSerializer.retrieveIntValue("DOCUMENT", "EnableDocumentCreationDateCoverage", 0) != 0);
		} catch (Exception ex) {
			VKCLogManager.errorLog(WebShare.class, "1", "Exception while getting categorySettings!", ex);
		}

		return conf;
	}
	
	public static final DocumentViewSettings getDocumentViewSettings(Integer userId) {
		HashMap map = new HashMap();
		DocumentViewSettings view = new DocumentViewSettings();

		try {
			view.setDocViewElements(map);
			
			return VKCDocumentViewFieldSerializer.retrieveDocumentViewSettings(userId);
		} catch (Exception ex) {
			VKCLogManager.errorLog(WebShare.class, "1", "Exception while getting documentViewSettings!", ex);			
			
			return view;
		}

	}

	public static Properties getProperties() {
		return properties;
	}
	
	/**
	 * Initializes the VKC Application
	 * 
	 * @param webAppDir path to the webapps root directory
	 */
	public static void init(String webAppDir) throws Exception{
		VKC_ROOT_PATH 		= webAppDir;
		webApplicationDir	= new File(webAppDir);
		File webInfDir 		= new File(webApplicationDir, "WEB-INF");

		resources = MessageResources.getMessageResources("vkc.resources.application");
		
		/**
		 * Load all application context relevant properties and store them into
		 * a system wide available container
		 */
		FileInputStream fis = new FileInputStream(new File(webInfDir, "vkc.properties"));
		WebShare.getProperties().load(fis);
		fis.close();

		checkDatabaseConnection();
		
		// Database Initialization       
		WebShare.database = VKCDatabaseManager.getDatabase(WebShare.getProperties());

		//	logManagerInit  
		configureLogger();

		// get trash catgory
        getTrashCategory();
        
		// configure trace logger
		String traceLogFile = VKCSysParameterSerializer.retrieveValue("LOGGING", "TraceLogFile", webInfDir + "/log/vkc_trace.log");
		File traceFile = new File(traceLogFile);
		
		TraceLogger traceLogger = new TraceLogger(traceFile);
		traceLogger.printToConsole(true);
		WebShare.setTraceLogger(traceLogger);
		System.out.println("       TraceLogFile  = " + traceFile.getAbsolutePath());

		// log things at startup
		VKCLogManager.infoLog(WebShare.class.getName(), "+++*** VKC (" + WebShare.getProperties().getProperty("vkc.version") + ") is about to come up... ***+++");
		VKCLogManager.infoLog(WebShare.class.getName(), "Database Connection established: " + WebShare.getProperties().get("vkc.db.url"));
		VKCLogManager.infoLog(WebShare.class.getName(), "System parameters sucessfully loaded...");

		// Mail Initialization       
		WebShare.docPublishMail = new DocPublishNotification();
        WebShare.docPublishMail.setPriority(java.lang.Thread.MIN_PRIORITY);
		WebShare.docPublishMail.start();
		WebShare.docExpireMail = new DocExpiredNotification(VKCSysParameterSerializer.retrieveValue("MAIL", "CheckExpirationTime"));
        WebShare.docExpireMail.setPriority(java.lang.Thread.MIN_PRIORITY);
        WebShare.docExpireMail.start();
		WebShare.docDeleteMail = new DocDeleteNotification(VKCSysParameterSerializer.retrieveValue("MAIL", "CheckExpirationTime"));
        WebShare.docDeleteMail.setPriority(java.lang.Thread.MIN_PRIORITY);
        WebShare.docDeleteMail.start();
		UserDocMailsPopulator.getInstance().start();
		
		// Archive(Datastore) Initialization        
		configureDatastore();

		// Analyser Initialization
		String languageDirValue = VKCSysParameterSerializer.retrieveValue("SYSTEMPATHS", "LanguageDir" , "lang");
		String languageDir = new File(webApplicationDir, languageDirValue).getPath();
		VKCLogManager.infoLog(WebShare.class.getName(), "LanguageDir ==> " + languageDir);
		Analyser.init(languageDir);
        
		// Init Scheduler
        Properties schedProps = new Properties();
        schedProps.setProperty("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        schedProps.setProperty("org.quartz.threadPool.threadCount", "10");
        schedProps.setProperty("org.quartz.threadPool.threadPriority", ""+Thread.MIN_PRIORITY);
        SchedulerFactory schedFact = new StdSchedulerFactory(schedProps);
        scheduler = schedFact.getScheduler();
        scheduler.start();
	
        // Index Initialization
        IndexInitializer.initializeIndex(false);

		//Build the global treeview
		VKCLogManager.infoLog(WebShare.class.getName(), "Building the global tree...");
		TreeViewManager.getInstance().buildGlobalTree();
		VKCLogManager.infoLog(WebShare.class.getName(), "Building of global tree finished");

		// VKC Server starten, welcher auf eingehende archive requests von
		// Converter-Server lauscht
		server = new VKCServer(WebShare.getProperties());
		Thread serverThread = new Thread(server);
		serverThread.setPriority(Thread.NORM_PRIORITY);
		serverThread.start();
		
		initJobs();

		// init logging of SOAP Messages
//		Properties soapProperties = getProperties();
//		if (soapProperties != null && soapProperties.getProperty("axis.soapmonitor.enabled") != null)
//			SOAPMessageLogHandler.configure(getProperties());
		
		// server avaliability startup 
        VKC404Serializer.setServerIsUp();
        
        
        

        applicationCss = PropertyUtils.getValue(properties, 
        										"vkc.application.css", 
												applicationCss);
        
		VKCLogManager.infoLog(WebShare.class.getName(), "VKC successfully initialized!");
        
        //Bestimmung der URI-Kodierung nach 10 sec.
        Thread encodingRequest = new Thread() {
            public void run(){
                try {
                    sleep(10000);
                    //Test-Request absetzen um das URI-Encoding im HttpServletRequest zu bestimmen
                    InputStream testReq = (new URL(WebShare.getRootURL()+WebShare.getContextPath()+"/dav/_ENCODING_TEST_%E2%82%AC")).openStream();
                    testReq.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        
        encodingRequest.start();
	}

	/**
     * Routine zur Überprüfung der Datenbank-Konnektivität.
     * Falls keine Verbindung zur Datenbank möglich ist,
     * wird alle 10 Sekunden ein neuer Versuch gestartet. 
     */
    private static void checkDatabaseConnection() {
        try {
            Class.forName(properties.getProperty("vkc.db.driver_class")).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        } 
        
        while (true) {
            try {
                Connection testConn = DriverManager.getConnection( 
                        properties.getProperty("vkc.db.url"),
                        properties.getProperty("vkc.db.username"),
                        properties.getProperty("vkc.db.password"));
                DBHelper.close(testConn);
                
                return;
            } catch (SQLException e) {
                e.printStackTrace();
                System.err.println("Database connection failed due to:" + e.getMessage());
                System.err.println("Retry after 10s!");
            }   
            
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e1) {
                return;
            }
        }
    }

    /**
     * Initialisierung der Jobs für den Scheduler
     */
    private static void initJobs() throws Exception{
        // Garbage Collection
		JobDetail gcJob = new JobDetail(GarbageCollectionJob.NAME,
                				Scheduler.DEFAULT_GROUP,
                				GarbageCollectionJob.class);

		SimpleTrigger gcTrigger = new SimpleTrigger(gcJob.getName()+"_TRIGGER",
                      Scheduler.DEFAULT_GROUP,
                      new Date(System.currentTimeMillis() + 10000),
                      null,
                      SimpleTrigger.REPEAT_INDEFINITELY,
                      2 * 60 * 1000L);

		scheduler.scheduleJob(gcJob, gcTrigger);
		VKCLogManager.infoLog(WebShare.class, gcJob.getName() + " scheduled with repeat interval: " + DateUtils.formatDuration(gcTrigger.getRepeatInterval()));
		
		// Publishing Process
		JobDetail publishingJob = new JobDetail(PublishingJob.NAME,
                				Scheduler.DEFAULT_GROUP,
                				PublishingJob.class);

		// Fire once after system start
		SimpleTrigger publishingTrigger = new SimpleTrigger(publishingJob.getName() + "_TRIGGER",
                      Scheduler.DEFAULT_GROUP,
                      new Date(System.currentTimeMillis() + 15000),
                      null,
                      0,
                      0);

		// Fire at 00:00 every day, see http://quartz.sourceforge.net/javadoc/org/quartz/CronTrigger.html
		// for cron expression syntax!
		CronTrigger pubCronTrigger = new CronTrigger(publishingJob.getName() + "_CRONTRIGGER",
                      Scheduler.DEFAULT_GROUP, "0 0 0 * * ? *");
		pubCronTrigger.setJobGroup(Scheduler.DEFAULT_GROUP);
		pubCronTrigger.setJobName(publishingJob.getName());

		scheduler.scheduleJob(publishingJob, publishingTrigger);
		scheduler.scheduleJob(pubCronTrigger);
		
		VKCLogManager.infoLog(WebShare.class, publishingJob.getName() + " scheduled with cron expression: " + pubCronTrigger.getCronExpression());
		
		// Datastore cleaner
		JobDetail cleaningJob = new JobDetail(DatastoreCleaningJob.NAME,
						Scheduler.DEFAULT_GROUP,
						DatastoreCleaningJob.class);
		
		int cleaningPeriod = VKCSysParameterSerializer.retrieveIntValue("ARCHIVE", "CleaningPeriod", 7);
		
		SimpleTrigger cleaningTrigger = new SimpleTrigger(cleaningJob.getName() + "_TRIGGER",
		      Scheduler.DEFAULT_GROUP,
		      new Date(System.currentTimeMillis() + 5000),
		      null,
		      SimpleTrigger.REPEAT_INDEFINITELY,
		      cleaningPeriod * 24 * 3600 * 1000L);
		
		scheduler.scheduleJob(cleaningJob, cleaningTrigger);
		VKCLogManager.infoLog(WebShare.class, cleaningJob.getName() + " scheduled with repeat interval: " + DateUtils.formatDuration(cleaningTrigger.getRepeatInterval()));
		
		
		 SimpleTrigger SessionCleaningTrigger = new SimpleTrigger(SessionCleaningJob.NAME+"_TRIGGER",
                 Scheduler.DEFAULT_GROUP,
                 SessionCleaningJob.startTime, null,
                 SimpleTrigger.REPEAT_INDEFINITELY,
                 SessionCleaningJob.cleaningPeriod );
		 JobDetail sessionCleaningJob = new JobDetail(SessionCleaningJob.NAME,
					Scheduler.DEFAULT_GROUP,
					SessionCleaningJob.class);
         WebShare.scheduler.scheduleJob(sessionCleaningJob,
        		 SessionCleaningTrigger);

         VKCLogManager.infoLog(WebShare.class,
        		 sessionCleaningJob.getName() +
             " scheduled with repeat interval: " +
             DateUtils.formatDuration(SessionCleaningTrigger.getRepeatInterval())+               
             " starting at: " + SessionCleaningJob.startTime);  
    } 

    /**
	 * Configures the VKC Datastore
	 */
	private static void configureDatastore() throws DataStoreException, DBException, MalformedURLException {
		String dataStoreDir = VKCSysParameterSerializer.retrieveValue("SYSTEMPATHS", "DatastoreDir" , "WEB-INF/datastorage");
		
		if (!new File(dataStoreDir).isAbsolute()) {
			dataStoreDir = new File(WebShare.getWebApplicationDir(), dataStoreDir).getAbsolutePath();
		}
				
		String dataStoreUrl = new File(dataStoreDir).toURL().toString(); 
		 
		WebShare.archive = new FileDataStore(dataStoreUrl, new HashStoreKeeper(1000));
		VKCLogManager.infoLog(WebShare.class.getName(), dataStoreUrl);
		
		WebShare.archive.open();
	}

	/**
	 * Configures the logger according
	 * to the database settings
	 */
	private static void configureLogger() throws DBException {
		int maxLogFileSize = VKCSysParameterSerializer.retrieveIntValue("LOGGING", "MaxLogFileSize", 1024*1024);
		VKCLogManager.setMaxLogFileSize(maxLogFileSize);

		int maxLogFileCount = VKCSysParameterSerializer.retrieveIntValue("LOGGING", "MaxLogFileCount", 1);
		VKCLogManager.setMaxLogFileCount(maxLogFileCount);

        int maxWebdavLogFileSize = VKCSysParameterSerializer.retrieveIntValue("LOGGING", "MaxWebdavLogFileSize", 1024*1024);
        VKCLogManager.setMaxWebdavLogFileSize(maxWebdavLogFileSize);

		int enableLogging = VKCSysParameterSerializer.retrieveIntValue("LOGGING", "EnableLogging", 1);
		VKCLogManager.setEnableLogging(enableLogging != 0);

		String timestampFormat = VKCSysParameterSerializer.retrieveValue("LOGGING", "TimeStampFormat", "");
		VKCLogManager.setTimestampFormat(timestampFormat);

		VKCLogManager.init(VKCSysParameterSerializer.retrieveValue("LOGGING", "ErrorLogFile", "WEB-INF/log/vkc_error.log"),
		        		   VKCSysParameterSerializer.retrieveValue("LOGGING", "AccessLogFile", "WEB-INF/log/vkc_access.log"),
                           VKCSysParameterSerializer.retrieveValue("LOGGING", "InfoLogFile", "WEB-INF/log/vkc_info.log"),
		        		   VKCSysParameterSerializer.retrieveValue("LOGGING", "WebdavAccessLogFile", "WEB-INF/log/vkc_webdav_access.log"),
		        		   VKCSysParameterSerializer.retrieveValue("LOGGING", "MigrationLogFile", "WEB-INF/log/vkc_migration.log"));

		VKCLogManager.setLogToConsole(true);
	}

	/**
	 * Shuts down the VKC application
	 */
	public static void shutdown() {
	    if (scheduler != null) {
	        try {
                scheduler.shutdown(true);
            } catch (SchedulerException e) {
                VKCLogManager.errorLog(WebShare.class, "", "Scheduler could not be shutdown properly!", e);
            }
	    }
	    
		if (WebShare.archive != null) {
			try {
				WebShare.archive.close();
			} catch (DataStoreException e) {
			    VKCLogManager.errorLog(WebShare.class, "", "Datastore could not be shutdown properly!", e);
			}
		}
        
		//Index mit Platte synchronisieren
        Search.saveKeyBase();
        WebShare.classifier.saveCatBase();

        //Alle offenen Sessions schließen
        final UserTrackingInfo[] users = WebShare.getActiveUsers();
        
        for (int i = 0; i < users.length; i++) {
            UserTrackingInfo info = users[i];
            try {
                info.getSession().invalidate();
            } catch (IllegalStateException e) {
            }
        }
        
		if (server != null) {
			server.shutdown();
		}

        try {
            // server avaliability shutdown
			VKC404Serializer.setServerIsDown();	  
        } catch (DBException ex) {
            VKCLogManager.errorLog(WebShare.class, "", "Server availability could not be shutdown properly!", ex);
        }
        
        VKCLogManager.close();
	}

    /**
     * gets the value of system parameter found for (context, name)
     *
     * @return value string 
     */
    public static String getSysParameterValue(String context, String name, String defaultValue) {
    	try {
			return VKCSysParameterSerializer.retrieveValue(context, name, defaultValue);
		} catch (DBException e) {
			return defaultValue;
		}
    }

	public static String getLoginPage() {
        String loginPage = getProperties().getProperty("vkc.server.defaultLoginPage");
        
		if (loginPage == null || "".equals(loginPage)) {
			try {
                loginPage = VKCSysParameterSerializer.retrieveValue("LOGIN", "DefaultLoginPage", WebShare.LOGIN_PAGE);
            } catch (DBException e) {
                loginPage = LOGIN_PAGE;
            }	 
		}
	    
		return loginPage;
	}

	public static String getDbPathInfo() {
	    String connUrl = (String) WebShare.getProperties().get("vkc.db.url");
	    String driverClass = (String) WebShare.getProperties().get("vkc.db.driver_class");
	    String dbPathInfo = ""; 
	    
	    if (driverClass.equals("org.firebirdsql.jdbc.FBDriver")) {
	        // interbase    
	        dbPathInfo = connUrl.substring(connUrl.lastIndexOf("/") + 1, connUrl.length());
	    } else if (driverClass.equals("oracle.jdbc.driver.OracleDriver")) {
	        // oracle
	        dbPathInfo = connUrl.substring(connUrl.lastIndexOf("\\") + 1, connUrl.length());
	    } else if (driverClass.equals("org.postgresql.Driver")) {
	        // postgres
            dbPathInfo = connUrl.substring(connUrl.lastIndexOf("/") + 1, connUrl.length());
	    } else if (true) {
            // what ever will follow...
            dbPathInfo = "?";
        }
	    
	    dbPathInfo += " (" + WebShare.getSysParameterValue("SYSTEMINFO", "DBVersionHigh", "?") + "." + WebShare.getSysParameterValue("SYSTEMINFO", "DBVersionLow", "?") + ")";
	    
	    return dbPathInfo;
	}
	
    public static String getContextPath() {
        if (StringUtils.isEmpty(contextPath) || contextPath.trim().equals("/")) {
            return "";
        }
        
        return contextPath;
    }

    public static void setContextPath(String contextPath) {
        WebShare.contextPath = contextPath;
    }

	public static String getApplicationCss() {
		return applicationCss;
	}

	public static void setApplicationCss(String applicationCss) {
		WebShare.applicationCss = StringUtils.normalize(applicationCss);
	}

	
	public static boolean isTrashEnabled() {
        if ("0".equals(WebShare.getSysParameterValue("TRASH", "EnableTrash", "0"))) {
            return false;
        }
        
        Integer trashCategoryId = new Integer(WebShare.getSysParameterValue("TRASH", "TrashCategoryId", "0"));
        
        try {
            if (!CategoryUtils.existsCategory(trashCategoryId, null, true)) {
            	return false;
            }
        } catch (DBException e) {
        	return false;
        }
        
        return true;
	}
	
	public static VKCCategory getTrashCategory() {
	    try {
		    if (!WebShare.isTrashEnabled()) {
		        return null;
		    }
		    
            Integer trashCategoryId = new Integer(WebShare.getSysParameterValue("TRASH", "TrashCategoryId", "0"));

            if (WebShare.trashCategory == null || !WebShare.trashCategory.getCategoryId().equals(trashCategoryId)) {
	            WebShare.trashCategory = VKCCategorySerializer.retrieveCategory(trashCategoryId);
	        }
		    
		    return WebShare.trashCategory;
	    } catch (DBException ex) {
	        return null;
	    }
    }

	public static VKCSysParameter getPermanentSystemParameter(String context, String name) {
		return (VKCSysParameter)permanentSystemParameters.get(context + "_" + name);
	}

	public static void setPermanentSystemParameters(HashMap permanentSystemParameters) {
		WebShare.permanentSystemParameters = permanentSystemParameters;
	}

	public static TabInfo getPermanentTabView(Integer id) {
		return (TabInfo)permanentTabViews.get(id);
	}

	public static void setPermanentTabViews(HashMap permanentTabViews) throws DBException {
//		if (permanentTabViews != null && !permanentTabViews.isEmpty()) {
//			HashMap tabIds = VKCTabViewSerializer.getTabIdsMappedByUniqueName();
//			HashMap tabViews = new HashMap();
//			
//			for (Iterator iter = permanentTabViews.values().iterator(); iter.hasNext();) {
//				TabInfo tab = (TabInfo) iter.next();
//				tab.setTabId((Integer)tabIds.get(tab.getUniqueName()));
//				tabViews.put(tab.getTabId(), tab);
//			}
//			
//			WebShare.permanentTabViews = tabViews;
//		} else {
			WebShare.permanentTabViews = permanentTabViews;
//		}
	}

    public static void setTrashCategory(VKCCategory category) {
        WebShare.trashCategory = category;
    }
}