/*
   Project: UL

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

   Author: Michael Johnston

   Created: 2005-05-23 15:46:27 +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 "ULIOManager.h"

static id ioManager;

@implementation ULIOManager

+ (id) appIOManager
{
	//check if we have already created the manager

	if(ioManager != nil)
	{
		return ioManager;
	}
	else
	{
		ioManager = [self new];
		return ioManager;
	}
}

/**
Usually only called when the application first starts up
*/

- (void) _createApplicationDirectories
{
	id tempObj;	
	
	if(![fileManager createDirectoryAtPath: applicationDir attributes: nil])
		[NSException raise: NSInternalInconsistencyException 
			format: @"Unable to create working directory!"];
	
	//Move database subdirectory creation to ULFileSystemDatabaseBackend
	[fileManager createDirectoryAtPath: databaseDir 
		attributes: nil];
	[fileManager createDirectoryAtPath: userPluginsDir 
		attributes: nil];
	[fileManager createDirectoryAtPath: 
			[userPluginsDir stringByAppendingPathComponent: @"Configurations"]
		 attributes: nil];
	[fileManager createDirectoryAtPath: 
			[userPluginsDir stringByAppendingPathComponent: @"Analysis"]
		 attributes: nil];
	[fileManager createDirectoryAtPath: 
			[userPluginsDir stringByAppendingPathComponent: @"Controllers"]
		 attributes: nil];

	//create the default host list

	tempObj = [NSMutableArray arrayWithCapacity:1];
	[tempObj addObject: [[NSHost currentHost] name]];
	[tempObj writeToFile: [applicationDir stringByAppendingPathComponent: @"AdunHosts.plist"]
		atomically: NO];
}

- (id) init
{
	BOOL isDir;

	//create filemanager instance

	if(self = [super init])
	{
		fileManager = [NSFileManager defaultManager];
		userHome = NSHomeDirectory();
		processInfo = [NSProcessInfo processInfo];

		currentDir = [fileManager currentDirectoryPath];
		[currentDir retain];

		applicationDir = [userHome stringByAppendingPathComponent: @"adun"];
		databaseDir = [applicationDir stringByAppendingPathComponent: @"Database"];
		userPluginsDir = [applicationDir stringByAppendingPathComponent: @"Plugins"];
		controllerOutputDir = [applicationDir stringByAppendingPathComponent: @"ControllerOutput"];

		[applicationDir retain];
		[databaseDir retain];
		[userPluginsDir retain];
		[controllerOutputDir retain];

		NSDebugLLog(@"ULIOManager", @"Current Dir: %@\n", currentDir);
		NSDebugLLog(@"ULIOManager", @"App Dir: %@\n", applicationDir);

		//check if adun directory exists and create it if it doesnt

		if(!([fileManager fileExistsAtPath: applicationDir isDirectory: &isDir] && isDir))
			[self _createApplicationDirectories];

		if(!([fileManager fileExistsAtPath: controllerOutputDir isDirectory: &isDir] && isDir))
			[fileManager createDirectoryAtPath: controllerOutputDir 
				attributes: nil];
	}

	return self;
}

- (void) dealloc
{
	[currentDir release];
	[applicationDir release];
	[databaseDir release];
	[userPluginsDir release];
	[controllerOutputDir release];
}

- (NSString*) applicationDir
{
	return [[applicationDir retain] autorelease];
}

- (NSString*) databaseDir
{
	return [[databaseDir retain] autorelease];
}

- (NSString*) controllerOutputDir
{
	return [[controllerOutputDir retain] autorelease];
}

- (NSArray*) configurationPlugins
{
	return [[NSFileManager defaultManager] directoryContentsAtPath: 
			[userPluginsDir stringByAppendingPathComponent: @"Configurations"]];
}

- (NSMutableArray*) AdunHosts
{
	return [NSMutableArray arrayWithContentsOfFile:
		[applicationDir stringByAppendingPathComponent: @"AdunHosts.plist"]];
}

