#include <assert.h>
#include <Foundation/Foundation.h>
#include <FT/FT.h>


id <FTServer> server = nil;

void startServer( BOOL firstStartOfServer ) {
  FTBootstrap *bootstrap;

  bootstrap = [FTBootstrap bootstrap];

  if( firstStartOfServer ) {
    server = [[bootstrap initializeServer] retain];
  } else {
    server = [[bootstrap startServer] retain];
  }

  [bootstrap release];
}


id <FTSession> login( 
  NSString *loginId, NSString *passwd )  {
  id <FTSessionManager> sessionManager;
  id <FTSession> toReturn;

  sessionManager = [server sessionManager];
  toReturn = [sessionManager loginAs: loginId withPassword: passwd];

  return [toReturn autorelease];
}


void createGraph( id session ) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  id <FTTransaction> transaction;
  id <FTObjectToIdMapper> sysOM;
  id <FTGraphManager> graphManager;

  id <FTObjectToIdMapper> graphOM;
  id <FTId> graphId;
  id <FTGraph> graph;
  id <FTId> id_application,id_ftsample,id_buildFile,id_ftconfig,id_ftdata;
  id <FTNode> node_application,node_ftsample,node_buildFile,node_ftconfig,node_ftdata;
  id <FTId> containsSrcId, containsBuildFileId, containsDbConfigFileId,
    createsSubDirId;
  id <FTDictionaryService> dictionaryService;
  NSData *fileContent;

  transaction = [session beginTransactionWithParent: nil withSettings: nil];

  sysOM = [session defaultObjectToIdMapper];
  graphManager = [session graphManager];

  // start transaction
  
  // Step I: create identifier for graph
  graphId = [sysOM mapObject: @"FTSampleGraph"];

  // Step II: create graph
  graph = [graphManager createGraphWithId: graphId];

  // Step III: get object mapper of the created graph
  graphOM = [graph objectToIdMapper];
  
  // Step IV: create the five identifiers:
  id_application = [graphOM mapObject: @"Application"];
  id_ftsample = [graphOM mapObject: @"FTSample.m"];
  id_buildFile = [graphOM mapObject: @"GNUmakefile"];
  id_ftconfig = [graphOM mapObject: @"ftconfig.xml"];
  id_ftdata = [graphOM mapObject: @"ftdata"];

  // Step V: create the five nodes
  node_application = [graph createNodeWithId: id_application];
  node_ftsample = [graph createNodeWithId: id_ftsample];
  node_buildFile = [graph createNodeWithId: id_buildFile];
  node_ftconfig = [graph createNodeWithId: id_ftconfig];
  node_ftdata = [graph createNodeWithId: id_ftdata];

  // Step VI: create all edge identifiers:
  containsSrcId = [graphOM mapObject: @"contains:src"];
  containsBuildFileId = [graphOM mapObject: @"contains:buildFile"];
  containsDbConfigFileId = [graphOM mapObject: @"contains:dbConfigFile"];
  createsSubDirId = [graphOM mapObject: @"creates:subDir"];

  // Step VII: Link the nodes appropriately to node node_aplication:
  [node_application createAndAppendEdgeWithId: containsSrcId
    withTargetNode: node_ftsample];

  [node_application createAndAppendEdgeWithId: containsBuildFileId
    withTargetNode: node_buildFile];

  [node_application createAndAppendEdgeWithId: containsDbConfigFileId
    withTargetNode: node_ftconfig];

  [node_application createAndAppendEdgeWithId: createsSubDirId
    withTargetNode: node_ftdata];

  // Step VIII
  // now store the content of the file FTSample.m within the node
  // "node_ftsample" using the dictionary service:

  // store FTSample.m in node_ftsample:
  dictionaryService = (id <FTDictionaryService>)
    [node_ftsample serviceWithId: @"FTDictionaryService"];

  fileContent = [[[NSData alloc] initWithContentsOfFile: @"FTSample.m"]
    autorelease];
  assert( nil != fileContent );

  [dictionaryService setObject: fileContent forKey: @"fileContent"];

  [dictionaryService close];
  // store GNUmakefile in node_buildFile
  dictionaryService = (id <FTDictionaryService>)
    [node_buildFile serviceWithId: @"FTDictionaryService"];

  fileContent = [[[NSData alloc] initWithContentsOfFile: @"GNUmakefile"]
    autorelease];
  assert( nil != fileContent );

  [dictionaryService setObject: fileContent forKey: @"fileContent"];

  [dictionaryService close];

  // store ftconfig.xml in node_ftconfig
  dictionaryService = (id <FTDictionaryService>)
    [node_ftconfig serviceWithId: @"FTDictionaryService"];

  fileContent = [[[NSData alloc] initWithContentsOfFile: @"ftconfig.xml"]
    autorelease];
  assert( nil != fileContent );

  [dictionaryService setObject: fileContent forKey: @"fileContent"];

  [dictionaryService close];

  [transaction commit];

  NSLog( @"Graph created!" );
  [pool release];
}


void checkout( id <FTSession> session, NSString *newLocation ) {
  id <FTGraphManager> graphManager;
  id <FTObjectToIdMapper> sysOM;
  id <FTObjectToIdMapper> graphOM;
  id <FTId> graphId;
  id <FTGraph> graph;
  id <FTId> id_application;
  id <FTNode> node_application;

  NSLog( @"Now reading graph content and performing a checkout..." );
  sysOM = [session defaultObjectToIdMapper];
  graphManager = [session graphManager];

  // start transaction
  
  // Step I: create identifier for graph
  graphId = [sysOM mapObject: @"FTSampleGraph"];

  // Step II: load graph
  graph = [graphManager graphWithId: graphId];

  // Step III: get object mapper of the created graph
  graphOM = [graph objectToIdMapper];
  
  // Step IV: create the five identifiers:
  id_application = [graphOM mapObject: @"Application"];

  // Step V: get  the application node
  node_application = [graph nodeWithId: id_application];
 
  // ... TODO
 
}


int main( int argc, char *argv[] ) {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  FTBootstrap *bootstrap;
  id <FTAdministrationSession> session;

  NSLog( @"**FTSample " );

  startServer(YES);
  session = (id <FTAdministrationSession>) login( @"altum", @"silentium" );

  createGraph( session );
  checkout( session, @"/tmp" );

  [pool release];

  NSLog( @"END OF FTSample" );
  return 0;
}

