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