/* BBBeaker.m				 
 *
 * This object controls the data of a beaker (molecules, cameras, groups etc.)
 * It is the main document of BeakerBoy and controls everything from loading to
 * setting up the browser which does most of the other work.
 *
 * For interface-info see the header file. The comments in this file mostly
 * cover only the real implementation details.
 *
 * Written by: 		Thomas Engel
 * Created:    		23.10.1993 (Copyleft)
 * Last modified: 	12.11.1994
 */

#define CURRENT_VERSION 1

#import "BBBeaker.h"
#import "BBMolecule.h"
#import "BBAtom.h"
#import "BBBond.h"
#import "BBCameraWindow.h"

#import "BBAppManager.h"
#import "FileManager.subproj/BBFileFilterManager.h"
#import "Inspector.subproj/BBMasterInspector.h"

#import <misckit/MiscString.h>
#import <iconkit/IKBrowser.h>
#import "BBBrowserManager.h"

@implementation BBBeaker

+ initialize
{
	if ( self == [BBBeaker class] )
		[BBBeaker setVersion:CURRENT_VERSION];

	return self;
}

- init
{
	return [self initFromFile:""];
}

- initFromFile:(const char *)fileName
{
	id	nameobj;
	
	self = [super init];
	if( !self ) return self;

	// OK. We really are an object...here we go with our init.
	// Lets load the NIB. It has set our beaker to be its window-delegate.
	// Without a NIB there will be no beaker object !

	if( [NXApp loadNibSection:"Beaker.nib" owner:self] == nil )
	{
		NXRunAlertPanel( NULL, "Couldn't load Beaker.nib", "OK", NULL, NULL );
		return nil;
	}
	// Lets setup the names.
	
	filename = [[MiscString new] setPath:fileName];
	nameobj = [filename fileBasename];
	[self setName:[nameobj stringValue]];
	[self setImage:[NXImage findImageNamed:"BeakerIcon"]];
	[nameobj free];
	
	// The next is to init all the lists we need. They are all IKSuitcases
	// because we want them to easily browse and drag or what ever.
	
	moleculeList = [BBSuitcase new];
	[moleculeList setName:"Molecules"];
	[moleculeList setImage:[NXImage findImageNamed:"MoleculeListIcon"]];

	cameraList = [BBSuitcase new];
	[cameraList setName:"Cameras"];
	[cameraList setImage:[NXImage findImageNamed:"CameraListIcon"]];

	[self addObject:moleculeList];
	[self addObject:cameraList];

	// OK the basic init seems to have passed with no problems. So now
	// its time to let the data in. This done using the fileFormatManager.
	// He can find the right parser for our file.
	
	[[[NXApp delegate] fileManager] readBeaker:self fromFile:[self filename]];
	
	// The browser should use our MatrixClass to give us the possibility to 
	// keep track of the object hierarchy.
	// Plus some inits for the methods we want to get if something happens.
	
	[browserManager initBrowser:browser root:self];	

	// Now there are some window settings to be done.
		
	[window setMiniwindowImage:[self image]];
	[window setTitleAsFilename:[self filename]];
		
	// ok now we are a new document so lets become active.
	
	[window makeKeyAndOrderFront:self];
	
	return self;
}

- free
 {
 	// We do not free all the NIB objects...hmm should check that out.
	
  	[[cameraList freeObjects] free];
 	[[moleculeList freeObjects] free];
	[filename free];
  	return [super free];
 }
 
- setName:(const char *)aString
{
	id		dir;
	id 		newName;
	id		nameobj;
	char	sepChar[2];
	
	[super setName:aString];
	
	nameobj = [MiscString new];
	[nameobj setStringValue:aString];
	
	dir = [(MiscString *)filename directory];
	sepChar[0] = [filename extensionSeparator];
	sepChar[1] = 0;
	newName = [filename fileExtension];
	[newName preCatStringValue:sepChar];
	[newName preCat:nameobj];
	[filename setDirectory:[dir stringValue] file:[newName stringValue]];
	
	// We need to free the unnecessary strings and set the new window title
	
	[dir free];
	[newName free];
	[nameobj free];
	[window setTitleAsFilename:[self filename]];

	return self;
}

- (const char *)filename
{
	return [filename stringValue];
}

- addMolecule:aMolecule
{
	[aMolecule setBeaker:self];
	[moleculeList addObject:aMolecule];
	return self;
}

- removeMolecule:aMolecule
{
	return self;
}

- emptyMoleculeList
{
	return self;
}

- moleculeList
{
	return moleculeList;
}

- addCamera:aCamera
{
	[cameraList addObjectIfAbsent:aCamera];
	return self;
}

- removeCamera:aCamera
{
	return self;
}

- emptyCameraList
{
	return self;
}

- cameraList
{
	return cameraList;
}

/*
 * Here come the methods we will implement to satisfy our window.
 * They are useful to change the inspector and handle oher tasks.
 */
 
- close:sender
{
	// If we really have to/can close this document
	// we should close our cameras first...
	
	[cameraList makeObjectsPerform:@selector(closeWindow)];
	return self;
}

/*
 * Archiving the whole Beaker...
 */
 
- read:(NXTypedStream *)stream
{
	int version;
	
	[super read:stream];
	version = NXTypedStreamClassVersion( stream, "BBBeaker" );
	
	// Version 1
		
	if ( version == CURRENT_VERSION )
	{
		NXReadTypes( stream, "@", &moleculeList );
		NXReadTypes( stream, "@", &cameraList );
	}
	else
		NXRunAlertPanel( NULL, "Unknown version of the BBBeaker class.\n"\
							   "Maybe you should get a new release of BeakerBoy",
						 "Ooops", NULL, NULL );
	return self;
}

- write:(NXTypedStream *)stream
{
	[super write:stream];
	
	// Version 1:
	// Filename and all the browser stuff is not archived! Those infos are
	// created at launch time.
	
	NXWriteTypes( stream, "@", &moleculeList );
	NXWriteTypes( stream, "@", &cameraList );
	
	return self;
}

@end

/*
 * History: 12.11.94 Added archiving and versioning.
 *
 *			30.10.94 Switched to the MiscString.
 *
 *			17.05.94 AddCamera uses addObjectIfAbsent: to avoid multiple
 *					 camera add. Cameras always add themselfes when they get
 *					 initialized.
 *
 *			14.05.94 Small fixes to get it running..
 *
 *			02.05.94 We are draggable now. and a BBBeaker!
 *
 *			10.01.94 Made it conform to my new ObjectWell and adjusted the icon
 *					 method.
 *
 *			03.01.94 Added initFromFile and many other useful methods
 *
 *			28.12.93 Multiple cameraWindows have arrived today.
 *
 *			18.12.93 Some code for inspector-testing added. Will be removed
 *					 soon. Not mentiones in the header-file.
 *
 *			25.11.93 Added the FileManager to provide the first beaker.
 *
 *			23.10.93 Just got it working to get some feeling for the app.
 *			
 *
 * Bugs: - Maybe we will have to ad a [self windowDidBecomeMain:self]
 *		   inside the init if we include some appControlling action.
 *
 *		 - The initFromFile should add a check when lists could not be 
 *		   allocated. Ok we have a unix system so this should not be a problem
 *		   because we do not have limited memory.
 */