/*!
  @header FTGraphImpl
  @abstract Module of FT
 
  @availability OS X, GNUstep
  @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

  23.02.05 ola     initial version
  27.03.06 ola     added a database used to manage general information 
                   belonging to a graph, like e.g. the ID's of all
                   objects of a graph.
  06.06.06 ola     keyToGraphInfo now is an instance of FTPersistentSet
  23.08.06 ola     license changed
  -------------------------------------------------------------------------
  </pre>
*/

#if !defined(__FTGraphImpl_H)
#define __FTGraphImpl_H

#include <Foundation/Foundation.h>
#include <Encore/Encore.h>

#include <FT/FTObject.h>
#include <FT/FTBootstrap.h>
#include <FT/FTExceptions.h>
#include <FT/FTGraph.h>
#include <FT/FTId.h>
#include <FT/FTDefaultObjectToIdMapper.h>
#include <FT/FTPersistentSet.h>

@class FTServerImpl;
@class FTGraphManagerImpl;
@class FTNodeImpl;

/*!
 * @class FTGraphImpl
 * @abstract Instances of this class represent graphs
 */
@interface FTGraphImpl : FTObject <FTGraph, NSCoding> {
  @private 
    FTServerImpl *server;
    FTGraphManagerImpl *graphManager;
    id <FTId> graphId;
    FTDefaultObjectToIdMapper *objectToIdMapper;

    /**
     */
    NSLock *globalLock;
    
    
    /**
     * Very simply cache mechanism at present
     */
    ECCache *idToNodeCache;
    
    
    /**
     * Maps id's to record numbers 
     */
    BDBDatabase *idToRecnoDB;
	
    /**
     * Maps record number --> node data
     */
    BDBDatabase *nodeDB;
    
    
    /**
     * Contains "general" information related to this graph
     */
    id <FTPersistentSet> keyToGraphInfo;
    
    
    /**
     * indicates wether all databases are mounted or not
     */
    BOOL databasesMounted;
	
	
    /**
     * The graph database name refers to the name of a directory
     * where this graph instances store the data<p/>
     * This item must be persistent!
     */
    NSString *graphDatabaseName;
	
	
    /**
     * This field refers to the directory where the graph stores
     * all its data. It is based on the server's base directory and the
     * name of the graph database {@link #graphDatabaseName}<p/>
     * It is transient and has to be reconstructed for each allocation of
     * this class.
     */
    NSString *graphDatabaseDirectory;
}


/*!
 * @method init
 * @abstract May not be called directly.
 * @result self
 */
- init;


/*!
 * @method initForServer
 * @abstract initializes the receiver
 * @param theServer reference to the underlying server
 * @param anId id of this graph
 * @result self
 */
- initForServer: (FTServerImpl *) theServer 
  graphManager: (FTGraphManagerImpl *) theGraphManager withId: (id <FTId>) anId;


/*!
 * @method initWithCoder
 * @abstract Initializes a newly allocated instance from data in decoder
 */
- initWithCoder: (NSCoder *) coder;


/*!
 * @method initAfterDecodeForServer
 * @abstract this method may directly be called after deserialization of 
 *   this object
 * @param theServer reference to underlying server
 * @param theGraphManager graph manager to use
 * @result self
 */
- initAfterDecodeForServer: (FTServerImpl *) theServer
  graphManager: (FTGraphManagerImpl *) theGraphManager;


- (void) dealloc;


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


/*!
 * @method createDatabaseGraphDirectory
 * @abstract Creates the (sub) directory for a new graph
 * @result name of created directory excluding the base directory path
 */
- (NSString *) createDatabaseGraphDirectory;


/*!
 * @method createNodeWithId
 * @abstract create a node of a certain node id
 */
- (id <FTNode>) createNodeWithId: (id <FTId>) aNodeId;


/*!
 * @emthod graphDatabaseDirectory
 * @result directory where the graph stores its databases
 */
- (NSString *) graphDatabaseDirectory;


/*!
 * @method encodeWithCoder
 * @abstract Encodes the receiver using encoder
 */
- (void) encodeWithCoder: (NSCoder *) coder;


/*!
 * @method close
 * @abstract Call this method if you do not need this instance any more
 * @discussion After this method release may also be called
 */
- (void) close;


/*!
 * @method graphId
 * @result the identifier of this graph
 */
- (id <FTId>) graphId;


/*!
 * @method idToRecnoDBConfig
 * @result database configuration for the database "idToNode"
 */
- (BDBDatabaseConfig *) idToRecnoDBConfig;


/*!
 * @method insertNodeToDatabase
 * @discussion the caller has to make sure that the node is not already to
 *   be found in the database.
 * @abstract inserts a node to the database
 * @param node to insert
 * @result self
 */
- insertNodeToDatabase: (FTNodeImpl *) node;


/*!
 * @method internalStateChanged
 * @abstract Updates the persistent state of the given node
 * @param nodeToUpdate node to update in the database
 * @result self
 */
- internalStateChanged: (FTNodeImpl *) nodeToUpdate;


/*!
 * @method mountDatabases
 * @abstract Opens all databases
 * @result self
 * @throws ECIllegalStateException if databases are already mounted
 */
- mountDatabases;


/*!
 * @method nameOfkeyToGraphInfoDatabase
 * @result name of the database used to store generic
 *   information  related to a graph, such as the identifiers of
 *   all nodes
 */
- (NSString *) nameOfkeyToGraphInfoDatabase;


