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

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

#include <FT/FTGraphImplTransactions.h>
#include <FT/FTGraphImpl.h>
#include <FT/FTLogging.h>

/*!
 * @define __FTGRAPHIMPL_TRANSACTION_TYPEPARAM key within transaction context
 *   which refers to the type of transaction
 */
#define __FTGRAPHIMPL_TRANSACTION_TYPEPARAM @"@FTGraphImpl::typeParam"


/*!
 * @define __FTGRAPHIMPL_TRANSACTION_NODEPARAM key within transaction context
 *   which refers to the node paramater
 */
#define __FTGRAPHIMPL_TRANSACTION_NODEPARAM @"@FTGraphImpl::nodeParam"


/*!
 * @define __FTGRAPHIMPL_TRANSACTION_GRAPHPARAM key whose value refers to the
 *   graph instance
 */
#define __FTGRAPHIMPL_TRANSACTION_GRAPHPARAM @"FTGraphImpl::graphRef"


@implementation FTGraphImplTransactions
+ (void) addGenericContextData:(FTNodeImpl *) node
  graph: (FTGraphImpl *) graph
  operation: (int) operation
  toContext: (FTTransactionContext *) context {

  [context addObject: node forKey: __FTGRAPHIMPL_TRANSACTION_NODEPARAM ];
  [context addObject: graph forKey: __FTGRAPHIMPL_TRANSACTION_GRAPHPARAM ];
  [context addObject: [NSNumber numberWithInt: operation]
    forKey: __FTGRAPHIMPL_TRANSACTION_TYPEPARAM];

}


+ (FTGraphImplTransactions *) createForDeletionOfNode: (FTNodeImpl *) node
  withContext: (FTTransactionContext *) context
  withGraph: (FTGraphImpl *) graph {
  FTGraphImplTransactions *toReturn;
  
  [self addGenericContextData: node
    graph: graph
    operation: __FTGRAPHIMPL_TX_NODE_REMOVE
    toContext: context];

  toReturn = [[FTGraphImplTransactions alloc]  init];
  
  [toReturn enableOperation: YES];
  
  return toReturn;
}


+ (FTGraphImplTransactions *) createForUpdateOfNode: (FTNodeImpl *) node
  withContext: (FTTransactionContext *) context 
  withGraph: (FTGraphImpl *) graph {
  FTGraphImplTransactions *toReturn = nil;

  [self addGenericContextData: node
    graph: graph
    operation: __FTGRAPHIMPL_TX_NODE_UPDATE
    toContext: context];

  toReturn = [[FTGraphImplTransactions alloc]  init];
  
  [toReturn enableOperation: YES];
  
  return toReturn;
}


- (FTGraphImpl *) graphFromContext: 
  (FTTransactionContext *) transactionContext {
  FTGraphImpl *toReturn = nil;
  id tmp;
  
  tmp = [transactionContext objectForKey: __FTGRAPHIMPL_TRANSACTION_GRAPHPARAM];
  if( nil != tmp ) {
    if( [tmp isKindOfClass: [FTGraphImpl class]] ) {
      toReturn = (FTGraphImpl *) tmp;
    } else {
      [[FTLogging coreLog]
        error: @"Cannot find an instance of FTGraphImpl for context key: %@",
        __FTGRAPHIMPL_TRANSACTION_GRAPHPARAM ];
    }
  }
  
  return toReturn;
}


- enableOperation: (BOOL) doEnable {
  self->operationEnabled = doEnable;
  
  return self;
}


- (FTNodeImpl *) nodeFromContext: (FTTransactionContext *) transactionContext {
  FTNodeImpl *toReturn = nil;
  id tmp;
  
  tmp = [transactionContext objectForKey: __FTGRAPHIMPL_TRANSACTION_NODEPARAM];
  if( nil != tmp ) {
    if( [tmp isKindOfClass: [FTNodeImpl class]] ) {
      toReturn = (FTNodeImpl *) tmp;
    } else {
      [[FTLogging coreLog]
        error: @"Cannot find an instance of FTNodeImpl for context key: %@",
        __FTGRAPHIMPL_TRANSACTION_NODEPARAM ];
    }
  }
  
  return toReturn;
}


