/*
   Project: Adun

   Copyright (C) 2005 Michael Johnston & Jordi Villa-Freixa

   Author: Michael Johnston

   Created: 2005-06-23 11:06:55 +0200 by michael johnston

   This application is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This application 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
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#include "AdunKernel/AdunDataSource.h"

@implementation AdDataSource

/*******************************

Table conversions - to be moved to UL
\todo Table conversions must be moved to UL

********************************/

- (void) _convertBondsToSimulationUnits
{
	int i;
	InterTable* bnd_tbl;

	bnd_tbl = [[bondedInteractions valueForKey:@"HarmonicBond"] pointerValue];

	//convert bond constants to Da/fs^2
	
	for(i=0; i < bnd_tbl->no_interactions; i++)
		bnd_tbl->table[i][2] *= 2*BOND_FACTOR;
}

- (void) _convertAnglesToSimulationUnits
{
	int i;
	InterTable* ang_tbl;

	ang_tbl = [[bondedInteractions valueForKey:@"HarmonicAngle"] pointerValue];
	for(i=0; i < ang_tbl->no_interactions; i++)
	{
		ang_tbl->table[i][4] *= DEG_2_RAD;
		ang_tbl->table[i][3] *= 2*BOND_FACTOR;
	}
}

- (void) _convertTorsionsToSimulationUnits
{
	int i;
	InterTable* tor_tbl;

	tor_tbl = [[bondedInteractions valueForKey:@"FourierTorsion"] pointerValue];

	for(i=0; i < tor_tbl->no_interactions; i++)
		tor_tbl->table[i][4] *= BOND_FACTOR;
}

- (void) _convertImproperTorsionsToSimulationUnits
{
	int i;
	InterTable* tor_tbl;

	tor_tbl = [[bondedInteractions valueForKey:@"HarmonicImproperTorsion"] pointerValue];

	for(i=0; i < tor_tbl->no_interactions; i++)
	{
		tor_tbl->table[i][4] *= BOND_FACTOR;
		tor_tbl->table[i][5] *= DEG_2_RAD;
	}
}

/****************************************/

- (void) _nonbondedInteractionsFromSystem: (id) ulSystem
{
	NSMutableData* data;
	
	NSDebugLLog(@"AdDataSource", @"Getting nonbonded interactions");

	data = [ulSystem transmitNonbondedInteractions];

	NSDebugLLog(@"AdDataSource", @"Class is %@", [data class]);
	NSDebugLLog(@"AdDataSource", @"Is it a proxy? : %d", [data isProxy]);
	NSDebugLLog(@"AdDataSource", @"Allocated from zone %p", [data zone]);

	nonbondedInteractions = [NSUnarchiver unarchiveObjectWithData: data];
	[nonbondedInteractions retain];

	NSDebugLLog(@"AdDataSource", @"Complete");
}

- (void) _convertConfiguration: (id) ulSystem
{
	int i, j;
	id masses, partialCharges, vector, configuration;
	NSArray* matrixRows;

	NSDebugLLog(@"AdDataSource", @"Converting configuration");

	configuration = [ulSystem valueForKey: @"Configuration"];
	masses = [ulSystem transmitMasses];
	partialCharges = [ulSystem transmitPartialCharges];
	matrixRows = [ulSystem transmitMatrixRowsForConfiguration];
	atomTypes = [ulSystem transmitAtomTypes];
	[atomTypes retain];
	
	coordinates = [memoryManager allocateMatrixWithRows:
			  [[configuration valueForKeyPath: @"Coordinates.Rows"] intValue]
				withColumns: 6];
	
	for(i=0; i<coordinates->no_rows; i++)
	{
		vector = [matrixRows objectAtIndex:i];
		for(j=0; j< 3; j++)
			coordinates->matrix[i][j] = [[vector objectAtIndex:j] doubleValue];
			
		coordinates->matrix[i][3] = [[masses objectAtIndex: i] doubleValue];
		coordinates->matrix[i][4] = 1/coordinates->matrix[i][3];
		coordinates->matrix[i][5] = [[partialCharges objectAtIndex: i] doubleValue];
	}
	
	NSDebugLLog(@"AdDataSource", @"Complete");
}

