/* BBAtomLibraryManager.m				 
 *
 * This is the major Part of the AtomLibrary. Controls Nibs and more. Can
 * find the basic atom for any symbol (because it controls them)
 *
 * For interface-info see the header file. The comments in this file mostly
 * cover only the real implementation details.
 *
 * Written by: 		Thomas Engel
 * Created:    		25.11.1993 (Copyleft)
 * Last modified: 	30.10.1994
 */

#import "BBAtomLibraryManager.h"
#import "../BBBasicAtom.h"
#import "../BBAppManager.h"
#import "../Inspector.subproj/BBMasterInspector.h"
#import <iconkit/IKCell.h>
#import <misckit/MiscSwapView.h>
#import <misckit/MiscString.h>

@implementation BBAtomLibraryManager

- init
{
	self = [super init];
	if( !self ) return self;

	// OK. We really are an object...here we go with our init.
	// So lets setup the default Library
	
	atomList = [List new];
	[self createSimpleDefaultLibrary];

	return self;
}

- makeKeyAndOrderFront:sender
{
	// If we have no panel we will load the NIB and show the C as first.
	// Remember that we need a initial swap after loading the BIN.
	
	if( !window )
	{
		if ([NXApp loadNibSection:"AtomLibrary.nib" owner:self] == nil)
			NXRunAlertPanel( NULL, "Couldn't load AtomLibrary.nib",
							 "OK", NULL, NULL);
		
		[self selectBasicAtomWithProtons:6];
		[swapView swapContentView:self];
	}
	[window makeKeyAndOrderFront:self];
	return self;
}

- atomList
{
	return atomList;
}

- selectBasicAtom:anAtom
{
	[nameField setStringValue:[anAtom name]];
	[symbolField setStringValue:[anAtom symbol]];
	[protonsField setIntValue:[anAtom protons]];
	[dragWell setDelegate:anAtom];
	[[dragWell controlView] display];
	[[[NXApp delegate] inspector] inspect:anAtom];
	return self;
}

- selectedBasicAtom
{
	return [dragWell delegate];
}

- selectBasicAtomWithSymbol:(const char *)aString
{
	[self selectBasicAtom:[self findBasicAtomWithSymbol:aString]];
	return self;
}

- selectBasicAtomWithProtons:(short)protons
{
	[self selectBasicAtom:[self findBasicAtomWithProtons:protons]];
	return self;
}

- findBasicAtomWithSymbol:(const char *)aString
{
	// We try to find the atom in our List that matches the given symbol string
	// If there is none we will return the defaultAtom;
	
	id	matchingAtom;
	id	anAtom;
	int	i;
	
	matchingAtom = defaultAtom;
	
	for( i=0; i<[atomList count]; i++ )
	{
		anAtom = [atomList objectAt:i];
		if( [[anAtom symbolObject] compareStr:aString] == 0 )
			matchingAtom = anAtom;
	}
	return matchingAtom;
}

- findBasicAtomWithProtons:(short)protons
{
	// We try to find the atom in our List that matches the given proton count
	// If there is none we will return the defaultAtom;
	
	id	matchingAtom;
	id	anAtom;
	int	i;
	
	matchingAtom = defaultAtom;
	
	for( i=0; i<[atomList count]; i++ )
	{
		anAtom = [atomList objectAt:i];
		if( [anAtom protons] == protons )
			matchingAtom = anAtom;
	}
	return matchingAtom;
}

