/*
   Project: Adun

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

   Author: 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 "Commands/AdReloadCommand.h"

@implementation AdCore (AdReloadCommand)

- (BOOL) _loadSystemData: (NSDictionary*) options dataObject: (NSData**) systemData;
{
	BOOL isDirectory;
	NSFileManager* fileManager;
	id path;

	path = [options valueForKey:@"trajectory"];
	fileManager = [NSFileManager defaultManager];
	if(![fileManager fileExistsAtPath: path isDirectory: &isDirectory])
	{
		[self setErrorForCommand: @"reload" 
			description: [NSString stringWithFormat: @"No directory at path %@", path]];
		return NO;
	}

	//check its a results dir
	
	if(!isDirectory)
	{	
		[self setErrorForCommand: @"reload" 
			description: [NSString stringWithFormat:@"Trajectory must be a Adun results directory (%@)", path]];
		return NO;
	}

	//check it contains the required files

	if(![fileManager isReadableFileAtPath: [path stringByAppendingPathComponent: @"system.ad"]])
	{
		[self setErrorForCommand: @"reload" 
			description: @"Restart file (system.ad) not readable or not present"];
			return NO;
	}

	NSDebugLLog(@"Reload", @"Reading in trajectory from %@", path);
	if([[options valueForKey:@"restartPoint"] isEqual: @"Initial"])
	{
		if(![fileManager isReadableFileAtPath: [path stringByAppendingPathComponent: @"system.ad"]])
		{
			[self setErrorForCommand: @"reload" 
				description: @"Restart file (system.ad) not readable or not present"];
				return NO;
		}
		*systemData  = [fileManager contentsAtPath: [path stringByAppendingPathComponent: @"system.ad"]];
	}
	else if([[options valueForKey:@"restartPoint"] isEqual: @"Final"])
	{
		NSDebugLLog(@"Reload", @"Restarting from last saved position");
		if(![fileManager isReadableFileAtPath: [path stringByAppendingPathComponent: @"restart.ad"]])
		{
			[self setErrorForCommand: @"reload" 
				description: @"Restart file (restart.ad) not readable or not present"];
				return NO;
		}
		*systemData  = [fileManager contentsAtPath: [path stringByAppendingPathComponent: @"restart.ad"]];
	}	
	else
	{
		[self setErrorForCommand: @"reload"
			description: [NSString stringWithFormat:@"Specified restartPoint (%@) not valid", 
				[options valueForKey: @"restartPoint"]]];
		return NO;
	}	

	return YES;	
} 

- (id) reload: (NSDictionary*) options
{
	NSKeyedUnarchiver* unarchiver;
	BOOL retVal;
	id reason, path, environmentOptions;
	NSData* systemData;
	NSAutoreleasePool* autoreleasePool = [[NSAutoreleasePool alloc] init];

	NSLog(@"Received reload command with options %@", options);

	retVal = [self _loadSystemData: options dataObject: &systemData];
	if(retVal == NO)
		return [NSNumber numberWithBool: NO];

	unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData: systemData];

	//extract the options 
	
	environmentOptions = [unarchiver decodeObjectForKey: @"environmentOptions"];
	[environmentOptions setValue: [options valueForKey: @"outputPrefix"] 
		forKeyPath: @"Application.IO.OutputPrefix"];
	if([[options valueForKey: @"overrides"] isEqual: @"YES"])
	{
		NSLog(@"Overriding options");
		[environmentOptions setValue: 
				[options valueForKeyPath: @"overrides.general.timeStep"]
			forKeyPath: @"Simulation.General.TimeStep"];
		[environmentOptions setValue:
				 [options valueForKeyPath: @"overrides.general.numberOfSteps"]
			forKeyPath: @"Simulation.General.NumberOfSteps"];
		[environmentOptions setValue:
				 [options valueForKeyPath: @"overrides.outputIntervals.configuration"]
			forKeyPath: @"Application.IO.OutputIntervals.Configuration"];
		[environmentOptions setValue:
				 [options valueForKeyPath: @"overrides.outputIntervals.energy"]
			forKeyPath: @"Application.IO.OutputIntervals.Energy"];
		[environmentOptions setValue:
				 [options valueForKeyPath: @"overrides.outputIntervals.status"]
			forKeyPath: @"Application.IO.OutputIntervals.Status"];
	}

	NSDebugLLog(@"Reload", @"Using options dict %@", environmentOptions);

	[environment setOptions: environmentOptions];
	[ioManager createOutputDirectory];

	//create the simulator

	[self createSimulator: nil];

	//unarchive the system

	GSPrintf(stderr, @"Reload - Decoding data sources\n");
	dataSources = [unarchiver decodeObjectForKey: @"dataSources"];
	[dataSources retain];
	GSPrintf(stderr, @"Reload - Decoding system\n");
	system = [unarchiver decodeObjectForKey: @"system"];
	GSPrintf(stderr, @"Reload - Completed decoding system\n");

	[forceField setSystem: system];
	[simulator setSystem: system];

	//load the controller

	[self loadController: nil];
	[self checkpointSystem: @"system.ad"];
	[self initialCheckpoint];

	[unarchiver finishDecoding];
	[unarchiver release];

	NSDebugLLog(@"Reload", @"Using options dict %@", environmentOptions);

	[environment setOptions: environmentOptions];
	[ioManager createOutputDirectory];

	//create the simulator

	[self createSimulator: nil];

	//unarchive the system

	GSPrintf(stderr, @"Reload - Decoding data sources\n");
	dataSources = [unarchiver decodeObjectForKey: @"dataSources"];
	[dataSources retain];
	GSPrintf(stderr, @"Reload - Decoding system\n");
	system = [unarchiver decodeObjectForKey: @"system"];
	GSPrintf(stderr, @"Reload - Completed decoding system\n");

	[forceField setSystem: system];
	[simulator setSystem: system];

	//load the controller

	[self loadController: nil];
	[self checkpointSystem: @"system.ad"];
	[self initialCheckpoint];

	[unarchiver finishDecoding];
	[unarchiver release];

	[commandErrors removeObjectForKey: @"reload"];

	[autoreleasePool release];
}

- (NSMutableDictionary*) reloadOptions
{
	id options;
	NSString* optionsPath;

	optionsPath = [[[NSBundle mainBundle] resourcePath] 
			stringByAppendingPathComponent: @"reloadOptions.plist"];
	options = [NSMutableDictionary dictionaryWithContentsOfFile: optionsPath];

	return options;
}

- (NSError*) reloadError
{
	return [commandErrors objectForKey: @"reload"];
}

@end