- (void) _convertBondedTopologies: (id) ulSystem
{
	int i,j;
	InterTable *interactionTable;
	id top, interaction, vector, topology;
	NSArray* matrixRows;
	NSEnumerator *topologyEnum;

	NSDebugLLog(@"AdDataSource", @"Converting bonded topology");
	
	topology = [ulSystem valueForKeyPath: @"Topology.Bonded"];
	bondedInteractions = [NSMutableDictionary dictionaryWithCapacity:1];
	[bondedInteractions retain];
	topologyEnum = [[topology allValues] objectEnumerator];
	
	NS_DURING
	{
		while(top = [topologyEnum nextObject])
		{
			NSDebugLLog(@"AdDataSource", @"Topology is %@. Class is %@", 
				[top valueForKey:@"InteractionType"], 
				[top class]);
	
			interactionTable = [memoryManager allocateInterTableWithRows: 
						[[[top valueForKey:@"Matrix"] valueForKey: @"Rows"] intValue]
						withColumns: 
						[[[top valueForKey:@"Matrix"] valueForKey: @"Columns"] intValue]];

			NSDebugLLog(@"AdDataSource", @"Number of interactions %d. No columns %d",
					 interactionTable->no_interactions,
					 interactionTable->no_columns);
			
			[bondedInteractions setValue: [NSValue valueWithPointer: interactionTable]
					forKey: [top valueForKey:@"InteractionType"]];
			matrixRows = [ulSystem transmitMatrixRowsForPath: 
					[NSString stringWithFormat: @"Topology.Bonded.%@.Matrix",
						 [top valueForKey:@"InteractionType"]]];

			for(i=0; i<interactionTable->no_interactions; i++)
			{
				interaction = [matrixRows objectAtIndex:i];
				for(j=0; j<interactionTable->no_columns; j++)
					interactionTable->table[i][j] = [[interaction objectAtIndex: j] doubleValue];
			}
		}
	}
	NS_HANDLER
	{
		NSDebugLLog(@"AdDataSource", @"Caught exception %@ %@", 
			[localException name], 
			[localException reason]);
	}
	NS_ENDHANDLER

	//convert the parameters to simulation units - this will have to be moved to UL since the conversion
	//factor depends on the original unit AND the form of the interaction function. e.g. wheather the bond
	//function is k/2*(x-x0)² or k*(x-x0)². At the moment we are just assuming Enzymix Force Field
		
	if([bondedInteractions objectForKey: @"HarmonicBond"] != nil)
		[self _convertBondsToSimulationUnits];

	if([bondedInteractions objectForKey: @"HarmonicAngle"] != nil)
	 	[self _convertAnglesToSimulationUnits];

	if([bondedInteractions objectForKey: @"FourierTorsion"] != nil)
		[self _convertTorsionsToSimulationUnits];

	if([bondedInteractions objectForKey: @"HarmonicImproperTorsion"] != nil)
		[self _convertImproperTorsionsToSimulationUnits];
}	

- (void) _convertParameters:  (id) params usingSystem: (id) ulSystem
{
	int i, j;	
	id matrixRows, interaction;
	InterTable* parameterTable;	

	nonbondedInteractionTypes = [NSMutableDictionary dictionaryWithCapacity: 1];

	//VDW params - this is very hacky at the moment
	
	parameterTable = [memoryManager allocateInterTableWithRows: 
					[[[params valueForKey:@"Matrix"] valueForKey: @"Rows"] intValue]
				withColumns: 2];
	
	NSDebugLLog(@"AdDataSource", @"Number of interactions %d. No columns %d",
			 parameterTable->no_interactions, parameterTable->no_columns);
	
	matrixRows = [ulSystem transmitMatrixRowsForPath: @"Topology.Nonbonded.VDWParameters.Matrix"];
	for(i=0; i<parameterTable->no_interactions; i++)
	{
		interaction = [matrixRows objectAtIndex:i];
		for(j=0; j<parameterTable->no_columns; j++)
			parameterTable->table[i][j] = 
				[[interaction objectAtIndex: j+1] doubleValue];
	}

	//convert the parameters to simulation units
	//\note this could be moved to UL when the tables are created ....

	for(i=0; i < parameterTable->no_interactions; i++)
	{
		parameterTable->table[i][0] *= sqrt(BOND_FACTOR);
		parameterTable->table[i][1] *= sqrt(BOND_FACTOR);
	}

	[nonbondedInteractionTypes setObject: [NSValue valueWithPointer: parameterTable] 
		forKey: TypeOneVDWInteraction];
	//FIXME: We have to put a place holder for CoulombElectrostatic since at this moment
	//Its parameters are in the coordinate matrix. This needs to change.
	[nonbondedInteractionTypes setObject: [NSNull null]
		 forKey: CoulombElectrostatic];
	[nonbondedInteractionTypes retain];
}

