//
//  BCToolMassCalculator.m
//  BioCocoa
//
//  Created by Koen van der Drift on Wed Aug 25 2004.
//  Copyright (c) 2003-2009 The BioCocoa Project.
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions
//  are met:
//  1. Redistributions of source code must retain the above copyright
//  notice, this list of conditions and the following disclaimer.
//  2. Redistributions in binary form must reproduce the above copyright
//  notice, this list of conditions and the following disclaimer in the
//  documentation and/or other materials provided with the distribution.
//  3. The name of the author may not be used to endorse or promote products
//  derived from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
//  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
//  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
//  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
//  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
//  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
//  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#import "BCToolMassCalculator.h"
#import "BCToolSymbolCounter.h"
#import "BCSequence.h"
#import "BCSymbol.h"

#import "BCFoundationDefines.h"

@implementation BCToolMassCalculator


-(id) initWithSequence:(BCSequence *)list
{
    if ( (self = [super initWithSequence:list]) )
    {
		[self setMassType: BCMonoisotopic];
	}
	
	return self;
}


+ (BCToolMassCalculator *) massCalculatorWithSequence: (BCSequence *)list
{
     BCToolMassCalculator *massCalculator = [[BCToolMassCalculator alloc] initWithSequence: list];
     
	 return [massCalculator autorelease];
}


- (void)setMassType:(BCMassType)type
{
	massType = type;
}

-(NSArray *)calculateMass{
	return [self calculateMassForRange: NSMakeRange(0, [[self sequence] length])];
}


-(NSArray *)calculateMassForRange: (NSRange)aRange
{
	float			totalMin, totalMax;
    BCSymbol		*aSymbol;
	
	totalMin = totalMax = 0.0;

#if 1
	unsigned		symbolCount;
	BCToolSymbolCounter	*symbolCounter = [BCToolSymbolCounter symbolCounterWithSequence: [self sequence]];
	NSCountedSet	*sequenceSet = [symbolCounter countSymbolsForRange: aRange];
   
	NSEnumerator *objectEnumerator = [sequenceSet objectEnumerator];

    while ( (aSymbol = [objectEnumerator nextObject]) )
	{		
		symbolCount = [sequenceSet countForObject: aSymbol];

		totalMin += ((float)symbolCount * [aSymbol minMassUsingType: massType]);
		totalMax += ((float)symbolCount * [aSymbol maxMassUsingType: massType]);
	}

#else
    CFIndex			i;
	NSArray			*array = [sequence symbolArray];
	for ( i = 0; i < [array count]; i++ )
	{
		aSymbol = (BCSymbol *)CFArrayGetValueAtIndex( (CFArrayRef) array, i);				// use NSData instead ?

		totalMin += [aSymbol minMassUsingType: massType];
		totalMax += [aSymbol maxMassUsingType: massType];
	}
#endif	
	if ( totalMin )
	{
		totalMin += [self addWater];
		totalMax += [self addWater];
	}
	
	return [NSArray arrayWithObjects: 
				[NSNumber numberWithFloat:totalMin], [NSNumber numberWithFloat: totalMax], nil];
}


-(float) addWater
{
	// add water - cheers!
	if ( massType == BCMonoisotopic )
		return 2 * hydrogenMonoisotopicMass + oxygenMonoisotopicMass;
	else if ( massType == BCAverage )
		return 2 * hydrogenAverageMass + oxygenAverageMass;
	else
		return 0;
}


@end