/*!
 * @method nameOfNodesDatabase
 * @abstract Name of database mapping a record number to a node's data
 * @resulf name of node database
 */
- (NSString *) nameOfNodesDatabase;


/*!
 * @method nameOfIdToRecnoDatabase
 * @discussion {@link #graphDatabaseDirectory} must be set before
 * @result return the fully qualified name of the database idToNode
 */
- (NSString *) nameOfIdToRecnoDatabase;


/*!
 * @method nameOfObjectToIdMapperDatabase
 * @discussion {@link #graphDatabaseDirectory} must be set before
 * @result return the fully qualified name of the database objectToIdMapper
 */
- (NSString *) nameOfObjectToIdMapperDatabase;


/*!
 * @method nodeAtRecordNumber
 * @abstract fetch the node at the specified record number
 * @param recno record number related to database nodeDB
 * @result fetched node or nil if not existent
 */
- (FTNodeImpl *) nodeAtRecordNumber: (BDBDatabaseRecordNumber *) recno;


/*!
 * @method nodeDBConfig
 * @result database configuration for the node database
 */
- (BDBDatabaseConfig *) nodeDBConfig;


/*!
 * @method nodeIterator
 * @result iterator over <b>all</b> nodes of the graph
 */
- (id <ECIterator>) nodeIterator;


/*!
 * @method nodeWithId
 * @result return the node corresponding to the given identifier
 */
- (id <FTNode>) nodeWithId: (id <FTId>) aNodeId;


/*!
 * @method performAction 
 * @abstract Called by the transaction controll in order to run the 
 * transaction
 * @result return information about the success of this operation
 */
- (BOOL) performAction;


/*!
 * @method objectToIdMapper
 * @result mapper for this graph
 */
- (id <FTObjectToIdMapper>) objectToIdMapper;


/*!
 * @method recordNumberOfNode
 * @result returns the record number of a given node. 
 * @throws FTInternalDatamanagementException
 */
- recordNumberOfNode: (FTNodeImpl *) node;


/*!
 * @method recordNumberOfNodeId
 * @result returns the record number of a given node id. 
 * @throws FTInternalDatamanagementException
 */
- recordNumberOfNodeId: (id <FTId>) nodeId;


/*!
 * @method remove
 * @result YES if successful, NO otherwise
 * @abstract Removes the complete graph. Does <b>not</b> check wether the
 *   graph (or one of its elements) is still in use. (TODO)
 */
- (BOOL) remove;


/*!
 * @method removeNode
 * @abstract removes the specified node from the graph
 * @discussion A node can only be removed if it contains no incoming and no 
 *   outgoing links
 * @param nodeToRemove node to remove
 * @result self
 * @throws ECIllegalStateException if the node contains incoming/outgoing
 *   references
 */
- removeNode: (id <FTNode>) nodeToRemove;


/*!
 * @method removeNodeFromIdToRecnoDB
 * @abstract removed the specified node from the database idToRecnoDB and
 *   returns the record number (value) of the deleted entry.
 * @param node to remove. The node will only be removed from the database, not
 *   from memory.
 * @result the value (record number) of the entry being deleted ir nil
 *   if entry could not be found
 * @throws FTInternalDatamanagementException
 */
- removeNodeFromIdToRecnoDB: (FTNodeImpl *) node;


/*!
 * @method removeNodeWithRecordNumber
 * @param recordNumber specifies the entry to delete. the record number can
 *   be determined for a given node via method recordNumberOfNode.
 * @result YES if the node has successfully been removed
 * @throws ECIllegalArgumentException
 * @throws FTInternalDatamanagementException
 */
- (BOOL) removeNodeWithRecordNumber: (id) recordNumber;


/*!
 * @method removeNodeFromDatabase
 * @abstract removes the specified node from the database
 * @discussion Removes the node from both BDB databases: idToRecnoDB and
 *   nodeDB
 * @param node to remove
 * @result self
 * @throws FTInternalDatamanagementException
 * @throws ECIllegalArgumentException
 */
- removeNodeFromDatabase: (FTNodeImpl *) node;


/*!
 * @method serviceWithId
 * @abstract Fetch a service for the specified id
 * @param aServiceId id of the service
 * @result the specified service or nil if not existent
 */
- (id <FTService>) serviceWithId: (NSString *) aServiceId;
  
  
/*!
 * @method serviceWithId
 * @abstract Fetch a service for the specified id and node
 * @param aServiceId id of the service
 * @param aNode particular node for which the service has to been offered
 * @result the specified service or nil if not existent
 */
- (id <FTService>) serviceWithId: (NSString *) aServiceId
  forNode: (FTNodeImpl *) aNode;
  
  
/*!
 * @method setupDatabases
 * @abstract Initializes the graph database
 * @discussion Has to be called when creating a graph. It creates the
 *   underlying directory and files
 * @result self
 * @throws ECIllegalStateException if the database has already been created 
 *   before
 * @throws ECAlreadyExistsException if the directory, which has to be created
 *   for the new graph database, already exists.
 * @throws FTDatabaseCreationFailedException if the directory for the graph
 *   database cannot be created.
 */
- setupDatabases;


/*!
 * @method updateNode
 * @abstract removes the existing node data from the database(s) and adds the 
 *   current data of the given node to the database(s)
 * @param node node to update
 * @result self
 */
- updateNode: (FTNodeImpl *) node;


/*!
 * @method unmountDatabases
 * @abstract closes all databases used for this graph
 * @result self
 */
- unmountDatabases;
@end
#endif