- createSimpleDefaultLibrary
{
	// This methods is for the testing time and will be used in the later
	// normals release to provide some kind of startup or emergancy atomLibrary
	// that is always setup during the init phase.
	// Loading a atomLibrary only replaces the atom definitions made here.
	// This is how we can make sure that there will always the a atom for
	// every atomKind.
	// Could be define somewhere else but this is not subject to localization
	// so we will hardcode it here.

	id	anAtom;
	
	defaultAtom = [BBBasicAtom new];
	[(BBBasicAtom *)defaultAtom setName:"Unknown"];
	[defaultAtom setSymbol:"?"];
	[defaultAtom setProtons:0];
	[defaultAtom setNeutrons:0];
	[defaultAtom setMass:0];
	[defaultAtom setRadius:0.5];
	[defaultAtom setColor:NXConvertRGBToColor( 0.7, 0.7, 0.7 )];

	// First of all we created the defaultAtom. This atom does not appear in
	// the atom list. It is the motherAtom of every other atom. So it contains
	// the most general and very defaultish settings to every atom here.
	// We will set the Neutrons to the most common N-count and the mass
	// to the average mass for the atom type.
	// The next are the most commonly used atoms: H C N O P S
	// These are provided with some more settings. So our default library is
	// useful to some extand.

	anAtom = [self newLibAtom:"H" :"Hydrogen" withCore:1 :0 mass:1.00794];
	[anAtom setRadius:0.37];
	[anAtom setVanDerWaalsRadius:1.00];
	[anAtom setColor:NXConvertRGBToColor( 1, 1, 1 )];
	
	anAtom = [self newLibAtom:"C" :"Carbon" withCore:6 :6 mass:12.011];
	[anAtom setRadius:0.77];
	[anAtom setVanDerWaalsRadius:1.70];
	[anAtom setColor:NXConvertRGBToColor( 0.3, 0.3, 0.3 )];

	anAtom = [self newLibAtom:"N" :"Nitrogen" withCore:7 :7 mass:14.00674];
	[anAtom setRadius:0.7];
	[anAtom setVanDerWaalsRadius:1.5];
	[anAtom setColor:NXConvertRGBToColor( 0, 0.5, 1 )];

	anAtom = [self newLibAtom:"O" :"Oxygen" withCore:8 :8 mass:15.9994];
	[anAtom setRadius:0.66];
	[anAtom setVanDerWaalsRadius:1.4];
	[anAtom setColor:NXConvertRGBToColor( 1, 0, 0 )];

	anAtom = [self newLibAtom:"P" :"Phosphorus" withCore:15 :16
													mass:30.973762];
	[anAtom setRadius:1.1];
	[anAtom setVanDerWaalsRadius:1.9];
	[anAtom setColor:NXConvertRGBToColor( 1, 0.5, 0 )];

	anAtom = [self newLibAtom:"S" :"Sulfur" withCore:16 :16 mass:32.066];
	[anAtom setRadius:1.04];
	[anAtom setVanDerWaalsRadius:1.8];
	[anAtom setColor:NXConvertRGBToColor( 1, 1, 0 )];

	// To be able to view or LOOK example molecules we will define some more
	// atom types with color and radius.
	// F Cl Br I Mg Ca Fe Co Zn 

	anAtom = [self newLibAtom:"F" :"Fluorine" withCore:9 :10 mass:18.9984032];
	[anAtom setRadius:0.64];
	[anAtom setVanDerWaalsRadius:1.4];
	[anAtom setColor:NXConvertRGBToColor( 0.5, 1, 0 )];

	anAtom = [self newLibAtom:"Cl" :"Chlorine" withCore:17 :18 mass:35.4527];
	[anAtom setRadius:0.99];
	[anAtom setVanDerWaalsRadius:1.8];
	[anAtom setColor:NXConvertRGBToColor( 0.5, 1, 0.5 )];

	anAtom = [self newLibAtom:"Br" :"Bromine" withCore:35 :44 mass:79.904];
	[anAtom setRadius:1.14];
	[anAtom setVanDerWaalsRadius:2.0];
	[anAtom setColor:NXConvertRGBToColor( 0.72, 0.15, 0 )];

	anAtom = [self newLibAtom:"I" :"Iodine" withCore:53 :74 mass:126.0447];
	[anAtom setRadius:1.330];
	[anAtom setVanDerWaalsRadius:2.2];
	[anAtom setColor:NXConvertRGBToColor( 0.5, 0, 0.5 )];

	anAtom = [self newLibAtom:"Mg" :"Magnsium" withCore:12 :12 mass:24.3050];
	[anAtom setRadius:1.36];
	[anAtom setVanDerWaalsRadius:1.36];
	[anAtom setColor:NXConvertRGBToColor( 0.7, 0.7, 0.7 )];

	anAtom = [self newLibAtom:"Ca" :"Calcium" withCore:20 :20 mass:40.078];
	[anAtom setRadius:1.74];
	[anAtom setVanDerWaalsRadius:1.74];
	[anAtom setColor:NXConvertRGBToColor( 0.7, 0.7, 0.7 )];

	anAtom = [self newLibAtom:"Fe" :"Iron" withCore:26 :30 mass:55.847];
	[anAtom setRadius:1.16];
	[anAtom setVanDerWaalsRadius:1.16];
	[anAtom setColor:NXConvertRGBToColor( 0.8, 0.5, 0.5 )];

	anAtom = [self newLibAtom:"Co" :"Cobalt" withCore:27 :32 mass:58.93320];
	[anAtom setRadius:1.16];
	[anAtom setVanDerWaalsRadius:1.16];
	[anAtom setColor:NXConvertRGBToColor( 0.5, 0.8, 0.8 )];

	anAtom = [self newLibAtom:"Zn" :"Zinc" withCore:30 :34 mass:65.39];
	[anAtom setRadius:1.25];
	[anAtom setVanDerWaalsRadius:1.25];
	[anAtom setColor:NXConvertRGBToColor( 0.7, 0.7, 0.7 )];
	
	// Now we define all the other atom types. But with no specific settings.
	// They all refer to the defaultAtom.
	// Especially the lack of radius info is a problem

	[self newLibAtom:"He" :"Helium" withCore:2 :2 mass:4.002602];
	[self newLibAtom:"Li" :"Lithium" withCore:3 :4 mass:6.941];
	[self newLibAtom:"Be" :"Beryllium" withCore:4 :5 mass:9.012182];
	[self newLibAtom:"B" :"Boron" withCore:5 :6 mass:10.811];
	[self newLibAtom:"Ne" :"Neon" withCore:10: 10 mass:20.1797];
	[self newLibAtom:"Na" :"Sodium" withCore:11 :12 mass:22.989768];
	[self newLibAtom:"Al" :"Aluminium" withCore:13 :14 mass:26.981539];
	[self newLibAtom:"Si" :"Silicon" withCore:14 :14 mass:28.0855];
	[self newLibAtom:"Ar" :"Argon" withCore:18 :22 mass:39.948];
	[self newLibAtom:"K" :"Potassium" withCore:19 :20 mass:39.0983];
	[self newLibAtom:"Sc" :"Scandium" withCore:21 :24 mass:44.955910];
	[self newLibAtom:"Ti" :"Titanium" withCore:22 :26 mass:47.88];
	[self newLibAtom:"V" :"Vanadium" withCore:23 :28 mass:50.9415];
	[self newLibAtom:"Cr" :"Chromium" withCore:24 :28 mass:51.9961];
	[self newLibAtom:"Mn" :"Manganese" withCore:25 :30 mass:54.93805];
	[self newLibAtom:"Ni" :"Nickel" withCore:28 :30 mass:58.69];
	[self newLibAtom:"Cu" :"Copper" withCore:29 :34 mass:63.546];
	[self newLibAtom:"Ga" :"Gallium" withCore:31 :38 mass:69.723];
	[self newLibAtom:"Ge" :"Germanium" withCore:32 :42 mass:72.61];
	[self newLibAtom:"As" :"Arsenic" withCore:33 :42 mass:74.92159];
	[self newLibAtom:"Se" :"Selenium" withCore:34 :46 mass:78.96];
	[self newLibAtom:"Kr" :"Krypton" withCore:36 :48 mass:83.80];
	[self newLibAtom:"Rb" :"Rubidium" withCore:37 :48 mass:85.4678];
	[self newLibAtom:"Sr" :"Strontium" withCore:38 :50 mass:87.62];
	[self newLibAtom:"Y" :"Yttrium" withCore:39 :50 mass:88.90585];
	[self newLibAtom:"Zr" :"Zirconium" withCore:40 :50 mass:91.224];
	[self newLibAtom:"Nb" :"Niobium" withCore:41 :52 mass:92.90638];
	[self newLibAtom:"Mo" :"Molybdenum" withCore:42 :56 mass:95.94];
	[self newLibAtom:"Tc" :"Technetium" withCore:43 :56 mass:98.9063];
	[self newLibAtom:"Ru" :"Ruthenium" withCore:44 :58 mass:101.07];
	[self newLibAtom:"Rh" :"Rhodium" withCore:45 :58 mass:102.90550];
	[self newLibAtom:"Pd" :"Palladium" withCore:46 :60 mass:106.42];
	[self newLibAtom:"Ag" :"Silver" withCore:47 :60 mass:107.8682];
	[self newLibAtom:"Cd" :"Cadmium" withCore:48 :66 mass:112.411];
	[self newLibAtom:"In" :"Indium" withCore:49 :66 mass:114.82];
	[self newLibAtom:"Sn" :"Tin" withCore:50 :70 mass:118.710];
	[self newLibAtom:"Sb" :"Antimony" withCore:51 :70 mass:121.75];
	[self newLibAtom:"Te" :"Tellurium" withCore:52 :78 mass:127.60];
	[self newLibAtom:"Xe" :"Xenon" withCore:54 :78 mass:131.29];
	[self newLibAtom:"Cs" :"Caesium" withCore:55 :78 mass:132.90543];
	[self newLibAtom:"Ba" :"Barium" withCore:56 :82 mass:137.327];
	[self newLibAtom:"La" :"Lanthanum" withCore:57 :82 mass:138.9055];
	[self newLibAtom:"Ce" :"Cerium" withCore:58 :82 mass:140.115];
	[self newLibAtom:"Pr" :"Praseodymium" withCore:59 :82 mass:140.90765];
	[self newLibAtom:"Nd" :"Neodymium" withCore:60 :84 mass:144.24];
	[self newLibAtom:"Pm" :"Promethium" withCore:61 :86 mass:146.9141];
	[self newLibAtom:"Sm" :"Samarium" withCore:62 :90 mass:150.36];
	[self newLibAtom:"Eu" :"Europium" withCore:63 :90 mass:151.965];
	[self newLibAtom:"Gd" :"Gadolinium" withCore:64 :94 mass:157.25];
	[self newLibAtom:"Tb" :"Therbium" withCore:65 :94 mass:158.92534];
	[self newLibAtom:"Dy" :"Dysprosium" withCore:66 :98 mass:162.50];
	[self newLibAtom:"Ho" :"Holmium" withCore:67 :98 mass:164.93032];
	[self newLibAtom:"Er" :"Erbium" withCore:68 :98 mass:167.26];
	[self newLibAtom:"Tm" :"Thulium" withCore:69 :100 mass:168.93421];
	[self newLibAtom:"Yb" :"Ytterbium" withCore:70 :104 mass:173.04];
	[self newLibAtom:"Lu" :"Lutetium" withCore:71 :104 mass:174.967];
	[self newLibAtom:"Hf" :"Hafnium" withCore:72 :108 mass:178.49];
	[self newLibAtom:"Ta" :"Tantalum" withCore:73 :108 mass:180.9479];
	[self newLibAtom:"W" :"Tungsten" withCore:74 :110 mass:183.85];
	[self newLibAtom:"Re" :"Rhenium" withCore:75 :112 mass:186.207];
	[self newLibAtom:"Os" :"Osmium" withCore:76 :116 mass:190.2];
	[self newLibAtom:"Ir" :"Iridium" withCore:77 :116 mass:192.22];
	[self newLibAtom:"Pt" :"Platinum" withCore:78 :117 mass:195.08];
	[self newLibAtom:"Au" :"Gold" withCore:79 :118 mass:196.96654];
	[self newLibAtom:"Hg" :"Mercury" withCore:80 :122 mass:205.9];
	[self newLibAtom:"Tl" :"Thallium" withCore:81 :124 mass:204.3833];
	[self newLibAtom:"Pb" :"Lead" withCore:82 :126 mass:207.2];
	[self newLibAtom:"Bi" :"Bismuth" withCore:83 :126 mass:208.98037];
	[self newLibAtom:"Po" :"Polonium" withCore:84 :125 mass:208.9824];
	[self newLibAtom:"At" :"Asthatine" withCore:85 :125 mass:209.9871];
	[self newLibAtom:"Rn" :"Radon" withCore:86 :136 mass:222.0176];
	[self newLibAtom:"Fr" :"Francium" withCore:87 :136 mass:223.0197];
	[self newLibAtom:"Ra" :"Radium" withCore:88 :138 mass:226.0254];
	[self newLibAtom:"Ac" :"Actinium" withCore:89 :138 mass:227.0278];
	[self newLibAtom:"Th" :"Thorium" withCore:90 :142 mass:232.381];
	[self newLibAtom:"Pa" :"Protactinium" withCore:91 :140 mass:231.0359];
	[self newLibAtom:"U" :"Uranium" withCore:92 :146 mass:238.0289];
	[self newLibAtom:"Np" :"Neptunium" withCore:93 :144 mass:237.0482];
	[self newLibAtom:"Pu" :"Plutonium" withCore:94 :150 mass:244.0642];
	[self newLibAtom:"Am" :"Americium" withCore:95 :148 mass:243.0614];
	[self newLibAtom:"Cm" :"Curium" withCore:96 :151 mass:247.0703];
	[self newLibAtom:"Bk" :"Berkelium" withCore:97 :150 mass:247.0703];
	[self newLibAtom:"Cf" :"Californium" withCore:98 :153 mass:251.0796];
	[self newLibAtom:"Es" :"Einsteinium" withCore:99 :153 mass:252.0829];
	[self newLibAtom:"Fm" :"Fermium" withCore:100 :157 mass:257.0951];
	[self newLibAtom:"Md" :"Mendelevium" withCore:101 :157 mass:258.0986];
	[self newLibAtom:"No" :"Nobelium" withCore:102 :157 mass:259.1009];
	[self newLibAtom:"Lr" :"Lawrencium" withCore:103 :157 mass:260.1053];
	[self newLibAtom:"Rf" :"Rutherfordium" withCore:104 :157 mass:261.1087];
	[self newLibAtom:"Ha" :"Hahnium" withCore:105 :157 mass:262.1138];
	[self newLibAtom:"Unh" :"106" withCore:106 :157 mass:263.1182];
	[self newLibAtom:"Uns" :"107" withCore:107 :155 mass:262.1229];
	[self newLibAtom:"Uno" :"108" withCore:108 :157 mass:265];
	[self newLibAtom:"Une" :"109" withCore:109 :157 mass:266];

	// To create some special molecules or atoms we will define some non
	// standard atom types. The R-Rest is predefined.. all different atoms
	// will be mapped to 'Undefined'.

	anAtom = [self newLibAtom:"R" :"Rest" withCore:200 :0 mass:0];
	[anAtom setRadius:1.0];

	[self newLibAtom:"?" :"Undefined" withCore:0 :0 mass:0];

	return self;
}

