/******************************************************************************
  @header FTBootstrap
  @abstract Instances of this class are used to startup the server.
  
  @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>
******************************************************************************/

#include <Encore/Encore.h>
#include <FT/FTDefines.h>
#include <FT/FTBootstrap.h>
#include <FT/FTServerImpl.h>
#include <FT/FTVersion.h>
#include <FT/FTServiceLoader.h>
#include "FTLogging.h"

static FTBootstrap *_bootstrap = nil;

@implementation FTBootstrap

+ (FTBootstrap *) bootstrap {
  if( nil == _bootstrap ) {
    _bootstrap = [[FTBootstrap alloc] init];

    [_bootstrap readConfiguration];
    NSAssert( nil != _bootstrap, @"Could not allocate bootstrap instance!" );
  }
  
  return _bootstrap;
}


- init {
  self = [super init];
  self->server = nil;
  self->config = nil;

  return self;
}


- (void) dealloc {
  _bootstrap = nil;
  [self->server release];

  if( nil != self->config ) {
    [self->config release];
  }

  [super dealloc];
}


- (FTConfig *) config {
  return self->config;
}


- displayCommandlineOptions {
  NSLog( @"Command line options for the server:\n"\
    "\t%@ <configFile>\tpath to the configuration xml file",
    FTBOOTSTRAP_OPTION_CONFIG_FILE );

  return self;
}


- loadServices {
  EC_AUTORELEASEPOOL_BEGIN
  NSDictionary *serviceLoaders = [[self->config services] serviceLoaders];
  NSArray *allServiceLoaders = [serviceLoaders allValues];
  int i;
 
  for( i = 0; i < [allServiceLoaders count]; i++ ) {
    id <FTServiceLoader> current = [allServiceLoaders objectAtIndex: i];

    if( [[FTLogging coreLog] isDebugEnabled] ) {    
      [[FTLogging coreLog] 
        debug: @"FTBootstrap::loadServices: Loading service with id="\
          "\"%@\" and version=\"%@\"", [current serviceId], 
          [current serviceVersion]];
    }

    [[self->server serviceManager]
      registerServiceWithId: [current serviceId]
      withVersion: [current serviceVersion]
      withServiceLoader: current];
  }
  
#if 0 
DELETE 
  NSArray *servicesToLoad
    = [[[NSBundle bundleForClass: [self class]] 
        infoDictionary] objectForKey: FT_IP_SERVICES];

  if( nil != servicesToLoad ) {
    for( i = 0; i < [servicesToLoad count]; i++ ) {
      NSString *serviceLoaderClassName = [servicesToLoad objectAtIndex: i];
      Class serviceLoaderClass;
      NSString *serviceId;
      id <FTVersion> serviceVersion;
      
      if( [[FTLogging coreLog] isDebugEnabled] ) {    
        [[FTLogging coreLog]
          debug: @"FTBootstrap::loadServices: Loading class=%@", 
            serviceLoaderClassName ];
      }
      
      NS_DURING
        serviceId = nil;
        serviceVersion = nil;
        
        serviceLoaderClass = NSClassFromString( serviceLoaderClassName );
        if( nil != serviceLoaderClass ) {
          if( [serviceLoaderClass 
                conformsToProtocol: @protocol( FTServiceLoader )] ) {
            id <FTServiceLoader> loader = [[[serviceLoaderClass alloc] init] 
              autorelease];
              
            serviceId = [loader serviceId];
            serviceVersion = [loader serviceVersion];
            
            if( [[FTLogging coreLog] isDebugEnabled] ) {    
              [[FTLogging coreLog]
                debug: @"FTBootstrap::loadServices: Loading service with id="\
                  "\"%@\" and version=\"%@\"", serviceId, serviceVersion ];
            }
              
           [[self->server serviceManager] 
             registerServiceWithId: serviceId
             withVersion: serviceVersion
             withServiceLoader: loader];
          }
        }
      NS_HANDLER
        [[FTLogging coreLog]
          error: @"FTBootstrap::loadServices: FAILED to load service related "\
            "to service loader class=\"%@\"", serviceLoaderClassName ];
      NS_ENDHANDLER
    }
  }
#endif
  
  EC_AUTORELEASEPOOL_END
  
  return self;
}


- (id <FTServer>) initializeServer {
  if( nil != self->server ) {
    /**
	 * ups... should initialize a server which already runs...
	 */
	[[[ECIllegalStateException alloc] 
	  initWithIllegalStateInfo: @"Cannot initialize a server which is already "\
	  "running"] raise];
  }
  
  self->server = [[FTServerImpl alloc] 
    initWithConfig: config];

  [self loadServices];

  [((FTServerImpl *) self->server) setupDatabases];

  return self->server;
}


- readConfiguration {
  EC_AUTORELEASEPOOL_BEGIN
  NSProcessInfo *processInfo = [NSProcessInfo processInfo];
  int i;
  NSArray *arguments = [processInfo arguments];
  BOOL configFileRead = NO;

  for( i = 0; i < [arguments count]; i++ ) {
    if( [[arguments objectAtIndex: i] 
      isEqual: FTBOOTSTRAP_OPTION_CONFIG_FILE] ) {
      
      if( [arguments count] > i+1 ) {
        NSURL *configFileURL;
        ECXMLControl *xmlControl;
        configFileURL = [NSURL 
          fileURLWithPath: [arguments objectAtIndex: i+1]];
        
        // got specification of config file. Now read it!
        xmlControl = [[[ECXMLControl alloc]
          initWithContentsOfURL: configFileURL] autorelease];

        [xmlControl parseXML];

        self->config = [xmlControl rootUserObject];
 
        configFileRead = YES;

        i++; // skip parameter specifying the config file
      }
    }
  }

  if( !configFileRead ) {
    NSLog( @"FTBootstrap::readConfiguration: Configuration file "\
      "missing!" );

    [self displayCommandlineOptions];

    [[[ECIllegalArgumentException alloc]
      initWithArgumentInfo: @"FTBootstrap::readConfiguration: "\
      "Parameter for specifying config file is missing!"]
      raise];
  }
  
  EC_AUTORELEASEPOOL_END
  return self;
}


- (id <FTServer>) startServer {
  if( nil == self->server ) {
    self->server = [[FTServerImpl alloc] 
	  initWithConfig: config];
    [self loadServices];
	[((FTServerImpl *)self->server) mountDatabases];
  } else {
    /* are the databases mounted? */
	if( ![((FTServerImpl *)self->server) databasesMounted] ) {
	  [((FTServerImpl *)self->server) mountDatabases];
	}
  }
  
  return self->server;
}
@end
