taxon1.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:55k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: taxon1.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 19:35:15  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.25
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /* $Id: taxon1.cpp,v 1000.3 2004/06/01 19:35:15 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Vladimir Soussov, Michael Domrachev
  35.  *
  36.  * File Description:
  37.  *     NCBI Taxonomy information retreival library implementation
  38.  *
  39.  */
  40. #include <ncbi_pch.hpp>
  41. #include <corelib/ncbistr.hpp>
  42. #include <objects/taxon1/taxon1.hpp>
  43. #include <objects/seqfeat/seqfeat__.hpp>
  44. #include <connect/ncbi_conn_stream.hpp>
  45. #include <serial/serial.hpp>
  46. #include <serial/enumvalues.hpp>
  47. #include <serial/objistr.hpp>
  48. #include <serial/objostr.hpp>
  49. #include <algorithm>
  50. #include "cache.hpp"
  51. BEGIN_NCBI_SCOPE
  52. BEGIN_objects_SCOPE // namespace ncbi::objects::
  53. static const char s_achInvalTaxid[] = "Invalid tax id specified";
  54. CTaxon1::CTaxon1()
  55.     : m_pServer(NULL),
  56.       m_pOut(NULL),
  57.       m_pIn(NULL),
  58.       m_plCache(NULL),
  59.       m_bWithSynonyms(false)
  60. {
  61.     return;
  62. }
  63. CTaxon1::~CTaxon1()
  64. {
  65.     Reset();
  66. }
  67. void
  68. CTaxon1::Reset()
  69. {
  70.     SetLastError(NULL);
  71.     delete m_pIn;
  72.     delete m_pOut;
  73.     delete m_pServer;
  74.     m_pIn = NULL;
  75.     m_pOut = NULL;
  76.     m_pServer = NULL;
  77.     delete m_plCache;
  78.     m_plCache = NULL;
  79. }
  80. bool
  81. CTaxon1::Init(void)
  82. {
  83.     static const STimeout def_timeout = { 120, 0 };
  84.     return CTaxon1::Init(&def_timeout);
  85. }
  86. bool
  87. CTaxon1::Init(unsigned cache_capacity)
  88. {
  89.     static const STimeout def_timeout = { 120, 0 };
  90.     return CTaxon1::Init(&def_timeout, 5, cache_capacity);
  91. }
  92. bool
  93. CTaxon1::Init(const STimeout* timeout, unsigned reconnect_attempts,
  94.       unsigned cache_capacity)
  95. {
  96.     SetLastError(NULL);
  97.     if( m_pServer ) { // Already inited
  98.         SetLastError( "ERROR: Init(): Already initialized" );
  99.         return false;
  100.     }
  101.     try {
  102.         // Open connection to Taxonomy service
  103.         CTaxon1_req req;
  104.         CTaxon1_resp resp;
  105.         if ( timeout ) {
  106.             m_timeout_value = *timeout;
  107.             m_timeout = &m_timeout_value;
  108.         } else {
  109.             m_timeout = 0;
  110.         }
  111.         m_nReconnectAttempts = reconnect_attempts;
  112.         m_pchService = "TaxService";
  113.         const char* tmp;
  114.         if( ( (tmp=getenv("NI_TAXONOMY_SERVICE_NAME")) != NULL ) ||
  115.     ( (tmp=getenv("NI_SERVICE_NAME_TAXONOMY")) != NULL ) ) {
  116.             m_pchService = tmp;
  117.         }
  118.         auto_ptr<CObjectOStream> pOut;
  119.         auto_ptr<CObjectIStream> pIn;
  120.         auto_ptr<CConn_ServiceStream>
  121.             pServer( new CConn_ServiceStream(m_pchService, fSERV_Any,
  122.                                              0, 0, m_timeout) );
  123. #ifdef USE_TEXT_ASN
  124.         m_eDataFormat = eSerial_AsnText;
  125. #else
  126.         m_eDataFormat = eSerial_AsnBinary;
  127. #endif
  128.         pOut.reset( CObjectOStream::Open(m_eDataFormat, *pServer) );
  129.         pIn.reset( CObjectIStream::Open(m_eDataFormat, *pServer) );
  130.         req.SetInit();
  131.         m_pServer = pServer.release();
  132.         m_pIn = pIn.release();
  133.         m_pOut = pOut.release();
  134.         if( SendRequest( req, resp ) ) {
  135.             if( resp.IsInit() ) {
  136.                 // Init is done
  137.                 m_plCache = new COrgRefCache( *this );
  138.                 if( m_plCache->Init( cache_capacity ) ) {
  139.                     return true;
  140.                 }
  141.                 delete m_plCache;
  142.                 m_plCache = NULL;
  143.             } else { // Set error
  144.                 SetLastError( "ERROR: Response type is not Init" );
  145.             }
  146.         }
  147.     } catch( exception& e ) {
  148.         SetLastError( e.what() );
  149.     }
  150.     // Clean streams
  151.     delete m_pIn;
  152.     delete m_pOut;
  153.     delete m_pServer;
  154.     m_pIn = NULL;
  155.     m_pOut = NULL;
  156.     m_pServer = NULL;
  157.     return false;
  158. }
  159. void
  160. CTaxon1::Fini(void)
  161. {
  162.     SetLastError(NULL);
  163.     if( m_pServer ) {
  164.         CTaxon1_req req;
  165.         CTaxon1_resp resp;
  166.         req.SetFini();
  167.         if( SendRequest( req, resp ) ) {
  168.             if( !resp.IsFini() ) {
  169.                 SetLastError( "Response type is not Fini" );
  170.             }
  171.         }
  172.     }
  173.     Reset();
  174. }
  175. CRef< CTaxon2_data >
  176. CTaxon1::GetById(int tax_id)
  177. {
  178.     SetLastError(NULL);
  179.     if( tax_id > 0 ) {
  180.         // Check if this taxon is in cache
  181.         CTaxon2_data* pData = 0;
  182.         if( m_plCache->LookupAndInsert( tax_id, &pData ) && pData ) {
  183.             CTaxon2_data* pNewData = new CTaxon2_data();
  184.             SerialAssign<CTaxon2_data>( *pNewData, *pData );
  185.             return CRef<CTaxon2_data>(pNewData);
  186.         }
  187.     } else {
  188.         SetLastError( s_achInvalTaxid );
  189.     }
  190.     return CRef<CTaxon2_data>(NULL);
  191. }
  192. class PFindMod {
  193. public:
  194.     void SetModToMatch( const CRef< COrgMod >& mod ) {
  195. CanonizeName( mod->GetSubname(), m_sName );
  196. m_nType = mod->GetSubtype();
  197.     }
  198.     bool operator()( const CRef< COrgMod >& mod ) const {
  199. if( m_nType == mod->GetSubtype() ) {
  200.     string sCanoName;
  201.     CanonizeName( mod->GetSubname(), sCanoName );
  202.     return ( sCanoName == m_sName );
  203. }
  204. return false;
  205.     }
  206.     void CanonizeName( const string& in, string& out ) const {
  207. bool bSpace = true;
  208. char prevc = '';
  209. for( size_t i = 0; i < in.size(); ++i ) {
  210.     if( bSpace ) {
  211. if( !isspace(in[i]) ) {
  212.     bSpace = false;
  213.     if( prevc )
  214. out += tolower(prevc);
  215.     prevc = in[i];
  216. }
  217.     } else {
  218. if( prevc )
  219.     out += tolower(prevc);
  220. if( isspace(in[i]) ) {
  221.     prevc = ' ';
  222.     bSpace = true;
  223. } else {
  224.     prevc = in[i];
  225. }
  226.     }
  227. }
  228. if( prevc && prevc != ' ' )
  229.     out += tolower(prevc);
  230.     }
  231. private:
  232.     string  m_sName;
  233.     int     m_nType;
  234. };
  235. class PFindConflict {
  236. public:
  237.     void SetTypeToMatch( int type ) {
  238. m_nType = type;
  239. switch( type ) {
  240. case COrgMod::eSubtype_strain:
  241. case COrgMod::eSubtype_variety:
  242. //case COrgMod::eSubtype_sub_species:
  243.     m_bSubSpecType = true;
  244.     break;
  245. default:
  246.     m_bSubSpecType = false;
  247.     break;
  248. }
  249.     }
  250.     bool operator()( const CRef< COrgMod >& mod ) const {
  251. // mod is the destination modifier
  252. if( m_nType == mod->GetSubtype() ) {
  253.     return true;
  254. }
  255. switch( mod->GetSubtype() ) {
  256. case COrgMod::eSubtype_strain:
  257. case COrgMod::eSubtype_substrain:
  258. case COrgMod::eSubtype_type:
  259. case COrgMod::eSubtype_subtype:
  260. case COrgMod::eSubtype_variety:
  261. case COrgMod::eSubtype_serotype:
  262. case COrgMod::eSubtype_serogroup:
  263. case COrgMod::eSubtype_serovar:
  264. case COrgMod::eSubtype_cultivar:
  265. case COrgMod::eSubtype_pathovar:
  266. case COrgMod::eSubtype_chemovar:
  267. case COrgMod::eSubtype_biovar:
  268. case COrgMod::eSubtype_biotype:
  269. case COrgMod::eSubtype_group:
  270. case COrgMod::eSubtype_subgroup:
  271. case COrgMod::eSubtype_isolate:
  272. // case COrgMod::eSubtype_sub_species:
  273.     return m_bSubSpecType;
  274. //     if( (m_nType >= 2 && m_nType <= 17) ) return 1;
  275.   case COrgMod::eSubtype_other:
  276.       return true;
  277. default:
  278.     break;
  279. }
  280. return false;
  281.     }
  282. private:
  283.     int     m_nType;
  284.     bool    m_bSubSpecType;
  285. };
  286. class PFindModByType {
  287. public:
  288.     PFindModByType( int type ) : m_nType( type ) {}
  289.     bool operator()( const CRef< COrgMod >& mod ) const {
  290. return ( m_nType == mod->GetSubtype() );
  291.     }
  292. private:
  293.     int     m_nType;
  294. };
  295. class PRemoveSynAnamorph {
  296. public:
  297.     PRemoveSynAnamorph( const string& sTaxname ) : m_sName( sTaxname ) {}
  298.     bool operator()( const CRef< COrgMod >& mod ) const {
  299. switch( mod->GetSubtype() ) {
  300. case COrgMod::eSubtype_synonym:
  301. case COrgMod::eSubtype_anamorph:
  302.     return (NStr::CompareNocase( m_sName, mod->GetSubname() ) == 0);
  303. default:
  304.     break;
  305. }
  306. return false;
  307.     }
  308. private:
  309.     const string& m_sName;
  310. };
  311. void
  312. CTaxon1::OrgRefAdjust( COrg_ref& inp_orgRef, const COrg_ref& db_orgRef,
  313.        int tax_id )
  314. {
  315.     inp_orgRef.ResetCommon();
  316.     inp_orgRef.ResetSyn();
  317.     
  318.     // fill-up inp_orgRef based on db_orgRef
  319.     inp_orgRef.SetTaxname( db_orgRef.GetTaxname() );
  320.     if( db_orgRef.IsSetCommon() ) {
  321. inp_orgRef.SetCommon( db_orgRef.GetCommon() );
  322.     }
  323.     // Set tax id
  324.     inp_orgRef.SetTaxId( tax_id );
  325.     // copy the synonym list
  326.     if( m_bWithSynonyms && db_orgRef.IsSetSyn() ) {
  327. inp_orgRef.SetSyn() = db_orgRef.GetSyn();
  328.     }
  329.   
  330.     // copy orgname
  331.     COrgName& on = inp_orgRef.SetOrgname();
  332.     // Copy the orgname
  333.     on.SetName().Assign( db_orgRef.GetOrgname().GetName() );
  334.     bool bHasMod = on.IsSetMod();
  335.     const COrgName::TMod& lSrcMod = db_orgRef.GetOrgname().GetMod();
  336.     COrgName::TMod& lDstMod = on.SetMod();
  337.     if( bHasMod ) { // Merge modifiers
  338. // Find and remove gb_xxx modifiers
  339. // tc2proc.c: CleanOrgName
  340. // Service stuff
  341. CTaxon1_req req;
  342. CTaxon1_resp resp;
  343. CRef<CTaxon1_info> pModInfo( new CTaxon1_info() );
  344. PushDiagPostPrefix( "Taxon1::OrgRefAdjust" );
  345. for( COrgName::TMod::iterator i = lDstMod.begin();
  346.      i != lDstMod.end(); ) {
  347.     switch( (*i)->GetSubtype() ) {
  348.     case COrgMod::eSubtype_gb_acronym:
  349.     case COrgMod::eSubtype_gb_anamorph:
  350.     case COrgMod::eSubtype_gb_synonym:
  351. i = lDstMod.erase( i );
  352. break;
  353.     default: // Check the modifier validity
  354. if( (*i)->CanGetSubname() && (*i)->CanGetSubtype() &&
  355.     !(*i)->GetSubname().empty() && (*i)->GetSubtype() != 0 ) {
  356.     pModInfo->SetIval1( tax_id );
  357.     pModInfo->SetIval2( (*i)->GetSubtype() );
  358.     pModInfo->SetSval( (*i)->GetSubname() );
  359.     req.SetGetorgmod( *pModInfo );
  360.     try {
  361. if( SendRequest( req, resp ) ) {
  362.     if( !resp.IsGetorgmod() ) { // error
  363. ERR_POST( "Response type is not Getorgmod" );
  364.     } else {
  365. if( resp.GetGetorgmod().size() > 0 ) {
  366.     CRef<CTaxon1_info> pInfo
  367. = resp.GetGetorgmod().front();
  368.     if( pInfo->GetIval1() == tax_id ) {
  369. if( pInfo->GetIval2() == 0 ) {
  370. // Modifier is wrong (probably, hidden)
  371.     i = lDstMod.erase( i );
  372.     continue;
  373. } else {
  374.     (*i)->SetSubname( pInfo->GetSval() );
  375.     (*i)->SetSubtype( COrgMod::TSubtype( pInfo->GetIval2() ) );
  376. }
  377.     } else if( pInfo->GetIval1() != 0 ) {
  378. // Another redirection occurred
  379. // leave modifier but issue warning
  380. NCBI_NS_NCBI::CNcbiDiag(eDiag_Warning)
  381.     << "OrgMod type="
  382.     << COrgMod::GetTypeInfo_enum_ESubtype()
  383.     ->FindName( (*i)->GetSubtype(), true )
  384.     << " name='" << (*i)->GetSubname()
  385.     << "' causing illegal redirection"
  386.     << NCBI_NS_NCBI::Endm;
  387.     }
  388. }
  389.     }
  390. } else if( resp.IsError()
  391.    && resp.GetError().GetLevel() 
  392.    != CTaxon1_error::eLevel_none ) {
  393.     string sErr;
  394.     resp.GetError().GetErrorText( sErr );
  395.     ERR_POST( sErr );
  396. }
  397.     } catch( exception& e ) {
  398. ERR_POST( e.what() );
  399.     }
  400. }
  401. ++i;
  402. break;
  403.     }
  404. }
  405. PopDiagPostPrefix();
  406. PFindConflict predConflict;
  407. for( COrgName::TMod::const_iterator i = lSrcMod.begin();
  408.      i != lSrcMod.end();
  409.      ++i ) {
  410.     predConflict.SetTypeToMatch( (*i)->GetSubtype() );
  411.     if( (*i)->GetSubtype() != COrgMod::eSubtype_other ) {
  412. if( find_if( lDstMod.begin(), lDstMod.end(), predConflict )
  413.     == lDstMod.end() ) {
  414.     CRef<COrgMod> pMod( new COrgMod() );
  415.     pMod->Assign( *(*i) );
  416.     lDstMod.push_back( pMod );
  417. }
  418.     }
  419. }
  420.     } else { // Copy modifiers
  421. CRef<COrgMod> pMod;
  422. for( COrgName::TMod::const_iterator i = lSrcMod.begin();
  423.      i != lSrcMod.end();
  424.      ++i ) {
  425.     switch( (*i)->GetSubtype() ) {
  426.     case COrgMod::eSubtype_gb_acronym:
  427.     case COrgMod::eSubtype_gb_anamorph:
  428.     case COrgMod::eSubtype_gb_synonym:
  429.        pMod.Reset( new COrgMod() );
  430.        pMod->Assign( *(*i) );
  431.        lDstMod.push_back( pMod );
  432.     default:
  433.        break;
  434.     }
  435. }
  436. // Remove 'other' modifiers
  437. PFindModByType fmbt( COrgMod::eSubtype_other );
  438. remove_if( lDstMod.begin(), lDstMod.end(), fmbt );
  439.     }
  440.     // Remove 'synonym' or 'anamorph' it if coincides with taxname
  441.     PRemoveSynAnamorph rsa( inp_orgRef.GetTaxname() );
  442.     remove_if( lDstMod.begin(), lDstMod.end(), rsa );
  443.     // Reset destination modifiers if empty
  444.     if( lDstMod.size() == 0 ) {
  445. on.ResetMod();
  446.     }
  447.     // Copy lineage
  448.     if( db_orgRef.GetOrgname().IsSetLineage() ) {
  449. on.SetLineage() = db_orgRef.GetOrgname().GetLineage();
  450.     } else {
  451. on.ResetLineage();
  452.     }
  453.     if( db_orgRef.GetOrgname().IsSetGcode() ) {
  454. on.SetGcode( db_orgRef.GetOrgname().GetGcode() );
  455.     } else {
  456. on.ResetGcode();
  457.     }
  458.     if( db_orgRef.GetOrgname().IsSetMgcode() ) {
  459. on.SetMgcode( db_orgRef.GetOrgname().GetMgcode() );
  460.     } else {
  461. on.ResetMgcode();
  462.     }
  463.     if( db_orgRef.GetOrgname().IsSetDiv() ) {
  464. on.SetDiv( db_orgRef.GetOrgname().GetDiv() );
  465.     } else {
  466. on.ResetDiv();
  467.     }
  468. }
  469. bool
  470. CTaxon1::LookupByOrgRef(const COrg_ref& inp_orgRef, int* pTaxid,
  471. COrgName::TMod& hitMods )
  472. {
  473.     SetLastError(NULL);
  474.     CTaxon1_req  req;
  475.     CTaxon1_resp resp;
  476.     SerialAssign< COrg_ref >( req.SetLookup(), inp_orgRef );
  477.     if( SendRequest( req, resp ) ) {
  478.         if( resp.IsLookup() ) {
  479.             // Correct response, return object
  480.     COrg_ref& result = resp.SetLookup().SetOrg();
  481.     *pTaxid = result.GetTaxId();
  482.     if( result.IsSetOrgname() &&
  483. result.GetOrgname().IsSetMod() ) {
  484. hitMods.swap( result.SetOrgname().SetMod() );
  485.     }
  486. //  for( COrgName::TMod::const_iterator ci =
  487. //   result.GetOrgname().GetMod().begin();
  488. //       ci != result.GetOrgname().GetMod().end();
  489. //       ++ci ) {
  490. //      if( (*ci)->GetSubtype() == COrgMod::eSubtype_old_name ) {
  491. //  hitMod->Assign( *ci );
  492. //  bHitFound = true;
  493. //  break;
  494. //      }
  495. //  }
  496. //      }
  497. //      if( bHitFound ) {
  498. //  hitMod.Reset( NULL );
  499. //      }
  500.     return true;
  501.         } else { // Internal: wrong respond type
  502.             SetLastError( "Response type is not Lookup" );
  503.         }
  504.     }
  505.     return false;
  506. }
  507. void
  508. CTaxon1::PopulateReplaced( COrg_ref& org, COrgName::TMod& lMods  )
  509. {
  510.     if( org.IsSetOrgname() ) {
  511. CRef< COrgMod > pOldNameMod;
  512. COrgName& on = org.SetOrgname();
  513. for( COrgName::TMod::iterator i = lMods.begin();
  514.      i != lMods.end();
  515.      ++i ) {
  516.     if( (*i)->GetSubtype() == COrgMod::eSubtype_old_name ) {
  517. pOldNameMod = *i;
  518. continue;
  519.     }
  520.     if( on.IsSetMod() ) {
  521. PFindModByType fmbt( (*i)->GetSubtype() );
  522. if( find_if( on.GetMod().begin(), on.GetMod().end(), fmbt )
  523.     != on.GetMod().end() ) {
  524.     /* modifier already present in target orgref */
  525.     continue;
  526. }
  527.     }
  528.     /* adding this modifier */
  529.     on.SetMod().push_back( *i );
  530. }
  531. if( pOldNameMod ) {
  532.     if( on.IsSetMod() ) {
  533. PFindModByType fmbt( COrgMod::eSubtype_old_name );
  534. COrgName::TMod::iterator i =
  535.     find_if( on.SetMod().begin(), on.SetMod().end(), fmbt );
  536. if( i != on.SetMod().end() ) {
  537.     // There is old-name in the target already
  538.     if( !(*i)->IsSetAttrib() && pOldNameMod->IsSetAttrib() &&
  539. NStr::CompareNocase(pOldNameMod->GetSubname(), 
  540.     (*i)->GetSubname() ) == 0 ) {
  541. (*i)->SetAttrib( pOldNameMod->GetAttrib() );
  542.     }
  543.     return;
  544. }
  545.     }
  546.     /* we probably don't need to populate search name */
  547.     if( org.IsSetTaxname() &&
  548. NStr::CompareNocase( org.GetTaxname(),
  549.      pOldNameMod->GetSubname() ) == 0 ) {
  550. if( pOldNameMod->IsSetAttrib() ) {
  551.     const string& sAttrib = pOldNameMod->GetAttrib();
  552.     if( !sAttrib.empty() && sAttrib[0] == '(' ) {
  553. try {
  554.     CRef< COrgMod > srchMod( new COrgMod );
  555.     string::size_type pos = sAttrib.find("=");
  556.     if( pos == string::npos ) {
  557. return;
  558.     }
  559.     if( on.IsSetMod() ) {
  560. const COrgName::TMod& mods = on.GetMod();
  561. srchMod->SetSubname()
  562.     .assign( sAttrib.c_str()+pos+1 );
  563. srchMod->SetSubtype
  564.     ( COrgMod::TSubtype
  565.                                       (NStr::StringToInt
  566.       (sAttrib.substr(1, pos-1), 10,
  567.        NStr::eCheck_Skip) ) );
  568. PFindMod mf;
  569. mf.SetModToMatch( srchMod );
  570. if( find_if( mods.begin(), mods.end(),
  571.      mf ) != mods.end() ) {
  572.     return;
  573. }
  574.     }
  575. } catch(...) { return; }
  576.     } else
  577. return;
  578. } else
  579.     return;
  580.     }
  581.     // Add old-name to modifiers
  582.     on.SetMod().push_back( pOldNameMod );
  583. }
  584.     }
  585. }
  586. CRef< CTaxon2_data >
  587. CTaxon1::Lookup(const COrg_ref& inp_orgRef )
  588. {
  589.     SetLastError(NULL);
  590.     // Check if this taxon is in cache
  591.     CTaxon2_data* pData = 0;
  592.     COrgName::TMod hitMod;
  593.     int tax_id = 0; //GetTaxIdByOrgRef( inp_orgRef );
  594.     if( LookupByOrgRef( inp_orgRef, &tax_id, hitMod )
  595. && tax_id > 0
  596.         && m_plCache->LookupAndInsert( tax_id, &pData ) && pData ) {
  597.         CTaxon2_data* pNewData = new CTaxon2_data();
  598. //        SerialAssign<CTaxon2_data>( *pNewData, *pData  );
  599. COrg_ref* pOrf = new COrg_ref;
  600. pOrf->Assign( inp_orgRef );
  601. if( pOrf->IsSetOrgname() && pOrf->GetOrgname().IsSetMod() ) {
  602.     // Clean up modifiers
  603.     pOrf->SetOrgname().ResetMod();
  604. }
  605. pNewData->SetOrg( *pOrf );
  606. const COrg_ref& db_orgRef = pData->GetOrg();
  607. OrgRefAdjust( pNewData->SetOrg(), db_orgRef, tax_id );
  608. // Copy all other fields
  609. if( pData->IsSetBlast_name() ) {
  610.     pNewData->SetBlast_name() = pData->GetBlast_name();
  611. }
  612. if( pData->IsSetIs_uncultured() ) {
  613.     pNewData->SetIs_uncultured( pData->GetIs_uncultured() );
  614. }
  615. if( pData->IsSetIs_species_level() ) {
  616.     pNewData->SetIs_species_level( pData->GetIs_species_level() );
  617. }
  618. // Insert the hitMod if necessary
  619. if( hitMod.size() > 0 ) {
  620.     PopulateReplaced( pNewData->SetOrg(), hitMod );
  621. }
  622.         return CRef<CTaxon2_data>(pNewData);
  623.     }
  624.     return CRef<CTaxon2_data>(NULL);
  625. }
  626. CConstRef< CTaxon2_data >
  627. CTaxon1::LookupMerge(COrg_ref& inp_orgRef )
  628. {
  629.     CTaxon2_data* pData = 0;
  630.     SetLastError(NULL);
  631.     COrgName::TMod hitMod;
  632.     int tax_id = 0; //GetTaxIdByOrgRef( inp_orgRef );
  633.     if( LookupByOrgRef( inp_orgRef, &tax_id, hitMod )
  634. && tax_id > 0
  635.         && m_plCache->LookupAndInsert( tax_id, &pData ) && pData ) {
  636. const COrg_ref& db_orgRef = pData->GetOrg();
  637. OrgRefAdjust( inp_orgRef, db_orgRef, tax_id );
  638. if( hitMod.size() > 0 ) {
  639.     PopulateReplaced( inp_orgRef, hitMod );
  640. }
  641.     }
  642.     return CConstRef<CTaxon2_data>(pData);
  643. }
  644. int
  645. CTaxon1::GetTaxIdByOrgRef(const COrg_ref& inp_orgRef)
  646. {
  647.     SetLastError(NULL);
  648.     CTaxon1_req  req;
  649.     CTaxon1_resp resp;
  650.     SerialAssign< COrg_ref >( req.SetGetidbyorg(), inp_orgRef );
  651.     if( SendRequest( req, resp ) ) {
  652.         if( resp.IsGetidbyorg() ) {
  653.             // Correct response, return object
  654.             return resp.GetGetidbyorg();
  655.         } else { // Internal: wrong respond type
  656.             SetLastError( "Response type is not Getidbyorg" );
  657.         }
  658.     }
  659.     return 0;
  660. }
  661. int
  662. CTaxon1::GetTaxIdByName(const string& orgname)
  663. {
  664.     SetLastError(NULL);
  665.     if( orgname.empty() )
  666.         return 0;
  667.     COrg_ref orgRef;
  668.     
  669.     orgRef.SetTaxname().assign( orgname );
  670.     
  671.     return GetTaxIdByOrgRef(orgRef);
  672. }
  673. int
  674. CTaxon1::FindTaxIdByName(const string& orgname)
  675. {
  676.     SetLastError(NULL);
  677.     if( orgname.empty() )
  678.         return 0;
  679.     int id( GetTaxIdByName(orgname) );
  680.     if(id < 1) {
  681.         int idu = 0;
  682.         CTaxon1_req  req;
  683.         CTaxon1_resp resp;
  684.         req.SetGetunique().assign( orgname );
  685.         if( SendRequest( req, resp ) ) {
  686.             if( resp.IsGetunique() ) {
  687.                 // Correct response, return object
  688.                 idu = resp.GetGetunique();
  689.             } else { // Internal: wrong respond type
  690.                 SetLastError( "Response type is not Getunique" );
  691.             }
  692.         }
  693.         if( idu > 0 )
  694.             id= idu;
  695.     }
  696.     return id;
  697. }
  698. //----------------------------------------------
  699. // Get tax_id by organism name using fancy search modes.
  700. // Returns: tax_id - if the only organism found
  701. //               0 - no organism found
  702. //         -tax_id - if multiple nodes found
  703. //                   (where -tax_id is id of one of the nodes)
  704. ///
  705. int
  706. CTaxon1::SearchTaxIdByName(const string& orgname, ESearch mode,
  707.    list< CRef< CTaxon1_name > >* pNameList)
  708. {
  709.     // Use fancy searches
  710.     SetLastError(NULL);
  711.     if( orgname.empty() ) {
  712. return 0;
  713.     }
  714.     CRef< CTaxon1_info > pQuery( new CTaxon1_info() );
  715.     int nMode = 0;
  716.     switch( mode ) {
  717.     default:
  718.     case eSearch_Exact:    nMode = 0; break;
  719.     case eSearch_TokenSet: nMode = 1; break;
  720.     case eSearch_WildCard: nMode = 2; break; // shell-style wildcards, i.e. *,?,[]
  721.     case eSearch_Phonetic: nMode = 3; break;
  722.     }
  723.     pQuery->SetIval1( nMode );
  724.     pQuery->SetIval2( 0 );
  725.     pQuery->SetSval( orgname );
  726.     
  727.     CTaxon1_req  req;
  728.     CTaxon1_resp resp;
  729.     req.SetSearchname( *pQuery );
  730.     
  731.     if( SendRequest( req, resp ) ) {
  732. if( resp.IsSearchname() ) {
  733.     // Correct response, return object
  734.     int retc = 0;
  735.     const CTaxon1_resp::TSearchname& lNm = resp.GetSearchname();
  736.     if( lNm.size() == 0 ) {
  737. retc = 0;
  738.     } else if( lNm.size() == 1 ) {
  739. retc = lNm.front()->GetTaxid();
  740.     } else {
  741. retc = -1;
  742.     }
  743.     // Fill the names list
  744.     if( pNameList ) {
  745. pNameList->swap( resp.SetSearchname() );
  746.     }
  747.     return retc;
  748. } else { // Internal: wrong respond type
  749.     SetLastError( "Response type is not Searchname" );
  750.     return 0;
  751. }
  752.     }
  753.     return 0;
  754. }
  755. int
  756. CTaxon1::GetAllTaxIdByName(const string& orgname, TTaxIdList& lIds)
  757. {
  758.     int count = 0;
  759.     SetLastError(NULL);
  760.     if( orgname.empty() )
  761.         return 0;
  762.     CTaxon1_req  req;
  763.     CTaxon1_resp resp;
  764.     req.SetFindname().assign(orgname);
  765.     if( SendRequest( req, resp ) ) {
  766.         if( resp.IsFindname() ) {
  767.             // Correct response, return object
  768.             const list< CRef< CTaxon1_name > >& lNm = resp.GetFindname();
  769.             // Fill in the list
  770.             for( list< CRef< CTaxon1_name > >::const_iterator
  771.                      i = lNm.begin();
  772.                  i != lNm.end(); ++i, ++count )
  773.                 lIds.push_back( (*i)->GetTaxid() );
  774.         } else { // Internal: wrong respond type
  775.             SetLastError( "Response type is not Findname" );
  776.             return 0;
  777.         }
  778.     }
  779.     return count;
  780. }
  781. CConstRef< COrg_ref >
  782. CTaxon1::GetOrgRef(int tax_id,
  783.                    bool& is_species,
  784.                    bool& is_uncultured,
  785.                    string& blast_name)
  786. {
  787.     SetLastError(NULL);
  788.     if( tax_id > 1 ) {
  789.         CTaxon2_data* pData = 0;
  790.         if( m_plCache->LookupAndInsert( tax_id, &pData ) && pData ) {
  791.             is_species = pData->GetIs_species_level();
  792.             is_uncultured = pData->GetIs_uncultured();
  793.             if( pData->GetBlast_name().size() > 0 ) {
  794.                 blast_name.assign( pData->GetBlast_name().front() );
  795.             }
  796.             return CConstRef<COrg_ref>(&pData->GetOrg());
  797.         }
  798.     }
  799.     return null;
  800. }
  801. bool
  802. CTaxon1::SetSynonyms(bool on_off)
  803. {
  804.     SetLastError(NULL);
  805.     bool old_val( m_bWithSynonyms );
  806.     m_bWithSynonyms = on_off;
  807.     return old_val;
  808. }
  809. int
  810. CTaxon1::GetParent(int id_tax)
  811. {
  812.     CTaxon1Node* pNode = 0;
  813.     SetLastError(NULL);
  814.     if( m_plCache->LookupAndAdd( id_tax, &pNode )
  815.         && pNode && pNode->GetParent() ) {
  816.         return pNode->GetParent()->GetTaxId();
  817.     }
  818.     return 0;
  819. }
  820. int
  821. CTaxon1::GetGenus(int id_tax)
  822. {
  823.     CTaxon1Node* pNode = 0;
  824.     SetLastError(NULL);
  825.     if( m_plCache->LookupAndAdd( id_tax, &pNode )
  826.         && pNode ) {
  827.         int genus_rank(m_plCache->GetGenusRank());
  828.         while( !pNode->IsRoot() ) {
  829.             int rank( pNode->GetRank() );
  830.             if( rank == genus_rank )
  831.                 return pNode->GetTaxId();
  832.             if( (rank > 0) && (rank < genus_rank))
  833.                 return -1;
  834.             pNode = pNode->GetParent();
  835.         }
  836.     }
  837.     return -1;
  838. }
  839. int
  840. CTaxon1::GetSuperkingdom(int id_tax)
  841. {
  842.     CTaxon1Node* pNode = 0;
  843.     SetLastError(NULL);
  844.     if( m_plCache->LookupAndAdd( id_tax, &pNode )
  845.         && pNode ) {
  846.         int sk_rank(m_plCache->GetSuperkingdomRank());
  847.         while( !pNode->IsRoot() ) {
  848.             int rank( pNode->GetRank() );
  849.             if( rank == sk_rank )
  850.                 return pNode->GetTaxId();
  851.             if( (rank > 0) && (rank < sk_rank))
  852.                 return -1;
  853.             pNode = pNode->GetParent();
  854.         }
  855.     }
  856.     return -1;
  857. }
  858. int
  859. CTaxon1::GetChildren(int id_tax, TTaxIdList& children_ids)
  860. {
  861.     int count(0);
  862.     CTaxon1Node* pNode = 0;
  863.     SetLastError(NULL);
  864.     if( m_plCache->LookupAndAdd( id_tax, &pNode )
  865.         && pNode ) {
  866.         CTaxon1_req  req;
  867.         CTaxon1_resp resp;
  868.         req.SetTaxachildren( id_tax );
  869.         if( SendRequest( req, resp ) ) {
  870.             if( resp.IsTaxachildren() ) {
  871.                 // Correct response, return object
  872.                 list< CRef< CTaxon1_name > >& lNm = resp.SetTaxachildren();
  873.                 // Fill in the list
  874.                 CTreeIterator* pIt = m_plCache->GetTree().GetIterator();
  875.                 pIt->GoNode( pNode );
  876.                 for( list< CRef< CTaxon1_name > >::const_iterator
  877.                          i = lNm.begin();
  878.                      i != lNm.end(); ++i, ++count ) {
  879.                     children_ids.push_back( (*i)->GetTaxid() );
  880.                     // Add node to the partial tree
  881.                     CTaxon1Node* pNewNode = new CTaxon1Node(*i);
  882.                     m_plCache->SetIndexEntry(pNewNode->GetTaxId(), pNewNode);
  883.                     pIt->AddChild( pNewNode );
  884.                 }
  885.             } else { // Internal: wrong respond type
  886.                 SetLastError( "Response type is not Taxachildren" );
  887.                 return 0;
  888.             }
  889.         }
  890.     }
  891.     return count;
  892. }
  893. bool
  894. CTaxon1::GetGCName(short gc_id, string& gc_name_out )
  895. {
  896.     SetLastError(NULL);
  897.     if( m_gcStorage.empty() ) {
  898.         CTaxon1_req  req;
  899.         CTaxon1_resp resp;
  900.         req.SetGetgcs();
  901.         if( SendRequest( req, resp ) ) {
  902.             if( resp.IsGetgcs() ) {
  903.                 // Correct response, return object
  904.                 const list< CRef< CTaxon1_info > >& lGc = resp.GetGetgcs();
  905.                 // Fill in storage
  906.                 for( list< CRef< CTaxon1_info > >::const_iterator
  907.                          i = lGc.begin();
  908.                      i != lGc.end(); ++i ) {
  909.                     m_gcStorage.insert( TGCMap::value_type((*i)->GetIval1(),
  910.                                                            (*i)->GetSval()) );
  911. }
  912.             } else { // Internal: wrong respond type
  913.                 SetLastError( "Response type is not Getgcs" );
  914.                 return false;
  915.             }
  916.         }
  917.     }
  918.     TGCMap::const_iterator gci( m_gcStorage.find( gc_id ) );
  919.     if( gci != m_gcStorage.end() ) {
  920.         gc_name_out.assign( gci->second );
  921.         return true;
  922.     } else {
  923.         SetLastError( "ERROR: GetGCName(): Unknown genetic code" );
  924.         return false;
  925.     }
  926. }
  927. //---------------------------------------------
  928. // Get taxonomic rank name by rank id
  929. ///
  930. bool
  931. CTaxon1::GetRankName(short rank_id, string& rank_name_out )
  932. {
  933.     SetLastError( NULL );
  934.     const char* pchName = m_plCache->GetRankName( rank_id );
  935.     if( pchName ) {
  936. rank_name_out.assign( pchName );
  937. return true;
  938.     } else {
  939. SetLastError( "ERROR: GetRankName(): Rank not found" );
  940. return false;
  941.     }
  942. }
  943. //---------------------------------------------
  944. // Get taxonomic division name by division id
  945. ///
  946. bool
  947. CTaxon1::GetDivisionName(short div_id, string& div_name_out )
  948. {
  949.     SetLastError( NULL );
  950.     const char* pchName = m_plCache->GetDivisionName( div_id );
  951.     if( pchName ) {
  952. div_name_out.assign( pchName );
  953. return true;
  954.     } else {
  955. SetLastError( "ERROR: GetDivisionName(): Division not found" );
  956. return false;
  957.     }
  958. }
  959. //---------------------------------------------
  960. // Get taxonomic name class (scientific name, common name, etc.) by id
  961. ///
  962. bool
  963. CTaxon1::GetNameClass(short nameclass_id, string& name_class_out )
  964. {
  965.     SetLastError( NULL );
  966.     const char* pchName = m_plCache->GetNameClassName( nameclass_id );
  967.     if( pchName ) {
  968. name_class_out.assign( pchName );
  969. return true;
  970.     } else {
  971. SetLastError( "ERROR: GetNameClass(): Name class not found" );
  972. return false;
  973.     }
  974. }
  975. int
  976. CTaxon1::Join(int taxid1, int taxid2)
  977. {
  978.     int tax_id = 0;
  979.     CTaxon1Node *pNode1, *pNode2;
  980.     SetLastError(NULL);
  981.     if( m_plCache->LookupAndAdd( taxid1, &pNode1 ) && pNode1
  982.         && m_plCache->LookupAndAdd( taxid2, &pNode2 ) && pNode2 ) {
  983.         CRef< ITreeIterator > pIt( GetTreeIterator() );
  984.         pIt->GoNode( pNode1 );
  985.         pIt->GoAncestor( pNode2 );
  986.         tax_id = pIt->GetNode()->GetTaxId();
  987.     }
  988.     return tax_id;
  989. }
  990. int
  991. CTaxon1::GetAllNames(int tax_id, TNameList& lNames, bool unique)
  992. {
  993.     int count(0);
  994.     SetLastError(NULL);
  995.     CTaxon1_req  req;
  996.     CTaxon1_resp resp;
  997.     req.SetGetorgnames( tax_id );
  998.     if( SendRequest( req, resp ) ) {
  999.         if( resp.IsGetorgnames() ) {
  1000.             // Correct response, return object
  1001.             const list< CRef< CTaxon1_name > >& lNm = resp.GetGetorgnames();
  1002.             // Fill in the list
  1003.             for( list< CRef< CTaxon1_name > >::const_iterator
  1004.                      i = lNm.begin();
  1005.                  i != lNm.end(); ++i, ++count )
  1006.                 if( !unique ) {
  1007.                     lNames.push_back( (*i)->GetOname() );
  1008.                 } else {
  1009.                     lNames.push_back( ((*i)->IsSetUname() && !(*i)->GetUname().empty()) ?
  1010.                                       (*i)->GetUname() :
  1011.                                       (*i)->GetOname() );
  1012.                 }
  1013.         } else { // Internal: wrong respond type
  1014.             SetLastError( "Response type is not Getorgnames" );
  1015.             return 0;
  1016.         }
  1017.     }
  1018.     return count;
  1019. }
  1020. /*---------------------------------------------
  1021.  * Find organism name in the string (for PDB mostly)
  1022.  * Returns: nimber of tax_ids found
  1023.  * NOTE:
  1024.  * 1. orgname is substring of search_str which matches organism name
  1025.  *    (return parameter).
  1026.  * 2. Ids consists of tax_ids. Caller is responsible to free this memory
  1027.  */
  1028.  // int getTaxId4Str(const char* search_str, char** orgname, intPtr *Ids_out);
  1029. bool
  1030. CTaxon1::IsAlive(void)
  1031. {
  1032.     SetLastError(NULL);
  1033.     if( m_pServer ) {
  1034.         if( !m_pOut || !m_pOut->InGoodState() )
  1035.             SetLastError( "Output stream is not in good state" );
  1036.         else if( !m_pIn || !m_pIn->InGoodState() )
  1037.             SetLastError( "Input stream is not in good state" );
  1038.         else
  1039.             return true;
  1040.     } else {
  1041.         SetLastError( "Not connected to Taxonomy service" );
  1042.     }
  1043.     return false;
  1044. }
  1045. bool
  1046. CTaxon1::GetTaxId4GI(int gi, int& tax_id_out )
  1047. {
  1048.     SetLastError(NULL);
  1049.     CTaxon1_req  req;
  1050.     CTaxon1_resp resp;
  1051.     
  1052.     req.SetId4gi( gi );
  1053.     if( SendRequest( req, resp ) ) {
  1054.         if( resp.IsId4gi() ) {
  1055.             // Correct response, return object
  1056.             tax_id_out = resp.GetId4gi();
  1057.             return true;
  1058.         } else { // Internal: wrong respond type
  1059.             SetLastError( "Response type is not Id4gi" );
  1060.         }
  1061.     }
  1062.     return false;
  1063. }
  1064. bool
  1065. CTaxon1::GetBlastName(int tax_id, string& blast_name_out )
  1066. {
  1067.     CTaxon1Node* pNode = 0;
  1068.     SetLastError(NULL);
  1069.     if( m_plCache->LookupAndAdd( tax_id, &pNode ) && pNode ) {
  1070.         while( !pNode->IsRoot() ) {
  1071.             if( !pNode->GetBlastName().empty() ) {
  1072.                 blast_name_out.assign( pNode->GetBlastName() );
  1073.                 return true;
  1074.             }
  1075.             pNode = pNode->GetParent();
  1076.         }
  1077.         blast_name_out.erase();
  1078.         return true;
  1079.     }
  1080.     return false;
  1081. }
  1082. bool
  1083. CTaxon1::SendRequest( CTaxon1_req& req, CTaxon1_resp& resp )
  1084. {
  1085.     unsigned nIterCount( 0 );
  1086.     unsigned fail_flags( 0 );
  1087.     if( !m_pServer ) {
  1088.         SetLastError( "Service is not initialized" );
  1089.         return false;
  1090.     }
  1091.     SetLastError( NULL );
  1092.     do {
  1093.         bool bNeedReconnect( false );
  1094.         try {
  1095.             *m_pOut << req;
  1096.             m_pOut->Flush();
  1097.             if( m_pOut->InGoodState() ) {
  1098.                 try {
  1099.                     *m_pIn >> resp;
  1100.                     if( m_pIn->InGoodState() ) {
  1101.                         if( resp.IsError() ) { // Process error here
  1102.                             string err;
  1103.                             resp.GetError().GetErrorText( err );
  1104.                             SetLastError( err.c_str() );
  1105.                             return false;
  1106.                         } else
  1107.                             return true;
  1108.                     }
  1109.                 } catch( exception& e ) {
  1110.                     SetLastError( e.what() );
  1111.                 }
  1112.                 fail_flags = m_pIn->GetFailFlags();
  1113.                 bNeedReconnect = (fail_flags & ( CObjectIStream::eEOF
  1114.                                                  |CObjectIStream::eReadError
  1115.                                                  |CObjectIStream::eOverflow
  1116.                                                  |CObjectIStream::eFail
  1117.                                                  |CObjectIStream::eNotOpen )
  1118.                                   ? true : false);
  1119.             } else {
  1120.                 m_pOut->ThrowError((CObjectOStream::EFailFlags)
  1121.                                     m_pOut->GetFailFlags(),
  1122.                                     "Output stream is in bad state");
  1123.             }
  1124.         } catch( exception& e ) {
  1125.             SetLastError( e.what() );
  1126.             fail_flags = m_pOut->GetFailFlags();
  1127.             bNeedReconnect = (fail_flags & ( CObjectOStream::eEOF
  1128.                                              |CObjectOStream::eWriteError
  1129.                                              |CObjectOStream::eOverflow
  1130.                                              |CObjectOStream::eFail
  1131.                                              |CObjectOStream::eNotOpen )
  1132.                               ? true : false);
  1133.         }
  1134.         if( !bNeedReconnect )
  1135.             break;
  1136.         // Reconnect the service
  1137.         if( nIterCount < m_nReconnectAttempts ) {
  1138.             delete m_pOut;
  1139.             delete m_pIn;
  1140.             delete m_pServer;
  1141.             m_pOut = NULL;
  1142.             m_pIn = NULL;
  1143.             m_pServer = NULL;
  1144.             try {
  1145.                 auto_ptr<CObjectOStream> pOut;
  1146.                 auto_ptr<CObjectIStream> pIn;
  1147.                 auto_ptr<CConn_ServiceStream>
  1148.                     pServer( new CConn_ServiceStream(m_pchService, fSERV_Any,
  1149.                                                      0, 0, m_timeout) );
  1150.                 pOut.reset( CObjectOStream::Open(m_eDataFormat, *pServer) );
  1151.                 pIn.reset( CObjectIStream::Open(m_eDataFormat, *pServer) );
  1152.                 m_pServer = pServer.release();
  1153.                 m_pIn = pIn.release();
  1154.                 m_pOut = pOut.release();
  1155.             } catch( exception& e ) {
  1156.                 SetLastError( e.what() );
  1157.             }
  1158.         } else { // No more attempts left
  1159.             break;
  1160.         }
  1161.     } while( nIterCount++ < m_nReconnectAttempts );
  1162.     return false;
  1163. }
  1164. void
  1165. CTaxon1::SetLastError( const char* pchErr )
  1166. {
  1167.     if( pchErr )
  1168.         m_sLastError.assign( pchErr );
  1169.     else
  1170.         m_sLastError.erase();
  1171. }
  1172. static void s_StoreResidueTaxid( CTreeIterator* pIt, CTaxon1::TTaxIdList& lTo )
  1173. {
  1174.     CTaxon1Node* pNode =  static_cast<CTaxon1Node*>( pIt->GetNode() );
  1175.     if( !pNode->IsJoinTerminal() ) {
  1176. lTo.push_back( pNode->GetTaxId() );
  1177.     }
  1178.     if( pIt->GoChild() ) {
  1179. do {
  1180.     s_StoreResidueTaxid( pIt, lTo );
  1181. } while( pIt->GoSibling() );
  1182. pIt->GoParent();
  1183.     }
  1184. }
  1185. //--------------------------------------------------
  1186. // This function constructs minimal common tree from the gived tax id
  1187. // set (ids_in) treated as tree's leaves. It then returns a residue of 
  1188. // this tree node set and the given tax id set in ids_out.
  1189. // Returns: false if some error
  1190. //          true  if Ok
  1191. ///
  1192. typedef vector<CTaxon1Node*> TTaxNodeLineage;
  1193. bool
  1194. CTaxon1::GetPopsetJoin( const TTaxIdList& ids_in, TTaxIdList& ids_out )
  1195. {
  1196.     SetLastError(NULL);
  1197.     if( ids_in.size() > 0 ) {
  1198. map< int, CTaxon1Node* > nodeMap;
  1199. CTaxon1Node *pParent = 0, *pNode = 0, *pNewParent = 0;
  1200. CTreeCont tPartTree; // Partial tree
  1201. CTreeIterator* pIt = tPartTree.GetIterator();
  1202. TTaxNodeLineage vLin;
  1203. // Build the partial tree
  1204.   bool bHasSiblings;
  1205. vLin.reserve( 256 );
  1206. for( TTaxIdList::const_iterator ci = ids_in.begin();
  1207.      ci != ids_in.end();
  1208.      ++ci ) {
  1209.     map< int, CTaxon1Node* >::iterator nmi = nodeMap.find( *ci );
  1210.     if( nmi == nodeMap.end() ) {
  1211. if( m_plCache->LookupAndAdd( *ci, &pNode ) ) {
  1212.     if( !tPartTree.GetRoot() ) {
  1213. pNewParent = new CTaxon1Node
  1214.     ( *static_cast<const CTaxon1Node*>
  1215.       (m_plCache->GetTree().GetRoot()) );
  1216. tPartTree.SetRoot( pNewParent );
  1217. nodeMap.insert( map< int,CTaxon1Node* >::value_type
  1218. (pNewParent->GetTaxId(), pNewParent) );
  1219.     }
  1220.     if( pNode ) {
  1221. vLin.clear();
  1222. pParent = pNode->GetParent();
  1223. pNode = new CTaxon1Node( *pNode );
  1224. pNode->SetJoinTerminal();
  1225. vLin.push_back( pNode );
  1226. while( pParent &&
  1227.        ((nmi=nodeMap.find(pParent->GetTaxId()))
  1228.  == nodeMap.end()) ) {
  1229.     pNode = new CTaxon1Node( *pParent );
  1230.     vLin.push_back( pNode );
  1231.     pParent = pParent->GetParent();
  1232. }
  1233. if( !pParent ) {
  1234.     pIt->GoRoot();
  1235. } else {
  1236.     pIt->GoNode( nmi->second );
  1237. }
  1238. for( TTaxNodeLineage::reverse_iterator i =
  1239.  vLin.rbegin();
  1240.      i != vLin.rend();
  1241.      ++i ) {
  1242.     pNode = *i;
  1243.     nodeMap.insert( map< int,CTaxon1Node* >::value_type
  1244.     ( pNode->GetTaxId(), pNode ) );
  1245.     pIt->AddChild( pNode );
  1246.     pIt->GoNode( pNode );
  1247. }
  1248.     }
  1249. } else { // Error while adding - ignore invalid tax_ids
  1250.     continue;
  1251.     //return false;
  1252. }
  1253.     } else { // Node is already here
  1254. nmi->second->SetJoinTerminal();
  1255.     }
  1256. }
  1257. // Partial tree is build, make a residue
  1258. pIt->GoRoot();
  1259. bHasSiblings = true;
  1260. if( pIt->GoChild() ) {
  1261.     while( !pIt->GoSibling() ) {
  1262. pNode = static_cast<CTaxon1Node*>( pIt->GetNode() );
  1263. if( pNode->IsJoinTerminal() || !pIt->GoChild() ) {
  1264.     bHasSiblings = false;
  1265.     break;
  1266. }
  1267.     }
  1268.     if( bHasSiblings ) {
  1269. pIt->GoParent();
  1270.     }
  1271.     s_StoreResidueTaxid( pIt, ids_out );
  1272. }
  1273.     }
  1274.     return true;
  1275. }
  1276. //-----------------------------------
  1277. //  Tree-related functions
  1278. bool
  1279. CTaxon1::LoadSubtreeEx( int tax_id, int levels, const ITaxon1Node** ppNode )
  1280. {
  1281.     CTaxon1Node* pNode = 0;
  1282.     SetLastError(NULL);
  1283.     if( ppNode ) {
  1284. *ppNode = pNode;
  1285.     }
  1286.     if( m_plCache->LookupAndAdd( tax_id, &pNode )
  1287.         && pNode ) {
  1288. if( ppNode ) {
  1289.     *ppNode = pNode;
  1290. }
  1291. if( pNode->IsSubtreeLoaded() ) {
  1292.     return true;
  1293. }
  1294. if( levels == 0 ) {
  1295.     return true;
  1296. }
  1297.         CTaxon1_req  req;
  1298.         CTaxon1_resp resp;
  1299. if( levels < 0 ) {
  1300.     tax_id = -tax_id;
  1301. }
  1302.         req.SetTaxachildren( tax_id );
  1303.         if( SendRequest( req, resp ) ) {
  1304.             if( resp.IsTaxachildren() ) {
  1305.                 // Correct response, return object
  1306.                 list< CRef< CTaxon1_name > >& lNm = resp.SetTaxachildren();
  1307.                 // Fill in the list
  1308.                 CTreeIterator* pIt = m_plCache->GetTree().GetIterator();
  1309.                 pIt->GoNode( pNode );
  1310.                 for( list< CRef< CTaxon1_name > >::const_iterator
  1311.                          i = lNm.begin();
  1312.                      i != lNm.end(); ++i ) {
  1313.     if( (*i)->GetCde() == 0 ) { // Change parent node
  1314. if( m_plCache->LookupAndAdd( (*i)->GetTaxid(), &pNode )
  1315.     && pNode ) { 
  1316.     pIt->GoNode( pNode );
  1317. } else { // Invalid parent specified
  1318.     SetLastError( ("Invalid parent taxid "
  1319.   + NStr::IntToString((*i)->GetTaxid())
  1320.   ).c_str() );
  1321.     return false;
  1322. }
  1323.     } else { // Add node to the partial tree
  1324. if( !m_plCache->Lookup((*i)->GetTaxid(), &pNode) ) {
  1325.     pNode = new CTaxon1Node(*i);
  1326.     m_plCache->SetIndexEntry(pNode->GetTaxId(), pNode);
  1327.     pIt->AddChild( pNode );
  1328. }
  1329.     }
  1330.     pNode->SetSubtreeLoaded( pNode->IsSubtreeLoaded() ||
  1331.      (levels < 0) );
  1332.                 }
  1333. return true;
  1334.             } else { // Internal: wrong respond type
  1335.                 SetLastError( "Response type is not Taxachildren" );
  1336.                 return false;
  1337.             }
  1338.         } 
  1339.     }
  1340.     return false;
  1341. }
  1342. CRef< ITreeIterator >
  1343. CTaxon1::GetTreeIterator( CTaxon1::EIteratorMode mode )
  1344. {
  1345.     CRef< ITreeIterator > pIt;
  1346.     CTreeConstIterator* pIter = m_plCache->GetTree().GetConstIterator();
  1347.     switch( mode ) {
  1348.     default:
  1349.     case eIteratorMode_FullTree:
  1350. pIt.Reset( new CFullTreeConstIterator( pIter ) );
  1351. break;
  1352.     case eIteratorMode_LeavesBranches:
  1353. pIt.Reset( new CTreeLeavesBranchesIterator( pIter ) );
  1354. break;
  1355.     case eIteratorMode_Best:
  1356. pIt.Reset( new CTreeBestIterator( pIter ) );
  1357. break;
  1358.     case eIteratorMode_Blast:
  1359. pIt.Reset( new CTreeBlastIterator( pIter ) );
  1360. break;
  1361.     }
  1362.     SetLastError(NULL);
  1363.     return pIt;
  1364. }
  1365. CRef< ITreeIterator >
  1366. CTaxon1::GetTreeIterator( int tax_id, CTaxon1::EIteratorMode mode )
  1367. {
  1368.     CRef< ITreeIterator > pIt;
  1369.     CTaxon1Node* pData = 0;
  1370.     SetLastError(NULL);
  1371.     if( m_plCache->LookupAndAdd( tax_id, &pData ) ) {
  1372. pIt = GetTreeIterator( mode );
  1373. if( !pIt->GoNode( pData ) ) {
  1374.     SetLastError( "Iterator in this mode cannot point to the node with"
  1375.   " this tax id" );
  1376.     pIt.Reset( NULL );
  1377. }
  1378.     }
  1379.     return pIt;
  1380. }
  1381. bool
  1382. CTaxon1::GetNodeProperty( int tax_id, const string& prop_name,
  1383.   string& prop_val )
  1384. {
  1385.     SetLastError(NULL);
  1386.     CTaxon1_req req;
  1387.     CTaxon1_resp resp;
  1388.     CRef<CTaxon1_info> pProp( new CTaxon1_info() );
  1389.     CDiagAutoPrefix( "Taxon1::GetNodeProperty" );
  1390.     if( !prop_name.empty() ) {
  1391. pProp->SetIval1( tax_id );
  1392. pProp->SetIval2( -1 ); // Get string property by name
  1393. pProp->SetSval( prop_name );
  1394. req.SetGetorgprop( *pProp );
  1395. try {
  1396.     if( SendRequest( req, resp ) ) {
  1397. if( !resp.IsGetorgprop() ) { // error
  1398.     ERR_POST( "Response type is not Getorgprop" );
  1399. } else {
  1400.     if( resp.GetGetorgprop().size() > 0 ) {
  1401. CRef<CTaxon1_info> pInfo
  1402.     ( resp.GetGetorgprop().front() );
  1403. prop_val.assign( pInfo->GetSval() );
  1404. return true;
  1405.     }
  1406. }
  1407.     } else if( resp.IsError()
  1408.        && resp.GetError().GetLevel() 
  1409.        != CTaxon1_error::eLevel_none ) {
  1410. string sErr;
  1411. resp.GetError().GetErrorText( sErr );
  1412. ERR_POST( sErr );
  1413.     }
  1414. } catch( exception& e ) {
  1415.     ERR_POST( e.what() );
  1416.     SetLastError( e.what() );
  1417. }
  1418.     } else {
  1419. SetLastError( "Empty property name is not accepted" );
  1420. ERR_POST( GetLastError() );
  1421.     }
  1422.     return false;
  1423. }
  1424. bool
  1425. CTaxon1::GetNodeProperty( int tax_id, const string& prop_name,
  1426.   bool& prop_val )
  1427. {
  1428.     SetLastError(NULL);
  1429.     CTaxon1_req req;
  1430.     CTaxon1_resp resp;
  1431.     CRef<CTaxon1_info> pProp( new CTaxon1_info() );
  1432.     CDiagAutoPrefix( "Taxon1::GetNodeProperty" );
  1433.     if( !prop_name.empty() ) {
  1434. pProp->SetIval1( tax_id );
  1435. pProp->SetIval2( -3 ); // Get bool property by name
  1436. pProp->SetSval( prop_name );
  1437. req.SetGetorgprop( *pProp );
  1438. try {
  1439.     if( SendRequest( req, resp ) ) {
  1440. if( !resp.IsGetorgprop() ) { // error
  1441.     ERR_POST( "Response type is not Getorgprop" );
  1442. } else {
  1443.     if( resp.GetGetorgprop().size() > 0 ) {
  1444. CRef<CTaxon1_info> pInfo
  1445.     = resp.GetGetorgprop().front();
  1446. prop_val = pInfo->GetIval2() != 0;
  1447. return true;
  1448.     }
  1449. }
  1450.     } else if( resp.IsError()
  1451.        && resp.GetError().GetLevel() 
  1452.        != CTaxon1_error::eLevel_none ) {
  1453. string sErr;
  1454. resp.GetError().GetErrorText( sErr );
  1455. ERR_POST( sErr );
  1456.     }
  1457. } catch( exception& e ) {
  1458.     ERR_POST( e.what() );
  1459.     SetLastError( e.what() );
  1460. }
  1461.     } else {
  1462. SetLastError( "Empty property name is not accepted" );
  1463. ERR_POST( GetLastError() );
  1464.     }
  1465.     return false;
  1466. }
  1467. bool
  1468. CTaxon1::GetNodeProperty( int tax_id, const string& prop_name,
  1469.   int& prop_val )
  1470. {
  1471.     SetLastError(NULL);
  1472.     CTaxon1_req req;
  1473.     CTaxon1_resp resp;
  1474.     CRef<CTaxon1_info> pProp( new CTaxon1_info() );
  1475.     CDiagAutoPrefix( "Taxon1::GetNodeProperty" );
  1476.     if( !prop_name.empty() ) {
  1477. pProp->SetIval1( tax_id );
  1478. pProp->SetIval2( -2 ); // Get int property by name
  1479. pProp->SetSval( prop_name );
  1480. req.SetGetorgprop( *pProp );
  1481. try {
  1482.     if( SendRequest( req, resp ) ) {
  1483. if( !resp.IsGetorgprop() ) { // error
  1484.     ERR_POST( "Response type is not Getorgprop" );
  1485. } else {
  1486.     if( resp.GetGetorgprop().size() > 0 ) {
  1487. CRef<CTaxon1_info> pInfo
  1488.     = resp.GetGetorgprop().front();
  1489. prop_val = pInfo->GetIval2();
  1490. return true;
  1491.     }
  1492. }
  1493.     } else if( resp.IsError()
  1494.        && resp.GetError().GetLevel() 
  1495.        != CTaxon1_error::eLevel_none ) {
  1496. string sErr;
  1497. resp.GetError().GetErrorText( sErr );
  1498. ERR_POST( sErr );
  1499.     }
  1500. } catch( exception& e ) {
  1501.     ERR_POST( e.what() );
  1502.     SetLastError( e.what() );
  1503. }
  1504.     } else {
  1505. SetLastError( "Empty property name is not accepted" );
  1506. ERR_POST( GetLastError() );
  1507.     }
  1508.     return false;
  1509. }
  1510. //-----------------------------------
  1511. //  Iterator stuff
  1512. //
  1513. // 'Downward' traverse mode (nodes that closer to root processed first)
  1514. ITreeIterator::EAction 
  1515. ITreeIterator::TraverseDownward(I4Each& cb, unsigned levels)
  1516. {
  1517.     if( levels ) {
  1518.         switch( cb.Execute(GetNode()) ) {
  1519.         default:
  1520.         case eOk:
  1521.             if(!IsTerminal()) {
  1522.                 switch( cb.LevelBegin(GetNode()) ) {
  1523.                 case eStop: return eStop;
  1524.                 default:
  1525.                 case eOk:
  1526.                     if(GoChild()) {
  1527.                         do {
  1528.                             if(TraverseDownward(cb, levels-1)==eStop)
  1529.                                 return eStop;
  1530.                         } while(GoSibling());
  1531.                     }
  1532.                 case eSkip: // Means skip this level
  1533.                     break;
  1534.                 }
  1535.                 GoParent();
  1536.                 if( cb.LevelEnd(GetNode()) == eStop )
  1537.                     return eStop;
  1538.             }
  1539.         case eSkip: break;
  1540.         case eStop: return eStop;
  1541.         }
  1542.     }
  1543.     return eOk;
  1544. }
  1545. // 'Upward' traverse mode (nodes that closer to leaves processed first)
  1546. ITreeIterator::EAction
  1547. ITreeIterator::TraverseUpward(I4Each& cb, unsigned levels)
  1548. {
  1549.     if( levels > 0 ) {
  1550.         if(!IsTerminal()) {
  1551.             switch( cb.LevelBegin(GetNode()) ) {
  1552.             case eStop: return eStop;
  1553.             default:
  1554.             case eOk:
  1555.                 if(GoChild()) {
  1556.                     do {
  1557.                         if( TraverseUpward(cb, levels-1) == eStop )
  1558.                             return eStop;
  1559.                     } while(GoSibling());
  1560.                 }
  1561.             case eSkip: // Means skip this level
  1562.                 break;
  1563.             }
  1564.             GoParent();
  1565.             if( cb.LevelEnd(GetNode()) == eStop )
  1566.                 return eStop;
  1567.         }
  1568.         return cb.Execute(GetNode());
  1569.     }
  1570.     return eOk;
  1571. }
  1572. // 'LevelByLevel' traverse (nodes that closer to root processed first)
  1573. ITreeIterator::EAction
  1574. ITreeIterator::TraverseLevelByLevel(I4Each& cb, unsigned levels)
  1575. {
  1576.     switch( cb.Execute( GetNode() ) ) {
  1577.     case eStop:
  1578. return eStop;
  1579.     case eSkip:
  1580. return eSkip;
  1581.     case eOk:
  1582.     default:
  1583. break;
  1584.     }
  1585.     if(!IsTerminal()) {
  1586. vector< const ITaxon1Node* > skippedNodes;
  1587. return TraverseLevelByLevelInternal(cb, levels, skippedNodes);
  1588.     }
  1589.     return eOk;
  1590. }
  1591. ITreeIterator::EAction
  1592. ITreeIterator::TraverseLevelByLevelInternal(I4Each& cb, unsigned levels,
  1593.     vector< const ITaxon1Node* >& skp)
  1594. {
  1595.     size_t skp_start = skp.size();
  1596.     if( levels > 1 ) {
  1597. if(!IsTerminal()) {
  1598.     switch( cb.LevelBegin(GetNode()) ) {
  1599.     case eStop: return eStop;
  1600.     default:
  1601.     case eOk:
  1602. if(GoChild()) {
  1603.     // First pass - call Execute for all children
  1604.     do {
  1605. switch( cb.Execute(GetNode()) ) {
  1606. default:
  1607. case eOk:
  1608.     break;
  1609. case eSkip: // Means skip this node
  1610.     skp.push_back( GetNode() );
  1611.     break;
  1612. case eStop: return eStop;
  1613. }
  1614.     } while( GoSibling() );
  1615.     GoParent();
  1616.     // Start second pass
  1617.     size_t skp_cur = skp_start;
  1618.     GoChild();
  1619.     do {
  1620. if( skp.size() == skp_start ||
  1621.     skp[skp_cur] != GetNode() ) {
  1622.     if(TraverseLevelByLevelInternal(cb, levels-1, skp)
  1623.        == eStop ) {
  1624. return eStop;
  1625.     }
  1626. } else {
  1627.     ++skp_cur;
  1628. }
  1629.     } while(GoSibling());
  1630.     GoParent();
  1631. }
  1632. if( cb.LevelEnd( GetNode() ) == eStop )
  1633.     return eStop;
  1634. break;
  1635.     case eSkip:
  1636. break;
  1637.     }
  1638. }
  1639.     }
  1640.     skp.resize( skp_start );
  1641.     return eOk;
  1642. }
  1643. // Scans all the ancestors starting from immediate parent up to the root
  1644. // (no levelBegin, levelEnd calls performed)
  1645. ITreeIterator::EAction
  1646. ITreeIterator::TraverseAncestors(I4Each& cb)
  1647. {
  1648.     const ITaxon1Node* pNode = GetNode();
  1649.     EAction stat = eOk;
  1650.     while( GoParent() ) {
  1651. stat = cb.Execute(GetNode());
  1652. switch( stat ) {
  1653. case eStop: return eStop; // Stop scan, some error occurred
  1654. default:
  1655. case eOk:
  1656. case eSkip: // Means skip further scan, no error generated
  1657.     break;
  1658. }
  1659. if( stat == eSkip ) {
  1660.     break;
  1661. }
  1662.     }
  1663.     GoNode( pNode );
  1664.     return stat;
  1665. }
  1666. bool
  1667. CTaxon1::CheckOrgRef( const COrg_ref& orgRef, TOrgRefStatus& stat_out )
  1668. {
  1669.     CDiagAutoPrefix( "Taxon1::CheckOrgRef" );
  1670.     SetLastError(NULL);
  1671.     int tax_id;
  1672.     tax_id = GetTaxIdByOrgRef( orgRef );
  1673.     stat_out = eStatus_Ok;
  1674.     if( tax_id == 0 ) {
  1675. SetLastError( "No organism found for specified org_ref" );
  1676. ERR_POST( GetLastError() );
  1677. return false;
  1678.     } else if( tax_id < 0 ) {
  1679. SetLastError( "Multiple organisms found for specified org_ref" );
  1680. ERR_POST( GetLastError() );
  1681. return false;
  1682.     } else {
  1683. CRef< CTaxon2_data > pData( GetById( tax_id ) );
  1684. if( pData ) {
  1685.     // Compare orgrefs
  1686.     const COrg_ref& goodOr = pData->GetOrg();
  1687.     if( !orgRef.IsSetOrgname() ) {
  1688. stat_out |= eStatus_NoOrgname;
  1689.     } else {
  1690. const COrgName& goodOn = goodOr.GetOrgname();
  1691. const COrgName& inpOn = orgRef.GetOrgname();
  1692. if( !inpOn.IsSetGcode() || !goodOn.IsSetGcode() ||
  1693.     inpOn.GetGcode() != goodOn.GetGcode() ) {
  1694.     stat_out |= eStatus_WrongGC;
  1695. }
  1696. if( !inpOn.IsSetMgcode() ) { // mgc not set in input
  1697.     if( goodOn.IsSetMgcode() &&
  1698. goodOn.GetMgcode() != 0 ) {
  1699. stat_out |= eStatus_WrongMGC;
  1700.     }
  1701. } else { // mgc set
  1702.     if( !goodOn.IsSetMgcode() ) {
  1703. if( inpOn.GetMgcode() != 0 ) { // not unassigned
  1704.     stat_out |= eStatus_WrongMGC;
  1705. }
  1706.     } else if( inpOn.GetMgcode() != goodOn.GetMgcode() ) {
  1707. stat_out |= eStatus_WrongMGC;
  1708.     }
  1709. }
  1710. if( !inpOn.IsSetLineage() || !goodOn.IsSetLineage() ||
  1711.     inpOn.GetLineage().compare( goodOn.GetLineage() ) != 0 ) {
  1712.     stat_out |= eStatus_WrongLineage;
  1713. }
  1714. if( !inpOn.IsSetName() || !goodOn.IsSetName() ||
  1715.     inpOn.GetName().Which() != goodOn.GetName().Which() ) {
  1716.     stat_out |= eStatus_WrongOrgname;
  1717. }
  1718. if( !inpOn.IsSetDiv() ) {
  1719.     if( goodOn.IsSetDiv() &&
  1720. goodOn.GetDiv().compare( "UNA" ) != 0 ) {
  1721. stat_out |= eStatus_WrongDivision;
  1722.     }
  1723. } else {
  1724.     if( !goodOn.IsSetDiv() ) {
  1725. if( inpOn.GetDiv().compare( "UNA" ) != 0 ) {
  1726.     stat_out |= eStatus_WrongDivision;
  1727. }
  1728.     } else if( inpOn.GetDiv().compare( goodOn.GetDiv() )
  1729.        != 0 ) {
  1730. stat_out |= eStatus_WrongDivision;
  1731.     }
  1732. }
  1733. if( goodOn.IsSetMod() ) {
  1734.     if( inpOn.IsSetMod() ) {
  1735. const COrgName::TMod& inpMods = inpOn.GetMod();
  1736. const COrgName::TMod& goodMods = goodOn.GetMod();
  1737. for( COrgName::TMod::const_iterator gi =
  1738.  goodMods.begin();
  1739.      gi != goodMods.end();
  1740.      ++gi ) {
  1741.     bool bFound = false;
  1742.     for( COrgName::TMod::const_iterator ii = 
  1743.      inpMods.begin();
  1744.  ii != inpMods.end();
  1745.  ++ii ) {
  1746. if( (*gi)->GetSubtype() == (*ii)->GetSubtype()
  1747.     && ((*gi)->GetSubname() ==
  1748. (*ii)->GetSubname()) ) {
  1749.     bFound = true;
  1750.     break;
  1751. }
  1752.     }
  1753.     if( !bFound ) {
  1754. stat_out |= eStatus_WrongOrgmod;
  1755. break;
  1756.     }
  1757. }
  1758.     } else {
  1759. stat_out |= eStatus_WrongOrgmod;
  1760.     }
  1761. }
  1762.     }
  1763.     // Check taxname
  1764.     if( orgRef.IsSetTaxname() ) {
  1765. if( !goodOr.IsSetTaxname() ||
  1766.     orgRef.GetTaxname().compare( goodOr.GetTaxname() ) != 0 ) {
  1767.     stat_out |= eStatus_WrongTaxname;
  1768. }
  1769.     } else if( goodOr.IsSetTaxname() ) {
  1770. stat_out |= eStatus_WrongTaxname;
  1771.     }
  1772.     // Check common name
  1773.     if( orgRef.IsSetCommon() ) {
  1774. if( !goodOr.IsSetCommon() ||
  1775.     orgRef.GetCommon().compare( goodOr.GetCommon() ) != 0 ) {
  1776.     stat_out |= eStatus_WrongCommonName;
  1777. }
  1778.     } else if( goodOr.IsSetCommon() ) {
  1779. stat_out |= eStatus_WrongCommonName;
  1780.     }
  1781. } else { // Internal error: Cannot find orgref by tax_id
  1782.     SetLastError( "No organisms found for tax id" );
  1783.     ERR_POST( GetLastError() );
  1784.     return false;
  1785. }
  1786.     }
  1787.     return true;
  1788. }
  1789. END_objects_SCOPE
  1790. END_NCBI_SCOPE
  1791. /*
  1792.  * $Log: taxon1.cpp,v $
  1793.  * Revision 1000.3  2004/06/01 19:35:15  gouriano
  1794.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.25
  1795.  *
  1796.  * Revision 6.25  2004/05/19 17:27:10  gorelenk
  1797.  * Added include of PCH - ncbi_pch.hpp
  1798.  *
  1799.  * Revision 6.24  2004/04/01 14:14:02  lavr
  1800.  * Spell "occurred", "occurrence", and "occurring"
  1801.  *
  1802.  * Revision 6.23  2004/03/12 20:07:24  domrach
  1803.  * CheckOrgRef() function added for checking the user orgref against the orgref from Taxonomy db
  1804.  *
  1805.  * Revision 6.22  2004/02/04 16:14:44  domrach
  1806.  * New iterator types (modes of operation) are introduced. They include:
  1807.  * full tree, branches'n'leaves, best, and blast. Position inquiry f-ns
  1808.  * IsTerminal(), IsFirstChild(), and IsLastChild() has been moved from
  1809.  * ITreeNode to ITreeIterator. Node loading f-ns() now return the ITreeNode
  1810.  * for tax id.
  1811.  *
  1812.  * Revision 6.21  2003/11/20 15:42:19  ucko
  1813.  * Update for new (saner) treatment of ASN.1 NULLs.
  1814.  *
  1815.  * Revision 6.20  2003/11/18 17:50:51  dicuccio
  1816.  * Rearranged #include statements to avoid warning on MSVC
  1817.  *
  1818.  * Revision 6.19  2003/10/23 18:52:47  domrach
  1819.  * Unique name bug fixed
  1820.  *
  1821.  * Revision 6.18  2003/07/09 15:41:31  domrach
  1822.  * SearchTaxIdByName(), GetNameClass(), and GetNodeProperty() functions added
  1823.  *
  1824.  * Revision 6.17  2003/06/23 20:42:08  domrach
  1825.  * New treatment of subspecies names introduced
  1826.  *
  1827.  * Revision 6.16  2003/06/05 20:44:02  domrach
  1828.  * Adjusted to the new CanGetXxx verification methods
  1829.  *
  1830.  * Revision 6.15  2003/05/06 19:53:54  domrach
  1831.  * New functions and interfaces for traversing the cached partial taxonomy tree introduced. Convenience functions GetDivisionName() and GetRankName() were added
  1832.  *
  1833.  * Revision 6.14  2003/03/10 20:59:37  ucko
  1834.  * ThrowError1 -> ThrowError, per the recent change to <serial/objostr.hpp>.
  1835.  * Explicitly cast ints to COrgMod::TSubtype when setting OrgMod.subtype.
  1836.  *
  1837.  * Revision 6.13  2003/03/05 21:33:52  domrach
  1838.  * Enhanced orgref processing. Orgref cache capacity control added.
  1839.  *
  1840.  * Revision 6.12  2003/01/31 03:46:46  lavr
  1841.  * Heed int->bool performance warnings
  1842.  *
  1843.  * Revision 6.11  2003/01/21 19:38:59  domrach
  1844.  * GetPopsetJoin() member function optimized to copy partial tree from cached tree
  1845.  *
  1846.  * Revision 6.10  2003/01/10 19:58:46  domrach
  1847.  * Function GetPopsetJoin() added to CTaxon1 class
  1848.  *
  1849.  * Revision 6.9  2002/11/08 20:55:58  ucko
  1850.  * CConstRef<> now requires an explicit constructor.
  1851.  *
  1852.  * Revision 6.8  2002/11/08 14:39:52  domrach
  1853.  * Member function GetSuperkingdom() added
  1854.  *
  1855.  * Revision 6.7  2002/11/04 21:29:18  grichenk
  1856.  * Fixed usage of const CRef<> and CRef<> constructor
  1857.  *
  1858.  * Revision 6.6  2002/08/06 16:12:34  domrach
  1859.  * Merging of modifiers is now performed in LookupMerge
  1860.  *
  1861.  * Revision 6.5  2002/07/25 15:01:56  grichenk
  1862.  * Replaced non-const GetXXX() with SetXXX()
  1863.  *
  1864.  * Revision 6.4  2002/02/14 22:44:50  vakatov
  1865.  * Use STimeout instead of time_t.
  1866.  * Get rid of warnings and extraneous #include's, shuffled code a little.
  1867.  *
  1868.  * Revision 6.3  2002/01/31 00:31:26  vakatov
  1869.  * Follow the renaming of "CTreeCont.hpp" to "ctreecont.hpp".
  1870.  * Get rid of "std::" which is unnecessary and sometimes un-compilable.
  1871.  * Also done some source identation/beautification.
  1872.  *
  1873.  * Revision 6.2  2002/01/30 16:13:38  domrach
  1874.  * Changes made to pass through MSVC compiler. Some src files renamed
  1875.  *
  1876.  * Revision 6.1  2002/01/28 19:56:10  domrach
  1877.  * Initial checkin of the library implementation files
  1878.  *
  1879.  * ===========================================================================
  1880.  */