1//
2//  BCNucleotideDNA.m
3//  BioCocoa
4//
5//  Created by John Timmer on 8/11/04.
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 "BCNucleotideDNA.h"
32#import "BCNucleotideRNA.h"
33
34
35static  BCNucleotideDNA *adenosineRepresentation = nil;
36static  BCNucleotideDNA *thymidineRepresentation = nil;
37static  BCNucleotideDNA *cytidineRepresentation = nil;
38static  BCNucleotideDNA *guanidineRepresentation = nil;
39static  BCNucleotideDNA *anyBaseRepresentation = nil;
40static  BCNucleotideDNA *purineRepresentation = nil;
41static  BCNucleotideDNA *pyrimidineRepresentation = nil;
42static  BCNucleotideDNA *strongRepresentation = nil;
43static  BCNucleotideDNA *weakRepresentation = nil;
44static  BCNucleotideDNA *aminoRepresentation = nil;
45static  BCNucleotideDNA *ketoRepresentation = nil;
46static  BCNucleotideDNA *HRepresentation = nil;
47static  BCNucleotideDNA *VRepresentation = nil;
48static  BCNucleotideDNA *DRepresentation = nil;
49static  BCNucleotideDNA *BRepresentation = nil;
50static  BCNucleotideDNA *gapRepresentation = nil;
51static  BCNucleotideDNA *undefinedRepresentation = nil;
52
53static  NSMutableDictionary *customBases = nil;
54
55
56@implementation BCNucleotideDNA
57
58
59#if 0
60#pragma mark � CLASS METHODS
61#endif
62////////////////////////////////////////////////////////////////////////////
63//  THIS METHOD CREATES THE SINGLETON REFERENCES TO ALL THE STANDARD BASES
64////////////////////////////////////////////////////////////////////////////
65+ (void) initBases {
66    // FIND OUR BUNDLE AND LOAD UP THE BASE DEFINITIONS
67    NSBundle *biococoaBundle = [NSBundle bundleForClass: [BCNucleotideDNA class]];
68    NSString *filePath = [biococoaBundle pathForResource: @"nucleotides" ofType: @"plist"];
69    if ( filePath == nil )
70        return;
71
72    NSMutableDictionary *baseDefinitions = [NSMutableDictionary dictionaryWithContentsOfFile: filePath];
73    if ( baseDefinitions == nil )
74        return;
75
76    customBases = [baseDefinitions retain];
77
78    // GO THROUGH AND CREATE EACH SINGLETON BASE DEFINITION, USING THE DICTIONARY
79    NSDictionary *tempDict = [baseDefinitions objectForKey: @"A"];
80    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
81        adenosineRepresentation = [[BCNucleotideDNA alloc] initWithSymbolChar:  'A'];
82        [baseDefinitions removeObjectForKey: @"A"];
83    }
84
85    tempDict = [baseDefinitions objectForKey: @"T"];
86    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
87        thymidineRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'T'];
88        [baseDefinitions removeObjectForKey: @"T"];
89    }
90
91    tempDict = [baseDefinitions objectForKey: @"C"];
92    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
93        cytidineRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'C'];
94        [baseDefinitions removeObjectForKey: @"C"];
95    }
96
97    tempDict = [baseDefinitions objectForKey: @"G"];
98    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
99        guanidineRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'G'];
100        [baseDefinitions removeObjectForKey: @"G"];
101    }
102
103    tempDict = [baseDefinitions objectForKey: @"N"];
104    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
105        anyBaseRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'N'];
106        [baseDefinitions removeObjectForKey: @"N"];
107    }
108
109    tempDict = [baseDefinitions objectForKey: @"R"];
110    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
111        purineRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'R'];
112        [baseDefinitions removeObjectForKey: @"R"];
113    }
114
115    tempDict = [baseDefinitions objectForKey: @"Y"];
116    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
117        pyrimidineRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'Y'];
118        [baseDefinitions removeObjectForKey: @"Y"];
119    }
120
121    tempDict = [baseDefinitions objectForKey: @"S"];
122    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
123        strongRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'S'];
124        [baseDefinitions removeObjectForKey: @"S"];
125    }
126
127    tempDict = [baseDefinitions objectForKey: @"W"];
128    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
129        weakRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'W'];
130        [baseDefinitions removeObjectForKey: @"W"];
131    }
132
133    tempDict = [baseDefinitions objectForKey: @"M"];
134    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
135        aminoRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'M'];
136        [baseDefinitions removeObjectForKey: @"M"];
137    }
138
139    tempDict = [baseDefinitions objectForKey: @"K"];
140    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
141        ketoRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'K'];
142        [baseDefinitions removeObjectForKey: @"K"];
143    }
144
145    tempDict = [baseDefinitions objectForKey: @"H"];
146    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
147        HRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'H'];
148        [baseDefinitions removeObjectForKey: @"H"];
149    }
150
151    tempDict = [baseDefinitions objectForKey: @"V"];
152    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
153        VRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'V'];
154        [baseDefinitions removeObjectForKey: @"V"];
155    }
156
157    tempDict = [baseDefinitions objectForKey: @"D"];
158    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
159        DRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'D'];
160        [baseDefinitions removeObjectForKey: @"D"];
161    }
162
163    tempDict = [baseDefinitions objectForKey: @"B"];
164    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
165        BRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  'B'];
166        [baseDefinitions removeObjectForKey: @"B"];
167    }
168
169    tempDict = [baseDefinitions objectForKey: @"-"];
170    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
171        gapRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  '-'];
172        [baseDefinitions removeObjectForKey: @"-"];
173    }
174
175    tempDict = [baseDefinitions objectForKey: @"?"];
176    if ( tempDict != nil  && [tempDict isKindOfClass: [NSDictionary class]] ) {
177        undefinedRepresentation = [[BCNucleotideDNA alloc]  initWithSymbolChar:  '?'];
178        [baseDefinitions removeObjectForKey: @"?"];
179    }
180
181    // hang on to the dictionary, in case there are custom bases
182    customBases = [baseDefinitions retain];
183}
184
185
186
187+ (id) objectForSavedRepresentation: (NSString *)aSymbol {
188    return [BCNucleotideDNA symbolForChar: [aSymbol characterAtIndex: 0]];
189}
190
191
192////////////////////////////////////////////////////////////////////////////
193//  THE FOLLOWING IS A METHOD FOR OBTAINING REFERENCES TO THE
194//  INDIVIDUAL BASE REPRESENTATIONS WHEN GIVEN A SINGLE LETTER CODE
195//
196//  THIS WILL NOT WORK WITH CUSTOM BASES, SINCE THEIR SYMBOLS ARE NOT KNOWN IN ADVACE
197////////////////////////////////////////////////////////////////////////////
198+ (id) symbolForChar: (unsigned char)entry {
199    switch ( entry ) {
200
201        case 'A' :
202        case 'a' : {
203            return [BCNucleotideDNA adenosine];
204            break;
205        }
206
207
208        case 'T' :
209        case 't' : {
210            return [BCNucleotideDNA thymidine];
211            break;
212        }
213
214        case 'C' :
215        case 'c' : {
216            return [BCNucleotideDNA cytidine];
217            break;
218        }
219
220        case 'G' :
221        case 'g' : {
222            return [BCNucleotideDNA guanidine];
223            break;
224        }
225
226        case 'N' :
227        case 'n' :  {
228            return [BCNucleotideDNA anyBase];
229            break;
230        }
231
232
233        case 'R' :
234        case 'r' :  {
235            return [BCNucleotideDNA purine];
236            break;
237        }
238
239
240        case 'Y' :
241        case 'y' :  {
242            return [BCNucleotideDNA pyrimidine];
243            break;
244        }
245
246
247        case 'W' :
248        case 'w' :  {
249            return [BCNucleotideDNA weak];
250            break;
251        }
252
253
254        case 'S' :
255        case 's' :  {
256            return [BCNucleotideDNA strong];
257            break;
258        }
259
260
261        case 'M' :
262        case 'm' :  {
263            return [BCNucleotideDNA amino];
264            break;
265        }
266
267
268        case 'K' :
269        case 'k' :  {
270            return [BCNucleotideDNA keto];
271            break;
272        }
273
274
275        case 'H' :
276        case 'h' :  {
277            return [BCNucleotideDNA H];
278            break;
279        }
280
281
282        case 'V' :
283        case 'v' :  {
284            return [BCNucleotideDNA V];
285            break;
286        }
287
288
289        case 'D' :
290        case 'd' :  {
291            return [BCNucleotideDNA D];
292            break;
293        }
294
295
296        case 'B' :
297        case 'b' :  {
298            return [BCNucleotideDNA B];
299            break;
300        }
301
302
303        case '-' :  {
304            return [BCNucleotideDNA gap];
305            break;
306        }
307
308
309        default :
310            return [BCNucleotideDNA undefined];
311    }
312}
313
314
315
316////////////////////////////////////////////////////////////////////////////
317//  THE FOLLOWING ARE METHODS FOR OBTAINING REFERENCES TO THE
318//  INDIVIDUAL BASE REPRESENTATIONS
319////////////////////////////////////////////////////////////////////////////
320
321+ (BCNucleotideDNA *) adenosine {
322    if ( adenosineRepresentation == nil )
323        [BCNucleotideDNA initBases];
324    return adenosineRepresentation;
325}
326
327
328+ (BCNucleotideDNA *) thymidine {
329    if ( thymidineRepresentation == nil )
330        [BCNucleotideDNA initBases];
331    return thymidineRepresentation;
332}
333
334
335+ (BCNucleotideDNA *) cytidine {
336    if ( cytidineRepresentation == nil )
337        [BCNucleotideDNA initBases];
338    return cytidineRepresentation;
339}
340
341+ (BCNucleotideDNA *) guanidine {
342    if ( guanidineRepresentation == nil )
343        [BCNucleotideDNA initBases];
344    return guanidineRepresentation;
345}
346
347+ (BCNucleotideDNA *) anyBase {
348    if ( anyBaseRepresentation == nil )
349        [BCNucleotideDNA initBases];
350    return anyBaseRepresentation;
351}
352
353
354+ (BCNucleotideDNA *) purine {
355    if ( purineRepresentation == nil )
356        [BCNucleotideDNA initBases];
357    return purineRepresentation;
358}
359
360
361+ (BCNucleotideDNA *) pyrimidine {
362    if ( pyrimidineRepresentation == nil )
363        [BCNucleotideDNA initBases];
364    return pyrimidineRepresentation;
365}
366
367
368+ (BCNucleotideDNA *) strong {
369    if ( strongRepresentation == nil )
370        [BCNucleotideDNA initBases];
371    return strongRepresentation;
372}
373
374
375+ (BCNucleotideDNA *) weak {
376    if ( weakRepresentation == nil )
377        [BCNucleotideDNA initBases];
378    return weakRepresentation;
379}
380
381
382+ (BCNucleotideDNA *) amino {
383    if ( aminoRepresentation == nil )
384        [BCNucleotideDNA initBases];
385    return aminoRepresentation;
386}
387
388
389+ (BCNucleotideDNA *) keto {
390    if ( ketoRepresentation == nil )
391        [BCNucleotideDNA initBases];
392    return ketoRepresentation;
393}
394
395+ (BCNucleotideDNA *) H {
396    if ( HRepresentation == nil )
397        [BCNucleotideDNA initBases];
398    return HRepresentation;
399}
400
401+ (BCNucleotideDNA *) V {
402    if ( VRepresentation == nil )
403        [BCNucleotideDNA initBases];
404    return VRepresentation;
405}
406
407+ (BCNucleotideDNA *) D {
408    if ( DRepresentation == nil )
409        [BCNucleotideDNA initBases];
410    return DRepresentation;
411}
412
413+ (BCNucleotideDNA *) B {
414    if ( BRepresentation == nil )
415        [BCNucleotideDNA initBases];
416    return BRepresentation;
417}
418
419+ (BCNucleotideDNA *) gap {
420    if ( gapRepresentation == nil )
421        [BCNucleotideDNA initBases];
422    return gapRepresentation;
423}
424
425+ (BCNucleotideDNA *) undefined {
426    if ( undefinedRepresentation == nil )
427        [BCNucleotideDNA initBases];
428    return undefinedRepresentation;
429}
430
431
432
433+ (BCNucleotideDNA *) customBase: (NSString *)baseName {
434    if ( customBases == nil )
435        [BCNucleotideDNA initBases];
436    id aBase = [customBases objectForKey: baseName];
437    if ( aBase == nil)
438        return nil;
439
440    if (  [aBase isKindOfClass: [BCNucleotideDNA class]] )
441        return aBase;
442
443
444    if (  [aBase isKindOfClass: [NSDictionary class]] ) {
445        aBase = [[[BCNucleotideDNA alloc] initWithDictionary: aBase] autorelease];
446        if ( aBase != nil ) {
447            [customBases setObject: aBase forKey: baseName];
448            return aBase;
449        }
450    }
451    return nil;
452}
453
454
455
456
457////////////////////////////////////////////////////////////////////////////
458// OBJECT METHODS
459////////////////////////////////////////////////////////////////////////////
460#if 0
461#pragma mark �
462#pragma mark � OBJECT METHODS
463#pragma mark �
464#pragma mark �INITIALIZATION METHODS
465#endif
466
467
468- (id) initWithSymbolChar: (unsigned char)aSymbol {
469    self = [super initWithSymbolChar: aSymbol];
470    if ( self == nil )
471        return nil;
472
473    // we hang onto the dictionary in order to establish complement realtionships
474    // once all the bases are generated
475    symbolInfo = [[customBases objectForKey: symbolString] copy];
476
477    // get basic information about this base
478    name = [symbolInfo objectForKey: @"Name"];
479    if (name == nil)
480        return nil;
481    else
482    [name retain];
483
484	[self setMonoisotopicMass: [[symbolInfo objectForKey:@"MonoisotopicMass"] floatValue]];
485	[self setAverageMass: [[symbolInfo objectForKey:@"AverageMass"] floatValue]];
486
487    return self;
488}
489
490#if 0
491#pragma mark �BASE INFORMATION METHODS
492#endif
493
494- (BOOL) isBase {
495    if ( self == [BCNucleotideDNA gap] || self == [BCNucleotideDNA undefined] )
496        return NO;
497    return YES;
498}
499
500#if 0
501#pragma mark �BASE RELATIONSHIP METHODS
502#endif
503
504- (BCNucleotideRNA *) RNABaseEquivalent {
505    if ( self != [BCNucleotideDNA thymidine] )
506        return [BCNucleotideRNA performSelector: NSSelectorFromString( name )];
507    return [BCNucleotideRNA uridine] ;
508}
509
510
511@end
512