/***************************************************************************** # Copyright (C) 1994-2008 by David Gordon. # All rights reserved. # # This software is part of a beta-test version of the Consed/Autofinish # package. It should not be redistributed or # used for any commercial purpose, including commercially funded # sequencing, without written permission from the author and the # University of Washington. # # This software is provided ``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 authors or the University of Washington 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. # # Building Consed from source is error prone and not simple which is # why I provide executables. Due to time limitations I cannot # provide any assistance in building Consed. Even if you do not # modify the source, you may introduce errors due to using a # different version of the compiler, a different version of motif, # different versions of other libraries than I used, etc. For this # reason, if you discover Consed bugs, I can only offer help with # those bugs if you first reproduce those bugs with an executable # provided by me--not an executable you have built. # # Modifying Consed is also difficult. Although Consed is modular, # some modules are used by many other modules. Thus making a change # in one place can have unforeseen effects on many other features. # It may takes months for you to notice these other side-effects # which may not seen connected at all. It is not feasable for me to # provide help with modifying Consed sources because of the # potentially huge amount of time involved. # #*****************************************************************************/ #include using namespace std; #include #include "tagTypes.h" #include "tag.h" #include "consed.h" #include "assert.h" #include #include "soEmptyString.h" #include "primerType.h" #include "contig.h" #include "oligoTag.h" #include "autoFinishExpTag.h" #include "rwctokenizer.h" #include "popupErrorMessage.h" #include "userDefinedTagFieldType.h" #include "userDefinedTagField.h" // initialization/definition of static member data tagTypes* tagTypes :: pGlobalTagTypes_ = NULL; bool tagTypes :: bTagTypesCreated_ = false; tagTypes :: tagTypes() { if (bTagTypesCreated_) { cerr << "Fatal program error: tagTypes ctor called twice. " << endl; cerr.flush(); exit( -1 ); } pGlobalTagTypes_ = this; bTagTypesCreated_ = true; } bool tagTypes :: bIsAValidTagType( const RWCString& soTagType ) { int n = 0; bool bFound = false; while( !bFound && n < aTagTypes_.length() ) { if ( aTagTypes_[n]->soTagType_ == soTagType ) bFound = true; else ++n; } return( bFound ); } GuiColorText* tagTypes :: pGetGuiColorTextForTagType( const RWCString& soTagType ) { GuiColorText* pGuiColorText; bool bFound = false; for( int n = 0; n < aTagTypes_.length() && !bFound; ++n ) { if ( aTagTypes_[n]->soTagType_ == soTagType ) { bFound = true; pGuiColorText = aTagTypes_[n]->pGuiColorText_; } } if ( !bFound ) { RWCString soErrorMessage = RWCString( "could not find tag type \"" ) + soTagType + "\" at " + __LINE__ + " in " + __FILE__; ProgramLogicError ple( soErrorMessage ); throw ple; } return( pGuiColorText ); } GuiColorText* tagTypes :: pGetGuiColorTextForTag( tag* pTag ) { RWCString soTagType = pTag->soGetTagType(); try { return( pGetGuiColorTextForTagType( soTagType ) ); } catch( ProgramLogicError ple ) { RWCString soErrorMessage( ple.szGetDesc() ); if ( pTag->bReadTagNotConsensusTag_ ) { soErrorMessage += " read tag on read "; soErrorMessage += pTag->pLocFrag_->soGetName(); if ( pTag->bWriteToPhdFileNotAceFile_ ) soErrorMessage += " for phd file"; else soErrorMessage += " for ace file"; } else { soErrorMessage += " consensus tag in contig "; soErrorMessage += pTag->pContig_->soGetName(); } soErrorMessage += " source: "; soErrorMessage += pTag->soSource_; soErrorMessage += " date: "; soErrorMessage += pTag->soDate_; soErrorMessage += " from padded cons pos "; soErrorMessage += RWCString( (long) pTag->nPaddedConsPosStart_ ); soErrorMessage += " to "; soErrorMessage += RWCString( (long) pTag->nPaddedConsPosEnd_ ); if ( pTag->bReadTagNotConsensusTag_ ) { soErrorMessage += " which means from padded read pos "; soErrorMessage += RWCString( (long) pTag->pLocFrag_->nGetFragIndexFromConsPos( pTag->nPaddedConsPosStart_ ) ); soErrorMessage += " to "; soErrorMessage += RWCString( (long) pTag->pLocFrag_->nGetFragIndexFromConsPos( pTag->nPaddedConsPosEnd_ ) ); } ProgramLogicError ple2( soErrorMessage ); // rethrow, so this routine does not return // otherwise there will be some obscure side-effect message throw ple2; } } GuiColorText* tagTypes :: pGetGuiColorTextForTagsOverlap() { return( pGetGuiColorTextForTagType( "tagsOverlap" ) ); } void tagTypes :: assignValidTagType( const RWCString& soTagType, const RWCString& soColor, const tagType::readOrConsensusType readOrConsensus, const bool bCanBeCreatedBySwiping ) { if (soTagType.isNull() ) return; GuiColorText* pGuiColorText = new GuiColorText( "black", soColor ); tagType* pTagType = new tagType( soTagType, soColor, pGuiColorText, readOrConsensus, bCanBeCreatedBySwiping ); aTagTypes_.insert( pTagType ); } tag* tagTypes :: pCreateReadTag( const RWCString& soTagType, const RWCString& soComment, const int nConsPosStart, const int nConsPosEnd, LocatedFragment* pLocFrag, const bool bWriteToPhdFileNotAceFile, bool& bUserPushedCancel ) { tag* pTag = new tag( pLocFrag, NULL, // contig soTagType, nConsPosStart, nConsPosEnd, bWriteToPhdFileNotAceFile, soComment, "consed", // soSource "", // current date false ); // bNoTrans if ( pTag->bTagHasExtraInformation() ) { pTag->askUserForExtraTagInformation( bUserPushedCancel ); if (bUserPushedCancel ) { delete pTag; return NULL; } } bUserPushedCancel = false; return( pTag ); } tag* tagTypes :: pCreateConsensusTag( const RWCString& soTagType, const RWCString& soComment, const int nConsPosStart, const int nConsPosEnd, Contig* pContig, const bool bNoTrans, bool& bUserPushedCancel, const RWCString& soContigName ) { tag* pTag; if (soTagType == "oligo" ) { pTag = new oligoTag( pContig, nConsPosStart, nConsPosEnd, "consed", soEmptyString, // date will be current date bNoTrans, ConsEd::pGetAssembly()->soGetNextOligoName(), "????", // bases should be filled in!!! false, // bComplementedWithRespectToWayPhrapCreatedContig 0, // melting temp could be calculated!!! "????", // purpose soComment ); // soComment } else pTag = new tag( NULL, // LocatedFragment pContig, soTagType, nConsPosStart, nConsPosEnd, false, // bWriteToPhdFileNotAceFile // all consensus tags are in ace file soComment, soConsed, // "consed" soEmptyString, // current date/time bNoTrans ); if ( soTagType == "contigName" ) { pTag->soMiscData_ = ( pContig->bComplementedFromWayPhrapCreated_ ) ? "C" : "U"; pTag->soMiscData_ += soContigName; } if ( pTag->bTagHasExtraInformation() ) { pTag->askUserForExtraTagInformation( bUserPushedCancel ); if (bUserPushedCancel ) { delete pTag; return NULL; } } bUserPushedCancel = false; return( pTag ); } void tagTypes :: getColumnHeadingsForNavigatorBox( const RWCString& soTagType, RWCString& soColumnHeadings1, RWCString& soColumnHeadings2 ) { soColumnHeadings1 = "Contig Read Consensus"; soColumnHeadings2 = "Name Name Positions"; if ( soTagType == "oligo" ) { soColumnHeadings1 += " Comment Oligo Oligo"; soColumnHeadings2 += " Name Templates"; } else { soColumnHeadings1 += " Tag Comment"; soColumnHeadings2 += " Length "; } } bool tagTypes :: bAreTagsOfThisTypeHidden( const RWCString& soTagType ) { RWCString soDelimitedByCommas = "," + soTagType + ","; if ( soTagTypesToHide_.index( soDelimitedByCommas ) == RW_NPOS ) return false; else return true; } // This take a space-separated list and makes a comma-separated list // (I just did it this way for ease of debugging). void tagTypes :: setTagTypesToHide( char* szTagTypesToHide ) { soTagTypesToHide_ = ""; if ( !szTagTypesToHide ) { return; } if ( strlen( szTagTypesToHide ) == 0 ) { return; } RWCTokenizer tokTagTypesToHide( szTagTypesToHide ); RWCString soOneTagTypeToHide; while( ! (soOneTagTypeToHide = tokTagTypesToHide() ).isNull() ) { soTagTypesToHide_ += ","; soTagTypesToHide_ += soOneTagTypeToHide; } if ( !soTagTypesToHide_.isNull() ) soTagTypesToHide_ += ","; } tag* tagTypes :: pDuplicateTag( tag* pTag ) { tag* pNewTag; if ( pTag->soType_ == "oligo" ) { oligoTag* pOldTag = (oligoTag*) pTag; pNewTag = new oligoTag( pOldTag->pContig_, pOldTag->nPaddedConsPosStart_, pOldTag->nPaddedConsPosEnd_, "consed_duplicated_from_" + pTag->soSource_, pOldTag->soDate_, pOldTag->bNoTrans_, pOldTag->soName_, pOldTag->soBases_, pOldTag->nMeltingTemperature_, pOldTag->bComplementedWithRespectToWayPhrapCreatedContig_, pOldTag->soTemplates_, pOldTag->soComment_ ); } else if ( pTag->soType_ == "autoFinishExp" ) { autoFinishExpTag* pOldTag = (autoFinishExpTag*) pTag; pNewTag = new autoFinishExpTag( pOldTag->pContig_, pOldTag->nPaddedConsPosStart_, pOldTag->nPaddedConsPosEnd_, "consed_duplicated_from_" + pTag->soSource_, pOldTag->soDate_, pOldTag->soMiscData_ ); autoFinishExpTag* pNewTag2 = (autoFinishExpTag*) pNewTag; pNewTag2->soPrimerBases_ = pOldTag->soPrimerBases_; pNewTag2->nMeltingTemp_ = pOldTag->nMeltingTemp_; pNewTag2->aTemplates_ = pOldTag->aTemplates_; pNewTag2->aExpID_ = pOldTag->aExpID_; pNewTag2->bComplementedFromWayPhrapCreatedContig_ = pOldTag->bComplementedFromWayPhrapCreatedContig_; pNewTag2->nUnpaddedOffsetToStartOfHighQualityRegion_ = pOldTag->nUnpaddedOffsetToStartOfHighQualityRegion_; pNewTag2->nUnpaddedOffsetToEndOfHighQualityRegion_ = pOldTag->nUnpaddedOffsetToEndOfHighQualityRegion_; pNewTag2->nUnpaddedOffsetOfBeginningOfReadFromTag_ = pOldTag->nUnpaddedOffsetOfBeginningOfReadFromTag_; pNewTag2->dErrorsFixed_ = pOldTag->dErrorsFixed_; pNewTag2->nSingleSubcloneBasesFixed_ = pOldTag->nSingleSubcloneBasesFixed_; pNewTag2->nReadType_ = pOldTag->nReadType_; pNewTag2->nPurpose_ = pOldTag->nPurpose_; pNewTag2->soPrimerID_ = pOldTag->soPrimerID_; pNewTag2->nExtendingIntoGapThisManyBases_ = pOldTag->nExtendingIntoGapThisManyBases_; pNewTag2->nOriginalNumberOfSingleSubcloneBases_ = pOldTag->nOriginalNumberOfSingleSubcloneBases_; pNewTag2->dOriginalNumberOfErrors_ = pOldTag->dOriginalNumberOfErrors_; } else if ( pTag->pUserDefinedTagType_ ) { // since I'm not writing all the code to duplicate user-defined // tags, just make sure they aren't corrupted (DG, July 2009) return( 0 ); } else if ( pTag->lID_ != nUndefinedTagID ) { // duplicating tag IDs creates a can of worms since if another // tag refers to it, which of the 2 copies should it refer to? // This is in the context of not duplicating tear tags (DG, July 2009) return( 0 ); } else { tag* pOldTag = pTag; pNewTag = new tag( pOldTag->pLocFrag_, pOldTag->pContig_, pOldTag->soType_, pOldTag->nPaddedConsPosStart_, pOldTag->nPaddedConsPosEnd_, pOldTag->bWriteToPhdFileNotAceFile_, pOldTag->soComment_, "consed_duplicated_from_" + pOldTag->soSource_, pOldTag->soDate_, pOldTag->bNoTrans_ ); } pNewTag->soMiscData_ = pTag->soMiscData_; return( pNewTag ); } void tagTypes :: checkingAfterStoringAllTagTypes() { for( int nTagType = 0; nTagType < aTagTypes_.length(); ++nTagType ) { tagType* pTagType = aTagTypes_[ nTagType ]; if ( pTagType->bIsAUserDefinedTagType() ) { for( int nField = 0; nField < ((userDefinedTagType*) pTagType)->aUserDefinedTagFieldType_.length(); ++nField ) { userDefinedTagFieldType* pField = ((userDefinedTagType*) pTagType)->aUserDefinedTagFieldType_[ nField ]; if ( pField->eFieldType_ == userDefinedTagFieldType::ePointer ) { RWCString soTagType = pField->soPointerToWhichTagType_.returnToLower(); bool bFound = false; for( int nTagType2 = 0; nTagType2 < aTagTypes_.length() && !bFound; ++nTagType2 ) { if ( aTagTypes_[ nTagType2 ]->soTagType_.returnToLower() == soTagType ) bFound = true; } if ( !bFound ) { RWCString soMessage = "FATAL: tag type "; soMessage += pTagType->soTagType_; soMessage += " has a field that points to tag type "; soMessage += pField->soPointerToWhichTagType_; soMessage += " which doesn't exist."; fprintf( stderr, "%s\n", soMessage.data() ); exit( -1 ); } } } } } } tagType* tagTypes :: pGetTagType( const RWCString& soTagType ) { tagType dummyTagType( soTagType, "", NULL, tagType::undefined, true ); return( aTagTypes_.find( &dummyTagType ) ); } bool userDefinedTagType :: bCorrectNumberOfEachField( RWTPtrOrderedVector* pArrayOfUserDefinedTagFields, RWCString& soErrorMessage ) { int nType; for( nType = 0; nType < aUserDefinedTagFieldType_.length(); ++nType) aUserDefinedTagFieldType_[ nType ]->nNumberOfCopiesFound_ = 0; // initialize an array which gives the number of each // field type. Its index is the index of // userDefinedTagType::aUserDefinedTagFieldType_ if ( pArrayOfUserDefinedTagFields ) { for( int nField = 0; nField < pArrayOfUserDefinedTagFields->length(); ++nField ) { userDefinedTagField* pUserDefinedTagField = (*pArrayOfUserDefinedTagFields)[ nField ]; ++pUserDefinedTagField->pUserDefinedTagFieldType_->nNumberOfCopiesFound_; } } // now go through types checking whether they each have the correct // number of fields for( nType = 0; nType < aUserDefinedTagFieldType_.length(); ++nType) { userDefinedTagFieldType* pUserDefinedTagFieldType = aUserDefinedTagFieldType_[ nType ]; if ( !pUserDefinedTagFieldType->bFoundCorrectNumberOfCopies( soErrorMessage ) ) { return false; } } return true; }