/* Copyright 2003  Alexander V. Diemand

    This file is part of MolTalk.

    MolTalk 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.

    MolTalk 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MolTalk; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */

/* vim: set filetype=objc: */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>

#include "Structure.oh"
#include "privateStructure.oh"
#include "Chain.oh"
#include "Residue.oh"
#include "Atom.oh"
#include "FileStream.oh"
#include "String.oh"


@implementation Structure


-(id)init    // @nodoc
{
	[super init];
	resolution = -1.0f;
	expdata = Structure_Unknown;
	chains = RETAIN([NSMutableArray new]);
	hetnames = nil;
	return self;
}


-(void)dealloc    // @nodoc
{
	//printf("Structure_dealloc %s\n",[[self description] cString]);
	if (header)
	{
		RELEASE(header);
	}
	if (pdbcode)
	{
		RELEASE(pdbcode);
	}
	if (title)
	{
		RELEASE(title);
	}
	if (keywords)
	{
		RELEASE(keywords);
	}
	if (author)
	{
		RELEASE(author);
	}
	if (date)
	{
		RELEASE(date);
	}
	if (revdate)
	{
		RELEASE(revdate);
	}
	if (chains) 
	{
		[chains removeAllObjects];
		RELEASE(chains);
	}
	if (hetnames)
	{
		[hetnames removeAllObjects];
		RELEASE(hetnames);
	}
	[super dealloc];
}


/*
 *   returns the header of the structure (|/HEADER/| entry, without date and code)
 */
-(NSString*)header
{
	return header;
}


/*
 *   returns the 4 character PDB code
 */
-(NSString*)pdbcode
{
	return pdbcode;
}


/*
 *   returns the title of the structure (|/TITLE/| entry)
 */
-(NSString*)title
{
	return title;
}


/*
 *   returns the list of keywords of the structure (|/KEYWDS/| entry)
 */
-(NSArray*)keywords
{
	return keywords;
}


/*
 *   returns the date of deposition of the structure (from |/HEADER/| entry)
 */
-(NSCalendarDate*)date
{
	return date;
}


/*
 *   returns the date of the last revision of the structure (|/REVDAT/| entries)
 */
-(NSCalendarDate*)revdate
{
	return revdate;
}


/*
 *   returns the resolution of the structure determination (if applicable)
 */
-(float)resolution
{
	return resolution;
}


/*
 *   returns the type of the structure determination method<br>
 *   |Structure_XRay|=100 <br>
 *   |Structure_NMR|=101 <br>
 *   |Structure_TheoreticalModel|=102 <br>
 *   |Structure_Other|=103 <br>
 *   |Structure_Unknown|=104
 */
-(ExperimentType)expdata
{
	return expdata;
}


/*
 *   return the description of a hetero group (|/HETNAM/| entries)
 */
-(NSString*)hetnameForKey:(NSString*)key
{
	if (hetnames)
	{
		return [hetnames objectForKey:key];
	}
	return nil;
}


/*
 *   add a chain to this structure
 */
-(Chain *)addChain:(Chain*)p_chain
{
        Chain *chain = [self getChain:[p_chain codeNumber]];
        if (chain == nil)
        {
                [chains addObject:p_chain];
                [p_chain setStructure:self];
		return p_chain;
        }
	return nil;
}


/*
 *   remove a chain from this structure
 */
-(void)removeChain:(Chain*)p_chain
{
	[chains removeObject:p_chain];
}


/*
 *   write this structure to a file in PDB format
 */
-(void)writePDBFile:(NSString*)p_fn
{
	NSString *fn;
#ifdef SAFEENV
	fn = [NSString stringWithFormat: @"tempstrx/%@",[p_fn lastPathComponent]];
#else
	fn = p_fn;
#endif
	FileStream *fout = [FileStream streamToFile: fn];
	if (![fout ok])
	{
		NSLog(@"error: cannot open file %@",fn);
		return;
	}
	[self writePDBToStream: fout];
}


-(void)writePDBToStream:(Stream*)stream
{
	CREATE_AUTORELEASE_POOL(pool);
	if (![stream ok])
	{
		NSLog(@"error: cannot write to stream");
		RELEASE(pool);
		return;
	}
	
	/* set number printing locale format to POSIX */
	setlocale(LC_NUMERIC, "C");
	
	[self writePDBHeaderTo: stream];
	unsigned int serial = 1;
	NSEnumerator *e_chain = [chains objectEnumerator];
	id chain;
	while ((chain = [e_chain nextObject]))
	{
		[self writePDBChain: chain to: stream fromSerial: &serial];
	}
	
	[self writePDBConectTo: stream];
	char buffer[82];
	memset(buffer,32,80);
	buffer[81]='\0';
	buffer[80]='\n';
	buffer[0]='E';buffer[1]='N';buffer[2]='D';
	[stream writeCString: buffer];
	[stream close];
	RELEASE(pool);
}


/*
 *   access chain by its code
 */
-(Chain*)getChain:(NSNumber*)p_chain
{
	char t_code = [p_chain charValue];
	int i=0;
	Chain *t_chain;
	while (i < [chains count])
	{
		t_chain = [chains objectAtIndex:i];
		if ([t_chain code]==t_code)
		{
			return t_chain;
		}
		i++;
	}
	return nil;
}


/*
 *   returns an enumerator over all chains of this structure
 */
-(NSEnumerator*)allChains
{
	return [[NSArray arrayWithArray:chains] objectEnumerator];
}


@end


