/*
   Project: EnergyConverter

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

   Author: Michael Johnston

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

#include "EnergyConverter.h"

@implementation EnergyConverter

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

Formatting

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

//use NSNumberFormatter when it is finally implemented

- (void) _formatEnergies: (NSDictionary*) energies
{
	int i;
	id subsystem, energy, field, number;
	NSEnumerator* subsystemEnum, *energyEnum, *fieldEnum;
	NSMutableArray *fieldWidths;
	NSArray *fields;
	NSRange range;

	subsystemEnum = [energies objectEnumerator];
	while(subsystem = [subsystemEnum nextObject])
	{
		//calculate the width of each field 

		fields = [subsystem columnHeaders];
		fieldEnum = [fields objectEnumerator];
		fieldWidths = [NSMutableArray arrayWithCapacity: 1];
		while(field = [fieldEnum nextObject])
			[fieldWidths addObject: [NSNumber numberWithInt: [field length] +1]];

		energyEnum = [[subsystem matrixRows] objectEnumerator];
		while(energy = [energyEnum nextObject])
		{
			for(i=0; i<[energy count]; i++)
			{
				number = [energy objectAtIndex: i];
				if([[fields objectAtIndex: i] isEqual: @"Time"])
					number = [NSString stringWithFormat: @"%-*.2lf", 
							[[fieldWidths objectAtIndex: i] intValue],
							 [number doubleValue]];
				else
					number = [NSString stringWithFormat: @"%-*.3lf", 
							[[fieldWidths objectAtIndex: i] intValue], 
							[number doubleValue]];

				[energy replaceObjectAtIndex: i withObject: number];
			}
		}
	}
}

- (id) _retrieveEnergies
{
	int stepsize;
	NSString* energyUnit;
	NSArray* selectedTerms;
	NSArray* selectedSubsystems;
	NSRange frameRange;
	NSEnumerator* enumerator;
	NSArray* holder;
	NSMutableArray* energies;
	id subsystem, result;

	[currentResults setEnergyUnit: [currentOptions valueForKey: @"EnergyUnit"]];
	energies = [NSMutableArray array];
	selectedSubsystems = [currentOptions valueForKeyPath: @"Subsystems.Selection"];
	enumerator = [selectedSubsystems objectEnumerator];
	while(subsystem = [enumerator nextObject])
	{
		selectedTerms = [currentOptions valueForKeyPath: [NSString stringWithFormat:	
					 @"Subsystems.%@.Selection", subsystem]];
		frameRange.location = [[currentOptions valueForKeyPath: [NSString stringWithFormat:	
					 @"Frames.Start", subsystem]] intValue];
		frameRange.length = [[currentOptions valueForKeyPath: [NSString stringWithFormat:	
					 @"Frames.Length", subsystem]] intValue];
		stepsize = [[currentOptions valueForKeyPath: [NSString stringWithFormat:	
					 @"Stepsize", subsystem]] intValue];
		result = [currentResults energiesForSubsystem: subsystem
				terms: selectedTerms
				inFrames: &frameRange
				step: stepsize];
		if(result == nil)
			NSWarnLog(@"Warning: No energies available for subsystem %@", subsystem);
		else
			[energies addObject: result];
	}

	return energies;
}

/**********

Protocols

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

- (id) init
{
	if(self == [super init])
	{
		infoDict = [[NSBundle bundleForClass: [self class]]
				infoDictionary];
		[infoDict retain];		
	}

	return self;
}

- (NSDictionary*) pluginOptions: (NSArray*) inputs
{
	ULSimulation* simulation;

	simulation = [inputs objectAtIndex: 0];
	if(![simulation isKindOfClass: [ULSimulation class]])
		[NSException raise: NSInvalidArgumentException
			format: @"EnergyConverter cannot process %@ objects", 
			NSStringFromClass([simulation class])];

	return [simulation optionsDict];
}	

- (id) processInputs: (id) inputs userOptions: (NSDictionary*) options; 
{ 
	int i;
	id energies;
	AdDataSet* dataSet;
	NSMutableDictionary* resultsDict = [NSMutableDictionary dictionary];

	currentResults = [inputs objectAtIndex: 0];

	//check its a ULSimulation

	if(![currentResults isKindOfClass: [ULSimulation class]])
		[NSException raise: NSInvalidArgumentException
			format: @"EnergyConverter cannot process %@ objects", 
			NSStringFromClasss([currentResults class])];
	
	currentOptions = options;
	energies = [self _retrieveEnergies];

	if([energies count] == 0)
		return nil;

	//create the data set
	//Property lists in old format cant handle numbers
	dataSet = [[AdDataSet alloc] initWithName: @"DataSet One"
			inputReferences: nil
			dataGeneratorName: @"EnergyConverter"
			dataGeneratorVersion: [infoDict objectForKey: @"PluginVersion"]];
	[dataSet autorelease];
	
	[resultsDict setObject: [NSArray arrayWithObject: dataSet] 
		forKey: @"ULAnalysisPluginDataSets"];
		
	[self _formatEnergies: energies];
	for(i=0; i<[energies count]; i++)
		[dataSet addDataMatrix: [energies objectAtIndex: i]];

	return resultsDict;
}

@end