/************

Creation

*************/

+ (id) dataSourceForULSystem: (id) ulSystem withEnvironment: (id) object
{
	id dataSource;

	dataSource = [[AdDataSource alloc] initWithULSystem: ulSystem 
			environment: object 
			observe: YES];
	return [dataSource autorelease];
}

- (id) initWithULSystem: (id) ulSystem environment: (id) object observe: (BOOL) value
{
	if(ulSystem == nil)
		[NSException raise: NSInternalInconsistencyException	
			format: @"ULSystem cannot be nil"];

	if(self = [super initWithEnvironment: environment observe: value])
	{
		memoryManager = [AdMemoryManager appMemoryManager];
		currentCaptureMethod = @"Standard";
		[currentCaptureMethod retain];	
		memento = NO;

		NSDebugLLog(@"AdDataSource", @"Beginning Data Source Conversion");

		[self _convertConfiguration: ulSystem]; 
		[self _convertBondedTopologies:	ulSystem]; 
		[self _nonbondedInteractionsFromSystem: ulSystem];
		[self _convertParameters: [ulSystem valueForKeyPath: @"Topology.Nonbonded.VDWParameters"] 
			usingSystem: ulSystem];
		systemName = [ulSystem valueForKey: @"name"];

		NSDebugLLog(@"AdDataSource", @"System Name %@", systemName);

		//hack since solvent system has no id at the moment

		if([systemName isEqual:@""] || [systemName isEqual:@"None"])
			systemName = @"Solvent";
		[systemName retain];
		
		NSDebugLLog(@"AdDataSource", @"System Name Now %@", systemName);
		NSDebugLLog(@"AdDataSource", @"Conversion complete");

		if(environment != nil)
		{
			[self registerWithEnvironment];
			[self synchroniseWithEnvironment];
		}
	}

	return self;
}

- (id) initWithEnvironment: (id) object observe: (BOOL) value
{
	return	[self initWithULSystem: nil environment: object observe: value];
}

- (id) initWithEnvironment: (id) object
{
	return [self initWithEnvironment: object observe: YES];
}

- (id) init
{
	return [self initWithEnvironment: nil];
}

- (void) dealloc
{
	NSEnumerator* matrixEnum;
	id matrix;

	[atomTypes release];
	[systemName release];
	[currentCaptureMethod release];
	[type release];
	[nonbondedInteractions release];

	matrixEnum = [bondedInteractions objectEnumerator];
	while(matrix = [matrixEnum nextObject])
		[memoryManager freeInterTable: [matrix pointerValue]];

	[bondedInteractions release];

	matrixEnum = [nonbondedInteractionTypes objectEnumerator];
	while(matrix = [matrixEnum nextObject])
		if([matrix isKindOfClass: [NSValue class]])
			[memoryManager freeInterTable: [matrix pointerValue]];

	[nonbondedInteractionTypes release];
	[memoryManager freeMatrix: coordinates];

	[super dealloc];
}	

/*
 * Environment observation
 */

- (void) updateForKey: (NSString*) key value: (id) value object: (id) object
{
	//no updates as of yet
}

- (void) registerWithEnvironment
{
	//nothing to register
}

- (void) deregisterWithEnvironment
{
	//nothing to deregister
}

- (void) synchroniseWithEnvironment
{
	//nothing to retrieve
}

- (void) setEnvironment: (id) object
{
	[self deregisterWithEnvironment];
	object = environment;
	[self registerWithEnvironment];
}

/************************

AdSystemDataSource Methods

**************************/

- (NSValue*) objectValueForCoordinates: (id) sender
{
	return [NSValue valueWithPointer: coordinates];
}

- (NSValue*) objectValueForVelocities: (id) sender
{
	return nil;
}

