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

  28.09.05 ola     initial version
  23.08.06 ola     license changed
  -------------------------------------------------------------------------
  </pre>
*/

#include <FT/FTDefaultServiceManagerImpl.h>
#include <FT/FTServiceLoader.h>
#include <FT/FTDefaultServiceEnvironment.h>
#include <FT/FTLogging.h>

@implementation FTDefaultServiceManagerImpl

- initWithServer: (FTServerImpl *) aServer {
  self = [super init];
  
  self->serviceIdToServiceLoader = [[NSMutableDictionary alloc] init];
  self->rwLock = [[NSLock alloc] init];
  self->server = [aServer retain];
  
  return self;
}


- (void) dealloc {
  if( nil != self->serviceIdToServiceLoader ) {
    [self->serviceIdToServiceLoader release];
  }
  
  if( nil != self->rwLock ) {
    [self->rwLock release];
  }
  
  if( nil != self->server ) {
    [self->server release];
  }
  
  [super dealloc];
}


- (id <ECIterator>) allServicesForGraph: (id <FTGraph>) aGraph {
  return [self allServicesForNode: nil ofGraph: aGraph];
}


- (id <ECIterator>) allServicesForNode: (id <FTNode>) aNode 
  ofGraph: (id <FTGraph>) aGraph {
  
  NSMutableArray *availServices = [[[NSMutableArray alloc] init] autorelease];
  NSArray *allServices;
  int i;
  ECArrayIterator *toReturn;
  BOOL isAvailable;
  BOOL checkForNode = nil != aNode;
  
  EC_AUTORELEASEPOOL_BEGIN
  
  allServices = [self->serviceIdToServiceLoader allValues];
  
  for( i = 0; i < [allServices count]; i++ ) {
    id <FTServiceAvailability> availability;
    
    NS_DURING
      availability = [[allServices objectAtIndex: i] serviceAvailability];

      if( checkForNode ) {
        isAvailable = [availability availableForNode: aNode
          ofGraph: aGraph];
      } else {
        isAvailable = [availability availableForGraph: aGraph];
      }
      
      if( isAvailable ) {
        if( checkForNode ) {
          [availServices addObject: 
            [[allServices objectAtIndex: i ] serviceForNode: aNode
              ofGraph: aGraph]];
        } else {
          [availServices addObject: 
            [[allServices objectAtIndex: i ] serviceForGraph: aGraph]];
        }
      }
    NS_HANDLER
      //ignore this exception and proceed
    NS_ENDHANDLER
  }
  
  toReturn = [[ECArrayIterator alloc] initWithArray: availServices];
  
  EC_AUTORELEASEPOOL_END
  
  return toReturn;
}



- registerServiceWithId: (NSString *) serviceId
  withVersion: (id <FTVersion>) serviceVersion 
  withServiceLoader: (id <FTServiceLoader>) serviceLoader {
  id <FTServiceLoader> tmp;
  
  EC_AUTORELEASEPOOL_BEGIN
  [self rwLock];
  
  tmp = [self->serviceIdToServiceLoader objectForKey: serviceId];
  
  if( nil != tmp ) {
    if( [[tmp serviceVersion] isEqual: serviceVersion] ) {
      [self rwUnlock];
      
      [[[ECAlreadyExistsException alloc] 
        initWithResourceInformation: 
          [[NSString alloc] initWithFormat: @"Service \"%@\" already exists "\
            "with service id=\"%@\" and version=\"%@\"",
            tmp, serviceId, serviceVersion]] raise];
    } else {
      [self unregisterAllVersionsOfServiceWithId: serviceId];
      tmp = nil;
    }
  }
  
  [self->serviceIdToServiceLoader setObject: serviceLoader forKey: serviceId];
  
  [serviceLoader setEnvironment: 
    [[FTDefaultServiceEnvironment alloc] initWithServer: self->server]];
  
  [self rwUnlock];
  
  EC_AUTORELEASEPOOL_END
  return self;
}
  

- rwLock {
  [self->rwLock lock];
  
  return self;
}


- rwUnlock {
  [self->rwLock unlock];

  return self;
}

  

- (id <FTService>) serviceWithId: (NSString *) aServiceId 
  forGraph: (id <FTGraph>) aGraph {
   
  return [self serviceWithId: aServiceId forGraph: aGraph forNode: nil];
}
  
  
- (id <FTService>) serviceWithId: (NSString *) aServiceId 
  forGraph: (id <FTGraph>) aGraph forNode: (id <FTNode>) aNode {
  id <FTService> toReturn = nil;
  
    id <FTServiceLoader> serviceLoader
      = [self->serviceIdToServiceLoader objectForKey: aServiceId];
     
    NS_DURING
      if( nil != serviceLoader ) {
        if( nil != aNode ) {
          toReturn = [serviceLoader serviceForNode: aNode ofGraph: aGraph];
        } else {
          toReturn = [serviceLoader serviceForGraph: aGraph];
        }
      }
    NS_HANDLER
      //ignore it
    NS_ENDHANDLER
  
  return toReturn;
}
  
  
- switchAllServicesToMode: (ft_serviceMode_t) serviceMode {
  NSEnumerator *serviceLoaders = [serviceIdToServiceLoader objectEnumerator];
  id current;
  
  EC_AUTORELEASEPOOL_BEGIN
  while( (current = [serviceLoaders nextObject]) ) {
    NS_DURING
      if( [[FTLogging coreLog] isDebugEnabled] ) {    
        [[FTLogging coreLog]
          debug: @"FTDefaultServiceManagerImpl::switchAllServicesToMode: "\
            "Switching mode of service: %@", current ];
      }
      [current switchToMode: serviceMode];
    NS_HANDLER      
      [[FTLogging coreLog]
        error: @"FTDefaultServiceManagerImpl::switchAllServicesToMode: "\
          "Switching mode of service \"%@\" FAILED! Ignoring it...", current ];
    NS_ENDHANDLER
  }
  EC_AUTORELEASEPOOL_END

  return self;
}


- unregisterAllVersionsOfServiceWithId: (NSString *) serviceId {
  [self->serviceIdToServiceLoader removeObjectForKey: serviceId];
  
  return self;
}
@end
