/*
   Project: ConformationConverter

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

   Author: Michael Johnston

   Created: 2005-11-04 16:43:29 +0100 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
a  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#include "ConformationConverter.h"

@implementation ConformationConverter

//use NSNumberFormatter when it is finally implemented

- (void) _outputXYZFor: (AdMatrix*) coordinates 
	withAtomTypes: (NSArray*) atomTypes 
	toFile: (FILE*) outFile
{
	int i, j;
	id atom;

	GSPrintf(outFile, @"%d\n", coordinates->no_rows);
	GSPrintf(outFile, @"Energy:\n");
	for(i=0; i<coordinates->no_rows; i++)
	{
		atom = [atomTypes objectAtIndex: i];
		GSPrintf(outFile, @"%-12@%-12.3lf%-12.3lf%-12.3lf\n", 
				atom, coordinates->matrix[i][0],
				coordinates->matrix[i][1], 
				coordinates->matrix[i][2]);
	} 
}

/**********

Protocols

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

- (id) init
{
	return self;
}

- (NSDictionary*) pluginOptions: (NSArray*) inputs
{
	NSMutableArray* subsystems;
	id simulationOptions;
	
	simulation = [inputs objectAtIndex: 0];
	if(![simulation isKindOfClass: [ULSimulation class]])
		[NSException raise: NSInvalidArgumentException
			format: @"ConformationConverter cannot process %@ objects", 
			NSStringFromClasss([simulation class])];

	simulationOptions = [simulation optionsDict];
	
	NSDebugLLog(@"ConformationConverter", @"Recieved options request (%@)", simulationOptions);

	subsystems = [[[simulationOptions valueForKey: @"Subsystems"] allKeys] mutableCopy];
	[subsystems removeObject: @"Selection"];
	[[simulationOptions objectForKey: @"Subsystems"] removeAllObjects];
	[simulationOptions setValue: subsystems forKeyPath: @"Subsystems.AvailableSubsystems"];
	[simulationOptions setValue: [NSMutableArray array] forKeyPath: @"Subsystems.Selection"];

	[simulationOptions setObject: @"XYZ" forKey: @"Format"];
	NSDebugLLog(@"ConformationConverter", @"\nReturing (%@)", simulationOptions);
	return simulationOptions;
}	

- (id) processInputs: (id) inputs userOptions: (NSDictionary*) options; 
{
	int i, step;
	int startFrame, endFrame, totalFrames, output;
	FILE* outFile;
	AdMatrix* coordinates;
	id subsystems, subsystem;
	NSString* filename;
	NSArray* atomTypes;
	NSEnumerator* subsystemEnum;
	NSMutableString* returnString;
	NSMutableDictionary* notificationDict;

	currentOptions = options;
	simulation = [inputs objectAtIndex: 0];
	if(![simulation isKindOfClass: [ULSimulation class]])
		[NSException raise: NSInvalidArgumentException
			format: @"ConformationConverter cannot process %@ objects", 
			NSStringFromClasss([simulation class])];
	
	subsystems = [options valueForKeyPath: @"Subsystems.Selection"];
	subsystemEnum = [subsystems objectEnumerator];
	returnString = [NSMutableString stringWithCapacity: 1];
	[returnString appendFormat:
		 @"Output conformations for simulation at %@\n\n", 
		 [[simulation dataStorage] storagePath]];

	NSDebugLLog(@"ConformationConverter", @"Selected subsystems %@. Simulation %@", subsystems, simulation);

	startFrame = [[currentOptions valueForKeyPath: @"Frames.Start"] intValue];
	if([[currentOptions valueForKeyPath: @"Frames.Length"] intValue] == 0)
		endFrame = [simulation numberOfCoordinateFramesForSubsystem: subsystem];
	else
		endFrame = startFrame +  [[currentOptions valueForKeyPath: @"Frames.Length"] intValue];

	NSDebugLLog(@"ConformationConverter", @"Start Frame %d. End Frame %d", startFrame, endFrame);

	step = [[currentOptions valueForKey: @"Stepsize"] intValue];
	totalFrames = [subsystems count]*(endFrame - startFrame);
	totalFrames = lround((double)totalFrames/(double)step);		
	output = 0;

	notificationDict = [NSMutableDictionary dictionary];	
	[notificationDict setObject: [NSNumber numberWithInt: totalFrames]
		forKey: @"ULAnalysisPluginTotalSteps"];
	
	
	while(subsystem = [subsystemEnum nextObject])
	{
		NSDebugLLog(@"ConformationConverter", @"Subsystem %@", subsystem);
		atomTypes = [simulation atomTypesForSubsystem: subsystem];
		NSDebugLLog(@"ConformationConverter", @"Beginning");
		if(atomTypes != nil)
		{
			filename = [NSString stringWithFormat: @"%@.xyz", subsystem];
			filename = [[[simulation dataStorage] storagePath] 
					stringByAppendingPathComponent: filename];
			[returnString appendFormat: @"\tSubsystem %@ - File %@\n", subsystem, filename];
			outFile = fopen([filename cString], "w");
			for(i=startFrame; i< endFrame; i = i+step)
			{
				NSDebugLLog(@"ConformationConverter", @"Retrieving frame %d", i);
				coordinates = [simulation coordinatesForFrame: i subsystem: subsystem];
				NSDebugLLog(@"ConformationConverter", @"Outputting frame %d", i);
				[self _outputXYZFor: coordinates withAtomTypes: atomTypes toFile: outFile];
				NSDebugLLog(@"ConformationConverter", @"Complete");
				output++;
				if(output%10 == 0)
				{
					[notificationDict setObject: [NSNumber numberWithInt: output]
						forKey: @"ULAnalysisPluginCompletedSteps"];
					[[NSNotificationCenter defaultCenter] postNotificationName:
						@"ULAnalysisPluginDidCompleteStepNotification"
						object: nil
						userInfo: notificationDict];
				}
			}

			fclose(outFile);
		}
		else
		{
			NSWarnLog(@"\tNo dynamics for %@\n", subsystem);
			[returnString appendFormat: @"No dynamics for %@\n", subsystem];
		}
 	}

	[returnString appendString: @"\nComplete\n"];
	
	return [NSDictionary dictionaryWithObject: returnString forKey: @"ULAnalysisPluginString"];
}

@end