- (NSValue*) objectValueForAccelerations: (id) sender
{
	return nil;
}

- (NSArray*) objectValueForAtomTypes: (id) sender
{
	return atomTypes;
}

- (NSDictionary*) objectValueForBondedInteractions: (id) object
{
	return bondedInteractions;
}

- (NSArray*) objectValueForNonbondedInteractions: (id) object
{
	return nonbondedInteractions;
}

- (NSDictionary*) objectValueForNonbondedInteractionTypes: (id) object
{
	return nonbondedInteractionTypes;
}

- (NSString*) systemName
{
	return systemName;
}

/****
Type and SystemName need to be combined
***/

- (NSString*) type
{
	return type;
}

- (void) setType: (id) string
{
	[type release];
	type = [string retain];
}

@end


/**
Category Containing all the NSCoding and AdMemento 
related methods.
**/

@implementation AdDataSource (AdDataSourceCodingExtensions)

//have to store all the matrices
//when it comes to archiving momentos we should only store the bonded interactions if they have changed
//not at each step. 
//we also assume here that matrices are allocated as arrays with overlying pointer indexes

- (InterTable*) _decodeTableForType: (NSString*) interactionType usingDecoder: (NSCoder*) decoder
{
	int i,j;
	int length;
	InterTable* table;
	double* buffer, *array;

	table = (InterTable*)malloc(sizeof(InterTable));
	buffer = (double*)[decoder decodeBytesForKey: 
		[NSString stringWithFormat: @"%@.Table", interactionType]
		 returnedLength: &length];

	if(buffer == NULL)
		return NULL;

	NSDebugLLog(@"AdDataSource", @"%@ (%d bytes)", interactionType, length);
	table->no_interactions = [decoder decodeIntForKey: 
		[NSString stringWithFormat: @"%@.NumberOfInteractions", interactionType]];

	table->no_columns = [decoder decodeIntForKey:
		 [NSString stringWithFormat: @"%@.NumberOfColumns", interactionType]];

	table->table = (double**)malloc(table->no_interactions*sizeof(double*));
	array = malloc(length);
	for(i=0, j=0; i<table->no_interactions; i ++, j = j + table->no_columns)
		table->table[i] = array + j;
	for(i=0; i< table->no_interactions*table->no_columns; i++)
		array[i] = buffer[i];

	NSDebugLLog(@"AdDataSource", @"Interactions %d. Columns %d", 
		table->no_interactions, 
		table->no_columns);

	return table;
}

- (void) _mementoDecode: (NSCoder*) decoder
{
	int i, j;
	int length, count;
	double* array, *buffer;

	//coordinates

	coordinates = (AdMatrix*)malloc(sizeof(AdMatrix));
	buffer = (double*)[decoder decodeBytesForKey: @"CoordinateMatrix" returnedLength: &length];
	coordinates->no_rows = [decoder decodeIntForKey: @"Coordinates.Rows"];
	coordinates->no_columns = 6;
	coordinates->matrix = (double**)malloc(coordinates->no_rows*sizeof(double*));
	array = calloc(coordinates->no_rows*6, sizeof(double));
	for(i=0, j=0; i<coordinates->no_rows; i ++, j = j + coordinates->no_columns)
		coordinates->matrix[i] = array + j;
	
	//The memento only has three columns!

	for(count=0,i=0; i< coordinates->no_rows; i++)
		for(j=0; j<3; j++)
		{
			coordinates->matrix[i][j] = buffer[count];
			count++;
		}
}