+ (enum __FTGraphImplTransactionType) 
  operationIdFromContext: (FTTransactionContext *) transactionContext {
  int operationId = __FTGRAPHIMPL_TX_UNKNOWN;
  
  if( nil != [transactionContext 
    objectForKey: __FTGRAPHIMPL_TRANSACTION_TYPEPARAM] ) {

    operationId = [((NSNumber *) [transactionContext
      objectForKey: __FTGRAPHIMPL_TRANSACTION_TYPEPARAM]) intValue];
  }
  
  return operationId;
}


- (BOOL) performAction: (FTTransactionContext *) transactionContext {
  BOOL success = NO;
  FTGraphImpl *graph;
  
  if( [[FTLogging coreLog] isTraceEnabled] ) {    
    [[FTLogging coreLog]
      trace: @"FTGraphImplTransactions::performAction" ];
  }
  
  if( self->operationEnabled ) {
    if( nil != [transactionContext 
      objectForKey: __FTGRAPHIMPL_TRANSACTION_TYPEPARAM] ) {

      graph = [self graphFromContext: transactionContext];
      if( nil == graph ) {
        /**
         * Something wrong here since we always expect a gaph instance in the 
         * transaction context
         */
        [[[ECIllegalStateException alloc] 
          initWithIllegalStateInfo: @"FTGraphImplTransactions::performAction: "\
            "Could not find graph parameter in transaction context"] raise ];
      }
    

      switch( [FTGraphImplTransactions 
        operationIdFromContext: transactionContext] ) {
        case __FTGRAPHIMPL_TX_NODE_UPDATE:
          success = [self 
            performUpdateWithContext: transactionContext
            withGraph: graph ];
          break;
        case __FTGRAPHIMPL_TX_NODE_REMOVE:
            success = [self
              performDeletionWithContext: transactionContext
              withGraph: graph];
          break;
        default:
          [[[ECIllegalStateException alloc] 
            initWithIllegalStateInfo: @"FTGraphImplTransactions::performAction"\
              ": Unsupported operation given!"] raise];
      }
    } 
  } else {
    success = YES;
    if( [[FTLogging coreLog] isDebugEnabled] ) {    
      [[FTLogging coreLog]
        debug: @"FTGraphImplTransactions::performAction: Action disabled" ];
    }
  }
  
  
  return success;
}


- (BOOL) performDeletionWithContext: (FTTransactionContext *) transactionContext
  withGraph: (FTGraphImpl *) aGraph {
  FTNodeImpl *node;
  
  if( [[FTLogging coreLog] isTraceEnabled] ) {    
    [[FTLogging coreLog]
      trace: @"%FTGraphImplTransactions::performDeletionWithContext..." ];
  }
  
  node = [self nodeFromContext: transactionContext];
  if( nil == node ) {
    [[[ECIllegalStateException alloc] 
        initWithIllegalStateInfo:
          @"FTGraphImplTransactions::performDeletionWithContext:"\
          "Could not find node parameter in transaction context"] raise ];
  }
  
  [aGraph removeNodeFromDatabase: node];
    
  return YES;
}


- (BOOL) performUpdateWithContext: (FTTransactionContext *) transactionContext
  withGraph: (FTGraphImpl *) aGraph {
  FTNodeImpl *node;
  
  if( [[FTLogging coreLog] isTraceEnabled] ) {    
    [[FTLogging coreLog]
      trace: @"%FTGraphImplTransactions::performUpdateWithContext..." ];
  }
  
  node = [self nodeFromContext: transactionContext];
  if( nil == node ) {
    [[[ECIllegalStateException alloc] 
        initWithIllegalStateInfo:
          @"FTGraphImplTransactions::performUpdateWithContext:"\
          "Could not find node parameter in transaction context"] raise ];
  }
  
  [aGraph updateNode: node];
  
  return YES;
}


- (BOOL) undoAction: (FTTransactionContext *) transactionContext {
  [[[ECNotImplementedException alloc] 
    initWithOperationInformation: @"FTGraphImplTransactions::undoAction" ]
    raise];
    
  return NO;
}
@end