- newLibAtom:(const char *)symbol:(const char*)name withCore:(short)p :(short)n
														mass:(float)m
{
	// This is a internal method to simplify the creation of the default
	// atom library it is used to set the essential data for each atom.
	// They are all linked to the defaultAtom.
	
	id	anAtom;
	
	anAtom = [BBBasicAtom new];
	[anAtom setMotherAtom:defaultAtom];
	[(BBBasicAtom *)anAtom setName:name];
	[anAtom setSymbol:symbol];
	[anAtom setProtons:p];
	[anAtom setNeutrons:n];
	[anAtom setMass:m];
	[atomList addObject:anAtom];

	// To be sure that they never get free without our knowledge we add
	// us to each atoms userlist.
	
	[anAtom addUser:self];
	
	return anAtom;
}

- windowDidBecomeMain:sender
{
	// Here we get informed when we become the main window. This is the point
	// to change the inspector to inspect our selection.
	
	[[[NXApp delegate] inspector] inspect:[dragWell delegate]];
	return self;
}

@end

/*
 * History: 30.10.94 Switched to the MiscString.
 *
 *			14.05.94 Switched to new name: BB...
 *
 *			10.02.94 Made it MiscSwap able.
 *
 *			12.01.94 Added the default library setting.
 *
 *			11.01.94 Implemented the find..atom/neutrons methods
 *
 *			09.01.94 Started to implement the rela database work;
 *
 *			03.12.93 Added some first serious coding sections.
 *
 *
 * Bugs: Yes.
 */