//
//  BCToolTranslator.m
//  BioCocoa
//
//  Created by John Timmer on 8/29/04.
//  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 "BCToolTranslator.h"
#import "BCNucleotideDNA.h"
#import "BCAminoAcid.h"
#import "BCSequence.h"
#import "BCSequenceCodon.h"
#import "BCCodonDNA.h"
#import "BCGeneticCode.h"

@implementation BCToolTranslator

- (BCToolTranslator *) initWithSequence: (BCSequence *)list {
	self = [super initWithSequence: list];

	// set some defaults
	if ( self != nil ) {
		readingFrame = 1;
		codeName = BCUniversalCode;
	}
	
	return self;
}


- (int) readingFrame {
	return readingFrame;
}


- (void) setReadingFrame: (int)theFrame {
	// this has got to be between -3 and 3, skipping 0.
	// we default to 1
	if ( theFrame > 3 || theFrame == 0 )
		readingFrame = 1;
	else if ( theFrame < -3 )
		readingFrame = -1;
	else
		readingFrame = theFrame;
}


- (BCGeneticCodeName) codeName {
	return codeName;
}


- (void)setCodeName: (BCGeneticCodeName)aName {
	codeName = aName;	
}


+ (BCToolTranslator *) translatorToolWithSequence: (BCSequence *)list {
     BCToolTranslator *translatorTool = [[BCToolTranslator alloc] initWithSequence: list];
     
	 return [translatorTool autorelease];
}

- (BCSequenceCodon *) codonTranslation {
	// check for the right kind of sequence
	if ( [sequence sequenceType] != BCSequenceTypeDNA && [sequence sequenceType] != BCSequenceTypeRNA )
		return nil;

	// next, grab the genetic code
    NSArray *theCode = [BCGeneticCode geneticCode: codeName forSequenceType: [sequence sequenceType]];
    if ( theCode == nil || [theCode count] == 0 )
        return nil;
    
	// adjust the sequence to reflect the desired frame
	BCSequence *tempSequence;
	if ( readingFrame < 0 )
		tempSequence = [sequence reverse];
	else tempSequence = sequence;
	
	NSArray *theSequenceArray;
	if ( abs( readingFrame ) == 1 )
		theSequenceArray = [tempSequence symbolArray];
	else if (  abs( readingFrame ) == 2 )
		theSequenceArray = [tempSequence subSymbolArrayInRange: NSMakeRange( 1, [sequence length] - 1) ];
	else
		theSequenceArray = [tempSequence subSymbolArrayInRange: NSMakeRange( 2, [sequence length] - 2) ];
		
    int codonCount = [theCode count];
    int loopCounter, innerCounter;
    NSMutableArray *returnArray = [NSMutableArray array];
    NSArray *tempCodon;
    BCCodonDNA *aCodon;
    BOOL oneMatch;

    for ( loopCounter = 0 ; loopCounter + 2 < [sequence length] ; loopCounter = loopCounter + 3 ) {
        tempCodon = [theSequenceArray subarrayWithRange: NSMakeRange( loopCounter, 3 ) ];
        oneMatch = NO;
        
        for ( innerCounter = 0 ; innerCounter < codonCount ; innerCounter++ ) {
            aCodon = [theCode objectAtIndex: innerCounter];
            if ( [aCodon matchesTriplet: tempCodon] ) {
                [returnArray addObject: aCodon];
                oneMatch = YES;
                break;
            }
        }
        
        if ( !oneMatch )
            [returnArray addObject: [BCCodonDNA unmatched]];
    }
    
	NSString *frameRep;
	if ( readingFrame > 0 )
		frameRep = [NSString stringWithFormat: @"+%i", readingFrame];
	else 
		frameRep = [NSString stringWithFormat: @"-%i", readingFrame];
	
    return [[[BCSequenceCodon alloc] initWithCodonArray: returnArray geneticCode: codeName frame: frameRep] autorelease];
	
}
	
- (NSDictionary *) allCodonTranslations {
	// we hang onto the frame that's set because we're going to change it repeatedly
	int holdingInt = readingFrame;
	int loopCounter = -4;
	NSMutableDictionary *theReturn = [NSMutableDictionary dictionary];
	BCSequenceCodon *codonSequence;
	while ( loopCounter < 3) {
		loopCounter++;
		if ( loopCounter == 0 )
			loopCounter++;
		readingFrame = loopCounter;
		codonSequence = [self codonTranslation];
		[theReturn setObject: codonSequence forKey: [codonSequence readingFrame]];
	}
	
	readingFrame = holdingInt;
	return theReturn;
}


@end

