//----------------------------------------------------------------------------------------------------
//
//	WrapperInspector
//
//	Inherits From:		Object
//
//	Declared In:		WrapperInspector.h
//
//	Disclaimer
//
//		You may freely copy, distribute and reuse this software and its
//		associated documentation. I disclaim any warranty of any kind, 
//		expressed or implied, as to its fitness for any particular use.
//
//----------------------------------------------------------------------------------------------------
#import "WrapperInspector.h"
#import "DefaultSubInspector.h"
#import <objc/objc-runtime.h>
#import <bsd/sys/dir.h>


@implementation WrapperInspector

static id 	_SELF = nil;

//----------------------------------------------------------------------------------------------------
//  WMInspector Methods
//----------------------------------------------------------------------------------------------------
+ new
{
	//  Required/called by WM.  Only allow one instance...
	
    	char 	path[MAXPATHLEN+1];
    	id 		bundle;

    	if (_SELF) return _SELF;

        _SELF = self = [super new];

    	if ( ! (bundle = [NXBundle bundleForClass: [WrapperInspector class]] ) ) return nil;          
	if ( ! [bundle getPath: path forResource: "WrapperInspector" ofType: "nib"] ) return nil;
    	[NXApp loadNibFile: path owner: self  withNames: NO fromZone: [self zone]];
 
 	[splitView addSubview: browser];
	[splitView addSubview: inspectorView];
	[splitView adjustSubviews];
	[splitView display];
	
 	return _SELF;
}


- revert: sender
{
	//  Called by WM when file selection is type we inspect or when 
	//  'Open As Folder' button is pressed.
	
	if (sender == [self revertButton])
		{
		[self openAsFolder: nil];
		return [super revert:sender];
		}

	[[[[self okButton] setTitle: "Open"] setIconPosition: NX_TITLEONLY] setEnabled: YES];
	[[[self revertButton] setTitle: "Open As Folder"] setEnabled: YES];

	[browser setDoubleAction: @selector(open:)];
	[browser setTitle: [fileNameField stringValue] ofColumn: 0];
	[browser loadColumnZero];
	
	if ([self isDirectory])
		[self noInspector];
	else
		[self selectionNotADirectory];
	
	[self updateSubPath];

	[super revert: sender];
	return self;
}


- ok: sender
{
	//  User pressed 'Open' button...
	
	[self open: nil];
	return [super ok:sender];
}


//----------------------------------------------------------------------------------------------------
//  Action Methods
//----------------------------------------------------------------------------------------------------
- fileSelected: sender
{
	//  Invoke inpector based on extension... Enable 'Open As Folder'
	//  button if directory.  Update subPath display.
	
	STR			currentPath;
	STR			extension;
	const char*	inspectorClass;	

	[self updateSubPath];

	if (! (currentPath = [self currentPath])) return [self noInspector];
	
	if ([[browser selectedCell] isLeaf]) 
		[[self revertButton] setEnabled: NO];
	else
		[[self revertButton] setEnabled: YES];
		
	if (! (extension = [self extension: currentPath]))
		{
		if (currentPath) free(currentPath);
		return [self noInspector];
		}

	if ((inspectorClass = [inspectorStrings valueForStringKey: extension]))
		[self inspect: (STR)currentPath usingInspectorClass: (STR)inspectorClass];
	else
		[self noInspector];

	if (currentPath) free(currentPath);
	if (extension) free(extension);
	
	return self;
}


- open: sender
{
	//  Open current selection in WM.

	STR		currentPath;
	
	if (! (currentPath = [self currentPath])) return NULL;
	[[Application workspace] openFile:currentPath withApplication: NULL andDeactivate: NO];
	if (currentPath) free(currentPath);
	return self;
}
	
	
- openAsFolder: sender
{
	//  Open current selection as folder in WM.

	STR		currentPath;
	
	if (! (currentPath = [self currentPath])) return NULL;
	[[Application workspace] selectFile:currentPath inFileViewerRootedAt:currentPath];
	if (currentPath) free(currentPath);
	return self;
}
	
	
//----------------------------------------------------------------------------------------------------
//  Inspection Methods
//----------------------------------------------------------------------------------------------------
- inspect: (STR)currentPath usingInspectorClass: (STR)inspectorClass
{
	//  Get the Class ID for the specified subinspector and send it the
	//  message 'new' to create an instance.  If successful, message 
	//  the instance for its inspectorView and to inspect the current path.
	
	id		inspector;
	Class  	inspectorClassID = objc_lookUpClass(inspectorClass);
	
	if ( ! inspectorClassID)  return [self noInspector];
	
	inspector = objc_msgSend ((id)inspectorClassID, @selector(new));
	if ( ! inspector)  return [self noInspector];

	[inspectorView setContentView: [inspector inspectorView]];
	[inspectorView display];
	
	[inspector inspect: currentPath];
	
	return self;
}
	

