+
+ // run internal FilterTool implementation, return success/fail
+ m_impl = new FilterToolPrivate(m_settings);
+
+ if ( m_impl->Run() ) return 0;
+ else return 1;
+}
+
+// ---------------------------------------------
+// FilterToolPrivate implementation
+
+// constructor
+FilterTool::FilterToolPrivate::FilterToolPrivate(FilterTool::FilterSettings* settings)
+ : m_settings(settings)
+{ }
+
+// destructor
+FilterTool::FilterToolPrivate::~FilterToolPrivate(void) { }
+
+bool FilterTool::FilterToolPrivate::AddPropertyTokensToFilter(const string& filterName, const map<string, string>& propertyTokens) {
+
+
+ // dummy temp values for token parsing
+ bool boolValue;
+ int32_t int32Value;
+ uint16_t uint16Value;
+ uint32_t uint32Value;
+ string stringValue;
+ PropertyFilterValue::ValueCompareType type;
+
+ // iterate over property token map
+ map<string, string>::const_iterator mapIter = propertyTokens.begin();
+ map<string, string>::const_iterator mapEnd = propertyTokens.end();
+ for ( ; mapIter != mapEnd; ++mapIter ) {
+
+ const string& propertyName = (*mapIter).first;
+ const string& token = (*mapIter).second;
+
+ // ------------------------------
+ // convert token to value & compare type
+ // then add to filter engine
+
+ // bool conversion
+ if ( propertyName == ISDUPLICATE_PROPERTY ||
+ propertyName == ISFAILEDQC_PROPERTY ||
+ propertyName == ISFIRSTMATE_PROPERTY ||
+ propertyName == ISMAPPED_PROPERTY ||
+ propertyName == ISMATEMAPPED_PROPERTY ||
+ propertyName == ISMATEREVERSESTRAND_PROPERTY ||
+ propertyName == ISPAIRED_PROPERTY ||
+ propertyName == ISPRIMARYALIGNMENT_PROPERTY ||
+ propertyName == ISPROPERPAIR_PROPERTY ||
+ propertyName == ISREVERSESTRAND_PROPERTY ||
+ propertyName == ISSECONDMATE_PROPERTY
+ )
+ {
+ FilterEngine::parseToken(token, boolValue, type);
+ FilterEngine::setProperty(filterName, propertyName, boolValue, type);
+ }
+
+ // int32_t conversion
+ else if ( propertyName == INSERTSIZE_PROPERTY ||
+ propertyName == MATEPOSITION_PROPERTY ||
+ propertyName == POSITION_PROPERTY
+ )
+ {
+ FilterEngine::parseToken(token, int32Value, type);
+ FilterEngine::setProperty(filterName, propertyName, int32Value, type);
+ }
+
+ // uint16_t conversion
+ else if ( propertyName == MAPQUALITY_PROPERTY )
+ {
+ FilterEngine::parseToken(token, uint16Value, type);
+ FilterEngine::setProperty(filterName, propertyName, uint16Value, type);
+ }
+
+ // uint32_t conversion
+ else if ( propertyName == ALIGNMENTFLAG_PROPERTY )
+ {
+ FilterEngine::parseToken(token, uint32Value, type);
+ FilterEngine::setProperty(filterName, propertyName, uint32Value, type);
+ }
+
+ // string conversion
+ else if ( propertyName == MATEREFERENCE_PROPERTY ||
+ propertyName == NAME_PROPERTY ||
+ propertyName == QUERYBASES_PROPERTY ||
+ propertyName == REFERENCE_PROPERTY
+ )
+ {
+ FilterEngine::parseToken(token, stringValue, type);
+ FilterEngine::setProperty(filterName, propertyName, stringValue, type);
+ }
+
+ // else unknown property
+ else {
+ cerr << "Unknown property: " << propertyName << "!" << endl;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool FilterTool::FilterToolPrivate::CheckAlignment(const BamAlignment& al) {
+
+ bool keepAlignment = true;
+
+ // only consider properties that are actually enabled
+ // iterate over these enabled properties
+ const vector<string> enabledProperties = FilterEngine::enabledPropertyNames();
+ vector<string>::const_iterator propIter = enabledProperties.begin();
+ vector<string>::const_iterator propEnd = enabledProperties.end();
+ for ( ; propIter != propEnd; ++propIter ) {
+
+ // check alignment data field depending on propertyName
+ const string& propertyName = (*propIter);
+ if ( propertyName == ALIGNMENTFLAG_PROPERTY ) keepAlignment &= FilterEngine::check(ALIGNMENTFLAG_PROPERTY, al.AlignmentFlag);
+ else if ( propertyName == INSERTSIZE_PROPERTY ) keepAlignment &= FilterEngine::check(INSERTSIZE_PROPERTY, al.InsertSize);
+ else if ( propertyName == ISDUPLICATE_PROPERTY ) keepAlignment &= FilterEngine::check(ISDUPLICATE_PROPERTY, al.IsDuplicate());
+ else if ( propertyName == ISFAILEDQC_PROPERTY ) keepAlignment &= FilterEngine::check(ISFAILEDQC_PROPERTY, al.IsFailedQC());
+ else if ( propertyName == ISFIRSTMATE_PROPERTY ) keepAlignment &= FilterEngine::check(ISFIRSTMATE_PROPERTY, al.IsFirstMate());
+ else if ( propertyName == ISMAPPED_PROPERTY ) keepAlignment &= FilterEngine::check(ISMAPPED_PROPERTY, al.IsMapped());
+ else if ( propertyName == ISMATEMAPPED_PROPERTY ) keepAlignment &= FilterEngine::check(ISMATEMAPPED_PROPERTY, al.IsMateMapped());
+ else if ( propertyName == ISMATEREVERSESTRAND_PROPERTY ) keepAlignment &= FilterEngine::check(ISMATEREVERSESTRAND_PROPERTY, al.IsMateReverseStrand());
+ else if ( propertyName == ISPAIRED_PROPERTY ) keepAlignment &= FilterEngine::check(ISPAIRED_PROPERTY, al.IsPaired());
+ else if ( propertyName == ISPRIMARYALIGNMENT_PROPERTY ) keepAlignment &= FilterEngine::check(ISPRIMARYALIGNMENT_PROPERTY, al.IsPrimaryAlignment());
+ else if ( propertyName == ISPROPERPAIR_PROPERTY ) keepAlignment &= FilterEngine::check(ISPROPERPAIR_PROPERTY, al.IsProperPair());
+ else if ( propertyName == ISREVERSESTRAND_PROPERTY ) keepAlignment &= FilterEngine::check(ISREVERSESTRAND_PROPERTY, al.IsReverseStrand());
+ else if ( propertyName == ISSECONDMATE_PROPERTY ) keepAlignment &= FilterEngine::check(ISSECONDMATE_PROPERTY, al.IsSecondMate());
+ else if ( propertyName == MAPQUALITY_PROPERTY ) keepAlignment &= FilterEngine::check(MAPQUALITY_PROPERTY, al.MapQuality);
+ else if ( propertyName == MATEPOSITION_PROPERTY ) keepAlignment &= ( al.IsPaired() && al.IsMateMapped() && FilterEngine::check(MATEPOSITION_PROPERTY, al.MateRefID) );
+ else if ( propertyName == MATEREFERENCE_PROPERTY ) {
+ if ( !al.IsPaired() || !al.IsMateMapped() ) return false;
+ BAMTOOLS_ASSERT_MESSAGE( (al.MateRefID>=0 && (al.MateRefID<(int)m_references.size())), "Invalid MateRefID");
+ const string& refName = m_references.at(al.MateRefID).RefName;
+ keepAlignment &= FilterEngine::check(MATEREFERENCE_PROPERTY, refName);
+ }
+ else if ( propertyName == NAME_PROPERTY ) keepAlignment &= FilterEngine::check(NAME_PROPERTY, al.Name);
+ else if ( propertyName == POSITION_PROPERTY ) keepAlignment &= FilterEngine::check(POSITION_PROPERTY, al.Position);
+ else if ( propertyName == QUERYBASES_PROPERTY ) keepAlignment &= FilterEngine::check(QUERYBASES_PROPERTY, al.QueryBases);
+ else if ( propertyName == REFERENCE_PROPERTY ) {
+ BAMTOOLS_ASSERT_MESSAGE( (al.RefID>=0 && (al.RefID<(int)m_references.size())), "Invalid RefID");
+ const string& refName = m_references.at(al.RefID).RefName;
+ keepAlignment &= FilterEngine::check(REFERENCE_PROPERTY, refName);
+ }
+ else BAMTOOLS_ASSERT_MESSAGE( false, "Unknown property");
+
+ // if alignment fails at ANY point, just quit and return false
+ if ( !keepAlignment ) return false;
+ }
+
+ // return success (should still be true at this point)
+ return keepAlignment;
+}
+
+const string FilterTool::FilterToolPrivate::GetScriptContents(void) {
+
+ // open script for reading
+ FILE* inFile = fopen(m_settings->ScriptFilename.c_str(), "rb");
+ if ( !inFile ) {
+ cerr << "FilterTool error: Could not open script: " << m_settings->ScriptFilename << " for reading" << endl;
+ return false;
+ }
+
+ // read in entire script contents
+ char buffer[1024];
+ ostringstream docStream("");
+ while ( true ) {
+
+ // peek ahead, make sure there is data available
+ char ch = fgetc(inFile);
+ ungetc(ch, inFile);
+ if( feof(inFile) ) break;
+
+ // read next block of data
+ if ( fgets(buffer, 1024, inFile) == 0 ) {
+ cerr << "FilterTool error : could not read from script" << endl;
+ return false;
+ }
+
+ docStream << buffer;
+ }
+
+ // close script file
+ fclose(inFile);
+
+ // import buffer contents to document, return
+ string document = docStream.str();
+ return document;
+}
+
+void FilterTool::FilterToolPrivate::InitProperties(void) {
+
+ // store property names in vector
+ m_propertyNames.push_back(ALIGNMENTFLAG_PROPERTY);
+ m_propertyNames.push_back(INSERTSIZE_PROPERTY);
+ m_propertyNames.push_back(ISDUPLICATE_PROPERTY);
+ m_propertyNames.push_back(ISFAILEDQC_PROPERTY);
+ m_propertyNames.push_back(ISFIRSTMATE_PROPERTY);
+ m_propertyNames.push_back(ISMAPPED_PROPERTY);
+ m_propertyNames.push_back(ISMATEMAPPED_PROPERTY);
+ m_propertyNames.push_back(ISMATEREVERSESTRAND_PROPERTY);
+ m_propertyNames.push_back(ISPAIRED_PROPERTY);
+ m_propertyNames.push_back(ISPRIMARYALIGNMENT_PROPERTY);
+ m_propertyNames.push_back(ISPROPERPAIR_PROPERTY);
+ m_propertyNames.push_back(ISREVERSESTRAND_PROPERTY);
+ m_propertyNames.push_back(ISSECONDMATE_PROPERTY);
+ m_propertyNames.push_back(MAPQUALITY_PROPERTY);
+ m_propertyNames.push_back(MATEPOSITION_PROPERTY);
+ m_propertyNames.push_back(MATEREFERENCE_PROPERTY);
+ m_propertyNames.push_back(NAME_PROPERTY);
+ m_propertyNames.push_back(POSITION_PROPERTY);
+ m_propertyNames.push_back(QUERYBASES_PROPERTY);
+ m_propertyNames.push_back(REFERENCE_PROPERTY);
+
+ // add vector contents to FilterEngine
+ vector<string>::const_iterator propertyNameIter = m_propertyNames.begin();
+ vector<string>::const_iterator propertyNameEnd = m_propertyNames.end();
+ for ( ; propertyNameIter != propertyNameEnd; ++propertyNameIter )
+ FilterEngine::addProperty((*propertyNameIter));
+}
+
+bool FilterTool::FilterToolPrivate::ParseCommandLine(void) {
+
+ // add a rule set to filter engine
+ const string CMD = "COMMAND_LINE";
+ FilterEngine::addFilter(CMD);
+
+ // map property names to command line args
+ map<string, string> propertyTokens;
+ if ( m_settings->HasAlignmentFlagFilter ) propertyTokens.insert( make_pair(ALIGNMENTFLAG_PROPERTY, m_settings->AlignmentFlagFilter) );
+ if ( m_settings->HasInsertSizeFilter ) propertyTokens.insert( make_pair(INSERTSIZE_PROPERTY, m_settings->InsertSizeFilter) );
+ if ( m_settings->HasIsDuplicateFilter ) propertyTokens.insert( make_pair(ISDUPLICATE_PROPERTY, m_settings->IsDuplicateFilter) );
+ if ( m_settings->HasIsFailedQCFilter ) propertyTokens.insert( make_pair(ISFAILEDQC_PROPERTY, m_settings->IsFailedQCFilter) );
+ if ( m_settings->HasIsFirstMateFilter ) propertyTokens.insert( make_pair(ISFIRSTMATE_PROPERTY, m_settings->IsFirstMateFilter) );
+ if ( m_settings->HasIsMappedFilter ) propertyTokens.insert( make_pair(ISMAPPED_PROPERTY, m_settings->IsMappedFilter) );
+ if ( m_settings->HasIsMateMappedFilter ) propertyTokens.insert( make_pair(ISMATEMAPPED_PROPERTY, m_settings->IsMateMappedFilter) );
+ if ( m_settings->HasIsMateReverseStrandFilter ) propertyTokens.insert( make_pair(ISMATEREVERSESTRAND_PROPERTY, m_settings->IsMateReverseStrandFilter) );
+ if ( m_settings->HasIsPairedFilter ) propertyTokens.insert( make_pair(ISPAIRED_PROPERTY, m_settings->IsPairedFilter) );
+ if ( m_settings->HasIsPrimaryAlignmentFilter ) propertyTokens.insert( make_pair(ISPRIMARYALIGNMENT_PROPERTY, m_settings->IsPrimaryAlignmentFilter) );
+ if ( m_settings->HasIsProperPairFilter ) propertyTokens.insert( make_pair(ISPROPERPAIR_PROPERTY, m_settings->IsProperPairFilter) );
+ if ( m_settings->HasIsReverseStrandFilter ) propertyTokens.insert( make_pair(ISREVERSESTRAND_PROPERTY, m_settings->IsReverseStrandFilter) );
+ if ( m_settings->HasIsSecondMateFilter ) propertyTokens.insert( make_pair(ISSECONDMATE_PROPERTY, m_settings->IsSecondMateFilter) );
+ if ( m_settings->HasMapQualityFilter ) propertyTokens.insert( make_pair(MAPQUALITY_PROPERTY, m_settings->MapQualityFilter) );
+ if ( m_settings->HasNameFilter ) propertyTokens.insert( make_pair(NAME_PROPERTY, m_settings->NameFilter) );
+ if ( m_settings->HasQueryBasesFilter ) propertyTokens.insert( make_pair(QUERYBASES_PROPERTY, m_settings->QueryBasesFilter) );
+
+ // send add these properties to filter set "COMMAND_LINE"
+ return AddPropertyTokensToFilter(CMD, propertyTokens);
+}
+
+bool FilterTool::FilterToolPrivate::ParseFilterObject(const string& filterName, const Json::Value& filterObject) {
+
+ // filter object parsing variables
+ Json::Value null(Json::nullValue);
+ Json::Value propertyValue;
+
+ // store results
+ map<string, string> propertyTokens;
+
+ // iterate over known properties
+ vector<string>::const_iterator propertyNameIter = m_propertyNames.begin();
+ vector<string>::const_iterator propertyNameEnd = m_propertyNames.end();
+ for ( ; propertyNameIter != propertyNameEnd; ++propertyNameIter ) {
+ const string& propertyName = (*propertyNameIter);
+
+ // if property defined in filter, add to token list
+ propertyValue = filterObject.get(propertyName, null);
+ if ( propertyValue != null )
+ propertyTokens.insert( make_pair(propertyName, propertyValue.asString()) );
+ }
+
+ // add this filter to engin
+ FilterEngine::addFilter(filterName);