1//
2//  BCSequence.m
3//  BioCocoa
4//
5//  Created by Koen van der Drift on 12/14/2004.
6//  Copyright (c) 2003-2009 The BioCocoa Project.
7//  All rights reserved.
8//
9//  Redistribution and use in source and binary forms, with or without
10//  modification, are permitted provided that the following conditions
11//  are met:
12//  1. Redistributions of source code must retain the above copyright
13//  notice, this list of conditions and the following disclaimer.
14//  2. Redistributions in binary form must reproduce the above copyright
15//  notice, this list of conditions and the following disclaimer in the
16//  documentation and/or other materials provided with the distribution.
17//  3. The name of the author may not be used to endorse or promote products
18//  derived from this software without specific prior written permission.
19//
20//  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21//  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22//  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23//  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24//  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25//  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26//  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27//  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28//  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31#import "BCSequence.h"
32#import "BCAnnotation.h"
33#import "BCFoundationDefines.h"
34#import "BCSymbol.h"
35#import "BCAminoAcid.h"
36#import "BCSymbolSet.h"
37#import "BCToolSequenceFinder.h"
38#import "BCToolComplement.h"
39#import "BCUtilData.h"
40
41#import "BCInternal.h"
42
43@implementation BCSequence
44
45// TODO:
46
47// MOVE MUTABLE METHODS TO ...
48
49// UPDATE THE REVERSE METHOD - SHOULD THIS BE DONE STRING-BASED?
50
51// UPDATE MORE HEADERDOC INFORMATION
52
53// LOOK AGAIN AT SYMBOLATINDEX METHOD
54
55// ADD METHODS FOR NSDATA <-> NSSTRING CONVERSIONS, PROBABLY NOT IN THIS CLASS
56
57// FIX COMPILER WARNINGS
58
59// ....
60
61////////////////////////////////////////////////////////////////////////////
62#if 0
63#pragma mark �
64#pragma mark � INITIALIZATION METHODS
65#endif
66//
67//  INITIALIZATION METHODS
68////////////////////////////////////////////////////////////////////////////
69
70// designated initializer
71- (id)initWithString:(NSString *)aString symbolSet:(BCSymbolSet *)aSet
72{
73    if ( (self = [super init]) )
74    {
75		if ( aString != nil )
76		{
77			if ( aSet == nil )
78			{
79				aSet = [BCSymbolSet symbolSetForSequenceType: [self sequenceTypeForString: aString]];
80			}
81
82		 //let the set check the chars
83			NSString *finalString = [aSet stringByRemovingUnknownCharsFromString: aString];
84
85		 // fill the NSData buffer with the contents of the NSString
86			sequenceData = [[finalString dataUsingEncoding: NSUTF8StringEncoding] retain];
87		}
88		else
89		{
90			sequenceData = nil;
91		}
92
93		symbolSet = [aSet retain];
94		sequenceType = [aSet sequenceType];
95
96		annotations = nil;
97		symbolArray = nil;
98	}
99
100	return self;
101}
102
103- (id)initWithData:(NSData *)aData symbolSet:(BCSymbolSet *)aSet
104{
105  if ( (self = [super init]) ) {
106		if ( aData != nil ) {
107			if ( aSet == nil ) {
108				aSet = [BCSymbolSet symbolSetForSequenceType: [self sequenceTypeForData: aData]];
109			}
110
111      // let the set check the chars
112      sequenceData = [aSet dataByRemovingUnknownCharsFromData: aData];
113			[sequenceData retain];
114		} else {
115			sequenceData = nil;
116		}
117
118		symbolSet = [aSet retain];
119		sequenceType = [aSet sequenceType];
120
121		annotations = nil;
122		symbolArray = nil;
123	}
124
125	return self;
126}
127
128- (id)initWithSymbolArray:(NSArray *)anArray symbolSet:(BCSymbolSet *)aSet
129{
130    if ( (self = [super init]) )
131    {
132		if ( aSet==nil )
133		{
134			aSet = [BCSymbolSet symbolSetForSequenceType: [self sequenceTypeForSymbolArray: anArray]];
135		}
136
137	  //let the set check the symbols
138
139		NSArray *finalArray=[aSet arrayByRemovingUnknownSymbolsFromArray:anArray];
140		symbolArray=[[NSMutableArray alloc] initWithArray:finalArray];
141
142	 // fill the NSData buffer with the contents of the array of symbols
143		sequenceData = [[[self sequenceStringFromSymbolArray: symbolArray]
144							dataUsingEncoding: NSUTF8StringEncoding] retain];
145
146		symbolSet=[aSet retain];
147		annotations=nil;
148		sequenceType = [symbolSet sequenceType];
149    }
150
151    return self;
152}
153
154- (id)initWithSymbolArray:(NSArray *)anArray
155{
156    return [self initWithSymbolArray:anArray symbolSet: nil];
157}
158
159// returns an empty sequence by calling the designated initializer
160- (id)init
161{
162    return [self initWithString:[NSString string] symbolSet:[BCSymbolSet unknownSymbolSet]];
163}
164
165- (id)initWithString:(NSString*)aString
166{
167    return [self initWithString:aString symbolSet: nil];
168}
169
170- (id)initWithString:(NSString*)aString range:(NSRange)aRange
171{
172    return [self initWithString:[aString substringWithRange:aRange]];
173}
174
175- (id)initWithString:(NSString*)aString range:(NSRange)aRange symbolSet:(BCSymbolSet *)aSet
176{
177    return [self initWithString:[aString substringWithRange:aRange] symbolSet: aSet];
178}
179
180- (id)initWithThreeLetterString:(NSString*)aString symbolSet:(BCSymbolSet *)aSet
181{
182    return [self initWithString:
183					[self convertThreeLetterStringToOneLetterString: aString symbolSet: aSet] symbolSet: aSet];
184}
185
186+ (BCSequence *)sequenceWithString: (NSString *)aString
187{
188	return [[[BCSequence alloc] initWithString:aString] autorelease];
189}
190
191+ (BCSequence *)sequenceWithString:(NSString *)aString symbolSet:(BCSymbolSet *)aSet
192{
193	return [[[BCSequence alloc] initWithString:aString symbolSet:aSet] autorelease];
194}
195
196+ (BCSequence *)sequenceWithThreeLetterString:(NSString *)aString symbolSet:(BCSymbolSet *)aSet
197{
198	return [[[BCSequence alloc] initWithThreeLetterString: aString symbolSet:aSet] autorelease];
199}
200
201+ (BCSequence *)sequenceWithSymbolArray:(NSArray *)entry
202{
203	return [[[BCSequence alloc] initWithSymbolArray:entry] autorelease];
204}
205
206+ (BCSequence *)sequenceWithSymbolArray:(NSArray *)entry symbolSet: (BCSymbolSet *)aSet;
207{
208	return [[[BCSequence alloc] initWithSymbolArray:entry symbolSet: aSet] autorelease];
209}
210
211+ (BCSequence *) objectForSavedRepresentation: (NSString *)aSequence
212{
213	return [[[BCSequence alloc] initWithString: aSequence] autorelease];
214}
215
216- (NSString *)convertThreeLetterStringToOneLetterString:(NSString *)aString symbolSet: (BCSymbolSet *)aSet
217{
218	int				i;
219	NSArray			*anArray = [aString componentsSeparatedByString:@" "];
220	NSString		*oneLetterCode, *threeLetterCode;
221	NSMutableString	*convertedString = [[NSMutableString alloc] initWithString: @""];
222
223	// build a temporary dictionary with the one-letter code as objects and the three-letter code as keys
224	// the easiest seems to use a symbolset and iterate over all the symbols
225	// for now only works for amino acids. However, if 3-letter codes are also available
226	// for nucleotides, the code can be extended to use BCSymbol. That means that the ivar threeLetterCode
227	// should be moved to BCSymbol from BCAminoAcid
228
229	NSArray			*symArray = [[BCSymbolSet proteinSymbolSet] allSymbols];
230	BCAminoAcid		*symbol;
231
232	NSMutableDictionary	*symbolDict = [NSMutableDictionary dictionaryWithCapacity: [symArray count]];
233
234	for (i = 0; i < [symArray count]; i++)
235	{
236		symbol = [symArray objectAtIndex: i];
237		[symbolDict setObject: [symbol symbolString] forKey: [symbol threeLetterCode]];
238	}
239
240	// now we have the temp symbolDict, iterate over the sequence (in 3-letter code)
241	// and create a new string using the 1-letter code
242
243	for (i = 0; i < [anArray count]; i++)
244	{
245		threeLetterCode = [anArray objectAtIndex: i];
246		oneLetterCode = [symbolDict objectForKey: [threeLetterCode capitalizedString]];
247
248		if ( oneLetterCode )
249		{
250			[convertedString appendString: oneLetterCode];
251		}
252	}
253
254	return [convertedString autorelease];
255}
256
257
258// BCSequence is immutable, no need to copy anything just retain and return self
259- (id)copyWithZone:(NSZone *)zone
260{
261	return [self retain];
262}
263
264- (void)dealloc
265{
266	[sequenceData release];
267	[symbolSet release];
268	[annotations release];
269
270	[self clearSymbolArray];
271	[super dealloc];
272}
273
274
275////////////////////////////////////////////////////////////////////////////
276#if 0
277#pragma mark �
278#pragma mark � SEQUENCE TYPE DETERMINATION
279#endif
280//
281//  INFORMATIONAL METHODS
282////////////////////////////////////////////////////////////////////////////
283
284// This method guesses the sequence type based on a string.
285// The method creates new sequences of the different types
286//	and checks which one results in the longer sequence,
287//	which is also the one having the lowest number of unknown symbols.
288- (BCSequenceType)sequenceTypeForString:(NSString *)string
289{
290	// bestSequenceType = best sequence type so far
291	// bestSymbolCount = the length of the best sequence type so far
292	BCSequence *testSequence;
293	BCSequenceType bestSequenceType;
294	unsigned int bestSymbolCount;
295
296	// use a DNA sequence to initialize the values of bestSequenceType and bestSymbolCount
297	testSequence=[BCSequence sequenceWithString:string symbolSet: [BCSymbolSet dnaSymbolSet]];
298	bestSequenceType=BCSequenceTypeDNA;
299	bestSymbolCount=[testSequence length];
300
301	// test RNA sequence
302	testSequence=[BCSequence sequenceWithString:string symbolSet: [BCSymbolSet rnaSymbolSet]];
303	if ([testSequence length]>bestSymbolCount) {
304		bestSequenceType=BCSequenceTypeRNA;
305		bestSymbolCount=[testSequence length];
306	}
307
308	// test Protein sequence
309	testSequence=[BCSequence sequenceWithString:string symbolSet: [BCSymbolSet proteinSymbolSet]];
310	if ([testSequence length]>bestSymbolCount) {
311		bestSequenceType=BCSequenceTypeProtein;
312		bestSymbolCount=[testSequence length];
313	}
314
315	//TO DO: is it a BCSequenceCodon?
316	// * symbols = DNA or RNA > protein
317	// * length = multiple of three
318	// * first 3 letters = ATG / AUG
319	// * no stop codon, except at the end
320
321	return bestSequenceType;
322}
323
324// This method guesses the sequence type for data
325- (BCSequenceType)sequenceTypeForData:(NSData *)aData
326{
327  unsigned char *seqData = (unsigned char *)[aData bytes];
328  unsigned i, len = [aData length];
329
330  // hopefully can determine in first 10,000 symbols
331  if (len > 10000) len = 10000;
332
333  BCSymbolSet *dna = [BCSymbolSet dnaSymbolSet];
334  BCSymbolSet *rna = [BCSymbolSet rnaSymbolSet];
335  BCSymbolSet *prot = [BCSymbolSet proteinSymbolSet];
336  unsigned dnaCount = 0, rnaCount = 0, protCount = 0;
337
338	// bestSequenceType = best sequence type so far
339	// bestSymbolCount = the length of the best sequence type so far
340	BCSequenceType bestSequenceType;
341
342	// use a DNA sequence to initialize the values of bestSequenceType and bestSymbolCount
343  for (i = 0; i < len; ++i) {
344    if ([dna symbolForChar: seqData[i]]) ++dnaCount;
345    if ([rna symbolForChar: seqData[i]]) ++rnaCount;
346    if ([prot symbolForChar: seqData[i]]) ++protCount;
347  }
348
349  // Note that the DNA and RNA symbols is a subset of protein symbols
350  // so assume DNA/RNA and only use protein if count is higher
351  if (dnaCount > rnaCount) {
352    if (protCount > dnaCount) {
353      bestSequenceType = BCSequenceTypeProtein;
354    } else {
355      bestSequenceType = BCSequenceTypeDNA;
356    }
357  } else {
358    if (protCount > rnaCount) {
359      bestSequenceType = BCSequenceTypeProtein;
360    } else {
361      bestSequenceType = BCSequenceTypeRNA;
362    }
363  }
364
365	//TO DO: is it a BCSequenceCodon?
366	// * symbols = DNA or RNA > protein
367	// * length = multiple of three
368	// * first 3 letters = ATG / AUG
369	// * no stop codon, except at the end
370
371	return bestSequenceType;
372}
373
374
375// This method guesses the sequence type based on an NSArray of BCSymbol.
376// The method creates new sequences of the different types
377//	and checks which one results in the longer sequence,
378//	which is also the one having the lowest number of unknown symbols.
379- (BCSequenceType)sequenceTypeForSymbolArray:(NSArray *)anArray;
380{
381	// bestSequenceType = best sequence type so far
382	// bestSymbolCount = the length of the best sequence type so far
383	BCSequence *testSequence;
384	BCSequenceType bestSequenceType;
385	unsigned int bestSymbolCount;
386
387	// use DNA sequence to initialize the values of bestSequenceType and bestSymbolCount
388	testSequence=[BCSequence sequenceWithSymbolArray:anArray symbolSet: [BCSymbolSet dnaSymbolSet]];
389	bestSequenceType=BCSequenceTypeDNA;
390	bestSymbolCount=[testSequence length];
391
392	// test RNA sequence
393	testSequence=[BCSequence sequenceWithSymbolArray:anArray symbolSet: [BCSymbolSet rnaSymbolSet]];
394	if ([testSequence length]>bestSymbolCount) {
395		bestSequenceType=BCSequenceTypeRNA;
396		bestSymbolCount=[testSequence length];
397	}
398
399	// test protein sequence
400	testSequence=[BCSequence sequenceWithSymbolArray:anArray symbolSet: [BCSymbolSet proteinSymbolSet]];
401	if ([testSequence length]>bestSymbolCount) {
402		bestSequenceType=BCSequenceTypeProtein;
403		bestSymbolCount=[testSequence length];
404	}
405
406	//TO DO: is it a BCSequenceCodon?
407	// * symbols = DNA or RNA > protein
408	// * length = multiple of three
409	// * first 3 letters = ATG / AUG
410	// * no stop codon, except at the end
411
412	return bestSequenceType;
413}
414
415
416////////////////////////////////////////////////////////////////////////////
417#if 0
418#pragma mark �
419#pragma mark � OBTAINING SEQUENCE INFORMATION
420#endif
421//
422//  INFORMATIONAL METHODS
423////////////////////////////////////////////////////////////////////////////
424
425- (NSData *) sequenceData
426{
427	return sequenceData;
428}
429
430- (const unsigned char *) bytes
431{
432	return (const unsigned char *)[[self sequenceData] bytes];
433}
434
435
436- (BCSymbolSet *)symbolSet
437{
438	return symbolSet;
439}
440
441
442// we can now allow to modify a symbolset, eg from strict -> non strict
443
444- (void)setSymbolSet:(BCSymbolSet *)set
445{
446	[set retain];
447	[symbolSet release];
448	symbolSet = set;
449}
450
451
452- (BCSequenceType)sequenceType
453{
454    return sequenceType;
455}
456
457// should this be commented out?
458/*
459- (void) setSequenceType:(BCSequenceType)aType
460{
461	sequenceType = aType;
462}
463*/
464
465- (unsigned int) length
466{
467    return [[self sequenceData] length];
468}
469
470
471- (BCSymbol *)symbolAtIndex: (int)theIndex
472{
473	if ( theIndex < [self length] )
474	{
475		BCSymbol	*aSymbol;
476
477#if 1
478		unsigned char	c = [[self sequenceData] charAtIndex: theIndex];
479		aSymbol = [[self symbolSet] symbolForChar: c];
480#else
481	// or maybe use getBytes - not faster according to reply on CocoaDev-list
482
483		unsigned char buffer;
484
485		[[self sequenceData] getBytes: &buffer range: NSMakeRange( theIndex, 1 )];
486		aSymbol = [[self symbolSet] symbolForChar: buffer];
487
488#endif
489		return aSymbol;
490	}
491
492	return nil;
493}
494
495
496- (BOOL) containsAmbiguousSymbols {
497    BCSymbol *aSymbol;
498    DECLARE_INDEX(loopCounter);
499    int theLimit = [symbolArray count];
500
501    for ( loopCounter = 0 ; loopCounter < theLimit ; loopCounter++ ) {
502        aSymbol = (BCSymbol *)ARRAY_GET_VALUE_AT_INDEX(symbolArray, loopCounter);
503        if ( [aSymbol isCompoundSymbol] )
504            return YES;
505    }
506
507    return NO;
508}
509
510- (NSArray *)symbolArray
511{
512	if ( sequenceData == nil )
513	{
514		return nil;
515	}
516
517    if ( symbolArray == nil )
518	{
519	 // creates a symbol array from the NSData sequence
520
521		const unsigned char	*data;
522		unsigned int		i, len;
523		BCSymbol			*aSymbol;
524
525		data = [self bytes];
526		len = strlen((char *)data);
527
528		NSMutableArray *anArray = [NSMutableArray array];
529
530		for (i = 0; i < len; i++)
531		{
532		  if ( (aSymbol = [[self symbolSet] symbolForChar: data[i]]) )
533			{
534				[anArray addObject: aSymbol];
535			}
536		}
537
538		symbolArray = [[NSArray alloc] initWithArray: anArray];
539	}
540
541    return symbolArray;
542}
543
544
545- (void)clearSymbolArray
546{
547    [symbolArray release];
548    symbolArray = nil;
549}
550
551
552// TO DO : use BCSymbolSet for filtering
553// DO WE STILL NEED THIS METHOD ??
554
555- (void) setSymbolArray: (NSArray *) anArray
556{
557    [symbolArray release];
558    symbolArray = [[NSMutableArray alloc] init];
559
560    id		aSymbol;
561    DECLARE_INDEX(loopCounter);
562    int		theLimit = [anArray count];
563
564    for ( loopCounter = 0 ; loopCounter < theLimit ; loopCounter++ ) {
565      aSymbol = (id)ARRAY_GET_VALUE_AT_INDEX(anArray, loopCounter);
566      ARRAY_APPEND_VALUE((NSMutableArray *)symbolArray, aSymbol);
567    }
568}
569
570
571- (NSArray *)subSymbolArrayInRange:(NSRange)aRange
572{
573    if ( aRange.location + aRange.length > [symbolArray count] )
574        return nil;
575
576    return [symbolArray subarrayWithRange: aRange];
577}
578
579
580- (NSString*)sequenceString
581{
582	unsigned int length = [self length];
583
584	if ( length )
585		return [self subSequenceStringInRange: NSMakeRange( 0, length ) ];
586	else
587	        return @"";	// return empty string, not nil.
588}
589
590
591- (NSString *)subSequenceStringInRange:(NSRange)aRange
592{
593    if ( aRange.location + aRange.length > [self length] )
594        return nil;
595
596	NSData		*data = [[self sequenceData] subdataWithRange: aRange];	// Man, I love Cocoa !!
597	NSString	*theReturn = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
598
599	return theReturn;
600}
601
602
603- (NSString *)sequenceStringFromSymbolArray:(NSArray *)anArray
604{
605	NSMutableString	*symbols = [NSMutableString string];
606	BCSymbol		*symbol;
607	int				i;
608
609	for ( i = 0; i < [anArray count]; i++)
610	{
611		symbol = [anArray objectAtIndex: i];
612		[symbols appendString: [symbol symbolString]];
613	}
614
615	return symbols;
616}
617
618- (BCSequence *)subSequenceInRange:(NSRange)aRange {
619    if ( aRange.location + aRange.length > [symbolArray count] )
620        return nil;
621
622	return [BCSequence sequenceWithSymbolArray: [symbolArray subarrayWithRange: aRange]];
623}
624
625
626- (NSString *) savableRepresentation {
627    return [self sequenceString];
628}
629
630
631- (NSString *) description  {
632    return [self sequenceString];
633}
634
635- (void) addAnnotation:(BCAnnotation *)annotation
636{
637	[self addAnnotation: (id)[annotation content] forKey: [annotation name]];
638}
639
640
641- (void) addAnnotation:(NSString *)annotation forKey: (NSString *) key
642{
643	NSMutableString	*oldValue;
644	BCAnnotation	*oldAnnotation, *newAnnotation;
645
646	if ( annotations == nil )
647	{
648		annotations = [[NSMutableDictionary alloc] init];
649	}
650
651 // If key already exists, then we need to append the value, instead of replacing it.
652 // This will happen when annotations are in the entry in multiple lanes.
653
654	oldAnnotation = (BCAnnotation *) [[self annotations] valueForKey: key];
655
656	if ( oldAnnotation )
657	{
658		oldValue = [[oldAnnotation content] mutableCopy];
659
660		[oldValue appendString: @"\n"];
661		[oldValue appendString: annotation];
662
663		newAnnotation = [[BCAnnotation alloc] initWithName: key content: oldValue];
664	}
665	else
666	{
667		newAnnotation = [[BCAnnotation alloc] initWithName: key content: annotation];
668	}
669
670	[[self annotations] setObject: newAnnotation forKey: key];
671}
672
673
674- (id) annotationForKey: (NSString *) key
675{
676	return [[self annotations] objectForKey: key];
677}
678
679
680- (NSMutableDictionary *) annotations
681{
682	return annotations;
683}
684
685
686//- (void) setAnnotations:(NSMutableDictionary *)aDict
687//{
688//    [aDict retain];
689//    [annotations release];
690//    annotations=aDict;
691//}
692
693
694
695////////////////////////////////////////////////////////////////////////////
696#if 0
697#pragma mark �
698#pragma mark � DERIVING RELATED SEQUENCES
699#endif
700//  DERIVING OTHER SEQUENCES
701////////////////////////////////////////////////////////////////////////////
702
703- (BCSequence *) reverse
704{
705#if 1
706    NSMutableArray	*theReverse = [NSMutableArray array];
707    BCSymbol		*aSymbol;
708    DECLARE_INDEX(loopCounter);
709    int				theLimit = [[self symbolArray] count];	// or use [self length] ???
710
711    for ( loopCounter = 0 ; loopCounter < theLimit ; loopCounter++ ) {
712      aSymbol = (id)ARRAY_GET_VALUE_AT_INDEX(symbolArray, loopCounter);
713      ARRAY_INSERT_VALUE_AT_INDEX(theReverse, 0, aSymbol);
714    }
715
716    return [BCSequence sequenceWithSymbolArray: theReverse symbolSet: [self symbolSet]];
717
718#else
719
720	NSMutableData *reverseSequence = [[NSMutableData alloc] initWithLength: [self length]];
721
722	const unsigned char *normal = [self bytes];
723	unsigned char *reverse = [reverseSequence mutableBytes];
724
725	unsigned int len = strlen( (char *)normal );
726
727	unsigned i, j;
728	j = 0;
729
730	for(i = len; i >= 0; --i)
731	{
732		reverse[j] = normal[i];
733		j++;
734	}
735
736	NSString	*reverseString = [[NSString alloc] initWithData: reverseSequence encoding: NSUTF8StringEncoding];
737
738    return [[BCSequence alloc] initWithString: [reverseString autorelease] symbolSet: [self symbolSet]];
739
740#endif
741
742}
743
744- (BCSequence *)complement
745{
746    BCToolComplement *complementTool = [BCToolComplement complementToolWithSequence: self];
747
748    return [complementTool sequenceComplement];
749}
750
751- (BCSequence *) reverseComplement
752{
753    BCToolComplement *complementTool = [BCToolComplement complementToolWithSequence: self];
754
755    [complementTool setReverse: YES];
756
757    return [complementTool sequenceComplement];
758}
759
760
761////////////////////////////////////////////////////////////////////////////
762////////////////////////////////////////////////////////////////////////////
763#if 0
764#pragma mark �
765#pragma mark � MANIPULATING SEQUENCE CONTENTS
766#endif
767//
768//  INFORMATIONAL METHODS
769////////////////////////////////////////////////////////////////////////////
770
771// THIS SHOULD ALL GO INTO THE MUTABLE SEQUENCE CLASS
772- (void)removeSymbolsInRange:(NSRange)aRange
773{
774    if ( aRange.location + aRange.length > [symbolArray count] )
775        return;
776	//    [symbolArray removeObjectsInRange: aRange];
777}
778
779- (void)removeSymbolAtIndex:(int)index
780{
781    if ( index > [symbolArray count] - 1 )
782        return;
783	//    [symbolArray removeObjectAtIndex:index];
784}
785
786// TO DO : use BCSymbolSet for filtering //
787- (void)insertSymbolsFromSequence:(BCSequence *)entry atIndex:(int)index
788{
789    if ( index > [symbolArray count] - 1 )
790        return;
791	//    [symbolArray replaceObjectsInRange:NSMakeRange(index,0) withObjectsFromArray:[entry symbolArray]];
792}
793
794
795////////////////////////////////////////////////////////////////////////////
796#if 0
797#pragma mark �
798#pragma mark � FINDING SUBSEQUENCES
799#endif
800//  FINDING SUBSEQUENCES
801////////////////////////////////////////////////////////////////////////////
802
803
804- (NSArray *) findSequence: (BCSequence *) entry
805{
806	return [self findSequence: entry usingStrict: NO];
807}
808
809- (NSArray *) findSequence: (BCSequence *) entry usingStrict: (BOOL) strict
810{
811	return [self findSequence: entry usingStrict: strict firstOnly: NO];
812}
813
814- (NSArray *) findSequence: (BCSequence *) entry usingStrict: (BOOL) strict firstOnly: (BOOL) firstOnly
815{
816	return [self findSequence: entry usingStrict: strict
817					firstOnly: NO usingSearchRange: NSMakeRange(0, [self length])];
818}
819
820- (NSArray *) findSequence: (BCSequence *) entry usingStrict: (BOOL) strict
821				firstOnly: (BOOL) firstOnly usingSearchRange: (NSRange) range
822{
823	BCToolSequenceFinder *sequenceFinder = [BCToolSequenceFinder sequenceFinderWithSequence: self];
824
825	[sequenceFinder setStrict: strict];
826	[sequenceFinder setFirstOnly: firstOnly];
827	[sequenceFinder setSearchRange: range];
828
829	return [sequenceFinder findSequence: entry];
830}
831
832
833
834@end
835