// // BCNucleotideDNA.m // BioCocoa // // Created by John Timmer on 8/11/04. // Copyright 2004 John Timmer. All rights reserved. // #import "BCNucleotideDNA.h" static BCNucleotideDNA *adenosineRepresentation = nil; static BCNucleotideDNA *thymidineRepresentation = nil; static BCNucleotideDNA *cytidineRepresentation = nil; static BCNucleotideDNA *guanidineRepresentation = nil; static BCNucleotideDNA *anyBaseRepresentation = nil; static BCNucleotideDNA *purineRepresentation = nil; static BCNucleotideDNA *pyrimadineRepresentation = nil; static BCNucleotideDNA *strongRepresentation = nil; static BCNucleotideDNA *weakRepresentation = nil; static BCNucleotideDNA *MRepresentation = nil; static BCNucleotideDNA *KRepresentation = nil; static BCNucleotideDNA *HRepresentation = nil; static BCNucleotideDNA *VRepresentation = nil; static BCNucleotideDNA *DRepresentation = nil; static BCNucleotideDNA *BRepresentation = nil; static NSMutableDictionary *customBases = nil; @implementation BCNucleotideDNA #pragma mark â CLASS METHODS //////////////////////////////////////////////////////////////////////////// // THIS METHOD CREATES THE SINGLETON REFERENCES TO ALL THE STANDARD BASES //////////////////////////////////////////////////////////////////////////// + (void) initBases { // FIND OUR BUNDLE AND LOAD UP THE BASE DEFINITIONS NSBundle *biococoaBundle = [NSBundle bundleForClass: [BCNucleotideDNA class]]; NSString *filePath = [biococoaBundle pathForResource: @"base template" ofType: @"plist"]; if ( filePath == nil ) return; NSMutableDictionary *baseDefinitions = [NSMutableDictionary dictionaryWithContentsOfFile: filePath]; if ( baseDefinitions == nil ) return; // GO THROUGH AND CREATE EACH SINGLETON BASE DEFINITION, USING THE DICTIONARY NSDictionary *tempDict = [baseDefinitions objectForKey: @"adenosine"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { adenosineRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"adenosine"]; } tempDict = [baseDefinitions objectForKey: @"thymidine"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { thymidineRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"thymidine"]; } tempDict = [baseDefinitions objectForKey: @"cytidine"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { cytidineRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"cytidine"]; } tempDict = [baseDefinitions objectForKey: @"guanidine"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { guanidineRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"guanidine"]; } tempDict = [baseDefinitions objectForKey: @"any base"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { anyBaseRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"any base"]; } tempDict = [baseDefinitions objectForKey: @"purine"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { purineRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"purine"]; } tempDict = [baseDefinitions objectForKey: @"pyrimadine"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { pyrimadineRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"pyrimadine"]; } tempDict = [baseDefinitions objectForKey: @"strong"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { strongRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"strong"]; } tempDict = [baseDefinitions objectForKey: @"weak"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { weakRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"weak"]; } tempDict = [baseDefinitions objectForKey: @"M"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { MRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"M"]; } tempDict = [baseDefinitions objectForKey: @"K"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { KRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"K"]; } tempDict = [baseDefinitions objectForKey: @"H"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { HRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"H"]; } tempDict = [baseDefinitions objectForKey: @"V"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { VRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"V"]; } tempDict = [baseDefinitions objectForKey: @"D"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { DRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"D"]; } tempDict = [baseDefinitions objectForKey: @"B"]; if ( tempDict != nil && [tempDict isKindOfClass: [NSDictionary class]] ) { BRepresentation = [[BCNucleotideDNA alloc] initWithDictionary: tempDict]; [baseDefinitions removeObjectForKey: @"B"]; } // hang on to the dictionary, in case there are custom bases customBases = [baseDefinitions retain]; } //////////////////////////////////////////////////////////////////////////// // THE FOLLOWING IS A METHOD FOR OBTAINING REFERENCES TO THE // INDIVIDUAL BASE REPRESENTATIONS WHEN GIVEN A SINGLE LETTER CODE // // THIS WILL NOT WORK WITH CUSTOM BASES, SINCE THEIR SYMBOLS ARE NOT KNOWN IN ADVACE //////////////////////////////////////////////////////////////////////////// + (id) baseForSymbol: (unichar)entry { switch ( entry ) { case 'A' : case 'a' : { return [BCNucleotideDNA adenosine]; break; } case 'T' : case 't' : { return [BCNucleotideDNA thymidine]; break; } case 'C' : case 'c' : { return [BCNucleotideDNA cytidine]; break; } case 'G' : case 'g' : { return [BCNucleotideDNA guanidine]; break; } case 'N' : case 'n' : { return [BCNucleotideDNA anyBase]; break; } case 'R' : case 'r' : { return [BCNucleotideDNA purine]; break; } case 'Y' : case 'y' : { return [BCNucleotideDNA pyrimadine]; break; } case 'W' : case 'w' : { return [BCNucleotideDNA weak]; break; } case 'S' : case 's' : { return [BCNucleotideDNA strong]; break; } case 'M' : case 'm' : { return [BCNucleotideDNA M]; break; } case 'K' : case 'k' : { return [BCNucleotideDNA K]; break; } case 'H' : case 'h' : { return [BCNucleotideDNA H]; break; } case 'V' : case 'v' : { return [BCNucleotideDNA V]; break; } case 'D' : case 'd' : { return [BCNucleotideDNA D]; break; } case 'B' : case 'b' : { return [BCNucleotideDNA B]; break; } default : return nil; } } //////////////////////////////////////////////////////////////////////////// // THE FOLLOWING ARE METHODS FOR OBTAINING REFERENCES TO THE // INDIVIDUAL BASE REPRESENTATIONS //////////////////////////////////////////////////////////////////////////// + (BCNucleotideDNA *) adenosine { if ( adenosineRepresentation == nil ) [BCNucleotideDNA initBases]; return adenosineRepresentation; } + (BCNucleotideDNA *) thymidine { if ( thymidineRepresentation == nil ) [BCNucleotideDNA initBases]; return thymidineRepresentation; } + (BCNucleotideDNA *) cytidine { if ( cytidineRepresentation == nil ) [BCNucleotideDNA initBases]; return cytidineRepresentation; } + (BCNucleotideDNA *) guanidine { if ( guanidineRepresentation == nil ) [BCNucleotideDNA initBases]; return guanidineRepresentation; } + (BCNucleotideDNA *) anyBase { if ( anyBaseRepresentation == nil ) [BCNucleotideDNA initBases]; return anyBaseRepresentation; } + (BCNucleotideDNA *) purine { if ( purineRepresentation == nil ) [BCNucleotideDNA initBases]; return purineRepresentation; } + (BCNucleotideDNA *) pyrimadine { if ( pyrimadineRepresentation == nil ) [BCNucleotideDNA initBases]; return pyrimadineRepresentation; } + (BCNucleotideDNA *) strong { if ( strongRepresentation == nil ) [BCNucleotideDNA initBases]; return strongRepresentation; } + (BCNucleotideDNA *) weak { if ( weakRepresentation == nil ) [BCNucleotideDNA initBases]; return weakRepresentation; } + (BCNucleotideDNA *) M { if ( MRepresentation == nil ) [BCNucleotideDNA initBases]; return MRepresentation; } + (BCNucleotideDNA *) K { if ( KRepresentation == nil ) [BCNucleotideDNA initBases]; return KRepresentation; } + (BCNucleotideDNA *) H { if ( HRepresentation == nil ) [BCNucleotideDNA initBases]; return HRepresentation; } + (BCNucleotideDNA *) V { if ( VRepresentation == nil ) [BCNucleotideDNA initBases]; return VRepresentation; } + (BCNucleotideDNA *) D { if ( DRepresentation == nil ) [BCNucleotideDNA initBases]; return DRepresentation; } + (BCNucleotideDNA *) B { if ( BRepresentation == nil ) [BCNucleotideDNA initBases]; return BRepresentation; } + (BCNucleotideDNA *) customBase: (NSString *)baseName { if ( customBases == nil ) [BCNucleotideDNA initBases]; id aBase = [customBases objectForKey: baseName]; if ( aBase == nil) return nil; if ( [aBase isKindOfClass: [BCNucleotideDNA class]] ) return aBase; if ( [aBase isKindOfClass: [NSDictionary class]] ) { aBase = [[[BCNucleotideDNA alloc] initWithDictionary: aBase] autorelease]; if ( aBase != nil ) { [customBases setObject: aBase forKey: baseName]; return aBase; } } return nil; } //////////////////////////////////////////////////////////////////////////// // OBJECT METHODS //////////////////////////////////////////////////////////////////////////// #pragma mark â #pragma mark â OBJECT METHODS #pragma mark â #pragma mark âINITIALIZATION METHODS // this class needs to be initialized with a full dictionary of information - (id)initWithName:(NSString*)aName { return nil; } - (BCNucleotideDNA *) initWithDictionary: (NSDictionary *)entry { self = [super init]; if ( self == nil ) return nil; // we hang onto the dictionary in order to establish complement realtionships // once all the bases are generated baseInfo = [entry copy]; // get basic information about this base name = [baseInfo objectForKey: @"Name"]; if (name == nil) return nil; else [name retain]; symbolString = [baseInfo objectForKey: @"Symbol"]; if (symbolString == nil || [symbolString length] == 0) return nil; else [symbolString retain]; symbol = [symbolString characterAtIndex: 0]; NSNumber *tempNumber = [baseInfo objectForKey: @"single base"]; if (tempNumber == nil) return nil; isSingleBase = [tempNumber boolValue]; // nil out the base relationships so that we can detect // that they still need to be initialized complement = nil; complements = nil; represents = nil; representedBy = nil; return self; } - (void) initializeBaseRelationships { // THIS METHOD IS CALLED AFTER OBJECT INITIALIZATION BECAUSE IT // REQUIRES THE EXISTENCE OF ALL THE OTHER BASES IN ORDER TO WORK // IT SHOULD BE CALLED THE FIRST TIME ONE OF THESE OBJECTS IS NEEDED NSString *baseReference = [baseInfo objectForKey: @"Complement"]; if ( baseReference == nil || [baseReference length] == 0 ) return; complement = [BCNucleotideDNA performSelector: NSSelectorFromString( baseReference )]; if (complement == nil) return; NSArray *infoArray = [baseInfo objectForKey: @"All Complements"]; if ( infoArray == nil || [infoArray count] == 0 ) return; NSEnumerator *objectEnumerator = [infoArray objectEnumerator]; NSMutableArray *tempArray = [NSMutableArray array]; BCNucleotideDNA *tempBase; while ( baseReference = [objectEnumerator nextObject] ) { if ( baseReference == nil || [baseReference length] == 0 ) return; tempBase = [BCNucleotideDNA performSelector: NSSelectorFromString( baseReference )]; if ( tempBase != nil ) [tempArray addObject: tempBase]; else return; } complements = [tempArray copy]; infoArray = [baseInfo objectForKey: @"Represents"]; if ( infoArray == nil || [infoArray count] == 0 ) return; objectEnumerator = [infoArray objectEnumerator]; tempArray = [NSMutableArray array]; while ( baseReference = [objectEnumerator nextObject] ) { if ( baseReference == nil || [baseReference length] == 0 ) return; tempBase = [BCNucleotideDNA performSelector: NSSelectorFromString( baseReference )]; if ( tempBase != nil ) [tempArray addObject: tempBase]; else return; } represents = [tempArray copy]; infoArray = [baseInfo objectForKey: @"Represented by"]; if ( infoArray == nil || [infoArray count] == 0 ) return; objectEnumerator = [infoArray objectEnumerator]; tempArray = [NSMutableArray array]; while ( baseReference = [objectEnumerator nextObject] ) { if ( baseReference == nil || [baseReference length] == 0 ) return; tempBase = [BCNucleotideDNA performSelector: NSSelectorFromString( baseReference )]; if ( tempBase != nil ) [tempArray addObject: tempBase]; else return; } representedBy = [tempArray copy]; } - (void) dealloc { [baseInfo release]; [name release]; [symbolString release]; [complements release]; [represents release]; [representedBy release]; [super dealloc]; } #pragma mark âBASE INFORMATION METHODS // we override this, as bases do not allow their names to be changed. - (void)setName:(NSString *)s { return; } - (BOOL) isSingleBase { return isSingleBase; } #pragma mark âBASE RELATIONSHIP METHODS /////////////////////////////////////////////////////////// // COMPLEMENTATION METHODS /////////////////////////////////////////////////////////// - (BCNucleotideDNA *)complement { if ( complement == nil ) [self initializeBaseRelationships];; return complement; } - (NSArray *)complements { if ( complements == nil ) [self initializeBaseRelationships];; return [[complements copy] autorelease]; } - (BOOL) complementsBase: (BCNucleotideDNA *)entry { if ( complements == nil ) [self initializeBaseRelationships]; return [complements containsObject: entry]; } - (BOOL) isComplementOfBase: (BCNucleotideDNA *)entry { return [entry complementsBase: self]; } /////////////////////////////////////////////////////////// // REPRESENTATION METHODS FOR AMBIGUOUS BASES /////////////////////////////////////////////////////////// - (NSArray *) representedBases { if ( represents == nil ) [self initializeBaseRelationships]; return [[represents copy] autorelease]; } - (NSArray *) representingBases { if ( representedBy == nil ) [self initializeBaseRelationships]; return [[representedBy copy] autorelease]; } - (BOOL) representsBase: (BCNucleotideDNA *) entry { if ( represents == nil ) [self initializeBaseRelationships]; return [represents containsObject: entry]; } - (BOOL) isRepresentedByBase: (BCNucleotideDNA *) entry { if ( representedBy == nil ) [self initializeBaseRelationships]; return [representedBy containsObject: entry]; } - (NSCharacterSet *) symbolsOfRepresentedBases { if ( representedBy == nil ) [self initializeBaseRelationships]; NSMutableCharacterSet *returnSet = [[[NSMutableCharacterSet alloc] init] autorelease]; NSEnumerator *arrayEnumerator = [representedBy objectEnumerator]; BCNucleotideDNA *aBase; while ( aBase = [arrayEnumerator nextObject] ) { [returnSet addCharactersInString: [aBase symbolString]]; } return [[returnSet copy] autorelease]; } @end