/******************************************************************************
  @header FTServer
  @abstract Base class for all FT classes
 
  @copyright 2004, 2005, 2006 Free Software Foundation, Inc.
  
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA

  <pre>
  -------------------------------------------------------------------------
  Modification history

  30.01.2005 ola     initial version
  23.08.2006 ola     license changed
  -------------------------------------------------------------------------
  </pre>
******************************************************************************/


#if !defined(__FTSERVERIMPL_H)
#define __FTSERVERIMPL_H

#include <Foundation/Foundation.h>
#include <FT/FTObject.h>
#include <FT/FTAdministrationSession.h>
#include <FT/FTSessionManagerImpl.h>
#include <FT/FTObjectToIdMapper.h>
#include <FT/FTDefaultObjectToIdMapper.h>
#include <FT/FTGraphManagerImpl.h>
#include <FT/FTDictionaryProvider.h>
#include <FT/FTGenericDictionaryProviderImpl.h>
#include <FT/FTSystemDictionary.h>
#include <FT/FTServer.h>
#include <FT/FTTransactionManager.h>
#include <FT/FTTransactionManagerImpl.h>
#include <FT/FTServiceManager.h>
#include <FT/FTConfig.h>
#include <BDB/BDB.h>

/*!
 * @typedef ft_server_state_t
 * @abstract possible internal states of the server
 * @field FT_SERVER_STATE_UNKNOWN may never be the case
 * @field FT_SERVER_STATE_STARTED server started but no database has been 
 *   mounted and therefore no data accessing objects can be requested
 * @field FT_SERVER_STATE_MOUNTED databases have been mounted and data
 *   accessing objects can be retrieved
 */
typedef enum {
  FT_SERVER_STATE_UNKNOWN = 0,
  FT_SERVER_STATE_STARTED,
  FT_SERVER_STATE_MOUNTED
} ft_server_state_t;


/*!
 * @typedef __ft_req_operation_t
 * @abstract gives information for @link{#checkServerstate} about the action
 *   to perform next
 * @field __FT_REQ_UNKNOWN
 * @field __FT_REQ_DATA_ACCESS request for accessing data e.g. through a 
 *   data accessing object like e.g. session manager
 */
typedef enum {
  __FT_REQ_UNKNOWN = 0,
  __FT_REQ_MOUNT_DATABASES = 2,
  __FT_REQ_UNMOUNT_DATABASES = 4,
  __FT_REQ_DATA_ACCESS = 8
} __ft_req_operation_t;



/*!
 * @method FTServerImpl
 * @abstract Server implementation of the server interface
 */
@interface FTServerImpl : FTObject <FTServer> {
  @private
	/**
	 * The notificationCenter is used to inform instances about important
	 * server actions, like e.g. a shutdown action
	 */
	NSNotificationCenter *notificationCenter;
	
	BDBDatabase *graphIdToGraphDB;
	BDBDatabase *nodeidToProviderManagerDB;
	BDBDatabase *defaultDictionaryProviderDB;
	
	FTSessionManagerImpl *sessionManager;	
	FTDefaultObjectToIdMapper *defaultObjectToIdMapper;
	FTGraphManagerImpl *graphManager;
	FTGenericDictionaryProviderImpl *defaultDictionaryProvider;
	FTSystemDictionary *systemDictionary;
	FTTransactionManagerImpl *transactionManager;
    
    FTConfig *config;

    /**
     * Service management
     */
    id <FTServiceManager> serviceManager;
	ft_server_state_t server_state;
}


/**
 * @method initialize
 * @abstract setups diverse mutexs and the like
 */
+ initialize;


/*!
 * @method initWithBaseDir 
 * @abstract startup the server with the given basis directory
 * @param theBaseDir basis directory to use
 */
- initWithConfig: (FTConfig *) theConfig;
- (void) dealloc;


/*!
 * @method addOberver
 * @abstract adds a listener which listenes to notifications of this server 
 *   instance
 * @param anObserver instance to notificate
 * @param aSelector selector to use
 * @result self
 */
