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

  21.09.05 ola     initial version
  16.07.06 ola     new implementation
  23.08.06 ola     license changed
  -------------------------------------------------------------------------
  </pre>
*/

#include <FT/FTDictionaryServiceStorageException.h>
#include <FT/FTDictionaryServiceLoader.h>
#include <FT/FTDictionaryService.h>
#include <FT/FTVersionImpl.h>
#include <FT/FTLogging.h>
#include "FTDictionaryServiceForGraphImpl.h"
#include <FTNotifications.h>

#define __VERSION_MAJOR 0
#define __VERSION_MINOR 2
#define __VERSION_BUILD 1
#define __VERSION_STATE FT_VERSION_SNAPSHOT

#define __FTDictionaryServiceId @"FTDictionaryService"
#define __FTDictionaryServiceDataDirectory @"FTDictionaryServiceData"
#define __FTDictionaryIndexDB @"DictionaryIndex.db"

@implementation FTDictionaryServiceLoader

- init {
  self = [super init];
  self->serviceVersion = [[FTVersionImpl alloc]
    initWithMajor: __VERSION_MAJOR
    withMinor: __VERSION_MINOR
    withBuild: __VERSION_BUILD
    asState: __VERSION_STATE];

  self->serviceAvailability = [[FTDictionaryServiceAvailability alloc] init];
  self->serviceEnvironment = nil;

  self->graphToServiceImpl = nil;
  self->generalLock = [[NSLock alloc] init];
  
  return self;
}


- (void) dealloc {
  [self->generalLock release];
  
  if( nil != self->serviceVersion ) {
    [self->serviceVersion release];
  }
  
  if( nil != self->serviceAvailability ) {
    [self->serviceAvailability release];
  }
  
  if( nil != self->serviceEnvironment ) {
    [self->serviceEnvironment release];
  }
  
  
  [self->databaseNameScheme release];
  
  [super dealloc];
}


- (NSString *) databaseNameScheme {
  return self->databaseNameScheme;
}


- onGraphClosed: (NSNotification *) notification {
  FTDictionaryServiceForGraphImpl *serviceImpl;
  FTGraphImpl *graphImpl;
  unsigned cnt;
  
  graphImpl = [notification object];
  
  if( [[FTLogging coreLog] isTraceEnabled] ) {
    [[FTLogging coreLog] 
      trace: @"FTDictionaryServiceLoader::onGraphClosed"];
  }
 
  serviceImpl = [[self->graphToServiceImpl 
    objectForKey: [graphImpl graphId]
    incrementRefCounter: NO] retain];
  
  NS_DURING
    
    cnt =  [self->graphToServiceImpl 
        referenceCounterOfObjectForKey: [graphImpl graphId]] ;
    if( nil != serviceImpl ) {
      [self->graphToServiceImpl 
        decrementRefCounterForKey: [graphImpl graphId]];
      cnt =  [self->graphToServiceImpl 
        referenceCounterOfObjectForKey: [graphImpl graphId]] ;
      if(0 == cnt ) {
        [[NSNotificationCenter defaultCenter]
          removeObserver: self];
        [serviceImpl close];
      }
    } else {
      [[NSNotificationCenter defaultCenter]
        removeObserver: self];
    }
  NS_HANDLER
    [serviceImpl release];
    [localException raise];
  NS_ENDHANDLER
  
  [serviceImpl release];
  return self;
}


- (id <FTServiceAvailability>) serviceAvailability {
  return self->serviceAvailability;
}


- (id <FTService>) serviceForGraph: (id <FTGraph>) aGraph {

  return nil;
}


- (id <FTService>) serviceForNode: (id <FTNode>) aNode 
  ofGraph: (id <FTGraph>) aGraph {
  FTDictionaryServiceForGraphImpl *serviceImpl;
  
  [self->generalLock lock];
  
  serviceImpl = [self->graphToServiceImpl 
    objectForKey: [aGraph graphId]
    incrementRefCounter: NO];
  
  if( nil == serviceImpl ) {
    NS_DURING
      serviceImpl = [[FTDictionaryServiceForGraphImpl alloc]
        initForGraph: aGraph
        serviceLoader: self];
      [self->graphToServiceImpl 
        addObject: serviceImpl
        forKey: [aGraph graphId]];
                
      [[NSNotificationCenter defaultCenter]
        addObserver: self
        selector: @selector(onGraphClosed:)
        name: FTNotification_Graph_afterClosed
        object: nil];
    NS_HANDLER
      [self->generalLock unlock];
      [[FTLogging coreLog] 
        error: @"FTDictionaryServiceLoader::serviceForNode: Unable to create "\
          "new dictionary service instance due to exception: %@",
          localException];
      [localException raise];
    NS_ENDHANDLER
  }    
  
  [self->generalLock unlock];
  
  return [serviceImpl serviceForNode: aNode];
}
  
  
- (NSString *) serviceId {
  return __FTDictionaryServiceId;
}


- (id <FTVersion>) serviceVersion {
  return self->serviceVersion;
}


- setDatabaseNameSchema: (NSString *) aDatabaseName {
  [aDatabaseName retain];
  
  [self->databaseNameScheme release];
  self->databaseNameScheme = aDatabaseName;
  
  return self;

}


- setEnvironment: (id <FTServiceEnvironment>) aServiceEnvironment {
  if( nil != self->serviceEnvironment ) {
    [self->serviceEnvironment release];
  }
  
  self->serviceEnvironment = [aServiceEnvironment retain];
  
  return self;
}


- switchToMode: (ft_serviceMode_t) aServiceMode {
    id <ECIterator> allKeys;
    id <FTDictionaryService> currentService;
    id graphId;
    
  switch( aServiceMode ) {
    case FT_SERVICE_MODE_ONLINE: 
      [self->graphToServiceImpl release];
      self->graphToServiceImpl = [[ECCache alloc] init];    
      break;
    case FT_SERVICE_MODE_SHUTDOWN:
      /* close all dictionaries: */
      allKeys = [self->graphToServiceImpl allKeys];
      while( [allKeys hasNext] ) {
        graphId = [allKeys next];
        currentService = [self->graphToServiceImpl 
          objectForKey: [allKeys next]
          incrementRefCounter: NO];
        NS_DURING
          [currentService close];
        NS_HANDLER
          [[FTLogging coreLog]
            error: @"FTDictionaryServiceLoader::switchToMode: Unable to close "\
              "dictionary identified by: %@", graphId];
        NS_ENDHANDLER
      }
      
      [self->graphToServiceImpl release];
      self->graphToServiceImpl = nil; 
      break;
    default:
      [[FTLogging coreLog]
        error: @"FTDictionaryServiceLoader::switchToMode: "\
         "Unknown mode=%u given. Ignoring it.", (unsigned) aServiceMode];
        
  }
  return self;
}


@end


@implementation FTDictionaryServiceAvailability

- (BOOL) availableForGraph: (id <FTGraph>) aGraph {
  return nil != aGraph;
}


- (BOOL) availableForNodesOfGraph: (id <FTGraph>) aGraph {
  return nil != aGraph;
}


- (BOOL) availableForNode: (id <FTNode>) aNode ofGraph: (id <FTGraph>) aGraph {
  return ((nil != aNode) && (nil != aGraph));
}
@end