- (BOOL) writeObject: (id) object toFile: (NSString*) filename error: (NSError**) error
{
	BOOL isDir;
	NSString* dir, *reason;
	NSMutableDictionary* userInfo;
	id temp, name;

	userInfo = [NSMutableDictionary dictionary];
	
	//check object

	if(![object respondsToSelector: @selector(writeToFile:atomically:)])
	{
		reason = @"Object invalid - must respond to writeToFile:atomically:";
		[userInfo setObject: reason forKey: NSLocalizedDescriptionKey];
		*error = [NSError errorWithDomain: @"ULErrorDomain"
				code: 1
				userInfo: userInfo];
		return NO;
	}

	//check file
	name = 	[[filename lastPathComponent] stringByTrimmingCharactersInSet: 
						[NSCharacterSet whitespaceCharacterSet]];
						
	NSDebugLLog(@"Export", @"Name of file is %@", name);
	if([name isEqual: @""])
	{
		reason = @"Filename invalid - Must contain characters other than whitespace";
		[userInfo setObject: reason forKey: NSLocalizedDescriptionKey];
		*error = [NSError errorWithDomain: @"ULErrorDomain"
				code: 1
				userInfo: userInfo];
		return NO;
	}

	temp = [[filename pathComponents] mutableCopy];
	[temp removeLastObject];
	dir = [NSString pathWithComponents: temp];

	NSDebugLLog(@"Export", @"Exporting to dir %@", dir);
	
	
	if(![fileManager fileExistsAtPath: dir isDirectory: &isDir])
	{
		reason = [NSString stringWithFormat: @"The specfied directory (%@) does not exist", dir];
		[userInfo setObject: reason forKey: NSLocalizedDescriptionKey];
		*error = [NSError errorWithDomain: @"ULErrorDomain"
				code: 1
				userInfo: userInfo];
		return NO;
	}
	
	if(!isDir)
	{
		reason = [NSString stringWithFormat: @"%@ is not a directory", dir];
		[userInfo setObject: reason forKey: NSLocalizedDescriptionKey];
		*error = [NSError errorWithDomain: @"ULErrorDomain"
				code: 1
				userInfo: userInfo];
		return NO;
	}

	if(![fileManager isWritableFileAtPath: dir])
	{
		reason = [NSString stringWithFormat: @"Specified directory (%@) is not writable", dir];
		[userInfo setObject: reason forKey: NSLocalizedDescriptionKey];
		*error = [NSError errorWithDomain: @"ULErrorDomain"
				code: 1
				userInfo: userInfo];
		return NO;
	}


	if([fileManager fileExistsAtPath: filename])
		if(![fileManager isWritableFileAtPath:filename]) 
		{
			reason = @"Cannot overwrite file - write protected";
			[userInfo setObject: reason forKey: NSLocalizedDescriptionKey];
			*error = [NSError errorWithDomain: @"ULErrorDomain"
					code: 1
					userInfo: userInfo];
			return NO;
		}

	if(![object writeToFile: filename atomically: NO])
	{
		reason = @"Unable to export file - Reason unknown";
		[userInfo setObject: reason forKey: NSLocalizedDescriptionKey];
		*error = [NSError errorWithDomain: @"ULErrorDomain"
				code: 1
				userInfo: userInfo];
		return NO;
	}

	return YES;
}

@end


@implementation ULIOManager (ULTemporaryFileExtensions)


- (NSString*) temporaryDirectoryWithPrefix: (NSString*) prefix
{
	NSString* uniqueString = [processInfo globallyUniqueString];
	NSString* tempDir;

	if(prefix == nil)
		prefix = @"";

	tempDir = [NSTemporaryDirectory() stringByAppendingPathComponent:
			[NSString stringWithFormat: @"%@_%@", prefix, uniqueString]];

	NSDebugLLog(@"ULIOManager", @"Generated temp dir name %@", tempDir);

	//create the directory - raise an exception if we cant since 
	//this is a critical error. We should always be able to create
	//a temporary directory

	if(![fileManager createDirectoryAtPath: tempDir attributes: nil])
		[NSException raise: NSInternalInconsistencyException
			format: @"Unable to create temporary directory!"];

	return tempDir;
}

@end