- addOberver: (id) anObserver selector: (SEL) aSelector;


/*!
 * µethod baseDataDir
 * @result return the base data dir where all database data has to be stored
 */
- (NSString *) baseDataDir;


/*!
 * @method checkServerState
 * @abstract checks the internal state of the server with respect to the 
 *   specified operation.
 * @discussion Throws an @{link ECIllegalStateException} if the specified
 *   operation is not valid wrt. the current state of the server
 * @param reqOperation information about the operation to perform next
 * @result if this operation returns (self) then the operation is valid
 *   wrt. to the current state
 */
- checkServerState: (__ft_req_operation_t) reqOperation;


/*!
 * @method config
 * @result the configuration for this server
 * @abstract This configuration is hand-off by the FTBootstrap instance and
 *   read from a ftconfig.xml file.
 */
- (FTConfig *) config;


/*!
 * @method constructDatabaseFilename
 * @abstract Internal method used to construct the filename for the given
 *   database name
 * @discussionion This construction is based on the base data directory
 * @param databaseName name of database
 * @result constructed filename
 * @throws ECIllegalArgumentException if an illegal database name is specified
 * @throws ECIncompleteInitializationException is base data dir is not specified 
 */
- (NSString *) constructDatabaseFilename: (NSString *) databaseName;


/*!
 * @method createUserDatabase
 * @abstract create a database with the given configuration
 * @discussionion Especially this method ensures that the database does not
 *   exist before.
 * @throws ECIncompleteInitializationException if base data dir is not given or
 *    if the name of the user database is not given in the info.plist file.
 * @throws ECIllegalStateException if a database file already exists.
 */
- (BDBDatabase *) createDatabaseWithName: (NSString *) databaseName
  withConfig: (BDBDatabaseConfig *) aConfig;


/*!
 * @method dbConfigForDefaultDictionaryProvider
 * @abstract create the database configuration instance for the
 * "defaultDictionaryProvider" database
 */
- (BDBDatabaseConfig *) dbConfigForDefaultDictionaryProvider;


/*!
 * @method dbConfigForGraphIdToGraphDatabase
 * @abstract create the database configuration instance for the
 * "graphIdToGraphDatabase" database
 */
- (BDBDatabaseConfig *) dbConfigForGraphIdToGraphDatabase;


/*!
 * @method dbConfigForGraphIdToGraphDatabase
 * @abstract create the database configuration instance for the
 * "NodeIdToProviderManager" database
 */
- (BDBDatabaseConfig *) dbConfigForNodeIdToProviderManager;


/*!
 * @method defaultDictionaryProvider
 * @result return the default dictionary provider
 */
- (id <FTDictionaryProvider>) defaultDictionaryProvider;


/*!
 * @method defaultObjectToIdMapper
 * @result return the default object to id mapper used e.g. to retrieve
 *    graphs based on their id's
 */
- (id <FTObjectToIdMapper>) defaultObjectToIdMapper;


/*!
 * @method graphManager
 * @result return the graph manager
 */
- (FTGraphManagerImpl *) graphManager;
 

/*!
 * @method databasesMounted
 * @result YES if all databases are mounted
 */
- (BOOL) databasesMounted;


/*!
 * @method mountDatabases
 * @abstract used to open all necessary database connections
 * @discussionion in contrast to {@link #setupDatabases} this method does not 
 *   create any database
 * @throws ECIllegalStateException if the server is not in the state
 *   FT_SERVER_STATE_STARTED
 */
- mountDatabases;


/*!
 * @method mountDatabasesByAdminSession
 * @abstract This call is initiaited by an administration session is used
 *   to set up the databases
 * @discussion This method calls {@link #setupDatabases} and reconnects the
 *   given session to the session manager
 * @param adminSession calling admin session
 * @result self
 */
- mountDatabasesByAdminSession: (id <FTAdministrationSession>) adminSession;


/*!
 * @method nameOfDefaultDictionaryProviderDatabase
 * @result name of dataase used to map keys to values
 */