- (void) _fullDecode: (NSCoder*) decoder
{
	int i, j;
	int length;
	double* array, *buffer;
	InterTable* table;
	id interactionTypes, interactionType, object;
	NSEnumerator* typeEnum;

	atomTypes = [[decoder decodeObjectForKey: @"AtomTypes"] retain];	
	systemName = [[decoder decodeObjectForKey: @"SystemName"] retain];	

	//coordinates

	coordinates = (AdMatrix*)malloc(sizeof(AdMatrix));
	buffer = (double*)[decoder decodeBytesForKey: @"CoordinateMatrix" returnedLength: &length];
	coordinates->no_rows = [decoder decodeIntForKey: @"Coordinates.Rows"];
	coordinates->no_columns = 6;
	coordinates->matrix = (double**)malloc(coordinates->no_rows*sizeof(double*));
	array = malloc(length);
	for(i=0, j=0; i<coordinates->no_rows; i ++, j = j + coordinates->no_columns)
		coordinates->matrix[i] = array + j;
	for(i=0; i< coordinates->no_rows*coordinates->no_columns; i++)
		array[i] = buffer[i];

	//bonded interactions

	interactionTypes = [decoder decodeObjectForKey: @"BondedInteractionTypes"];
	bondedInteractions = [[NSMutableDictionary dictionaryWithCapacity: 1] retain];
	typeEnum = [interactionTypes objectEnumerator];
	while(interactionType = [typeEnum nextObject])
	{
		table = [self _decodeTableForType: interactionType  usingDecoder: decoder];
		[bondedInteractions setObject: [NSValue valueWithPointer: table]
			forKey: interactionType];
	}

	//nonbonded params

	interactionTypes = [decoder decodeObjectForKey: @"NonbondedInteractionTypes"];
	nonbondedInteractionTypes = [[NSMutableDictionary dictionaryWithCapacity: 1] retain];
	typeEnum = [interactionTypes objectEnumerator];
	while(interactionType = [typeEnum nextObject])
	{
		table = [self _decodeTableForType: interactionType  usingDecoder: decoder];
		//FIXME: Due to no encoding of electrostatic parameters.
		if(table == NULL)
			object = [NSNull null];
		else
			object = [NSValue valueWithPointer: table];

		[nonbondedInteractionTypes setObject: object
			forKey: interactionType];
	}

	nonbondedInteractions = [decoder decodeObjectForKey: @"NonbondedInteractions"];
	[nonbondedInteractions retain];
}

- (id) initWithCoder: (NSCoder*) decoder
{	
	NSString* archiveType;

	self = [super initWithCoder: decoder];
	memoryManager = [AdMemoryManager appMemoryManager];
	if([decoder allowsKeyedCoding])
	{
		archiveType = [decoder decodeObjectForKey: @"ArchiveType"];
		currentCaptureMethod = [decoder decodeObjectForKey: @"CurrentCaptureMethod"];
		[currentCaptureMethod retain];
	
		NSDebugLLog(@"AdDataSource", @"Archive Type is %@", archiveType);

		if([archiveType isEqual: @"Memento"])
			[self _mementoDecode: decoder];
		else
			[self _fullDecode: decoder];
	}
	else
		[NSException raise: NSInvalidArgumentException 
			format: @"%@ does not support non keyed coding", [self classDescription]];
	
	environment = [AdEnvironment globalEnvironment];
	if(environment != nil)
	{
		[self synchroniseWithEnvironment];
		[self registerWithEnvironment];
	}

	return self;
}

//Encoding related methods.

- (void) _mementoEncodeWithCoder: (NSCoder*) encoder
{
	int i, j, count;
	int bytesLength;
	double *buffer;

	bytesLength = sizeof(AdMatrixSize)*coordinates->no_rows*3;	
	buffer = (double*)malloc(bytesLength*sizeof(double));
	
	for(i=0, count=0; i<coordinates->no_rows; i++)
		for(j=0; j<3; j++)
		{
			buffer[count] = coordinates->matrix[i][j];
			count++;
		}

	[encoder encodeBytes: (uint8_t*)buffer
		length: bytesLength 
		forKey: @"CoordinateMatrix"];
	[encoder encodeInt: coordinates->no_rows 
		forKey: @"Coordinates.Rows"];	
	free(buffer);
}


