/*!
  @header FTGenericDictionaryProviderImpl
  @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

  01.03.05 ola     initial version
  23.08.06 ola     license changed
  -------------------------------------------------------------------------
  </pre>
*/
#include <Encore/Encore.h>
#include <FT/FTExceptions.h>
#include <FT/FTGenericDictionaryProviderImpl.h>
#include <FT/FTLogging.h>

@implementation FTGenericDictionaryProviderImpl
- initWithDatabase: (BDBDatabase *) aDatabase {
  self = [super init];
  self->database = [aDatabase retain];
  self->lock = [[NSLock alloc] init];
  return self;
}


- (void) dealloc {
  [self->lock release];
  [self->database release];
  
  [super dealloc];
}


- (BDBDatabaseEntry *) lookupEntryForKey: (id <NSCoding>) aKey {
  BDBDatabaseEntry *key, *entry;
  BDBOperationStatus operationStatus = BDB_STATUS_UNKNOWN;
  
  EC_AUTORELEASEPOOL_BEGIN
  
  key = [[[BDBDatabaseEntry alloc] initWithObject: aKey] autorelease];
  entry = [[BDBDatabaseEntry alloc] init];
	
  operationStatus = [self->database getEntryWithTransaction: nil
	key: key data: entry];
  if( BDB_STATUS_NOTFOUND != operationStatus ) {
    if( BDB_STATUS_SUCCESS != operationStatus ) {
      /** an error occured */
	  EC_AUTORELEASEPOOL_RELEASE
  	  [[[ FTInternalDatamanagementException alloc] 
	    initWithOperationStatus: operationStatus] raise];
	}
  } else {
    [entry release];
	entry = nil;
  }
  
  EC_AUTORELEASEPOOL_END
  
  return entry;
}


- objectForKey: (id <NSCoding>) aKey {
  BDBDatabaseEntry *value;
  id toReturn = nil;
  
  if( [[FTLogging coreLog] isDebugEnabled] ) {    
    [[FTLogging coreLog]
      debug: @"FTGenericDictionaryProviderImpl::objectForKey: key= %@", aKey ];
  }
  
  value = [self lookupEntryForKey: aKey];
  if( nil != value ) {
	toReturn = [[value object] retain];
	[value release];
  }
  
  return toReturn;
}


- setObject: (id <NSCoding>) anObject forKey: (id <NSCoding>) aKey {
  BDBDatabaseEntry *key, *value;
  BDBOperationStatus operationStatus = BDB_STATUS_UNKNOWN;
  
  EC_AUTORELEASEPOOL_BEGIN

  [self->lock lock];
  NS_DURING
    /**
     * Lookup the entry first. If there already exists an entry then remove it
     * first.
     */  
    value = [self lookupEntryForKey: aKey];
    if( nil != value ) {
      key = [[[BDBDatabaseEntry alloc] initWithObject: aKey] autorelease];
	
      /**
	   * delete this entry: 
	   */
	  operationStatus = [self->database deleteEntryWithTransaction: nil 
	    key: key];
	  if( BDB_STATUS_SUCCESS != operationStatus ) {
	    [[[ECIllegalStateException alloc] initWithIllegalStateInfo:
	      @"FTGenericDictionaryProviderImpl::setObject: Unable to delete "\
		  "existing entry" ] raise];
	  }
    }
  
    key = [[[BDBDatabaseEntry alloc] initWithObject: aKey] autorelease];
    value = [[[BDBDatabaseEntry alloc] initWithObject: anObject] autorelease];
	
    operationStatus = [self->database putEntryWithTransaction: nil
	  key: key value: value];

    if( BDB_STATUS_SUCCESS != operationStatus ) {
      /** an error occured */
  	    [[[FTInternalDatamanagementException alloc] 
	      initWithOperationStatus: operationStatus] raise];
	}
  NS_HANDLER
    [self->lock unlock];
	EC_AUTORELEASEPOOL_RELEASE
	[localException raise];
  NS_ENDHANDLER
  
  [self->lock unlock];
  EC_AUTORELEASEPOOL_END

  return self;
}

@end
