/*!
  @header BDBDatabaseEntry
  @abstract BDB 
 
  @availability OS X, GNUstep
  @copyright (C) 2004, 2005, 2006 Oliver Langer
 
  Author: Oliver Langer

  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

  03.01.2005 ola     initial version
  22.08.2006 ola     license changed
  -------------------------------------------------------------------------
  </pre>
*/

#include <BDB/BDBDatabaseEntry.h>


/**
 * Key used to store the data of an entry
 */
#define __archiveKey @"__BDBDatabaseEntry"

/*!
 * @enum __deserialization_method_t
 * @abstract Stores information at the beginning of each NSData block which
 *   tells this implementation, how the NSData should be handled in order to
 *   return the correct object via the method "object"
 * @constant SER_METHOD_NONE No serialization has been used. That is, an
 *   instance of NSData has originally been hand-off and has to be returned.
 * @constant SER_METHOD_KEYED_ARCHIVER NSKeyedArchiver has to be used for
 *   deserialization.
 */
enum __deserialization_method_t {
  SER_METHOD_NONE = 0,
  SER_METHOD_KEYED_ARCHIVER
  //SER_METHOD_BINARY_ARCHIVER
};

@implementation BDBDatabaseEntry
- initWithObject: (id <NSCoding>) object {
  
  self = [super init];
  
  EC_AUTORELEASEPOOL_BEGIN
  if( [((NSObject *) object) isKindOfClass: [NSData class]] ) {
    [self setData: ((NSData *) object) 
      usedSerializationMethod: SER_METHOD_NONE];
  } else {
    NSKeyedArchiver *archiver;
    NSMutableData *objData = [[[NSMutableData alloc] init] autorelease];
  
    archiver = [[[NSKeyedArchiver alloc] 
     initForWritingWithMutableData: objData]
     autorelease];

    [archiver 
      encodeObject: object 
      forKey: __archiveKey];
 
    [archiver finishEncoding];
  
    [self setData: objData usedSerializationMethod: SER_METHOD_KEYED_ARCHIVER];
  }
  	
  return self;
  
  EC_AUTORELEASEPOOL_END
}


- (NSData *) dataWithDeserializationMethodInfo: (int *) deserializationInfo {
  NSData *data;
  NSData *toReturn = nil;
  int tmp;
  
  data = [self data];
  if( nil != data ) {
    NSRange userDataRange;
    
    // read hint about deserialization method first, then the rest:
    [data getBytes: &tmp length: sizeof(int)];

    if( NULL != deserializationInfo ) {
      *deserializationInfo = tmp;
    }
    
    userDataRange.location = sizeof(int);
    userDataRange.length = [data length] - sizeof(int);
    
    if( 0 < userDataRange.length ) {
      toReturn = [data subdataWithRange: userDataRange];
    }
  } else {
    if( NULL != deserializationInfo ) {
      *deserializationInfo = SER_METHOD_NONE;
    }
  }
  
  return toReturn;
}


- object {
  id toReturn = nil;
  int deserializationInfo;
  NSData *userData;
  /**
   * Does not run under GS:
  NS_DURING
    toReturn = [ NSUnarchiver unarchiveObjectWithData: [ self data ] ];
  NS_HANDLER
    NSLog( @"BDBDatabaseEntry::object: gotException %@", 
      [localException name] );
    [localException raise];
  NS_ENDHANDLER
  */
  
  userData = [self dataWithDeserializationMethodInfo: &deserializationInfo];

  if( nil != userData ) {
    if( SER_METHOD_NONE == deserializationInfo ) {
      toReturn = userData;
    } else 
    if( SER_METHOD_KEYED_ARCHIVER == deserializationInfo ) {
      NSKeyedUnarchiver *unarchiver;
  
      unarchiver = [[[NSKeyedUnarchiver alloc]
        initForReadingWithData: userData]
        autorelease];

      toReturn = [unarchiver decodeObjectForKey: __archiveKey];
 
      [unarchiver finishDecoding];
    } else {
      [[[ECIllegalStateException alloc] 
        initWithIllegalStateInfo: @"BDBDatabaseEntry::object: Data buffer "\
          "contains unknown flag value at offset 0"] raise];
    }
  }
  
  return toReturn;
}


- setData: (NSData *) dataToSet 
  usedSerializationMethod: (int) serializationMethod {
  NSMutableData *data = [[NSMutableData init] alloc];
  
  [data appendBytes: &serializationMethod length: sizeof(int)];
  [data appendData: dataToSet];
  
  [self setData: data];
  
  [data release];
  
  return self;
}
@end