- (void) _fullEncodeWithCoder: (NSCoder*) encoder
{
	int bytesLength;
	id interactionType;
	InterTable* table;
	NSEnumerator *typesEnum;
	NSMutableArray *bondedInteractionRows, *bondedInteractionColumns;
	NSMutableArray *nonbondedParamsRows, *nonbondedParamsColumns;

	bytesLength = sizeof(AdMatrixSize)*coordinates->no_rows*coordinates->no_columns;	
	[encoder encodeBytes: (uint8_t*)coordinates->matrix[0] 
		length: bytesLength 
		forKey: @"CoordinateMatrix"];
	[encoder encodeInt: coordinates->no_rows 
		forKey: @"Coordinates.Rows"];	

	[encoder encodeObject: atomTypes forKey: @"AtomTypes"]; 
	[encoder encodeObject: systemName forKey: @"SystemName"]; 

	//bonded topology

	[encoder encodeObject: [bondedInteractions allKeys] 
		forKey: @"BondedInteractionTypes"];		
	typesEnum = [bondedInteractions keyEnumerator];
	while(interactionType = [typesEnum nextObject])
	{
		table = [[bondedInteractions valueForKey: interactionType] pointerValue];
		bytesLength = table->no_interactions*table->no_columns*sizeof(double);
		[encoder encodeBytes: (uint8_t*)table->table[0] 
			length: bytesLength 
			forKey: [NSString stringWithFormat: @"%@.Table", interactionType]];
		[encoder encodeInt: table->no_interactions 
			forKey: [NSString stringWithFormat: @"%@.NumberOfInteractions", interactionType]];		
		[encoder encodeInt: table->no_columns
			forKey: [NSString stringWithFormat: @"%@.NumberOfColumns", interactionType]];		
	}
	
	//nonbonded types

	typesEnum = [nonbondedInteractionTypes keyEnumerator];
	[encoder encodeObject: [nonbondedInteractionTypes allKeys] forKey: @"NonbondedInteractionTypes"];		
	while(interactionType = [typesEnum nextObject])
	{
		if(![[nonbondedInteractionTypes objectForKey: interactionType] isKindOfClass: [NSNull class]])
		{
			table = [[nonbondedInteractionTypes valueForKey: interactionType] pointerValue];
			bytesLength = table->no_interactions*table->no_columns*sizeof(double);
			[encoder encodeBytes: (uint8_t*)table->table[0] 
				length: bytesLength forKey: 
				[NSString stringWithFormat: @"%@.Table", interactionType]];
			[encoder encodeInt: table->no_interactions 
				forKey: [NSString stringWithFormat: @"%@.NumberOfInteractions", interactionType]];		
			[encoder encodeInt: table->no_columns
				forKey: [NSString stringWithFormat: @"%@.NumberOfColumns", interactionType]];		
		}
	}

	//nonbonded interactions

	[encoder encodeObject: nonbondedInteractions
		 forKey: @"NonbondedInteractions"];
}

- (void) encodeWithCoder: (NSCoder*) encoder
{
	int bytesLength;
	id interactionType;
	InterTable* table;
	NSEnumerator *typesEnum;
	NSMutableArray *bondedInteractionRows, *bondedInteractionColumns;
	NSMutableArray *nonbondedParamsRows, *nonbondedParamsColumns;

	[super encodeWithCoder: encoder];
	if([encoder allowsKeyedCoding])
	{
		[encoder encodeObject: currentCaptureMethod forKey: @"CurrentCaptureMethod"];
		if(memento)
		{
			[encoder encodeObject: @"Memento" forKey: @"ArchiveType"];
			[self _mementoEncodeWithCoder: encoder];
		}
		else
		{
			[encoder encodeObject: @"Complete" forKey: @"ArchiveType"];
			[self _fullEncodeWithCoder: encoder];
		}
	}
	else
		[NSException raise: NSInvalidArgumentException 
			format: @"%@ does not support non keyed coding", [self classDescription]];
} 

/********************

AdMemento

*******************/

- (id) setCaptureMethod: (NSString*) name
{
	if([name isEqual: @"Standard"] || [name isEqual: @"Full"])
	{
		[currentCaptureMethod release];
		currentCaptureMethod = [name retain];
	}
	else
		[NSException raise: NSInvalidArgumentException
			format: @"Capture Method %@ is not supported by this object"]; 	
}

- (void) captureStateWithArchiver: (NSCoder*) archiver key: (NSString*) key
{
	memento = YES;
	[archiver encodeObject: self forKey: key];
	memento = NO;
}

- (void) returnToState: (id) stateMemento
{
	[NSException raise: NSInternalInconsistencyException
		format: [NSString stringWithFormat: 
			@"Warning method %@ not implemented yet", NSStringFromSelector(_cmd)]];
}

- (id) captureState
{
	[NSException raise: NSInternalInconsistencyException
		format: [NSString stringWithFormat: 
			@"Warning method %@ not implemented yet", NSStringFromSelector(_cmd)]];
}

@end