- (NSString *) nameOfDefaultDictionaryProviderDatabase;


/*!
 * @method nameOfDefaultObjectToIdMapperDatabase
 * @result name of dataase mapping objects to identifiers. Do not release
 *   this object.
 */
- (NSString *) nameOfDefaultObjectToIdMapperDatabase;


/*!
 * @method nameOfGraphIdToGraphDatabase
 * @result name of database mapping graph id's to graph instances. Do not release
 *   this object.
 */
- (NSString *) nameOfGraphIdToGraphDatabase;


/*!
 * @method nameOfNodeIdToProviderManagerDatabase
 * @result name of database mapping node id -> provider manager. Do not release
 *   this object.
 */
- (NSString *) nameOfNodeIdToProviderManagerDatabase;


/*!
 * @method openDatabaseWithName
 * @abstract tries to open the specified database
 * @throws ECIncompleteInitializationException if base data dir is not given or
 *    if the name of the user database is not given in the info.plist file.
 * @throws ECIllegalStateException if the database file does not exists.
 */
- (BDBDatabase *) openDatabaseWithName: (NSString *) databaseName
  withConfig: (BDBDatabaseConfig *) aConfig;
  

/*!  
 * @method serviceManager
 * @abstract used to access the service manager
 * @result service manager
 */
- (id <FTServiceManager>) serviceManager;


/*!
 * @method setupDatabases
 * @abstract Internal method to create all databases. baseDataDir must be set 
 * @link baseDataDir
 * @result self
 */
- setupDatabases;


/*!
 * @method sessionManager
 * @result reference to the session manager
 */
- (id <FTSessionManager>) sessionManager;


/*!
 * @method shutdown
 * @abstract kills all sessions except for the calling one and closes
 *   all databases
 * @discussion Calls {@link #unmount} to close all databases and to release all
 *   data accessing objects.
 * After this call the server does not allow any I/O operations
 * @result self
 */
- shutdown;


/*!
 * @method systemDictionary
 * @result return the global, system-wide dictionary.
 * @discussion this dictionary is used to manage global settings and the like.
 */
- (FTSystemDictionary *) systemDictionary;


/*!
 * @method transactionManager
 * @result global transaction manager
 */
- (id <FTTransactionManager>) transactionManager;


/*!
 * @method unmount
 * @abstract closes all databases releases all data accessing objects.
 * @result self
 */
- unmount;
@end


/*!
 * @typedef ft_server_action_hint_t
 * @abstract Defines values which give a hint about the next server action 
 *   to be performed.
 * @discussion This typedef is used in conjunction with server 
 *   notifications via {@link FTServerNotification}.
 * @field FT_SERVER_ACTION_UNKNOWN may not occur within notifications.
 * @field FT_SERVER_ACTION_SHUTDOWN server will shutdown after this notification
 */
typedef enum {
  FT_SERVER_ACTION_UNKNOWN = 0,
  FT_SERVER_ACTION_SHUTDOWN
} ft_server_action_hint_t;


/*!
 * @class FTServerNotification
 * @abstract instances of this class are sent as notifications in order for the
 *   server to notify listeners about actions
 */
@interface FTServerNotification : FTObject {
  @private
    ft_server_action_hint_t serverActionHint;
}


/*!
 * @method sendShutdownNotificationTo
 * @dicussion Send a shutdown notification to the given center.
 */
+ (void) sendShutdownNotificationTo: (NSNotificationCenter *) center;


/*!
 * @method notificationName
 * @result name of notification
 */
+ (NSString *) notificationName;


/*!
 * @method initWithServerActionHint
 * @abstract initializes the receiver.
 * @param actionHint server's action to be performed next and for which
 *   this notification is being sent.
 * @result self
 */
- initWithServerActionHint: (ft_server_action_hint_t) actionHint;


/*!
 * @method serverActionHint
 * @result return information about the server's next action
 */
- (ft_server_action_hint_t) serverActionHint;
@end

#endif