- noInspector
{
	//  No Inspector for this file type.
	
	[messageText setStringValue: "No Inspector"];
	[inspectorView setContentView: [messageView contentView]];
	[inspectorView display];
	return self;
}


- selectionNotADirectory
{
	//  This for cases when WM selection has right extension, but is not
	//  actually a directory (for example, some .nibs are not directories).
	
	[[self okButton] setEnabled: NO];
	[[self revertButton] setEnabled: NO];
	[messageText setStringValue: "Not A Directory"];
	[inspectorView setContentView: [messageView contentView]];
	[inspectorView display];
	return self;
}


//----------------------------------------------------------------------------------------------------
//  Selection Path Methods
//----------------------------------------------------------------------------------------------------
- (STR) currentPath
{
	//  Original WM selection path plus current browser path.  Caller must free.
	
	char 	currentPath[MAXPATHLEN+1];
	char 	browserPath[MAXPATHLEN+1];

	[self selectionPathsInto:currentPath separator:'\0'];
	
	if ([browser selectedCell])
		{
		[browser getPath:browserPath toColumn: [browser selectedColumn]];
		strcat (currentPath, browserPath);
		strcat (currentPath, "/");
		strcat (currentPath, [[browser selectedCell] stringValue]);
		}
	
	return NXCopyStringBuffer (currentPath);
}


- (STR) extension: (const char*) path
{
	//  File's extension if found, pointer to NULL otherwise.  Caller must free.

	STR	start = (STR)path;
	STR	end;

	for (end = (start + strlen(start) -1); end >= start; end--)
		{
		if (*end == '.') break;
		if (*end == '/') return NULL;
		}

	if ((end - start) == -1) return NULL;
		
	start += (end - start) + 1;
	return NXCopyStringBuffer(start);
}


- (BOOL)isDirectory
{
	//  YES if current path is a directory...
	
	struct stat 	statBuffer;
	STR			currentPath = [self currentPath];

	if (! currentPath) return NO;
	
	stat (currentPath, &statBuffer); 
	if (currentPath) free(currentPath);
	if ( (statBuffer.st_mode & S_IFMT) != S_IFDIR)
		return NO;
		
	return YES;
}


- updateSubPath
{
	//  Update subPath display...
	
	char 	subPath[MAXPATHLEN+1];
	char 	browserPath[MAXPATHLEN+1];

	strcpy(subPath, [fileNameField stringValue]);

	if ([browser selectedCell])
		{
		[browser getPath:browserPath toColumn: [browser selectedColumn]];
		strcat (subPath, browserPath);
		strcat (subPath, "/");
		strcat (subPath, [[browser selectedCell] stringValue]);
		}

	[subPathText setStringValue: subPath];
	return self;
}


//----------------------------------------------------------------------------------------------------
//  Browser Delegate Method
//----------------------------------------------------------------------------------------------------
- (int) browser: aBrowser fillMatrix: aMatrix inColumn: (int)aColumn
{
	int			count = 0;
	DIR*			directory;
	STR 		currentPath;
	char 		pathBuffer[MAXPATHLEN+1];
	struct stat 	statBuffer;
	struct direct*	directoryPointer;

	currentPath = [self currentPath];
		
	if (! (directory = opendir(currentPath))) 
		{
		if (currentPath)  free(currentPath);
		[self selectionNotADirectory];
		return 0;
		}
	
	for (directoryPointer = readdir(directory); directoryPointer != NULL; 
			directoryPointer =  readdir(directory))
		{
		if (NXOrderStrings (directoryPointer->d_name, ".", YES, -1, NULL) == 0) continue;
		if (NXOrderStrings (directoryPointer->d_name, "..", YES, -1, NULL) == 0) continue;

		[aMatrix renewRows: (count+1) cols: 1];
		[[aMatrix cellAt: count :0] setStringValue: directoryPointer->d_name];
		[[aMatrix cellAt: count :0] setLoaded: YES];
		
		strcpy (pathBuffer, currentPath);
		strcat (pathBuffer, "/");
		strcat (pathBuffer, directoryPointer->d_name);

		stat (pathBuffer, &statBuffer); 
		if ( (statBuffer.st_mode & S_IFMT) != S_IFDIR)
				[[aMatrix cellAt: count :0] setLeaf:YES];
			
		count++;
		}
	
	if (currentPath)  free(currentPath);
	closedir(directory);
	return count;
}
	

@end