1 /* $Id: cache.cpp 609816 2020-06-08 15:50:52Z grichenk $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Vladimir Soussov, Michael Domrachev
27 *
28 * File Description:
29 * NCBI Taxonomy information retreival library caching implementation
30 *
31 */
32
33 #include <ncbi_pch.hpp>
34
35 #include <serial/serial.hpp>
36 #include <serial/objistrasn.hpp>
37
38 #include <objects/taxon1/taxon1.hpp>
39 #include "cache.hpp"
40
41 #include <vector>
42 #include <algorithm>
43
44 BEGIN_NCBI_SCOPE
45 BEGIN_objects_SCOPE
46
47
COrgRefCache(CTaxon1 & host)48 COrgRefCache::COrgRefCache( CTaxon1& host )
49 : m_host( host ), m_ppEntries( 0 ), m_nCacheCapacity( 10 )
50 {
51 return;
52 }
53
~COrgRefCache()54 COrgRefCache::~COrgRefCache()
55 {
56 delete[] m_ppEntries;
57 for( list<SCacheEntry*>::iterator i = m_lCache.begin();
58 i != m_lCache.end();
59 ++i ) {
60 delete *i;
61 }
62 }
63
64 bool
Init(unsigned nCapacity)65 COrgRefCache::Init( unsigned nCapacity )
66 {
67 CTaxon1_req req;
68 CTaxon1_resp resp;
69
70 req.SetMaxtaxid();
71
72 if( m_host.SendRequest( req, resp ) ) {
73 if( resp.IsMaxtaxid() ) {
74 // Correct response, return object
75 m_nMaxTaxId = TAX_ID_TO(unsigned, resp.GetMaxtaxid());
76 m_nMaxTaxId += m_nMaxTaxId/10;
77 m_ppEntries = new CTaxon1Node*[m_nMaxTaxId];
78 memset( m_ppEntries, '\0', m_nMaxTaxId*sizeof(*m_ppEntries) );
79 } else { // Internal: wrong respond type
80 m_host.SetLastError( "Response type is not Maxtaxid" );
81 return false;
82 }
83 } else {
84 return false;
85 }
86 CTaxon1_name* pNode = ( new CTaxon1_name );
87 pNode->SetTaxid( TAX_ID_CONST(1) );
88 pNode->SetOname().assign("root");
89 pNode->SetCde( 0x40000000 ); // Gene bank hidden
90 CTaxon1Node* pRoot = new CTaxon1Node( CRef<CTaxon1_name>(pNode) );
91 m_tPartTree.SetRoot( pRoot );
92 SetIndexEntry( 1, pRoot );
93
94 if( nCapacity != 0 ) {
95 m_nCacheCapacity = nCapacity;
96 }
97 // InitRanks();
98 // InitDivisions();
99 return true;
100 }
101
102 bool
Lookup(TTaxId tax_id,CTaxon1Node ** ppNode)103 COrgRefCache::Lookup( TTaxId tax_id, CTaxon1Node** ppNode )
104 {
105 if( TAX_ID_TO(unsigned, tax_id) < m_nMaxTaxId ) {
106 *ppNode = m_ppEntries[TAX_ID_TO(unsigned, tax_id)];
107 } else {
108 *ppNode = NULL;
109 }
110 return *ppNode != NULL;
111 }
112
113 bool
LookupAndAdd(TTaxId tax_id,CTaxon1Node ** ppData)114 COrgRefCache::LookupAndAdd( TTaxId tax_id, CTaxon1Node** ppData )
115 {
116 *ppData = NULL;
117 if(TAX_ID_TO(unsigned, tax_id) < m_nMaxTaxId ) {
118 CTaxon1Node* pNode = ( m_ppEntries[TAX_ID_TO(unsigned, tax_id)] );
119 if( pNode ) {
120 *ppData = pNode;
121 return true;
122 } else { // Add the entry from server
123 CTaxon1_req req;
124 CTaxon1_resp resp;
125
126 req.SetTaxalineage(TAX_ID_TO(int, tax_id) );
127
128 if( m_host.SendRequest( req, resp ) ) {
129 if( resp.IsTaxalineage() ) {
130 // Correct response, return object
131 list< CRef<CTaxon1_name> >& lLin = resp.SetTaxalineage();
132 CTaxon1Node* pParent = 0;
133 pNode = 0;
134 // Check if this is a secondary node
135 if( lLin.front()->GetTaxid() != tax_id ) {
136 // Secondary node, try to get primary from index
137 pNode = m_ppEntries[TAX_ID_TO(unsigned, lLin.front()->GetTaxid()) ];
138 }
139 if( !pNode ) {
140 list< CRef< CTaxon1_name > >::reverse_iterator i;
141 // Fill in storage
142 for( i = lLin.rbegin(); i != lLin.rend(); ++i ) {
143 if( !m_ppEntries[TAX_ID_TO(unsigned, (*i)->GetTaxid()) ] ) {
144 // Create node
145 break;
146 } else {
147 pParent = m_ppEntries[TAX_ID_TO(unsigned, (*i)->GetTaxid()) ];
148 }
149 }
150 // Create tree iterator
151 CTreeIterator* pIt = ( m_tPartTree.GetIterator() );
152 if( !pParent ) {
153 pParent = static_cast<CTaxon1Node*>(pIt->GetNode());
154 }
155 pIt->GoNode( pParent );
156 for( ; i != lLin.rend(); ++i ) {
157 pNode = new CTaxon1Node(*i);
158 m_ppEntries[TAX_ID_TO(unsigned, pNode->GetTaxId()) ] = pNode;
159 pIt->AddChild( pNode );
160 pIt->GoNode( pNode );
161 }
162 delete pIt;
163 } else { // Store secondary in index
164 m_ppEntries[TAX_ID_TO(unsigned, tax_id) ] = pNode;
165 }
166 _ASSERT( pNode );
167 *ppData = pNode;
168 return true;
169 } else { // Internal: wrong respond type
170 m_host.SetLastError( "Unable to get node lineage: "
171 "Response type is not Taxalineage" );
172 return false;
173 }
174 }
175 }
176 }
177 return false;
178 }
179
180 bool
LookupAndInsert(TTaxId tax_id,CTaxon2_data ** ppData)181 COrgRefCache::LookupAndInsert( TTaxId tax_id, CTaxon2_data** ppData )
182 {
183 CTaxon1Node* pNode = ( NULL );
184 *ppData = NULL;
185
186 if( LookupAndAdd( tax_id, &pNode ) && pNode ) {
187 SCacheEntry* pEntry = ( pNode->GetEntry() );
188 if( !pEntry ) {
189 if( !Insert2( *pNode ) )
190 return false;
191 pEntry = pNode->GetEntry();
192 } else {
193 m_lCache.remove( pEntry );
194 m_lCache.push_front( pEntry );
195 }
196 *ppData = pEntry->GetData();
197 return true;
198 }
199 return false;
200 }
201
202 bool
Lookup(TTaxId tax_id,CTaxon2_data ** ppData)203 COrgRefCache::Lookup( TTaxId tax_id, CTaxon2_data** ppData )
204 {
205 if(TAX_ID_TO(unsigned, tax_id) < m_nMaxTaxId ) {
206 CTaxon1Node* pNode = ( m_ppEntries[TAX_ID_TO(unsigned, tax_id)] );
207 SCacheEntry* pEntry;
208 if( pNode && (pEntry=pNode->GetEntry()) ) {
209 // Move in the list
210 m_lCache.remove( pEntry );
211 m_lCache.push_front( pEntry );
212 *ppData = pEntry->GetData();
213 return true;
214 }
215 }
216 *ppData = NULL;
217 return false;
218 }
219
220 bool
Insert2(CTaxon1Node & node)221 COrgRefCache::Insert2( CTaxon1Node& node )
222 {
223 CTaxon1_req req;
224 CTaxon1_resp resp;
225
226 req.SetLookup().SetTaxId( node.GetTaxId() );
227 // Set version db tag
228 COrgrefProp::SetOrgrefProp( req.SetLookup(), "version", 2 );
229 if( m_host.m_bWithSynonyms ) {
230 COrgrefProp::SetOrgrefProp( req.SetLookup(), "syn", m_host.m_bWithSynonyms );
231 }
232
233 if( m_host.SendRequest( req, resp ) ) {
234 if( resp.IsLookup() ) {
235 // Correct response, return object
236 struct SCacheEntry* pEntry = ( new SCacheEntry );
237 pEntry->m_pTax2 = new CTaxon2_data();
238 pEntry->m_pTreeNode = &node;
239
240 SerialAssign< COrg_ref >( pEntry->m_pTax2->SetOrg(), resp.GetLookup().GetOrg() );
241 m_host.x_ConvertOrgrefProps( *pEntry->m_pTax2 );
242
243 // Remove last element from list
244 if( m_lCache.size() >= m_nCacheCapacity ) {
245 CTaxon1Node* pNode = m_lCache.back()->m_pTreeNode;
246 pNode->m_cacheEntry = NULL;
247 delete m_lCache.back();
248 m_lCache.pop_back();
249 }
250
251 node.m_cacheEntry = pEntry;
252 m_lCache.push_front( pEntry );
253
254 return true;
255
256 } else { // Internal: wrong respond type
257 m_host.SetLastError( "Response type is not Lookup" );
258 }
259 }
260
261 return false;
262 }
263
264 TTaxRank
FindRankByName(const char * pchName)265 COrgRefCache::FindRankByName( const char* pchName )
266 {
267 if( InitRanks() ) {
268 int vid = m_rankStorage.FindValueIdByField( "rank_txt", pchName );
269 if( vid != CDomainStorage::kIllegalValue ) {
270 return m_rankStorage.HasField("oldid") ? m_rankStorage.FindFieldValueById( vid, "oldid" ) : vid;
271 }
272 }
273 return -1000;
274 }
275
276
277 const char*
GetRankName(int rank)278 COrgRefCache::GetRankName( int rank )
279 {
280 if( InitRanks() ) {
281 if( m_rankStorage.HasField("oldid") ) {
282 int vid = m_rankStorage.FindValueIdByField( "oldid", rank );
283 if( vid != CDomainStorage::kIllegalValue ) {
284 return m_rankStorage.FindFieldStringById( vid, "rank_txt" ).c_str();
285 }
286 } else { // old style ranks, use rank_txt
287 const string& s = m_rankStorage.FindFieldStringById( rank, "rank_txt" );
288 if( !s.empty() ) {
289 return s.c_str();
290 }
291 }
292 }
293 return NULL;
294 }
295
296 bool
InitDomain(const string & name,CDomainStorage & storage)297 COrgRefCache::InitDomain( const string& name, CDomainStorage& storage )
298 {
299 CTaxon1_req req;
300 CTaxon1_resp resp;
301
302 req.SetGetdomain(name);
303
304 if( m_host.SendRequest( req, resp ) ) {
305 if( resp.IsGetdomain() ) {
306 // Correct response, return object
307 list< CRef< CTaxon1_info > >& lRecords = resp.SetGetdomain();
308 // Get header [0]:id,nof_fields,name
309 storage.SetId( lRecords.front()->GetIval1() );
310 int nof_fields = lRecords.front()->GetIval2();
311 storage.SetName( lRecords.front()->GetSval() );
312 lRecords.pop_front();
313 // read in field descriptions [1..nof_fields]:field_no,val_type,field_name
314 while( nof_fields-- && !lRecords.empty() ) {
315 storage.AddField( lRecords.front()->GetIval1(), lRecords.front()->GetIval2(), lRecords.front()->GetSval() );
316 lRecords.pop_front();
317 }
318 // Fill in storage
319 for( list< CRef< CTaxon1_info > >::const_iterator i = lRecords.begin();
320 i != lRecords.end(); ++i ) {
321 if( (*i)->IsSetSval() ) {
322 storage.InsertFieldValue( (*i)->GetIval1(), (*i)->GetIval2(), (*i)->GetSval() );
323 } else {
324 storage.InsertFieldValue( (*i)->GetIval1(), (*i)->GetIval2() );
325 }
326 }
327 return true;
328 } else { // Internal: wrong respond type
329 m_host.SetLastError( "Invalid response type" );
330 return false;
331 }
332 }
333 return false;
334 }
335
336 bool
InitRanks()337 COrgRefCache::InitRanks()
338 {
339 if( m_rankStorage.empty() ) {
340 if( InitDomain("rank",m_rankStorage) ) {
341 // Find some old ranks
342 m_nSuperkingdomRank = FindRankByName( "superkingdom" );
343 if( m_nSuperkingdomRank < -10 ) {
344 m_host.SetLastError( "Superkingdom rank was not found" );
345 return false;
346 }
347 m_nGenusRank = FindRankByName( "genus" );
348 if( m_nGenusRank < -10 ) {
349 m_host.SetLastError( "Genus rank was not found" );
350 return false;
351 }
352 m_nSpeciesRank = FindRankByName( "species" );
353 if( m_nSpeciesRank < -10 ) {
354 m_host.SetLastError( "Species rank was not found" );
355 return false;
356 }
357 m_nSubspeciesRank = FindRankByName( "subspecies" );
358 if( m_nSubspeciesRank < -10 ) {
359 m_host.SetLastError( "Subspecies rank was not found" );
360 return false;
361 }
362 } else {
363 return false;
364 }
365 }
366 return true;
367 }
368
369 const char*
GetNameClassName(short nc)370 COrgRefCache::GetNameClassName( short nc )
371 {
372 if( !InitNameClasses() ) return NULL;
373 TNameClassMapCI ci( m_ncStorage.find( nc ) );
374 if( ci != m_ncStorage.end() ) {
375 return ci->second.c_str();
376 }
377 return NULL;
378 }
379
380 TTaxNameClass
FindNameClassByName(const char * pchName)381 COrgRefCache::FindNameClassByName( const char* pchName )
382 {
383 if( !InitNameClasses() ) return -1;
384 for( TNameClassMapCI ci = m_ncStorage.begin();
385 ci != m_ncStorage.end();
386 ++ci )
387 if( ci->second.compare( pchName ) == 0 )
388 return ci->first;
389 return -1;
390 }
391
392 bool
InitNameClasses()393 COrgRefCache::InitNameClasses()
394 {
395 if( m_ncStorage.size() == 0 ) {
396
397 CTaxon1_req req;
398 CTaxon1_resp resp;
399
400 req.SetGetcde();
401
402 if( m_host.SendRequest( req, resp ) ) {
403 if( resp.IsGetcde() ) {
404 // Correct response, return object
405 const list< CRef< CTaxon1_info > >&
406 l = ( resp.GetGetcde() );
407 // Fill in storage
408 for( list< CRef< CTaxon1_info > >::const_iterator
409 i = l.begin();
410 i != l.end(); ++i )
411 m_ncStorage
412 .insert( TNameClassMap::value_type((*i)->GetIval1(),
413 (*i)->GetSval()) );
414 } else { // Internal: wrong respond type
415 m_host.SetLastError( "Response type is not Getcde" );
416 return false;
417 }
418 }
419
420 m_ncPrefCommon = FindNameClassByName( "genbank common name" );
421 if( m_ncPrefCommon < 0 ) {
422 m_host.SetLastError( "Genbank common name class was not found" );
423 return false;
424 }
425 m_ncCommon = FindNameClassByName( "common name" );
426 if( m_ncCommon < 0 ) {
427 m_host.SetLastError( "Common name class was not found" );
428 return false;
429 }
430 }
431 return true;
432 }
433
434 TTaxDivision
FindDivisionByCode(const char * pchCode)435 COrgRefCache::FindDivisionByCode( const char* pchCode )
436 {
437 if( !InitDivisions() || pchCode == 0 ) return -1;
438 int result = -1;
439 result = m_divStorage.FindValueIdByField( "div_cde", pchCode );
440 if( result == CDomainStorage::kIllegalValue ) {
441 result = -1;
442 }
443 return result;
444 }
445
446 TTaxDivision
FindDivisionByName(const char * pchName)447 COrgRefCache::FindDivisionByName( const char* pchName )
448 {
449 if( !InitDivisions() || pchName == 0 ) return -1;
450 int result = -1;
451 result = m_divStorage.FindValueIdByField( "div_txt", pchName );
452 if( result == CDomainStorage::kIllegalValue ) {
453 result = -1;
454 }
455 return result;
456 }
457
458 const char*
GetDivisionCode(short div_id)459 COrgRefCache::GetDivisionCode( short div_id )
460 {
461 if( !InitDivisions() ) return NULL;
462 const string& sCode = m_divStorage.FindFieldStringById( div_id, "div_cde" );
463 if( !sCode.empty() ) {
464 return sCode.c_str();
465 }
466 return NULL;
467 }
468
469 const char*
GetDivisionName(short div_id)470 COrgRefCache::GetDivisionName( short div_id )
471 {
472 if( !InitDivisions() ) return NULL;
473 const string& s = m_divStorage.FindFieldStringById( div_id, "div_txt" );
474 if( !s.empty() ) {
475 return s.c_str();
476 }
477 return NULL;
478 }
479
480
481 bool
InitDivisions()482 COrgRefCache::InitDivisions()
483 {
484 if( m_divStorage.empty() ) {
485
486 if( !InitDomain("division", m_divStorage) ) {
487 return false;
488 }
489 // CTaxon1_req req;
490 // CTaxon1_resp resp;
491
492 // req.SetGetdivs();
493
494 // if( m_host.SendRequest( req, resp ) ) {
495 // if( resp.IsGetdivs() ) {
496 // // Correct response, return object
497 // const list< CRef< CTaxon1_info > >&
498 // l = ( resp.GetGetdivs() );
499 // // Fill in storage
500 // for( list< CRef< CTaxon1_info > >::const_iterator
501 // i = l.begin();
502 // i != l.end(); ++i ) {
503 // SDivision& div = ( m_divStorage[(*i)->GetIval1()] );
504 // div.m_sName.assign( (*i)->GetSval() );
505 // int code = (*i)->GetIval2();
506 // for(int k= 0; k < 3; k++) {
507 // div.m_sCode.append( 1U, (code >> (8*(3-k))) & 0xFF );
508 // }
509 // div.m_sCode.append( 1U, code & 0xFF );
510 // }
511 // } else { // Internal: wrong response type
512 // m_host.SetLastError( "Response type is not Getdivs" );
513 // return false;
514 // }
515 // }
516 }
517 return true;
518 }
519
520 void
SetIndexEntry(int id,CTaxon1Node * pNode)521 COrgRefCache::SetIndexEntry( int id, CTaxon1Node* pNode )
522 {
523 m_ppEntries[id] = pNode;
524 }
525
526 //=======================================================
527 //
528 // Iterators implementation
529 //
530 bool
IsLastChild() const531 CTaxTreeConstIterator::IsLastChild() const
532 {
533 const CTreeContNodeBase* pOldNode = m_it->GetNode();
534 bool bResult = true;
535
536 while( m_it->GoParent() ) {
537 if( IsVisible( m_it->GetNode() ) ) {
538 const CTreeContNodeBase* pParent = m_it->GetNode();
539 m_it->GoNode( pOldNode );
540 while( m_it->GetNode() != pParent ) {
541 if( m_it->GoSibling() ) {
542 bResult = !NextVisible( pParent );
543 break;
544 }
545 if( !m_it->GoParent() ) {
546 break;
547 }
548 }
549 break;
550 }
551 }
552 m_it->GoNode( pOldNode );
553 return bResult;
554 }
555
556 bool
IsFirstChild() const557 CTaxTreeConstIterator::IsFirstChild() const
558 {
559 const CTreeContNodeBase* pOldNode = m_it->GetNode();
560 bool bResult = false;
561
562 while( m_it->GoParent() ) {
563 if( IsVisible( m_it->GetNode() ) ) {
564 const CTreeContNodeBase* pParent = m_it->GetNode();
565 if( m_it->GoChild() ) {
566 bResult = NextVisible(pParent) && m_it->GetNode() == pOldNode;
567 }
568 break;
569 }
570 }
571 m_it->GoNode( pOldNode );
572 return bResult;
573 }
574
575 bool
IsTerminal() const576 CTaxTreeConstIterator::IsTerminal() const
577 {
578 const CTreeContNodeBase* pOldNode = m_it->GetNode();
579
580 if( m_it->GoChild() ) {
581 bool bResult = NextVisible( pOldNode );
582 m_it->GoNode( pOldNode );
583 return !bResult;
584 }
585 return true;
586 }
587
588 bool
NextVisible(const CTreeContNodeBase * pParent) const589 CTaxTreeConstIterator::NextVisible( const CTreeContNodeBase* pParent ) const
590 {
591 if( m_it->GetNode() == pParent ) {
592 return false;
593 }
594 next:
595 if( IsVisible( m_it->GetNode() ) ) {
596 return true;
597 }
598 if( m_it->GoChild() ) {
599 goto next;
600 } else if( m_it->GoSibling() ) {
601 goto next;
602 } else {
603 while( m_it->GoParent() && m_it->GetNode() != pParent ) {
604 if( m_it->GoSibling() ) {
605 goto next;
606 }
607 }
608 }
609 return false;
610 }
611
612 bool
GoParent()613 CTaxTreeConstIterator::GoParent()
614 {
615 const CTreeContNodeBase* pOldNode = m_it->GetNode();
616 bool bResult = false;
617 while( m_it->GoParent() ) {
618 if( IsVisible( m_it->GetNode() ) ) {
619 bResult = true;
620 break;
621 }
622 }
623 if( !bResult ) {
624 m_it->GoNode( pOldNode );
625 }
626 return bResult;
627 }
628
629 bool
GoChild()630 CTaxTreeConstIterator::GoChild()
631 {
632 const CTreeContNodeBase* pOldNode = m_it->GetNode();
633 bool bResult = false;
634
635 if( m_it->GoChild() ) {
636 bResult = NextVisible( pOldNode );
637 }
638 if( !bResult ) {
639 m_it->GoNode( pOldNode );
640 }
641 return bResult;
642 }
643
644 bool
GoSibling()645 CTaxTreeConstIterator::GoSibling()
646 {
647 const CTreeContNodeBase* pOldNode = m_it->GetNode();
648 bool bResult = false;
649
650 if( GoParent() ) {
651 const CTreeContNodeBase* pParent = m_it->GetNode();
652 m_it->GoNode( pOldNode );
653 while( m_it->GetNode() != pParent ) {
654 if( m_it->GoSibling() ) {
655 bResult = NextVisible( pParent );
656 break;
657 }
658 if( !m_it->GoParent() ) {
659 break;
660 }
661 }
662 if( !bResult ) {
663 m_it->GoNode( pOldNode );
664 }
665 }
666 return bResult;
667 }
668
669 bool
GoNode(const ITaxon1Node * pNode)670 CTaxTreeConstIterator::GoNode( const ITaxon1Node* pNode )
671 {
672 const CTreeContNodeBase* pTaxNode = CastIC( pNode );
673
674 if( pNode && IsVisible( pTaxNode ) ) {
675 return m_it->GoNode( pTaxNode );
676 }
677 return false;
678 }
679
680 bool
GoAncestor(const ITaxon1Node * pINode)681 CTaxTreeConstIterator::GoAncestor(const ITaxon1Node* pINode)
682 {
683 const CTreeContNodeBase* pNode = CastIC( pINode );
684 if( pNode && IsVisible( pNode ) ) {
685 const CTreeContNodeBase* pOldNode = m_it->GetNode();
686
687 vector< const CTreeContNodeBase* > v;
688 do {
689 v.push_back( m_it->GetNode() );
690 } while( GoParent() );
691
692 m_it->GoNode( pNode );
693 vector< const CTreeContNodeBase* >::const_iterator vi;
694 do {
695 vi = find( v.begin(), v.end(), m_it->GetNode() );
696 if( vi != v.end() ) {
697 return true;
698 }
699 } while( GoParent() );
700 // Restore old position
701 m_it->GoNode( pOldNode );
702 }
703 return false;
704 }
705
706 bool
BelongSubtree(const ITaxon1Node * pIRoot) const707 CTaxTreeConstIterator::BelongSubtree(const ITaxon1Node* pIRoot) const
708 {
709 const CTreeContNodeBase* pRoot = CastIC( pIRoot );
710 if( pRoot && IsVisible( pRoot ) ) {
711 const CTreeContNodeBase* pOldNode = m_it->GetNode();
712 do {
713 if( IsVisible( m_it->GetNode() ) ) {
714 if( m_it->GetNode() == pRoot ) {
715 m_it->GoNode( pOldNode );
716 return true;
717 }
718 }
719 } while( m_it->GoParent() );
720 m_it->GoNode( pOldNode );
721 }
722 return false;
723 }
724
725 // check if given node belongs to subtree pointed by cursor
726 bool
AboveNode(const ITaxon1Node * pINode) const727 CTaxTreeConstIterator::AboveNode(const ITaxon1Node* pINode) const
728 {
729 const CTreeContNodeBase* pNode = CastIC( pINode );
730 if( pNode == m_it->GetNode() ) { // Node is not above itself
731 return false;
732 }
733
734 if( pNode && IsVisible( pNode ) ) {
735 const CTreeContNodeBase* pOldNode = m_it->GetNode();
736 m_it->GoNode( pNode );
737 do {
738 if( IsVisible( m_it->GetNode() ) ) {
739 if( m_it->GetNode() == pOldNode ) {
740 m_it->GoNode( pOldNode );
741 return true;
742 }
743 }
744 } while( m_it->GoParent() );
745 m_it->GoNode( pOldNode );
746 }
747 return false;
748 }
749
750 bool
IsVisible(const CTreeContNodeBase * pNode) const751 CTreeLeavesBranchesIterator::IsVisible( const CTreeContNodeBase* pNode ) const
752 {
753 return pNode &&
754 ( pNode->IsRoot() || pNode->IsTerminal() ||
755 !pNode->Child()->IsLastChild() );
756 }
757
758 bool
IsVisible(const CTreeContNodeBase * pNode) const759 CTreeBestIterator::IsVisible( const CTreeContNodeBase* pNode ) const
760 {
761 return pNode &&
762 ( pNode->IsRoot() || pNode->IsTerminal() ||
763 !pNode->Child()->IsLastChild() ||
764 !(pNode->IsLastChild() && pNode->IsFirstChild()) );
765
766 }
767
768 bool
IsVisible(const CTreeContNodeBase * pNode) const769 CTreeBlastIterator::IsVisible( const CTreeContNodeBase* pNode ) const
770 {
771 return pNode && ( pNode->IsRoot() ||
772 !CastCI(pNode)->GetBlastName().empty() );
773 }
774
775 /////////////////////////////////////////////////////////////////
776 // CDomainStorage impl
777 //
CDomainStorage()778 CDomainStorage::CDomainStorage()
779 : m_id(0)
780 {
781 }
782
783 void
AddField(int field_no,int val_type,const string & name)784 CDomainStorage::AddField( int field_no, int val_type, const string& name )
785 {
786 m_fields.insert( TFieldMap::value_type( name, field_no ) );
787 if( m_types.size() <= field_no ) {
788 m_types.resize(field_no+1);
789 }
790 m_types[field_no] = val_type;
791 }
792
793 bool
HasField(const string & field_name) const794 CDomainStorage::HasField( const string& field_name ) const
795 {
796 return m_fields.find( field_name ) != m_fields.end();
797 }
798
799 void
InsertFieldValue(int val_id,int str_len,const string & str)800 CDomainStorage::InsertFieldValue( int val_id, int str_len, const string& str )
801 {
802 vector< CDomainStorage::TValue >& val = m_values[val_id];
803 val.resize( val.size()+1 );
804 TValue& v = val.back();
805 v.m_int = str_len;
806 v.m_str = str;
807 }
808
809 void
InsertFieldValue(int val_id,int value)810 CDomainStorage::InsertFieldValue( int val_id, int value )
811 {
812 InsertFieldValue( val_id, value, "" );
813 }
814
815 int
FindValueIdByField(const string & fieldName,const string & searchstring) const816 CDomainStorage::FindValueIdByField( const string& fieldName, const string& searchstring ) const
817 {
818 TFieldMap::const_iterator ci = m_fields.find(fieldName);
819 if( ci != m_fields.end() ) {
820 ITERATE( TValues, cj, m_values ) {
821 if( cj->second[ci->second].m_str == searchstring ) {
822 return cj->first;
823 }
824 }
825 }
826 return kIllegalValue;
827 }
828
829 int
FindValueIdByField(const string & fieldName,int fieldValue) const830 CDomainStorage::FindValueIdByField( const string& fieldName, int fieldValue ) const
831 {
832 TFieldMap::const_iterator ci = m_fields.find(fieldName);
833 if( ci != m_fields.end() ) {
834 ITERATE( TValues, cj, m_values ) {
835 if( cj->second[ci->second].m_int == fieldValue ) {
836 return cj->first;
837 }
838 }
839 }
840 return kIllegalValue;
841 }
842
843 int
FindFieldValueById(int value_id,const string & fieldName) const844 CDomainStorage::FindFieldValueById( int value_id, const string& fieldName ) const
845 {
846 TFieldMap::const_iterator ci = m_fields.find(fieldName);
847 TValues::const_iterator cj = m_values.find(value_id);
848 if( ci != m_fields.end() && cj != m_values.end() ) {
849 return cj->second[ci->second].m_int;
850 }
851 return kIllegalValue;
852 }
853
854 const string&
FindFieldStringById(int value_id,const string & fieldName) const855 CDomainStorage::FindFieldStringById( int value_id, const string& fieldName ) const
856 {
857 TFieldMap::const_iterator ci = m_fields.find(fieldName);
858 TValues::const_iterator cj = m_values.find(value_id);
859 if( ci != m_fields.end() && cj != m_values.end() ) {
860 return cj->second[ci->second].m_str;
861 }
862 return kEmptyStr;
863 }
864
865 END_objects_SCOPE
866 END_NCBI_SCOPE
867