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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: feature_item.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 19:44:14  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.26
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: feature_item.cpp,v 1000.2 2004/06/01 19:44:14 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:  Aaron Ucko, NCBI
  35. *          Mati Shomrat
  36. *
  37. * File Description:
  38. *   new (early 2003) flat-file generator -- representation of features
  39. *   (mainly of interest to implementors)
  40. *
  41. * ===========================================================================
  42. */
  43. #include <ncbi_pch.hpp>
  44. #include <corelib/ncbistd.hpp>
  45. #include <serial/iterator.hpp>
  46. #include <objects/seq/Bioseq.hpp>
  47. #include <objects/seq/Heterogen.hpp>
  48. #include <objects/seqfeat/Org_ref.hpp>
  49. #include <objects/seqfeat/OrgName.hpp>
  50. #include <objects/seqfeat/OrgMod.hpp>
  51. #include <objects/seqfeat/Code_break.hpp>
  52. #include <objects/seqfeat/Genetic_code.hpp>
  53. #include <objects/seqfeat/Genetic_code_table.hpp>
  54. #include <objects/seqfeat/Imp_feat.hpp>
  55. #include <objects/seqfeat/RNA_ref.hpp>
  56. #include <objects/seqfeat/Trna_ext.hpp>
  57. #include <objects/seqloc/Seq_loc.hpp>
  58. #include <objects/seqloc/Seq_point.hpp>
  59. #include <objects/seqloc/Seq_interval.hpp>
  60. #include <objects/seqloc/Packed_seqpnt.hpp>
  61. #include <objects/seqloc/Textseq_id.hpp>
  62. #include <objects/general/Object_id.hpp>
  63. #include <objmgr/scope.hpp>
  64. #include <objmgr/seqdesc_ci.hpp>
  65. #include <objmgr/seq_vector.hpp>
  66. #include <objmgr/seq_loc_mapper.hpp>
  67. #include <objmgr/util/sequence.hpp>
  68. #include <objmgr/util/feature.hpp>
  69. #include <util/static_set.hpp>
  70. #include <util/static_map.hpp>
  71. #include <util/sequtil/sequtil.hpp>
  72. #include <util/sequtil/sequtil_convert.hpp>
  73. #include <algorithm>
  74. #include <objtools/format/formatter.hpp>
  75. #include <objtools/format/items/feature_item.hpp>
  76. #include <objtools/format/context.hpp>
  77. #include <objtools/format/items/qualifiers.hpp>
  78. #include "utils.hpp"
  79. // On Mac OS X 10.3, FixMath.h defines ff as a one-argument macro(!)
  80. #ifdef ff
  81. #  undef ff
  82. #endif
  83. BEGIN_NCBI_SCOPE
  84. BEGIN_SCOPE(objects)
  85. USING_SCOPE(sequence);
  86. // -- static functions
  87. const CGb_qual* s_GetQual(const CSeq_feat& feat, const string& qual)
  88. {
  89.     ITERATE(CSeq_feat::TQual, it, feat.GetQual()) {
  90.         if ( (*it)->CanGetQual()  &&
  91.              NStr::CompareNocase((*it)->GetQual(), qual) == 0  &&
  92.              (*it)->CanGetVal()  &&  !(*it)->GetVal().empty() ) {
  93.             return *it;
  94.         }
  95.     }
  96.     return 0;
  97. }
  98. static bool s_ValidId(const CSeq_id& id)
  99. {
  100.     return id.IsGenbank()  ||  id.IsEmbl()    ||  id.IsDdbj()  ||
  101.            id.IsOther()    ||  id.IsPatent()  ||  
  102.            id.IsTpg()      ||  id.IsTpe()     ||  id.IsTpd();
  103. }
  104. static bool s_CheckQuals_cdregion(const CSeq_feat& feat, CBioseqContext& ctx)
  105. {
  106.     if ( !ctx.Config().CheckCDSProductId() ) {
  107.         return true;
  108.     }
  109.     
  110.     CScope& scope = ctx.GetScope();
  111.     // non-pseudo CDS must have /product
  112.     bool pseudo = feat.CanGetPseudo()  &&  feat.GetPseudo();
  113.     if ( !pseudo ) {
  114.         const CGene_ref* grp = feat.GetGeneXref();
  115.         if ( grp == 0 ) {
  116.             CConstRef<CSeq_feat> gene = 
  117.                 GetOverlappingGene(feat.GetLocation(), scope);
  118.             if ( gene ) {
  119.                 pseudo = gene->CanGetPseudo()  &&  gene->GetPseudo();
  120.                 if ( !pseudo ) {
  121.                     grp = &(gene->GetData().GetGene());
  122.                 }
  123.             }
  124.         }
  125.         if ( !pseudo  &&  grp != 0 ) {
  126.             pseudo = grp->GetPseudo();
  127.         }
  128.     }
  129.     bool just_stop = false;
  130.     if ( feat.CanGetLocation() ) {
  131.         const CSeq_loc& loc = feat.GetLocation();
  132.         if ( loc.IsPartialLeft()  &&  !loc.IsPartialRight() ) {
  133.             if ( GetLength(loc, &scope) <= 5 ) {
  134.                 just_stop = true;
  135.             }
  136.         }
  137.     }
  138.     if ( pseudo ||  just_stop ) {
  139.         return true;
  140.     } 
  141.     // make sure the product has a valid accession
  142.     if ( feat.CanGetProduct() ) {
  143.         const CSeq_id* id = 0;
  144.         try {
  145.             id = &(GetId(feat.GetProduct(), &ctx.GetScope()));
  146.         } catch ( CException& ) {}
  147.         if ( id != 0 ) {
  148.             if ( (id->IsGi()  &&  id->GetGi() > 0) ||  id->IsLocal() ) {
  149.                 CBioseq_Handle prod = scope.GetBioseqHandle(*id);
  150.                 if ( prod ) {
  151.                     ITERATE (CBioseq_Handle::TId, it, prod.GetId()) {
  152.                         if ( s_ValidId(*it->GetSeqId()) ) {
  153.                             const CTextseq_id* tsip = it->GetSeqId()->GetTextseq_Id();
  154.                             if ( tsip != 0  &&  tsip->IsSetAccession()  &&
  155.                                  ValidateAccession(tsip->GetAccession()) ) {
  156.                                 return true;
  157.                             }
  158.                         }
  159.                     }
  160.                 } else if ( id->IsGi()  &&  id->GetGi() > 0 ) {
  161.                     // RELEASE_MODE requires that /protein_id is an accession
  162.                     // !!! need to be able to retrieve accession from server withou
  163.                     // retrieving the entire bioseq
  164.                     return true;
  165.                 }
  166.             } else if ( s_ValidId(*id) ) {
  167.                 const CTextseq_id* tsip = id->GetTextseq_Id();
  168.                 if ( tsip != 0  &&  tsip->CanGetAccession()  &&
  169.                      ValidateAccession(tsip->GetAccession()) ) {
  170.                     return true;
  171.                 }
  172.             }
  173.         }
  174.     } else {  // no product
  175.         if ( feat.CanGetExcept()  &&  feat.GetExcept()  &&
  176.              feat.CanGetExcept_text() ) {
  177.             if ( NStr::Find(feat.GetExcept_text(),
  178.                     "rearrangement required for product") != NPOS ) {
  179.                 return true;
  180.             }
  181.         }
  182.     }
  183.     return false;
  184. }
  185. // conflict and old_sequence require a publication printable on the segment
  186. static bool s_HasPub(const CSeq_feat& feat, CBioseqContext& ctx)
  187. {
  188.     if ( !feat.CanGetCit() ) {
  189.         return false;
  190.     }
  191.     ITERATE(CBioseqContext::TReferences, it, ctx.GetReferences()) {
  192.         if ( (*it)->Matches(feat.GetCit()) ) {
  193.             return true;
  194.         }
  195.     }
  196.     return false;
  197. }
  198. static bool s_CheckQuals_conflict(const CSeq_feat& feat, CBioseqContext& ctx)
  199. {
  200.     if ( !feat.CanGetCit() ) {
  201.         // RefSeq allows conflict with accession in comment instead of sfp->cit
  202.         if ( ctx.IsRefSeq()  &&
  203.              feat.CanGetComment()  &&  !feat.GetComment().empty() ) {
  204.             return true;
  205.         }
  206.     } else {
  207.         return s_HasPub(feat, ctx);
  208.     }
  209.     return false;
  210. }
  211. static bool s_CheckQuals_old_seq(const CSeq_feat& feat, CBioseqContext& ctx)
  212. {    
  213.     return s_HasPub(feat, ctx);
  214. }
  215. static bool s_CheckQuals_gene(const CSeq_feat& feat)
  216. {
  217.     // gene requires /gene or /locus_tag, but desc or syn can be mapped to /gene
  218.     const CSeqFeatData::TGene& gene = feat.GetData().GetGene();
  219.     if ( (gene.CanGetLocus()      &&  !gene.GetLocus().empty())      ||
  220.          (gene.CanGetLocus_tag()  &&  !gene.GetLocus_tag().empty())  ||
  221.          (gene.CanGetDesc()       &&  !gene.GetDesc().empty())       ||
  222.          (!gene.GetSyn().empty()  &&  !gene.GetSyn().front().empty()) ) {
  223.         return true;
  224.     }
  225.     return false;
  226. }
  227. static bool s_CheckQuals_bind(const CSeq_feat& feat)
  228. {
  229.     // protein_bind or misc_binding require eFQ_bound_moiety
  230.     return s_GetQual(feat, "bound_moiety") != 0;
  231. }
  232. static bool s_CheckQuals_mod_base(const CSeq_feat& feat)
  233. {
  234.     // modified_base requires eFQ_mod_base
  235.     return s_GetQual(feat, "mod_base") != 0;
  236. }
  237. static bool s_CheckMandatoryQuals(const CSeq_feat& feat, CBioseqContext& ctx)
  238. {
  239.     switch ( feat.GetData().GetSubtype() ) {
  240.     case CSeqFeatData::eSubtype_cdregion:
  241.         {
  242.             return s_CheckQuals_cdregion(feat, ctx);
  243.         }
  244.     case CSeqFeatData::eSubtype_conflict:
  245.         {
  246.             return s_CheckQuals_conflict(feat, ctx);
  247.         }
  248.     case CSeqFeatData::eSubtype_old_sequence:
  249.         {
  250.             return s_CheckQuals_old_seq(feat, ctx);
  251.         }
  252.     case CSeqFeatData::eSubtype_gene:
  253.         {
  254.             return s_CheckQuals_gene(feat);
  255.         }
  256.     case CSeqFeatData::eSubtype_protein_bind:
  257.     case CSeqFeatData::eSubtype_misc_binding:
  258.         {
  259.             return s_CheckQuals_bind(feat);
  260.         }
  261.     case CSeqFeatData::eSubtype_modified_base:
  262.         {
  263.             return s_CheckQuals_mod_base(feat);
  264.         }
  265.     default:
  266.         break;
  267.     }
  268.     return true;
  269. }
  270. static bool s_SkipFeature(const CSeq_feat& feat, CBioseqContext& ctx)
  271. {
  272.     CSeqFeatData::E_Choice type    = feat.GetData().Which();
  273.     CSeqFeatData::ESubtype subtype = feat.GetData().GetSubtype();        
  274.    
  275.     if ( subtype == CSeqFeatData::eSubtype_pub              ||
  276.          subtype == CSeqFeatData::eSubtype_non_std_residue  ||
  277.          subtype == CSeqFeatData::eSubtype_biosrc           ||
  278.          subtype == CSeqFeatData::eSubtype_rsite            ||
  279.          subtype == CSeqFeatData::eSubtype_seq ) {
  280.         return true;
  281.     }
  282.     
  283.     const CFlatFileConfig& cfg = ctx.Config();
  284.     // check feature customization flags
  285.     if ( cfg.ValidateFeats()  &&
  286.         (subtype == CSeqFeatData::eSubtype_bad  ||
  287.          subtype == CSeqFeatData::eSubtype_virion) ) {
  288.         return true;
  289.     }
  290.     
  291.     if ( ctx.IsNuc()  &&  subtype == CSeqFeatData::eSubtype_het ) {
  292.         return true;
  293.     }
  294.     
  295.     if ( cfg.HideImpFeats()  &&  type == CSeqFeatData::e_Imp ) {
  296.         return true;
  297.     }
  298.     
  299.     if ( cfg.HideSNPFeatures()  &&  subtype == CSeqFeatData::eSubtype_variation ) {
  300.         return true;
  301.     }
  302.     if ( cfg.HideExonFeatures()  &&  subtype == CSeqFeatData::eSubtype_exon ) {
  303.         return true;
  304.     }
  305.     if ( cfg.HideIntronFeatures()  &&  subtype == CSeqFeatData::eSubtype_intron ) {
  306.         return true;
  307.     }
  308.     if ( cfg.HideRemoteImpFeats()  &&  type == CSeqFeatData::e_Imp ) {
  309.         if ( subtype == CSeqFeatData::eSubtype_variation  ||
  310.              subtype == CSeqFeatData::eSubtype_exon       ||
  311.              subtype == CSeqFeatData::eSubtype_intron     ||
  312.              subtype == CSeqFeatData::eSubtype_misc_feature ) {
  313.             return true;
  314.         }
  315.     }
  316.     // skip genes in DDBJ format
  317.     if ( cfg.IsFormatDDBJ()  &&  type == CSeqFeatData::e_Gene ) {
  318.         return true;
  319.     }
  320.     // To Do:
  321.     // !!! supress full length comment features
  322.     // if RELEASE mode, make sure we have all info to create mandatory quals.
  323.     if ( cfg.NeedRequiredQuals() ) {
  324.         return !s_CheckMandatoryQuals(feat, ctx);
  325.     }
  326.     return false;
  327. }
  328. static const string s_BondList[] = {
  329.     "",
  330.     "disulfide",
  331.     "thiolester",
  332.     "xlink",
  333.     "thioether",
  334.     "unclassified"
  335. };
  336. static const string s_SiteList[] = {
  337.     "",
  338.     "active",
  339.     "binding",
  340.     "cleavage",
  341.     "inhibit",
  342.     "modified",
  343.     "glycosylation",
  344.     "myristoylation",
  345.     "mutagenized",
  346.     "metal-binding",
  347.     "phosphorylation",
  348.     "acetylation",
  349.     "amidation",
  350.     "methylation",
  351.     "hydroxylation",
  352.     "sulfatation",
  353.     "oxidative-deamination",
  354.     "pyrrolidone-carboxylic-acid",
  355.     "gamma-carboxyglutamic-acid",
  356.     "blocked",
  357.     "lipid-binding",
  358.     "np-binding",
  359.     "DNA binding",
  360.     "signal-peptide",
  361.     "transit-peptide",
  362.     "transmembrane-region",
  363.     "unclassified"
  364. };
  365. static const string s_PsecStrText[] = {
  366.     "",
  367.     "helix",
  368.     "sheet",
  369.     "turn"
  370. };
  371. // -- FeatureHeader
  372. CFeatHeaderItem::CFeatHeaderItem(CBioseqContext& ctx) : CFlatItem(&ctx)
  373. {
  374.     x_GatherInfo(ctx);
  375. }
  376. void CFeatHeaderItem::x_GatherInfo(CBioseqContext& ctx)
  377. {
  378.     if ( ctx.Config().IsFormatFTable() ) {
  379.         m_Id.Reset(ctx.GetPrimaryId());
  380.     }
  381. }
  382. // -- FeatureItem
  383. // constructor
  384. CFeatureItemBase::CFeatureItemBase
  385. (const CSeq_feat& feat,
  386.  CBioseqContext& ctx,
  387.  const CSeq_loc* loc) :
  388.     CFlatItem(&ctx), m_Feat(&feat), m_Loc(loc != 0 ? loc : &feat.GetLocation())
  389. {
  390. }
  391. CConstRef<CFlatFeature> CFeatureItemBase::Format(void) const
  392. {
  393.     CRef<CFlatFeature> ff(new CFlatFeature(GetKey(),
  394.                           *new CFlatSeqLoc(GetLoc(), *GetContext()),
  395.                           *m_Feat));
  396.     if ( ff ) {
  397.         x_FormatQuals(*ff);
  398.     }
  399.     return ff;
  400. }
  401. static bool s_CheckFuzz(const CInt_fuzz& fuzz)
  402. {
  403.     return !(fuzz.IsLim()  &&  fuzz.GetLim() == CInt_fuzz::eLim_unk);
  404. }
  405. static bool s_LocIsFuzz(const CSeq_feat& feat, const CSeq_loc& loc)
  406. {
  407.     if ( feat.GetData().GetSubtype() == CSeqFeatData::eSubtype_imp  &&
  408.          feat.GetData().IsImp() ) {  // unmappable impfeats
  409.         const CSeqFeatData::TImp& imp = feat.GetData().GetImp();
  410.         if ( imp.CanGetLoc() ) {
  411.             const string& imploc = imp.GetLoc();
  412.             if ( imploc.find('<') != NPOS  ||  imploc.find('>') != NPOS ) {
  413.                 return true;
  414.             }
  415.         }
  416.     } else {    // any regular feature test location for fuzz
  417.         for ( CSeq_loc_CI it(loc); it; ++it ) {
  418.             const CSeq_loc& l = it.GetSeq_loc();
  419.             switch ( l.Which() ) {
  420.             case CSeq_loc::e_Pnt:
  421.             {{
  422.                 if ( l.GetPnt().CanGetFuzz() ) {
  423.                     if ( s_CheckFuzz(l.GetPnt().GetFuzz()) ) {
  424.                         return true;
  425.                     }
  426.                 }
  427.                 break;
  428.             }}
  429.             case CSeq_loc::e_Packed_pnt:
  430.             {{
  431.                 if ( l.GetPacked_pnt().CanGetFuzz() ) {
  432.                     if ( s_CheckFuzz(l.GetPacked_pnt().GetFuzz()) ) {
  433.                         return true;
  434.                     }
  435.                 }
  436.                 break;
  437.             }}
  438.             case CSeq_loc::e_Int:
  439.             {{
  440.                 bool fuzz = false;
  441.                 if ( l.GetInt().CanGetFuzz_from() ) {
  442.                     fuzz = s_CheckFuzz(l.GetInt().GetFuzz_from());
  443.                 }
  444.                 if ( !fuzz  &&  l.GetInt().CanGetFuzz_to() ) {
  445.                     fuzz = s_CheckFuzz(l.GetInt().GetFuzz_to());
  446.                 }
  447.                 if ( fuzz ) {
  448.                     return true;
  449.                 }
  450.                 break;
  451.             }}
  452.             default:
  453.                 break;
  454.             }
  455.         }
  456.     }
  457.     return false;
  458. }
  459. /////////////////////////////////////////////////////////////////////////////
  460. //  CFeatureItem
  461. string CFeatureItem::GetKey(void) const
  462. {
  463.     CBioseqContext& ctx = *GetContext();
  464.     CSeqFeatData::E_Choice type = m_Feat->GetData().Which();
  465.     CSeqFeatData::ESubtype subtype = m_Feat->GetData().GetSubtype();
  466.     if ( GetContext()->IsProt() ) {
  467.         if ( IsMappedFromProt()  &&  type == CSeqFeatData::e_Prot ) {
  468.             if ( subtype == CSeqFeatData::eSubtype_preprotein         ||
  469.                  subtype == CSeqFeatData::eSubtype_mat_peptide_aa     ||
  470.                 subtype == CSeqFeatData::eSubtype_sig_peptide_aa     ||
  471.                 subtype == CSeqFeatData::eSubtype_transit_peptide_aa ) {
  472.                 return "Precursor";
  473.             } 
  474.         }
  475.         switch ( subtype ) {
  476.         case CSeqFeatData::eSubtype_region:
  477.             return "Region";
  478.         case CSeqFeatData::eSubtype_bond:
  479.             return "Bond";
  480.         case CSeqFeatData::eSubtype_site:
  481.             return "Site";
  482.         default:
  483.             break;
  484.         }
  485.     } else if ( subtype == CSeqFeatData::eSubtype_preprotein  &&  !ctx.IsRefSeq() ) {
  486.         return "misc_feature";
  487.     }
  488.     // deal with unmappable impfeats
  489.     if ( subtype == CSeqFeatData::eSubtype_imp  &&  type == CSeqFeatData::e_Imp ) {
  490.         const CSeqFeatData::TImp& imp = m_Feat->GetData().GetImp();
  491.         if ( imp.CanGetKey() ) {
  492.             return imp.GetKey();
  493.         }
  494.     }
  495.     return CFeatureItemBase::GetKey();
  496. }
  497. // constructor from CSeq_feat
  498. CFeatureItem::CFeatureItem
  499. (const CSeq_feat& feat,
  500.  CBioseqContext& ctx,
  501.  const CSeq_loc* loc,
  502.  EMapped mapped) :
  503.     CFeatureItemBase(feat, ctx, loc), m_Mapped(mapped)
  504. {
  505.     x_GatherInfo(ctx);
  506. }
  507. void CFeatureItem::x_GatherInfo(CBioseqContext& ctx)
  508. {
  509.     if ( s_SkipFeature(GetFeat(), ctx) ) {
  510.         x_SetSkip();
  511.         return;
  512.     }
  513.     m_Type = m_Feat->GetData().GetSubtype();
  514.     //x_FixLocation(ctx);
  515.     x_AddQuals(ctx);
  516. }
  517. void CFeatureItem::x_AddQuals(CBioseqContext& ctx)
  518. {
  519.     if ( ctx.Config().IsFormatFTable() ) {
  520.         x_AddFTableQuals(ctx);
  521.         return;
  522.     }
  523.     CScope&             scope = ctx.GetScope();
  524.     const CSeqFeatData& data  = m_Feat->GetData();
  525.     const CSeq_loc&     loc   = GetLoc();
  526.     CSeqFeatData::E_Choice type = data.Which();
  527.     CSeqFeatData::ESubtype subtype = data.GetSubtype();
  528.     bool pseudo = m_Feat->CanGetPseudo() ? m_Feat->GetPseudo() : false;
  529.     bool had_prot_desc = false;
  530.     string precursor_comment;
  531.     // add various common qualifiers...
  532.     // partial
  533.     if ( !(IsMappedFromCDNA()  &&  ctx.IsProt())  &&
  534.          !ctx.Config().HideUnclassPartial() ) {
  535.         if ( m_Feat->CanGetPartial()  &&  m_Feat->GetPartial() ) {
  536.             if ( !s_LocIsFuzz(*m_Feat, loc) ) {
  537.                 int partial = SeqLocPartialCheck(m_Feat->GetLocation(), &scope);
  538.                 if ( partial == eSeqlocPartial_Complete ) {
  539.                     x_AddQual(eFQ_partial, new CFlatBoolQVal(true));
  540.                 }
  541.             }
  542.         }
  543.     }
  544.     
  545.     // dbxref
  546.     if (m_Feat->IsSetDbxref()) {
  547.         x_AddQual(eFQ_db_xref, new CFlatXrefQVal(m_Feat->GetDbxref(), &m_Quals));
  548.     }
  549.     // model_evidance and go quals
  550.     if ( m_Feat->IsSetExt() ) {
  551.         x_AddExtQuals(m_Feat->GetExt());
  552.     }
  553.     // evidence
  554.     if ( !ctx.IsProt()  &&  m_Feat->IsSetExp_ev() ) {
  555.         x_AddQual(eFQ_evidence, new CFlatExpEvQVal(m_Feat->GetExp_ev()));
  556.     }
  557.     // citation
  558.     if (m_Feat->IsSetCit()) {
  559.         x_AddQual(eFQ_citation, new CFlatPubSetQVal(m_Feat->GetCit()));
  560.     }
  561.     // exception
  562.     x_AddExceptionQuals(ctx);
  563.     if ( !data.IsGene()  &&  (subtype != CSeqFeatData::eSubtype_operon) ) {
  564.         const CGene_ref* grp = m_Feat->GetGeneXref();
  565.         CConstRef<CSeq_feat> overlap_gene;
  566.         if ( grp != 0  &&  grp->CanGetDb() ) {
  567.             x_AddQual(eFQ_gene_xref, new CFlatXrefQVal(grp->GetDb()));
  568.         }
  569.         if ( grp == 0 ) {
  570.             const CSeq_loc& gene_loc = (ctx.IsProt()  ||  !IsMapped()) ? 
  571.                 m_Feat->GetLocation() : GetLoc();
  572.             overlap_gene = GetOverlappingGene(gene_loc, scope);
  573.             if ( overlap_gene ) {
  574.                 if ( overlap_gene->CanGetComment() ) {
  575.                     x_AddQual(eFQ_gene_note,
  576.                         new CFlatStringQVal(overlap_gene->GetComment()));
  577.                 }
  578.                 if ( overlap_gene->CanGetPseudo()  &&  overlap_gene->GetPseudo() ) {
  579.                     pseudo = true;
  580.                 }
  581.                 grp = &overlap_gene->GetData().GetGene();
  582.                 if ( grp != 0  &&  grp->IsSetDb() ) {
  583.                     x_AddQual(eFQ_gene_xref, new CFlatXrefQVal(grp->GetDb()));
  584.                 } else if ( overlap_gene->IsSetDbxref() ) {
  585.                     x_AddQual(eFQ_gene_xref, new CFlatXrefQVal(overlap_gene->GetDbxref()));
  586.                 }
  587.             }
  588.         }
  589.         if ( grp != 0 ) {
  590.             if (grp->CanGetPseudo()  &&  grp->GetPseudo() ) {
  591.                 pseudo = true;
  592.             }
  593.             if ( !grp->IsSuppressed()  &&
  594.                 (!overlap_gene  ||
  595.                  subtype != CSeqFeatData::eSubtype_repeat_region) ) {
  596.                 x_AddQuals(*grp);
  597.             }
  598.             if ( subtype != CSeqFeatData::eSubtype_variation ) {
  599.                 if ( grp->IsSetAllele()  &&  !grp->GetAllele().empty() ) {
  600.                     // now propagating /allele
  601.                     x_AddQual(eFQ_gene_allele, new CFlatStringQVal(grp->GetAllele()));
  602.                 }
  603.             }
  604.         }
  605.         if ( type != CSeqFeatData::e_Cdregion  &&  type !=  CSeqFeatData::e_Rna ) {
  606.             x_RemoveQuals(eFQ_gene_xref);
  607.         }
  608.     }
  609.     // specific fields set here...
  610.     switch ( type ) {
  611.     case CSeqFeatData::e_Gene:
  612.         x_AddGeneQuals(*m_Feat, scope);
  613.         break;
  614.     case CSeqFeatData::e_Cdregion:
  615.         x_AddCdregionQuals(*m_Feat, ctx, pseudo, had_prot_desc);
  616.         break;
  617.     case CSeqFeatData::e_Rna:
  618.         x_AddRnaQuals(*m_Feat, ctx, pseudo);
  619.         break;
  620.     case CSeqFeatData::e_Prot:
  621.         x_AddProtQuals(*m_Feat, ctx, pseudo, had_prot_desc, precursor_comment);
  622.         break;
  623.     case CSeqFeatData::e_Region:
  624.         x_AddRegionQuals(*m_Feat, ctx);
  625.         break;
  626.     // !!! case CSeqFeatData::e_XXX:
  627.     default:
  628.         break;
  629.     }
  630.     
  631.     if ( pseudo ) {
  632.         bool add_pseudo = true;
  633.         // if RELEASE_MODE, check list of features that can have /pseudo
  634.         if ( ctx.Config().DropIllegalQuals()  &&
  635.              (data.IsRna()  ||  data.IsImp()) ) {
  636.             switch ( subtype ) {
  637.             case  CSeqFeatData::eSubtype_allele:
  638.             case  CSeqFeatData::eSubtype_attenuator:
  639.             case  CSeqFeatData::eSubtype_CAAT_signal:
  640.             case  CSeqFeatData::eSubtype_conflict:
  641.             case  CSeqFeatData::eSubtype_D_loop:
  642.             case  CSeqFeatData::eSubtype_enhancer:
  643.             case  CSeqFeatData::eSubtype_GC_signal:
  644.             case  CSeqFeatData::eSubtype_iDNA:
  645.             case  CSeqFeatData::eSubtype_intron:
  646.             case  CSeqFeatData::eSubtype_LTR:
  647.             case  CSeqFeatData::eSubtype_misc_binding:
  648.             case  CSeqFeatData::eSubtype_misc_difference:
  649.             case  CSeqFeatData::eSubtype_misc_recomb:
  650.             case  CSeqFeatData::eSubtype_misc_RNA:
  651.             case  CSeqFeatData::eSubtype_misc_signal:
  652.             case  CSeqFeatData::eSubtype_misc_structure:
  653.             case  CSeqFeatData::eSubtype_modified_base:
  654.             case  CSeqFeatData::eSubtype_mutation:
  655.             case  CSeqFeatData::eSubtype_old_sequence:
  656.             case  CSeqFeatData::eSubtype_polyA_signal:
  657.             case  CSeqFeatData::eSubtype_polyA_site:
  658.             case  CSeqFeatData::eSubtype_precursor_RNA:
  659.             case  CSeqFeatData::eSubtype_prim_transcript:
  660.             case  CSeqFeatData::eSubtype_primer_bind:
  661.             case  CSeqFeatData::eSubtype_protein_bind:
  662.             case  CSeqFeatData::eSubtype_RBS:
  663.             case  CSeqFeatData::eSubtype_repeat_region:
  664.             case  CSeqFeatData::eSubtype_repeat_unit:
  665.             case  CSeqFeatData::eSubtype_rep_origin:
  666.             case  CSeqFeatData::eSubtype_satellite:
  667.             case  CSeqFeatData::eSubtype_stem_loop:
  668.             case  CSeqFeatData::eSubtype_STS:
  669.             case  CSeqFeatData::eSubtype_TATA_signal:
  670.             case  CSeqFeatData::eSubtype_terminator:
  671.             case  CSeqFeatData::eSubtype_unsure:
  672.             case  CSeqFeatData::eSubtype_variation:
  673.             case  CSeqFeatData::eSubtype_3clip:
  674.             case  CSeqFeatData::eSubtype_3UTR:
  675.             case  CSeqFeatData::eSubtype_5clip:
  676.             case  CSeqFeatData::eSubtype_5UTR:
  677.             case  CSeqFeatData::eSubtype_10_signal:
  678.             case  CSeqFeatData::eSubtype_35_signal:
  679.                 add_pseudo = false;
  680.                 break;
  681.             default:
  682.                 break;
  683.             }
  684.         }
  685.         if ( add_pseudo ) {
  686.             x_AddQual(eFQ_pseudo, new CFlatBoolQVal(true));
  687.         }
  688.     }
  689.     // comment
  690.     if (m_Feat->IsSetComment()) {
  691.         string comment = m_Feat->GetComment();
  692.         if ( had_prot_desc  &&  NStr::EndsWith(m_Feat->GetComment(), ".") ) {
  693.             comment.erase(comment.length() - 1);
  694.         }
  695.         if ( precursor_comment != comment ) {
  696.             x_AddQual(eFQ_seqfeat_note, new CFlatStringQVal(comment));
  697.         }
  698.     }
  699.     // now go through gbqual list
  700.     if (m_Feat->IsSetQual()) {
  701.         x_ImportQuals(m_Feat->GetQual());
  702.     }
  703.     // cleanup (drop illegal quals, duplicate information etc.)
  704.     x_CleanQuals();
  705. }
  706. static const string s_TrnaList[] = {
  707.   "tRNA-Gap",
  708.   "tRNA-Ala",
  709.   "tRNA-Asx",
  710.   "tRNA-Cys",
  711.   "tRNA-Asp",
  712.   "tRNA-Glu",
  713.   "tRNA-Phe",
  714.   "tRNA-Gly",
  715.   "tRNA-His",
  716.   "tRNA-Ile",
  717.   "tRNA-Lys",
  718.   "tRNA-Leu",
  719.   "tRNA-Met",
  720.   "tRNA-Asn",
  721.   "tRNA-Pro",
  722.   "tRNA-Gln",
  723.   "tRNA-Arg",
  724.   "tRNA-Ser",
  725.   "tRNA-Thr",
  726.   "tRNA-Sec",
  727.   "tRNA-Val",
  728.   "tRNA-Trp",
  729.   "tRNA-OTHER",
  730.   "tRNA-Tyr",
  731.   "tRNA-Glx",
  732.   "tRNA-TERM"
  733. };
  734. static const string& s_AaName(int aa)
  735. {
  736.     int shift = 0, idx = 255;
  737.     if ( aa <= 74 ) {
  738.         shift = 0;
  739.     } else if (aa > 79) {
  740.         shift = 2;
  741.     } else {
  742.         shift = 1;
  743.     }
  744.     if (aa != '*') {
  745.         idx = aa - (64 + shift);
  746.     } else {
  747.         idx = 25;
  748.     }
  749.     if ( idx > 0 && idx < 26 ) {
  750.         return s_TrnaList [idx];
  751.     }
  752.     return kEmptyStr;
  753. }
  754. static int s_ToIupacaa(int aa)
  755. {
  756.     vector<char> n(1, static_cast<char>(aa));
  757.     vector<char> i;
  758.     CSeqConvert::Convert(n, CSeqUtil::e_Ncbieaa, 0, 1, i, CSeqUtil::e_Iupacaa);
  759.     return i.front();
  760. }
  761. void CFeatureItem::x_AddRnaQuals
  762. (const CSeq_feat& feat,
  763.  CBioseqContext& ctx,
  764.  bool& pseudo) const
  765. {
  766.     const CRNA_ref& rna = feat.GetData().GetRna();
  767.     const CFlatFileConfig& cfg = ctx.Config();
  768.     if ( rna.CanGetPseudo()  &&  rna.GetPseudo() ) {
  769.         pseudo = true;
  770.     }
  771.     CRNA_ref::TType rna_type = rna.CanGetType() ?
  772.         rna.GetType() : CRNA_ref::eType_unknown;
  773.     switch ( rna_type ) {
  774.     case CRNA_ref::eType_tRNA:
  775.     {
  776.         if ( rna.CanGetExt() ) {
  777.             const CRNA_ref::C_Ext& ext = rna.GetExt();
  778.             switch ( ext.Which() ) {
  779.             case CRNA_ref::C_Ext::e_Name:
  780.             {
  781.                 // amino acid could not be parsed into structured form
  782.                 if ( !cfg.DropIllegalQuals() ) {
  783.                     x_AddQual(eFQ_product,
  784.                               new CFlatStringQVal(ext.GetName()));
  785.                 } else {
  786.                     x_AddQual(eFQ_product,
  787.                               new CFlatStringQVal("tRNA-OTHER"));
  788.                 }
  789.                 break;
  790.             }
  791.             case CRNA_ref::C_Ext::e_TRNA:
  792.             {
  793.                 const CTrna_ext& trna = ext.GetTRNA();
  794.                 int aa = 0;
  795.                 if ( trna.CanGetAa()  &&  trna.GetAa().IsNcbieaa() ) {
  796.                     aa = trna.GetAa().GetNcbieaa();
  797.                 } else {
  798.                     // !!!
  799.                     return;
  800.                 }
  801.                 if ( cfg.IupacaaOnly() ) {
  802.                     aa = s_ToIupacaa(aa);
  803.                 }
  804.                 const string& aa_str = s_AaName(aa);
  805.                 if ( !aa_str.empty() ) {
  806.                     x_AddQual(eFQ_product, new CFlatStringQVal(aa_str));
  807.                     if ( trna.CanGetAnticodon()  &&  !aa_str.empty() ) {
  808.                         x_AddQual(eFQ_anticodon,
  809.                             new CFlatAnticodonQVal(trna.GetAnticodon(),
  810.                                                    aa_str.substr(5, NPOS)));
  811.                     }
  812.                 }
  813.                 if ( trna.IsSetCodon() ) {
  814.                     x_AddQual(eFQ_trna_codons, new CFlatTrnaCodonsQVal(trna));
  815.                 }
  816.                 break;
  817.             }
  818.             default:
  819.                 break;
  820.             } // end of internal switch
  821.         }
  822.         break;
  823.     }
  824.     case CRNA_ref::eType_mRNA:
  825.     {
  826.         try {
  827.             if ( feat.CanGetProduct() ) {
  828.                 const CSeq_id& id = GetId(feat.GetProduct(), &ctx.GetScope());
  829.                 CBioseq_Handle prod = 
  830.                     ctx.GetScope().GetBioseqHandleFromTSE(id, ctx.GetHandle());
  831.                 EFeatureQualifier slot = 
  832.                     (ctx.IsRefSeq()  ||  cfg.IsModeDump()  ||  cfg.IsModeGBench()) ?
  833.                     eFQ_transcript_id : eFQ_transcript_id_note;
  834.                 if ( prod ) {
  835.                     x_AddProductIdQuals(prod, slot);
  836.                 } else {
  837.                     x_AddQual(slot, new CFlatSeqIdQVal(id));
  838.                     if ( id.IsGi() ) {
  839.                         x_AddQual(eFQ_db_xref, new CFlatSeqIdQVal(id, true));
  840.                     }
  841.                 }
  842.             }
  843.         } catch (CNotUnique&) {}
  844.         if ( !pseudo  &&  cfg.ShowTranscript() ) {
  845.             CSeqVector vec(feat.GetLocation(), ctx.GetScope());
  846.             vec.SetCoding(CBioseq_Handle::eCoding_Iupac);
  847.             string transcription;
  848.             vec.GetSeqData(0, vec.size(), transcription);
  849.             x_AddQual(eFQ_transcription, new CFlatStringQVal(transcription));
  850.         }
  851.         // intentional fall through
  852.     }
  853.     default:
  854.         if ( rna.CanGetExt()  &&  rna.GetExt().IsName() ) {
  855.             x_AddQual(eFQ_product, new CFlatStringQVal(rna.GetExt().GetName()));
  856.         }
  857.         break;
  858.     } // end of switch
  859. }
  860. void CFeatureItem::x_AddGeneQuals(const CSeq_feat& gene, CScope& scope) const
  861. {
  862.     _ASSERT(gene.GetData().Which() == CSeqFeatData::e_Gene);
  863.     x_AddQuals(gene.GetData().GetGene());
  864.     CConstRef<CSeq_feat> operon =
  865.         GetOverlappingOperon(gene.GetLocation(), scope);
  866.     if ( operon ) {
  867.         ITERATE (CSeq_feat::TQual, it, operon->GetQual()) {
  868.             if ( (*it)->CanGetQual()  &&  (*it)->GetQual() == "operon"  &&
  869.                  (*it)->CanGetVal() ) {
  870.                 x_AddQual(eFQ_operon, new CFlatStringQVal((*it)->GetVal()));
  871.             }
  872.         }
  873.     }
  874. }
  875. void CFeatureItem::x_AddCdregionQuals
  876. (const CSeq_feat& cds,
  877.  CBioseqContext& ctx,
  878.  bool& pseudo, bool& had_prot_desc) const
  879. {
  880.     CScope& scope = ctx.GetScope();
  881.     const CFlatFileConfig& cfg = ctx.Config();
  882.     
  883.     x_AddQuals(cds.GetData().GetCdregion());
  884.     if ( ctx.IsProt()  &&  IsMappedFromCDNA() ) {
  885.         x_AddQual(eFQ_coded_by, new CFlatSeqLocQVal(m_Feat->GetLocation()));
  886.     } else {
  887.         // protein qualifiers
  888.         if ( m_Feat->CanGetProduct() ) {
  889.             const CSeq_id* prot_id = 0;
  890.             // protein id
  891.             try {
  892.                 prot_id = &GetId(m_Feat->GetProduct(), &scope);
  893.                 CBioseq_Handle h = scope.GetBioseqHandle(*prot_id);
  894.                 if (h) {
  895.                     prot_id = &GetId(h, eGetId_Best);
  896.                 }
  897.             } catch (CException&) {
  898.                 prot_id = 0;
  899.             }
  900.             
  901.             if ( prot_id != 0 ) {
  902.                 CBioseq_Handle prot;
  903.                 if ( !cfg.AlwaysTranslateCDS() ) {
  904.                     // by default only show /translation if product bioseq is within
  905.                     // entity, but flag can override and force far /translation
  906.                     prot = cfg.ShowFarTranslations() ? 
  907.                         scope.GetBioseqHandle(*prot_id) : 
  908.                         scope.GetBioseqHandleFromTSE(*prot_id, ctx.GetHandle());
  909.                 }
  910.                 const CProt_ref* pref = 0;
  911.                 if ( prot ) {
  912.                     // Add protein quals (comment, note, names ...) 
  913.                     pref = x_AddProteinQuals(prot);
  914.                 } else {
  915.                     x_AddQual(eFQ_protein_id, new CFlatSeqIdQVal(*prot_id));
  916.                     if ( prot_id->IsGi() ) {
  917.                         x_AddQual(eFQ_db_xref, new CFlatSeqIdQVal(*prot_id, true));
  918.                     }
  919.                 }
  920.                 
  921.                 // protein xref overrides names, but should not prevent /protein_id, etc.
  922.                 const CProt_ref* p = m_Feat->GetProtXref();
  923.                 if ( p != 0 ) {
  924.                     pref = p;
  925.                 }
  926.                 if ( pref != 0 ) {
  927.                     if ( !pref->GetName().empty() ) {
  928.                         CProt_ref::TName names = pref->GetName();
  929.                         x_AddQual(eFQ_cds_product, new CFlatStringQVal(names.front()));
  930.                         names.pop_front();
  931.                         if ( !names.empty() ) {
  932.                             x_AddQual(eFQ_prot_names, new CFlatStringListQVal(names));
  933.                         }
  934.                     }
  935.                     if ( pref->CanGetDesc() ) {
  936.                         x_AddQual(eFQ_prot_desc, new CFlatStringQVal(pref->GetDesc()));
  937.                         had_prot_desc = true;
  938.                     }
  939.                     if ( !pref->GetActivity().empty() ) {
  940.                         x_AddQual(eFQ_prot_activity,
  941.                             new CFlatStringListQVal(pref->GetActivity()));
  942.                     }
  943.                     if ( !pref->GetEc().empty() ) {
  944.                         x_AddQual(eFQ_prot_EC_number,
  945.                             new CFlatStringListQVal(pref->GetEc()));
  946.                     }
  947.                 }
  948.                 // translation
  949.                 if ( !pseudo ) {
  950.                     string translation;
  951.                     if ( (!prot  &&  cfg.TranslateIfNoProduct())  ||
  952.                         cfg.AlwaysTranslateCDS() ) {
  953.                         CCdregion_translate::TranslateCdregion(translation, *m_Feat,
  954.                             scope);
  955.                     } else if ( prot ) {
  956.                         TSeqPos len = GetLength(cds.GetProduct(), &scope);
  957.                         if ( len > 0 ){
  958.                             CSeqVector seqv = 
  959.                                 prot.GetSeqVector(CBioseq_Handle::eCoding_Ncbi);
  960.                             if ( cfg.IupacaaOnly() ) {
  961.                                 seqv.SetCoding(CSeq_data::e_Iupacaa);
  962.                             } else {
  963.                                 seqv.SetCoding(CSeq_data::e_Ncbieaa);
  964.                             }
  965.                             seqv.GetSeqData(0, seqv.size(), translation);
  966.                         }
  967.                     }
  968.                     if ( !translation.empty() ) {
  969.                         x_AddQual(eFQ_translation, new CFlatStringQVal(translation));
  970.                     } else {
  971.                         // !!! release mode error
  972.                     }
  973.                 }
  974.             }
  975.         }
  976.     }
  977. }
  978. const CProt_ref* CFeatureItem::x_AddProteinQuals(CBioseq_Handle& prot) const
  979. {
  980.     _ASSERT(prot);
  981.     x_AddProductIdQuals(prot, eFQ_protein_id);
  982.     CSeqdesc_CI comm(prot, CSeqdesc::e_Comment, 1);
  983.     if ( comm  &&  !comm->GetComment().empty() ) {
  984.         x_AddQual(eFQ_prot_comment, new CFlatStringQVal(comm->GetComment()));
  985.     }
  986.     CSeqdesc_CI mi(prot, CSeqdesc::e_Molinfo);
  987.     if ( mi ) {
  988.         CMolInfo::TTech prot_tech = mi->GetMolinfo().GetTech();
  989.         if ( prot_tech >  CMolInfo::eTech_standard       &&
  990.              prot_tech != CMolInfo::eTech_concept_trans  &&
  991.              prot_tech != CMolInfo::eTech_concept_trans_a ) {
  992.             if ( !GetTechString(prot_tech).empty() ) {
  993.                 x_AddQual(eFQ_prot_method, 
  994.                     new CFlatStringQVal("Method: " + GetTechString(prot_tech)));
  995.             }
  996.         }
  997.     }
  998.     const CProt_ref* pref = 0;
  999.     CFeat_CI prot_feat(prot, 0, 0, CSeqFeatData::e_Prot);
  1000.     if ( prot_feat ) {
  1001.         pref = &(prot_feat->GetData().GetProt());
  1002.         if ( prot_feat->IsSetComment() ) {
  1003.             if ( pref->GetProcessed() == CProt_ref::eProcessed_not_set  ||
  1004.                  pref->GetProcessed() == CProt_ref::eProcessed_preprotein ) {
  1005.                 x_AddQual(eFQ_prot_note, 
  1006.                     new CFlatStringQVal(prot_feat->GetComment()));
  1007.             }
  1008.         }
  1009.     }
  1010.     bool maploc = false, fig = false;
  1011.     for ( CSeqdesc_CI it(prot, CSeqdesc::e_Pub); it; ++it ) {
  1012.         const CPubdesc& pub = it->GetPub();
  1013.         if ( !maploc  &&  pub.CanGetMaploc() ) {
  1014.             string mapstr = "Map location " + pub.GetMaploc();
  1015.             RemovePeriodFromEnd(mapstr);
  1016.             x_AddQual(eFQ_maploc, new CFlatStringQVal(mapstr));
  1017.             maploc = true;
  1018.         }
  1019.         if ( !fig  &&  pub.CanGetFig() ) {
  1020.             string figstr = "This sequence comes from " + pub.GetFig();
  1021.             RemovePeriodFromEnd(figstr);
  1022.             x_AddQual(eFQ_figure, new CFlatStringQVal(figstr));
  1023.             fig = true;
  1024.         }
  1025.     }
  1026.     return pref;
  1027. }
  1028. static const string s_ValidExceptionText[] = {
  1029.   "RNA editing",
  1030.   "reasons given in citation"
  1031. };
  1032. static const string s_ValidRefSeqExceptionText[] = {
  1033.     "RNA editing",
  1034.     "alternative processing",
  1035.     "alternative start codon",
  1036.     "artificial frameshift",
  1037.     "modified codon recognition",
  1038.     "nonconsensus splice site",
  1039.     "rearrangement required for product",
  1040.     "reasons given in citation",
  1041.     "ribosomal slippage",
  1042.     "trans-splicing",
  1043.     "unclassified transcription discrepancy",
  1044.     "unclassified translation discrepancy"
  1045. };
  1046. static bool s_IsValidExceptionText(const string& text)
  1047. {
  1048.     CStaticArraySet<string> legal_text(s_ValidExceptionText,
  1049.         sizeof(s_ValidExceptionText));
  1050.     return legal_text.find(text) != legal_text.end();
  1051. }
  1052. static bool s_IsValidRefSeqExceptionText(const string& text)
  1053. {
  1054.     CStaticArraySet<string> legal_refseq_text(s_ValidRefSeqExceptionText,
  1055.         sizeof(s_ValidRefSeqExceptionText));
  1056.     return legal_refseq_text.find(text) != legal_refseq_text.end();
  1057. }
  1058. static void s_ParseException
  1059. (const string& original,
  1060.  string& except,
  1061.  string& note,
  1062.  CBioseqContext& ctx)
  1063. {
  1064.     if ( original.empty() ) {
  1065.         return;
  1066.     }
  1067.     except.erase();
  1068.     note.erase();
  1069.     if ( !ctx.Config().DropIllegalQuals() ) {
  1070.         except = original;
  1071.         return;
  1072.     }
  1073.     list<string> l;
  1074.     NStr::Split(original, ",", l);
  1075.     NON_CONST_ITERATE (list<string>, it, l) {
  1076.         NStr::TruncateSpaces(*it);
  1077.     }
  1078.     list<string> except_list, note_list;
  1079.     ITERATE (list<string>, it, l) {
  1080.         if ( s_IsValidExceptionText(*it)  ||
  1081.              s_IsValidRefSeqExceptionText(*it) ) {
  1082.             except_list.push_back(*it);
  1083.         } else {
  1084.             note_list.push_back(*it);
  1085.         }
  1086.     }
  1087.     except = NStr::Join(except_list, ", ");
  1088.     note = NStr::Join(note_list, ", ");
  1089. }
  1090. void CFeatureItem::x_AddExceptionQuals(CBioseqContext& ctx) const
  1091. {
  1092.     string except_text, note_text;
  1093.     const CFlatFileConfig& cfg = ctx.Config();
  1094.     if ( m_Feat->CanGetExcept_text()  &&  !m_Feat->GetExcept_text().empty() ) {
  1095.         except_text = m_Feat->GetExcept_text();
  1096.     }
  1097.     
  1098.     // /exception currently legal only on cdregion
  1099.     if ( m_Feat->GetData().IsCdregion()  ||  !cfg.DropIllegalQuals() ) {
  1100.         // exception flag is set, but no exception text supplied
  1101.         if ( except_text.empty()  &&
  1102.              m_Feat->CanGetExcept()  &&  m_Feat->GetExcept() ) {
  1103.             // if no /exception text, use text in comment, remove from /note
  1104.             if ( x_HasQual(eFQ_seqfeat_note) ) {
  1105.                 const CFlatStringQVal* qval = 
  1106.                     dynamic_cast<const CFlatStringQVal*>(x_GetQual(eFQ_seqfeat_note).first->second.GetPointerOrNull());
  1107.                 if ( qval != 0 ) {
  1108.                     const string& seqfeat_note = qval->GetValue();
  1109.                     if ( !cfg.DropIllegalQuals()  ||
  1110.                         s_IsValidExceptionText(seqfeat_note) ) {
  1111.                         except_text = seqfeat_note;
  1112.                         x_RemoveQuals(eFQ_seqfeat_note);
  1113.                     }
  1114.                 }
  1115.             } else {
  1116.                 except_text = "No explanation supplied";
  1117.             }
  1118.             // if DropIllegalQuals is set, check CDS list here as well
  1119.             if ( cfg.DropIllegalQuals()  &&
  1120.                  !s_IsValidExceptionText(except_text) ) {
  1121.                 except_text.erase();
  1122.             }
  1123.         }
  1124.         
  1125.         if ( cfg.DropIllegalQuals() ) {
  1126.             string except = except_text;
  1127.             s_ParseException(except, except_text, note_text, ctx);
  1128.         }
  1129.     } else if ( !except_text.empty() ) {
  1130.         note_text = except_text;
  1131.         except_text.erase();
  1132.     }
  1133.     if ( !except_text.empty() ) {
  1134.         x_AddQual(eFQ_exception, new CFlatStringQVal(except_text));
  1135.     }
  1136.     if ( !note_text.empty() ) {
  1137.         x_AddQual(eFQ_exception_note, new CFlatStringQVal(note_text));
  1138.     }
  1139. }
  1140. void CFeatureItem::x_AddProductIdQuals(CBioseq_Handle& prod, EFeatureQualifier slot) const
  1141. {
  1142.     if ( !prod ) {
  1143.         return;
  1144.     }
  1145.     const CBioseq::TId& ids = prod.GetBioseqCore()->GetId();
  1146.     if ( ids.empty() ) {
  1147.         return;
  1148.     }
  1149.     // the product id (transcript or protein) is set to the best id
  1150.     const CSeq_id* best = FindBestChoice(ids, CSeq_id::Score);
  1151.     if ( best != 0 ) {
  1152.         switch ( best->Which() ) {
  1153.         case CSeq_id::e_Genbank:
  1154.         case CSeq_id::e_Embl:
  1155.         case CSeq_id::e_Ddbj:
  1156.         case CSeq_id::e_Gi:
  1157.         case CSeq_id::e_Other:
  1158.         case CSeq_id::e_General:
  1159.         case CSeq_id::e_Tpg:
  1160.         case CSeq_id::e_Tpe:
  1161.         case CSeq_id::e_Tpd:
  1162.             // these are the only types we allow as product ids
  1163.             break;
  1164.         default:
  1165.             best = 0;
  1166.         }
  1167.     }
  1168.     if ( best == 0 ) {
  1169.         return;
  1170.     }
  1171.     x_AddQual(slot, new CFlatSeqIdQVal(*best));
  1172.     ITERATE (CBioseq::TId, it, ids) {
  1173.         const CSeq_id& id = **it;
  1174.         CSeq_id::E_Choice choice = id.Which();
  1175.         if ( choice != CSeq_id::e_Genbank  &&
  1176.              choice != CSeq_id::e_Embl  &&
  1177.              choice != CSeq_id::e_Ddbj  &&
  1178.              choice != CSeq_id::e_Gi  &&
  1179.              choice != CSeq_id::e_Other  &&
  1180.              choice != CSeq_id::e_General  &&
  1181.              choice != CSeq_id::e_Tpg  &&
  1182.              choice != CSeq_id::e_Tpe  &&
  1183.              choice != CSeq_id::e_Tpd ) {
  1184.             continue;
  1185.         }
  1186.         if ( &id == best  &&  !id.IsGi() ) {
  1187.             // we've already done 'best'. 
  1188.             continue;
  1189.         }
  1190.         if ( id.IsGeneral() ) {
  1191.             const CDbtag& dbt = id.GetGeneral();
  1192.             if ( dbt.GetType() != CDbtag::eDbtagType_PID ) {
  1193.                 if ( ids.size() == 1 ) {
  1194.                     x_AddQual(eFQ_db_xref, new CFlatSeqIdQVal(id, id.IsGi()));
  1195.                 }
  1196.             }
  1197.         } else {
  1198.             x_AddQual(eFQ_db_xref, new CFlatSeqIdQVal(id, id.IsGi()));
  1199.         }
  1200.     }
  1201. }
  1202. void CFeatureItem::x_AddRegionQuals(const CSeq_feat& feat, CBioseqContext& ctx) const
  1203. {
  1204.     const string& region = feat.GetData().GetRegion();
  1205.     if ( region.empty() ) {
  1206.         return;
  1207.     }
  1208.     if ( ctx.IsProt()  &&
  1209.          feat.GetData().GetSubtype() == CSeqFeatData::eSubtype_region ) {
  1210.         x_AddQual(eFQ_region_name, new CFlatStringQVal(region));
  1211.     } else {
  1212.         x_AddQual(eFQ_region, new CFlatStringQVal("Region: " + region));
  1213.     }
  1214. }
  1215. void CFeatureItem::x_AddExtQuals(const CSeq_feat::TExt& ext) const
  1216. {
  1217.     ITERATE (CUser_object::TData, it, ext.GetData()) {
  1218.         const CUser_field& field = **it;
  1219.         if ( !field.CanGetData() ) {
  1220.             continue;
  1221.         }
  1222.         if ( field.GetData().IsObject() ) {
  1223.             const CUser_object& obj = field.GetData().GetObject();
  1224.             x_AddExtQuals(obj);
  1225.             return;
  1226.         } else if ( field.GetData().IsObjects() ) {
  1227.             ITERATE (CUser_field::C_Data::TObjects, o, field.GetData().GetObjects()) {
  1228.                 x_AddExtQuals(**o);
  1229.             }
  1230.             return;
  1231.         }
  1232.     }
  1233.     if ( ext.CanGetType()  &&  ext.GetType().IsStr() ) {
  1234.         const string& oid = ext.GetType().GetStr();
  1235.         if ( oid == "ModelEvidence" ) {
  1236.             x_AddQual(eFQ_modelev, new CFlatModelEvQVal(ext));
  1237.         } else if ( oid == "GeneOntology" ) {
  1238.             x_AddGoQuals(ext);
  1239.         }
  1240.     }
  1241. }
  1242. void CFeatureItem::x_AddGoQuals(const CUser_object& uo) const
  1243. {
  1244.     ITERATE (CUser_object::TData, uf_it, uo.GetData()) {
  1245.         const CUser_field& field = **uf_it;
  1246.         if ( field.IsSetLabel()  &&  field.GetLabel().IsStr() ) {
  1247.             const string& label = field.GetLabel().GetStr();
  1248.             EFeatureQualifier slot = eFQ_none;
  1249.             if ( label == "Process" ) {
  1250.                 slot = eFQ_go_process;
  1251.             } else if ( label == "Component" ) {               
  1252.                 slot = eFQ_go_component;
  1253.             } else if ( label == "Function" ) {
  1254.                 slot = eFQ_go_function;
  1255.             }
  1256.             if ( slot == eFQ_none ) {
  1257.                 continue;
  1258.             }
  1259.             ITERATE (CUser_field::TData::TFields, it, field.GetData().GetFields()) {
  1260.                 if ( (*it)->GetData().IsFields() ) {
  1261.                     x_AddQual(slot, new CFlatGoQVal(**it));
  1262.                 }
  1263.             }
  1264.         }
  1265.     }
  1266. }
  1267. void CFeatureItem::x_AddQuals(const CGene_ref& gene) const
  1268. {
  1269.     const string* locus = (gene.IsSetLocus()  &&  !gene.GetLocus().empty()) ?
  1270.         &gene.GetLocus() : 0;
  1271.     
  1272.     const string* desc = (gene.IsSetDesc() &&  !gene.GetDesc().empty()) ?
  1273.         &gene.GetDesc() : 0;
  1274.     const CGene_ref::TSyn* syn = (gene.IsSetSyn()  &&  !gene.GetSyn().empty()) ?
  1275.         &gene.GetSyn() : 0;
  1276.     const string* locus_tag = 
  1277.         (gene.IsSetLocus_tag()  &&  !gene.GetLocus_tag().empty()) ?
  1278.         &gene.GetLocus_tag() : 0;
  1279.     if ( locus ) {
  1280.         x_AddQual(eFQ_gene, new CFlatStringQVal(*locus));
  1281.         if ( locus_tag ) {
  1282.             x_AddQual(eFQ_locus_tag, new CFlatStringQVal(*locus_tag));
  1283.         }
  1284.         if ( desc ) {
  1285.             x_AddQual(eFQ_gene_desc, new CFlatStringQVal(*desc));
  1286.         }
  1287.         if ( syn ) {
  1288.             x_AddQual(eFQ_gene_syn, new CFlatStringListQVal(*syn));
  1289.         }
  1290.     } else if ( locus_tag ) {
  1291.         x_AddQual(eFQ_locus_tag, new CFlatStringQVal(*locus_tag));
  1292.         if ( desc ) {
  1293.             x_AddQual(eFQ_gene_desc, new CFlatStringQVal(*desc));
  1294.         }
  1295.         if ( syn ) {
  1296.             x_AddQual(eFQ_gene_syn, new CFlatStringListQVal(*syn));
  1297.         }
  1298.     } else if ( desc ) {
  1299.         x_AddQual(eFQ_gene, new CFlatStringQVal(*desc));
  1300.         if ( syn ) {
  1301.             x_AddQual(eFQ_gene_syn, new CFlatStringListQVal(*syn));
  1302.         }
  1303.     } else if ( syn ) {
  1304.         CGene_ref::TSyn syns = *syn;
  1305.         x_AddQual(eFQ_gene, new CFlatStringQVal(syns.front()));
  1306.         syns.pop_front();
  1307.         if ( !syns.empty() ) {
  1308.             x_AddQual(eFQ_gene_syn, new CFlatStringListQVal(syns));
  1309.         }
  1310.     }
  1311.     if ( gene.IsSetAllele()  &&  !gene.GetAllele().empty() ) {
  1312.         x_AddQual(eFQ_gene_allele, new CFlatStringQVal(gene.GetAllele()));
  1313.     }
  1314.     if ( gene.IsSetMaploc()  &&  !gene.GetMaploc().empty() ) {
  1315.         x_AddQual(eFQ_gene_map, new CFlatStringQVal(gene.GetMaploc()));
  1316.     }
  1317.     if ( gene.IsSetDb() ) {
  1318.         x_AddQual(eFQ_gene_xref, new CFlatXrefQVal(gene.GetDb()));
  1319.     }
  1320.     if ( gene.GetPseudo() ) {
  1321.         x_AddQual(eFQ_pseudo, new CFlatBoolQVal(true));
  1322.     }
  1323. }
  1324. void CFeatureItem::x_AddQuals(const CCdregion& cds) const
  1325. {
  1326.     CBioseqContext& ctx = *GetContext();
  1327.     CScope& scope = ctx.GetScope();
  1328.     CCdregion::TFrame frame = cds.GetFrame();
  1329.     // code break
  1330.     if ( cds.IsSetCode_break() ) {
  1331.         // set selenocysteine quals
  1332.         ITERATE (CCdregion::TCode_break, it, cds.GetCode_break()) {
  1333.             if ( !(*it)->IsSetAa() ) {
  1334.                 continue;
  1335.             }
  1336.             const CCode_break::C_Aa& cbaa = (*it)->GetAa();
  1337.             bool is_U = false;
  1338.             switch ( cbaa.Which() ) {
  1339.             case CCode_break::C_Aa::e_Ncbieaa:
  1340.                 is_U = (cbaa.GetNcbieaa() == 'U');
  1341.                 break;
  1342.             case CCode_break::C_Aa::e_Ncbi8aa:
  1343.                 is_U = (cbaa.GetNcbieaa() == 'U');
  1344.             case CCode_break::C_Aa::e_Ncbistdaa:
  1345.                 is_U = (cbaa.GetNcbieaa() == 24);
  1346.                 break;
  1347.             default:
  1348.                 break;
  1349.             }
  1350.             
  1351.             if ( is_U ) {
  1352.                 if ( ctx.Config().SelenocysteineToNote() ) {
  1353.                     x_AddQual(eFQ_selenocysteine_note,
  1354.                         new CFlatStringQVal("selenocysteine"));
  1355.                 } else {
  1356.                     x_AddQual(eFQ_selenocysteine, new CFlatBoolQVal(true));
  1357.                 }
  1358.                 break;
  1359.             }
  1360.         }
  1361.     }
  1362.     // translation table
  1363.     if ( cds.CanGetCode() ) {
  1364.         int gcode = cds.GetCode().GetId();
  1365.         if ( gcode > 0  &&  gcode != 255 ) {
  1366.             // show code 1 only in GBSeq format.
  1367.             if ( ctx.Config().IsFormatGBSeq()  ||  gcode > 1 ) {
  1368.                 x_AddQual(eFQ_transl_table, new CFlatIntQVal(gcode));
  1369.             }
  1370.         }
  1371.     }
  1372.     if ( !(ctx.IsProt()  && IsMappedFromCDNA()) ) {
  1373.         // frame
  1374.         if ( frame == CCdregion::eFrame_not_set ) {
  1375.             frame = CCdregion::eFrame_one;
  1376.         }
  1377.         x_AddQual(eFQ_codon_start, new CFlatIntQVal(frame));
  1378.         // translation exception
  1379.         if ( cds.IsSetCode_break() ) {
  1380.             x_AddQual(eFQ_transl_except, 
  1381.                 new CFlatCodeBreakQVal(cds.GetCode_break()));
  1382.         }
  1383.         
  1384.         // protein conflict
  1385.         static const string conflic_msg = 
  1386.             "Protein sequence is in conflict with the conceptual translation";
  1387.         bool has_prot = m_Feat->IsSetProduct()  &&
  1388.                         (GetLength(m_Feat->GetProduct(), &scope) > 0);
  1389.         if ( cds.CanGetConflict()  &&  cds.GetConflict()  &&  has_prot ) {
  1390.             x_AddQual(eFQ_prot_conflict, new CFlatStringQVal(conflic_msg));
  1391.         }
  1392.     } else {
  1393.         // frame
  1394.         if ( frame > 1 ) {
  1395.             x_AddQual(eFQ_codon_start, new CFlatIntQVal(frame));
  1396.         }
  1397.     }
  1398. }
  1399. void CFeatureItem::x_AddProtQuals
  1400. (const CSeq_feat& feat,
  1401.  CBioseqContext& ctx, 
  1402.  bool& pseudo,
  1403.  bool& had_prot_desc,
  1404.  string& precursor_comment) const
  1405. {
  1406.     const CProt_ref& pref = feat.GetData().GetProt();
  1407.     CProt_ref::TProcessed processed = pref.GetProcessed();
  1408.     if ( ctx.IsNuc()  ||  (ctx.IsProt()  &&  !IsMappedFromProt()) ) {
  1409.         if ( pref.IsSetName()  &&  !pref.GetName().empty() ) {
  1410.             CProt_ref::TName names = pref.GetName();
  1411.             x_AddQual(eFQ_product, new CFlatStringQVal(names.front()));
  1412.             names.pop_front();
  1413.             if ( !names.empty() ) {
  1414.                 x_AddQual(eFQ_prot_names, new CFlatStringListQVal(names));
  1415.             }
  1416.         }
  1417.         if ( pref.CanGetDesc()  &&  !pref.GetDesc().empty() ) {
  1418.             if ( !ctx.IsProt() ) {
  1419.                 x_AddQual(eFQ_prot_desc, new CFlatStringQVal(pref.GetDesc()));
  1420.                 had_prot_desc = true;
  1421.             } else {
  1422.                 x_AddQual(eFQ_prot_name, new CFlatStringQVal(pref.GetDesc()));
  1423.             }
  1424.         }
  1425.         if ( pref.IsSetActivity()  &&  !pref.GetActivity().empty() ) {
  1426.             if ( ctx.IsNuc()  ||  processed != CProt_ref::eProcessed_mature ) {
  1427.                 x_AddQual(eFQ_prot_activity, 
  1428.                     new CFlatStringListQVal(pref.GetActivity()));
  1429.             }
  1430.         }
  1431.         if ( feat.CanGetProduct() ) {
  1432.             CBioseq_Handle prot = 
  1433.                 ctx.GetScope().GetBioseqHandle(feat.GetProduct());
  1434.             if ( prot ) {
  1435.                 x_AddProductIdQuals(prot, eFQ_protein_id);
  1436.             } else {
  1437.                 try {
  1438.                     const CSeq_id& prod_id = 
  1439.                         GetId(feat.GetProduct(), &ctx.GetScope());
  1440.                     if ( ctx.IsRefSeq()  ||  !ctx.Config().ForGBRelease() ) {
  1441.                         x_AddQual(eFQ_protein_id, new CFlatSeqIdQVal(prod_id));
  1442.                     }
  1443.                 } catch (CNotUnique&) {}
  1444.             }
  1445.         }
  1446.     } else { // protein feature on subpeptide bioseq
  1447.         x_AddQual(eFQ_derived_from, new CFlatSeqLocQVal(m_Feat->GetLocation()));
  1448.         // check precursor_comment
  1449.         CConstRef<CSeq_feat> prot = 
  1450.             GetBestOverlappingFeat(m_Feat->GetProduct(),
  1451.                                    CSeqFeatData::e_Prot,
  1452.                                    eOverlap_Simple,
  1453.                                    ctx.GetScope());
  1454.         if ( (bool)prot  &&  prot->CanGetComment() ) {
  1455.             precursor_comment = prot->GetComment();
  1456.         }
  1457.     }
  1458.     if ( !pseudo  &&  ctx.Config().ShowPeptides() ) {
  1459.         if ( processed == CProt_ref::eProcessed_mature          ||
  1460.              processed == CProt_ref::eProcessed_signal_peptide  ||
  1461.              processed == CProt_ref::eProcessed_transit_peptide ) {
  1462.             CSeqVector pep(m_Feat->GetLocation(), ctx.GetScope());
  1463.             string peptide;
  1464.             pep.GetSeqData(pep.begin(), pep.end(), peptide);
  1465.             if ( !peptide.empty() ) {
  1466.                 x_AddQual(eFQ_peptide, new CFlatStringQVal(peptide));
  1467.             }
  1468.         }
  1469.     }
  1470.     // cleanup
  1471.     if ( processed == CProt_ref::eProcessed_signal_peptide  ||
  1472.          processed == CProt_ref::eProcessed_transit_peptide ) {
  1473.         if ( !ctx.IsRefSeq() ) {
  1474.            // Only RefSeq allows product on signal or transit peptide
  1475.            x_RemoveQuals(eFQ_product);
  1476.         }
  1477.     }
  1478.     if ( processed == CProt_ref::eProcessed_preprotein  &&
  1479.          !ctx.IsRefSeq()  &&  !ctx.IsProt()  &&  
  1480.          feat.GetData().GetSubtype() == CSeqFeatData::eSubtype_preprotein ) {
  1481.         TQI product = m_Quals.Find(eFQ_product);
  1482.         if (  product != m_Quals.end() ) {
  1483.             x_AddQual(eFQ_encodes, product->second);
  1484.             x_RemoveQuals(eFQ_product);
  1485.         }
  1486.     }
  1487. }
  1488. struct SLegalImport {
  1489.     const char*       m_Name;
  1490.     EFeatureQualifier m_Value;
  1491.     operator string(void) const { return m_Name; }
  1492. };
  1493. void CFeatureItem::x_ImportQuals(const CSeq_feat::TQual& quals) const
  1494. {
  1495.     typedef pair<const char*, EFeatureQualifier> TLegalImport;
  1496.     static const TLegalImport kLegalImports[] = {
  1497.         // Must be in case-insensitive alphabetical order!
  1498. #define DO_IMPORT(x) TLegalImport(#x, eFQ_##x)
  1499.         DO_IMPORT(allele),
  1500.         DO_IMPORT(bound_moiety),
  1501.         DO_IMPORT(clone),
  1502.         DO_IMPORT(codon),
  1503.         DO_IMPORT(cons_splice),
  1504.         DO_IMPORT(direction),
  1505.         DO_IMPORT(EC_number),
  1506.         DO_IMPORT(evidence),
  1507.         DO_IMPORT(frequency),
  1508.         DO_IMPORT(function),
  1509.         DO_IMPORT(insertion_seq),
  1510.         DO_IMPORT(label),
  1511.         DO_IMPORT(map),
  1512.         DO_IMPORT(mod_base),
  1513.         DO_IMPORT(number),
  1514.         DO_IMPORT(organism),
  1515.         DO_IMPORT(PCR_conditions),
  1516.         DO_IMPORT(phenotype),
  1517.         TLegalImport("product", eFQ_product_quals),
  1518.         DO_IMPORT(replace),
  1519.         DO_IMPORT(rpt_family),
  1520.         DO_IMPORT(rpt_type),
  1521.         DO_IMPORT(rpt_unit),
  1522.         DO_IMPORT(standard_name),
  1523.         DO_IMPORT(transposon),
  1524.         DO_IMPORT(usedin)
  1525. #undef DO_IMPORT
  1526.     };
  1527.     typedef const CStaticArrayMap<const char*, EFeatureQualifier, PNocase> TLegalImportMap;
  1528.     static TLegalImportMap kLegalImportMap(kLegalImports, sizeof(kLegalImports));
  1529.     ITERATE (CSeq_feat::TQual, it, quals) {
  1530.         const char* name = (*it)->GetQual().c_str();
  1531.         const TLegalImportMap::const_iterator li = kLegalImportMap.find(name);
  1532.         EFeatureQualifier   slot = eFQ_illegal_qual;
  1533.         if ( li != kLegalImportMap.end() ) {
  1534.             slot = li->second;
  1535.         }
  1536.         switch (slot) {
  1537.         case eFQ_codon:
  1538.         case eFQ_cons_splice:
  1539.         case eFQ_direction:
  1540.         case eFQ_evidence:
  1541.         case eFQ_mod_base:
  1542.         case eFQ_number:
  1543.         case eFQ_rpt_type:
  1544.         case eFQ_rpt_unit:
  1545.         case eFQ_usedin:
  1546.             // XXX -- each of these should really get its own class
  1547.             // (to verify correct syntax)
  1548.             x_AddQual(slot, new CFlatStringQVal((*it)->GetVal(),
  1549.                 CFormatQual::eUnquoted));
  1550.             break;
  1551.         case eFQ_label:
  1552.             x_AddQual(slot, new CFlatLabelQVal((*it)->GetVal()));
  1553.             break;
  1554.         case eFQ_illegal_qual:
  1555.             x_AddQual(slot, new CFlatIllegalQVal(**it));
  1556.             break;
  1557.         default:
  1558.             // XXX - should split off EC_number and replace
  1559.             // (to verify correct syntax)
  1560.             x_AddQual(slot, new CFlatStringQVal((*it)->GetVal()));
  1561.             break;
  1562.         }
  1563.     }
  1564. }
  1565. void CFeatureItem::x_FormatQuals(CFlatFeature& ff) const
  1566. {
  1567.     const CFlatFileConfig& cfg = GetContext()->Config();
  1568.     if ( cfg.IsFormatFTable() ) {
  1569.         ff.SetQuals() = m_FTableQuals;
  1570.         return;
  1571.     }
  1572.     ff.SetQuals().reserve(m_Quals.Size());
  1573.     CFlatFeature::TQuals& qvec = ff.SetQuals();
  1574. #define DO_QUAL(x) x_FormatQual(eFQ_##x, #x, qvec)
  1575.     DO_QUAL(partial);
  1576.     DO_QUAL(gene);
  1577.     DO_QUAL(locus_tag);
  1578.     DO_QUAL(gene_syn_refseq);
  1579.     x_FormatQual(eFQ_gene_allele, "allele", qvec);
  1580.     DO_QUAL(operon);
  1581.     DO_QUAL(product);
  1582.     x_FormatQual(eFQ_prot_EC_number, "EC_number", qvec);
  1583.     x_FormatQual(eFQ_prot_activity,  "function", qvec);
  1584.     DO_QUAL(standard_name);
  1585.     DO_QUAL(coded_by);
  1586.     DO_QUAL(derived_from);
  1587.     x_FormatQual(eFQ_prot_name, "name", qvec);
  1588.     DO_QUAL(region_name);
  1589.     DO_QUAL(bond_type);
  1590.     DO_QUAL(site_type);
  1591.     DO_QUAL(sec_str_type);
  1592.     DO_QUAL(heterogen);
  1593.     if ( !cfg.GoQualsToNote() ) {
  1594.         DO_QUAL(go_component);
  1595.         DO_QUAL(go_function);
  1596.         DO_QUAL(go_process);
  1597.     }
  1598.     x_FormatNoteQuals(ff);
  1599.         
  1600.     DO_QUAL(citation);
  1601.     DO_QUAL(number);
  1602.     DO_QUAL(pseudo);
  1603.     DO_QUAL(selenocysteine);
  1604.     DO_QUAL(codon_start);
  1605.     DO_QUAL(anticodon);
  1606.     DO_QUAL(bound_moiety);
  1607.     DO_QUAL(clone);
  1608.     DO_QUAL(cons_splice);
  1609.     DO_QUAL(direction);
  1610.     DO_QUAL(function);
  1611.     DO_QUAL(evidence);
  1612.     DO_QUAL(exception);
  1613.     DO_QUAL(frequency);
  1614.     DO_QUAL(EC_number);
  1615.     x_FormatQual(eFQ_gene_map, "map", qvec);
  1616.     DO_QUAL(allele);
  1617.     DO_QUAL(map);
  1618.     DO_QUAL(mod_base);
  1619.     DO_QUAL(PCR_conditions);
  1620.     DO_QUAL(phenotype);
  1621.     DO_QUAL(rpt_family);
  1622.     DO_QUAL(rpt_type);
  1623.     DO_QUAL(rpt_unit);
  1624.     DO_QUAL(insertion_seq);
  1625.     DO_QUAL(transposon);
  1626.     DO_QUAL(usedin);
  1627.     // extra imports, actually...
  1628.     x_FormatQual(eFQ_illegal_qual, "illegal", qvec);
  1629.     DO_QUAL(replace);
  1630.     DO_QUAL(transl_except);
  1631.     DO_QUAL(transl_table);
  1632.     DO_QUAL(codon);
  1633.     DO_QUAL(organism);
  1634.     DO_QUAL(label);
  1635.     x_FormatQual(eFQ_cds_product, "product", qvec);
  1636.     DO_QUAL(protein_id);
  1637.     DO_QUAL(transcript_id);
  1638.     DO_QUAL(db_xref);
  1639.     x_FormatQual(eFQ_gene_xref, "db_xref", qvec);
  1640.     DO_QUAL(translation);
  1641.     DO_QUAL(transcription);
  1642.     DO_QUAL(peptide);
  1643. #undef DO_QUAL
  1644. }
  1645. void CFeatureItem::x_FormatNoteQuals(CFlatFeature& ff) const
  1646. {
  1647.     CFlatFeature::TQuals qvec;
  1648. #define DO_NOTE(x) x_FormatNoteQual(eFQ_##x, #x, qvec)
  1649.     x_FormatNoteQual(eFQ_transcript_id_note, "tscpt_id_note", qvec);
  1650.     DO_NOTE(gene_desc);
  1651.     DO_NOTE(gene_syn);
  1652.     DO_NOTE(trna_codons);
  1653.     DO_NOTE(prot_desc);
  1654.     DO_NOTE(prot_note);
  1655.     DO_NOTE(prot_comment);
  1656.     DO_NOTE(prot_method);
  1657.     DO_NOTE(figure);
  1658.     DO_NOTE(maploc);
  1659.     DO_NOTE(prot_conflict);
  1660.     DO_NOTE(prot_missing);
  1661.     DO_NOTE(seqfeat_note);
  1662.     DO_NOTE(exception_note);
  1663.     DO_NOTE(region);
  1664.     DO_NOTE(selenocysteine_note);
  1665.     DO_NOTE(prot_names);
  1666.     DO_NOTE(bond);
  1667.     DO_NOTE(site);
  1668.     DO_NOTE(rrna_its);
  1669.     DO_NOTE(xtra_prod_quals);
  1670.     DO_NOTE(modelev);
  1671.     if ( GetContext()->Config().GoQualsToNote() ) {
  1672.         DO_NOTE(go_component);
  1673.         DO_NOTE(go_function);
  1674.         DO_NOTE(go_process);
  1675.     }
  1676. #undef DO_NOTE
  1677.     string notestr;
  1678.     const string* suffix = &kEmptyStr;
  1679.     CFlatFeature::TQuals::const_iterator last = qvec.end();
  1680.     CFlatFeature::TQuals::const_iterator end = last--;
  1681.     CFlatFeature::TQuals::const_iterator it = qvec.begin();
  1682.     bool add_period = false;
  1683.     for ( ; it != end; ++it ) {
  1684.         add_period = false;
  1685.         string note = (*it)->GetValue();
  1686.         if ( NStr::EndsWith(note, ".")  &&  !NStr::EndsWith(note, "...") ) {
  1687.             note.erase(note.length() - 1);
  1688.             add_period = true;
  1689.         }
  1690.         const string& prefix = *suffix + (*it)->GetPrefix();
  1691.         JoinNoRedund(notestr, prefix, note);
  1692.         suffix = &(*it)->GetSuffix();
  1693.     }
  1694.     if ( !notestr.empty() ) {
  1695.         NStr::TruncateSpaces(notestr);
  1696.         if ( add_period  &&  !NStr::EndsWith(notestr, ".") ) {
  1697.             notestr += ".";
  1698.         }
  1699.         CRef<CFormatQual> note(new CFormatQual("note", 
  1700.             ExpandTildes(notestr, eTilde_newline)));
  1701.         ff.SetQuals().push_back(note);
  1702.     }
  1703. }
  1704. void CFeatureItem::x_FormatQual
  1705. (EFeatureQualifier slot,
  1706.  const string& name,
  1707.  CFlatFeature::TQuals& qvec,
  1708.  IFlatQVal::TFlags flags) const
  1709. {
  1710.     pair<TQCI, TQCI> range = const_cast<const TQuals&>(m_Quals).GetQuals(slot);
  1711.     for (TQCI it = range.first;  it != range.second;  ++it) {
  1712.         it->second->Format(qvec, name, *GetContext(), flags);
  1713.     }
  1714. }
  1715. const CFlatStringQVal* CFeatureItem::x_GetStringQual(EFeatureQualifier slot) const
  1716. {
  1717.     const IFlatQVal* qual = 0;
  1718.     if ( x_HasQual(slot) ) {
  1719.         qual = m_Quals.Find(slot)->second;
  1720.     }
  1721.     return dynamic_cast<const CFlatStringQVal*>(qual);
  1722. }
  1723. void CFeatureItem::x_CleanQuals(void) const
  1724. {
  1725.     if ( GetContext()->Config().DropIllegalQuals() ) {
  1726.         x_DropIllegalQuals();
  1727.     }
  1728.     const CFlatStringQVal* gene = x_GetStringQual(eFQ_gene);
  1729.     if ( gene != 0 ) {
  1730.         // /gene same as feature.comment will suppress /note
  1731.         if ( m_Feat->CanGetComment() ) {
  1732.             if ( NStr::Equal(gene->GetValue(), m_Feat->GetComment()) ) {
  1733.                 x_RemoveQuals(eFQ_seqfeat_note);
  1734.             }
  1735.         }
  1736.         // remove protein description that equals the gene name, case sensitive
  1737.         const CFlatStringQVal* prod_desc = x_GetStringQual(eFQ_prot_desc);
  1738.         if ( prod_desc != 0 ) {
  1739.             if ( NStr::Equal(gene->GetValue(), prod_desc->GetValue()) ) {
  1740.                 x_RemoveQuals(eFQ_prot_desc);
  1741.             }
  1742.         }
  1743.     }
  1744. }
  1745. typedef pair<EFeatureQualifier, CSeqFeatData::EQualifier> TQualPair;
  1746. static const TQualPair sc_GbToFeatQualMap[] = {
  1747.     TQualPair(eFQ_none, CSeqFeatData::eQual_bad),
  1748.     TQualPair(eFQ_allele, CSeqFeatData::eQual_allele),
  1749.     TQualPair(eFQ_anticodon, CSeqFeatData::eQual_anticodon),
  1750.     TQualPair(eFQ_bond, CSeqFeatData::eQual_note),
  1751.     TQualPair(eFQ_bond_type, CSeqFeatData::eQual_bad),
  1752.     TQualPair(eFQ_bound_moiety, CSeqFeatData::eQual_bound_moiety),
  1753.     TQualPair(eFQ_cds_product, CSeqFeatData::eQual_product),
  1754.     TQualPair(eFQ_citation, CSeqFeatData::eQual_citation),
  1755.     TQualPair(eFQ_clone, CSeqFeatData::eQual_clone),
  1756.     TQualPair(eFQ_coded_by, CSeqFeatData::eQual_bad),
  1757.     TQualPair(eFQ_codon, CSeqFeatData::eQual_codon),
  1758.     TQualPair(eFQ_codon_start, CSeqFeatData::eQual_codon_start),
  1759.     TQualPair(eFQ_cons_splice, CSeqFeatData::eQual_cons_splice),
  1760.     TQualPair(eFQ_db_xref, CSeqFeatData::eQual_db_xref),
  1761.     TQualPair(eFQ_derived_from, CSeqFeatData::eQual_bad),
  1762.     TQualPair(eFQ_direction, CSeqFeatData::eQual_direction),
  1763.     TQualPair(eFQ_EC_number, CSeqFeatData::eQual_EC_number),
  1764.     TQualPair(eFQ_encodes, CSeqFeatData::eQual_note),
  1765.     TQualPair(eFQ_evidence, CSeqFeatData::eQual_evidence),
  1766.     TQualPair(eFQ_exception, CSeqFeatData::eQual_exception),
  1767.     TQualPair(eFQ_exception_note, CSeqFeatData::eQual_note),
  1768.     TQualPair(eFQ_figure, CSeqFeatData::eQual_note),
  1769.     TQualPair(eFQ_frequency, CSeqFeatData::eQual_frequency),
  1770.     TQualPair(eFQ_function, CSeqFeatData::eQual_function),
  1771.     TQualPair(eFQ_gene, CSeqFeatData::eQual_gene),
  1772.     TQualPair(eFQ_gene_desc, CSeqFeatData::eQual_note),
  1773.     TQualPair(eFQ_gene_allele, CSeqFeatData::eQual_allele),
  1774.     TQualPair(eFQ_gene_map, CSeqFeatData::eQual_bad),
  1775.     TQualPair(eFQ_gene_syn, CSeqFeatData::eQual_note),
  1776.     TQualPair(eFQ_gene_syn_refseq, CSeqFeatData::eQual_bad),
  1777.     TQualPair(eFQ_gene_note, CSeqFeatData::eQual_note),
  1778.     TQualPair(eFQ_gene_xref, CSeqFeatData::eQual_db_xref),
  1779.     TQualPair(eFQ_go_component, CSeqFeatData::eQual_note),
  1780.     TQualPair(eFQ_go_function, CSeqFeatData::eQual_note),
  1781.     TQualPair(eFQ_go_process, CSeqFeatData::eQual_note),
  1782.     TQualPair(eFQ_heterogen, CSeqFeatData::eQual_bad),
  1783.     TQualPair(eFQ_illegal_qual, CSeqFeatData::eQual_bad),
  1784.     TQualPair(eFQ_insertion_seq, CSeqFeatData::eQual_insertion_seq),
  1785.     TQualPair(eFQ_label, CSeqFeatData::eQual_label),
  1786.     TQualPair(eFQ_locus_tag, CSeqFeatData::eQual_locus_tag),
  1787.     TQualPair(eFQ_map, CSeqFeatData::eQual_map),
  1788.     TQualPair(eFQ_maploc, CSeqFeatData::eQual_note),
  1789.     TQualPair(eFQ_mod_base, CSeqFeatData::eQual_mod_base),
  1790.     TQualPair(eFQ_modelev, CSeqFeatData::eQual_note),
  1791.     TQualPair(eFQ_number, CSeqFeatData::eQual_number),
  1792.     TQualPair(eFQ_operon, CSeqFeatData::eQual_operon),
  1793.     TQualPair(eFQ_organism, CSeqFeatData::eQual_organism),
  1794.     TQualPair(eFQ_partial, CSeqFeatData::eQual_partial),
  1795.     TQualPair(eFQ_PCR_conditions, CSeqFeatData::eQual_PCR_conditions),
  1796.     TQualPair(eFQ_peptide, CSeqFeatData::eQual_bad),
  1797.     TQualPair(eFQ_phenotype, CSeqFeatData::eQual_phenotype),
  1798.     TQualPair(eFQ_product, CSeqFeatData::eQual_product),
  1799.     TQualPair(eFQ_product_quals, CSeqFeatData::eQual_product),
  1800.     TQualPair(eFQ_prot_activity, CSeqFeatData::eQual_bad),
  1801.     TQualPair(eFQ_prot_comment, CSeqFeatData::eQual_note),
  1802.     TQualPair(eFQ_prot_EC_number, CSeqFeatData::eQual_bad),
  1803.     TQualPair(eFQ_prot_note, CSeqFeatData::eQual_note),
  1804.     TQualPair(eFQ_prot_method, CSeqFeatData::eQual_note),
  1805.     TQualPair(eFQ_prot_conflict, CSeqFeatData::eQual_note),
  1806.     TQualPair(eFQ_prot_desc, CSeqFeatData::eQual_note),
  1807.     TQualPair(eFQ_prot_missing, CSeqFeatData::eQual_note),
  1808.     TQualPair(eFQ_prot_name, CSeqFeatData::eQual_bad),
  1809.     TQualPair(eFQ_prot_names, CSeqFeatData::eQual_note),
  1810.     TQualPair(eFQ_protein_id, CSeqFeatData::eQual_protein_id),
  1811.     TQualPair(eFQ_pseudo, CSeqFeatData::eQual_pseudo),
  1812.     TQualPair(eFQ_region, CSeqFeatData::eQual_note),
  1813.     TQualPair(eFQ_region_name, CSeqFeatData::eQual_bad),
  1814.     TQualPair(eFQ_replace, CSeqFeatData::eQual_replace),
  1815.     TQualPair(eFQ_rpt_family, CSeqFeatData::eQual_rpt_family),
  1816.     TQualPair(eFQ_rpt_type, CSeqFeatData::eQual_rpt_type),
  1817.     TQualPair(eFQ_rpt_unit, CSeqFeatData::eQual_rpt_unit),
  1818.     TQualPair(eFQ_rrna_its, CSeqFeatData::eQual_note),
  1819.     TQualPair(eFQ_sec_str_type, CSeqFeatData::eQual_bad),
  1820.     TQualPair(eFQ_selenocysteine, CSeqFeatData::eQual_bad),
  1821.     TQualPair(eFQ_selenocysteine_note, CSeqFeatData::eQual_note),
  1822.     TQualPair(eFQ_seqfeat_note, CSeqFeatData::eQual_note),
  1823.     TQualPair(eFQ_site, CSeqFeatData::eQual_note),
  1824.     TQualPair(eFQ_site_type, CSeqFeatData::eQual_bad),
  1825.     TQualPair(eFQ_standard_name, CSeqFeatData::eQual_bad),
  1826.     TQualPair(eFQ_transcription, CSeqFeatData::eQual_bad),
  1827.     TQualPair(eFQ_transcript_id, CSeqFeatData::eQual_bad),
  1828.     TQualPair(eFQ_transcript_id_note, CSeqFeatData::eQual_note),
  1829.     TQualPair(eFQ_transl_except, CSeqFeatData::eQual_transl_except),
  1830.     TQualPair(eFQ_transl_table, CSeqFeatData::eQual_transl_table),
  1831.     TQualPair(eFQ_translation, CSeqFeatData::eQual_translation),
  1832.     TQualPair(eFQ_transposon, CSeqFeatData::eQual_transposon),
  1833.     TQualPair(eFQ_trna_aa, CSeqFeatData::eQual_bad),
  1834.     TQualPair(eFQ_trna_codons, CSeqFeatData::eQual_note),
  1835.     TQualPair(eFQ_usedin, CSeqFeatData::eQual_usedin),
  1836.     TQualPair(eFQ_xtra_prod_quals, CSeqFeatData::eQual_note)
  1837. };
  1838. typedef CStaticArrayMap<EFeatureQualifier, CSeqFeatData::EQualifier> TQualMap;
  1839. static const TQualMap sc_QualMap(sc_GbToFeatQualMap, sizeof(sc_GbToFeatQualMap));
  1840. static CSeqFeatData::EQualifier s_GbToSeqFeatQual(EFeatureQualifier qual)
  1841. {
  1842.     TQualMap::const_iterator it = sc_QualMap.find(qual);
  1843.     if ( it != sc_QualMap.end() ) {
  1844.         return it->second;
  1845.     }
  1846.     return CSeqFeatData::eQual_bad;
  1847. }
  1848. void CFeatureItem::x_DropIllegalQuals(void) const
  1849. {
  1850.     const CSeqFeatData& data = m_Feat->GetData();
  1851.     TQI it = m_Quals.begin();
  1852.     while ( it != m_Quals.end() ) {
  1853.         CSeqFeatData::EQualifier qual = s_GbToSeqFeatQual(it->first);
  1854.         if ( !data.IsLegalQualifier(qual) ) {
  1855.             it = m_Quals.Erase(it);
  1856.         } else {
  1857.             ++it;
  1858.         }
  1859.     }
  1860. }
  1861. void CFeatureItem::x_AddFTableQuals(CBioseqContext& ctx) const
  1862. {
  1863.     bool pseudo = m_Feat->CanGetPseudo()  &&  m_Feat->GetPseudo();
  1864.     const CSeqFeatData& data = m_Feat->GetData();
  1865.     switch ( m_Feat->GetData().Which() ) {
  1866.     case CSeqFeatData::e_Gene:
  1867.         pseudo |= x_AddFTableGeneQuals(data.GetGene());
  1868.         break;
  1869.     case CSeqFeatData::e_Rna:
  1870.         x_AddFTableRnaQuals(*m_Feat, ctx);
  1871.         break;
  1872.     case CSeqFeatData::e_Cdregion:
  1873.         x_AddFTableCdregionQuals(*m_Feat, ctx);
  1874.         break;
  1875.     case CSeqFeatData::e_Prot:
  1876.         x_AddFTableProtQuals(*m_Feat);
  1877.         break;
  1878.     case CSeqFeatData::e_Region:
  1879.         x_AddFTableRegionQuals(data.GetRegion());
  1880.         break;
  1881.     case CSeqFeatData::e_Bond:
  1882.         x_AddFTableBondQuals(data.GetBond());
  1883.         break;
  1884.     case CSeqFeatData::e_Site:
  1885.         x_AddFTableSiteQuals(data.GetSite());
  1886.         break;
  1887.     case CSeqFeatData::e_Psec_str:
  1888.         x_AddFTablePsecStrQuals(data.GetPsec_str());
  1889.         break;
  1890.     case CSeqFeatData::e_Het:
  1891.         x_AddFTablePsecStrQuals(data.GetHet());
  1892.         break;
  1893.     case CSeqFeatData::e_Biosrc:
  1894.         x_AddFTableBiosrcQuals(data.GetBiosrc());
  1895.         break;
  1896.     default:
  1897.         break;
  1898.     }
  1899.     if ( pseudo ) {
  1900.         x_AddFTableQual("pseudo");
  1901.     }
  1902.     const CGene_ref* grp = m_Feat->GetGeneXref();
  1903.     if ( grp != 0  &&  grp->IsSuppressed() ) {
  1904.         x_AddFTableQual("gene", "-");
  1905.     }
  1906.     if ( m_Feat->CanGetComment()  &&  !m_Feat->GetComment().empty() ) {
  1907.         x_AddFTableQual("note", m_Feat->GetComment());
  1908.     }
  1909.     if ( m_Feat->CanGetExp_ev() ) {
  1910.         string ev;
  1911.         switch ( m_Feat->GetExp_ev() ) {
  1912.         case CSeq_feat::eExp_ev_experimental:
  1913.             ev = "experimental";
  1914.             break;
  1915.         case CSeq_feat::eExp_ev_not_experimental:
  1916.             ev = "not_experimental";
  1917.             break;
  1918.         }
  1919.         x_AddFTableQual("evidence", ev);
  1920.     }
  1921.     if ( m_Feat->CanGetExcept_text()  &&  !m_Feat->GetExcept_text().empty() ) {
  1922.         x_AddFTableQual("exception", m_Feat->GetExcept_text());
  1923.     } else if ( m_Feat->CanGetExcept()  &&  m_Feat->GetExcept() ) {
  1924.         x_AddFTableQual("exception");
  1925.     }
  1926.     ITERATE (CSeq_feat::TQual, it, m_Feat->GetQual()) {
  1927.         const CGb_qual& qual = **it;
  1928.         const string& key = qual.CanGetQual() ? qual.GetQual() : kEmptyStr;
  1929.         const string& val = qual.CanGetVal() ? qual.GetVal() : kEmptyStr;
  1930.         if ( !key.empty()  &&  !val.empty() ) {
  1931.             x_AddFTableQual(key, val);
  1932.         }
  1933.     }
  1934.     if ( m_Feat->IsSetExt() ) {
  1935.         x_AddFTableExtQuals(m_Feat->GetExt());
  1936.     }
  1937.     if ( data.IsGene() ) {
  1938.         x_AddFTableDbxref(data.GetGene().GetDb());
  1939.     } else if ( data.IsProt() ) {
  1940.         x_AddFTableDbxref(data.GetProt().GetDb());
  1941.     }
  1942.     x_AddFTableDbxref(m_Feat->GetDbxref());
  1943. }
  1944. void CFeatureItem::x_AddFTableExtQuals(const CSeq_feat::TExt& ext) const
  1945. {
  1946.     ITERATE (CUser_object::TData, it, ext.GetData()) {
  1947.         const CUser_field& field = **it;
  1948.         if ( !field.CanGetData() ) {
  1949.             continue;
  1950.         }
  1951.         if ( field.GetData().IsObject() ) {
  1952.             const CUser_object& obj = field.GetData().GetObject();
  1953.             x_AddExtQuals(obj);
  1954.             return;
  1955.         } else if ( field.GetData().IsObjects() ) {
  1956.             ITERATE (CUser_field::C_Data::TObjects, o, field.GetData().GetObjects()) {
  1957.                 x_AddExtQuals(**o);
  1958.             }
  1959.             return;
  1960.         }
  1961.     }
  1962.     if ( ext.CanGetType()  &&  ext.GetType().IsStr() ) {
  1963.         const string& oid = ext.GetType().GetStr();
  1964.         if ( oid == "GeneOntology" ) {
  1965.             ITERATE (CUser_object::TData, uf_it, ext.GetData()) {
  1966.                 const CUser_field& field = **uf_it;
  1967.                 if ( field.IsSetLabel()  &&  field.GetLabel().IsStr() ) {
  1968.                     const string& label = field.GetLabel().GetStr();
  1969.                     string name;
  1970.                     if ( label == "Process" ) {
  1971.                         name = "go_process";
  1972.                     } else if ( label == "Component" ) {               
  1973.                         name = "go_component";
  1974.                     } else if ( label == "Function" ) {
  1975.                         name = "go_function";
  1976.                     }
  1977.                     if ( name.empty() ) {
  1978.                         continue;
  1979.                     }
  1980.                     
  1981.                     ITERATE (CUser_field::TData::TFields, it, field.GetData().GetFields()) {
  1982.                         if ( (*it)->GetData().IsFields() ) {
  1983.                             CFlatGoQVal(**it).Format(m_FTableQuals, name, *GetContext(), 0);;
  1984.                         }
  1985.                     }
  1986.                 }
  1987.             }
  1988.         }
  1989.     }
  1990. }
  1991. void CFeatureItem::x_AddFTableDbxref(const CSeq_feat::TDbxref& dbxref) const
  1992. {
  1993.     ITERATE (CSeq_feat::TDbxref, it, dbxref) {
  1994.         const CDbtag& dbt = **it;
  1995.         if ( dbt.CanGetDb()  &&  !dbt.GetDb().empty()  &&
  1996.              dbt.CanGetTag() ) {
  1997.             const CObject_id& oid = dbt.GetTag();
  1998.             switch ( oid.Which() ) {
  1999.             case CObject_id::e_Str:
  2000.                 if ( !oid.GetStr().empty() ) {
  2001.                     x_AddFTableQual("db_xref", dbt.GetDb() + ":" + oid.GetStr());
  2002.                 }
  2003.                 break;
  2004.             case CObject_id::e_Id:
  2005.                 x_AddFTableQual("db_xref", dbt.GetDb() + ":" + NStr::IntToString(oid.GetId()));
  2006.                 break;
  2007.             default:
  2008.                 break;
  2009.             }
  2010.         }
  2011.     }
  2012. }
  2013. bool CFeatureItem::x_AddFTableGeneQuals(const CGene_ref& gene) const
  2014. {
  2015.     if ( gene.CanGetLocus()  &&  !gene.GetLocus().empty() ) {
  2016.         x_AddFTableQual("gene", gene.GetLocus());
  2017.     }
  2018.     ITERATE (CGene_ref::TSyn, it, gene.GetSyn()) {
  2019.         x_AddFTableQual("gene_syn", *it);
  2020.     }
  2021.     if ( gene.CanGetDesc()  &&  !gene.GetDesc().empty() ) {
  2022.         x_AddFTableQual("gene_desc", gene.GetDesc());
  2023.     }
  2024.     if ( gene.CanGetMaploc()  &&  !gene.GetMaploc().empty() ) {
  2025.         x_AddFTableQual("map", gene.GetMaploc());
  2026.     }
  2027.     if ( gene.CanGetLocus_tag()  &&  !gene.GetLocus_tag().empty() ) {
  2028.         x_AddFTableQual("locus_tag", gene.GetLocus_tag());
  2029.     }
  2030.     return (gene.CanGetPseudo()  &&  gene.GetPseudo());
  2031. }
  2032. void CFeatureItem::x_AddFTableRnaQuals(const CSeq_feat& feat, CBioseqContext& ctx) const
  2033. {
  2034.     string label;
  2035.     if ( !feat.GetData().IsRna() ) {
  2036.         return;
  2037.     }
  2038.     const CSeqFeatData::TRna& rna = feat.GetData().GetRna();
  2039.     if ( rna.CanGetExt() ) {
  2040.         const CRNA_ref::TExt& ext = rna.GetExt();
  2041.         switch ( ext.Which() ) {
  2042.         case CRNA_ref::TExt::e_Name:
  2043.             if ( !ext.GetName().empty() ) {
  2044.                 x_AddFTableQual("product", ext.GetName());
  2045.             }
  2046.             break;
  2047.         case CRNA_ref::TExt::e_TRNA:
  2048.             feature::GetLabel(feat, &label, feature::eContent, &ctx.GetScope());
  2049.             x_AddFTableQual("product", label);
  2050.             break;
  2051.         }
  2052.     }
  2053.     if ( feat.CanGetProduct() ) {
  2054.         CBioseq_Handle prod = 
  2055.             ctx.GetScope().GetBioseqHandle(m_Feat->GetProduct());
  2056.         if ( prod ) {
  2057.             const CSeq_id& id = GetId(prod, eGetId_Best);
  2058.             string id_str;
  2059.             if ( id.IsGenbank()  ||  id.IsEmbl()  ||  id.IsDdbj()  ||
  2060.                  id.IsTpg()  ||  id.IsTpd()  ||  id.IsTpe()  ||
  2061.                  id.IsOther() ||
  2062.                  (id.IsLocal()  &&  !ctx.Config().SuppressLocalId()) ) {
  2063.                 id_str = id.GetSeqIdString(true);
  2064.             } else if ( id.IsGeneral() ) {
  2065.                 id_str = id.AsFastaString();
  2066.             }
  2067.             x_AddFTableQual("transcript_id", id_str);
  2068.         }
  2069.     }
  2070. }
  2071. void CFeatureItem::x_AddFTableCdregionQuals(const CSeq_feat& feat, CBioseqContext& ctx) const
  2072. {
  2073.     CBioseq_Handle prod;
  2074.     if ( feat.CanGetProduct() ) {
  2075.         prod = ctx.GetScope().GetBioseqHandle(feat.GetProduct());
  2076.     }
  2077.     if ( prod ) {
  2078.         CConstRef<CSeq_feat> prot = GetBestOverlappingFeat(
  2079.             feat.GetProduct(),
  2080.             CSeqFeatData::e_Prot,
  2081.             eOverlap_Simple,
  2082.             ctx.GetScope());
  2083.         if ( prot ) {
  2084.             x_AddFTableProtQuals(*prot);
  2085.         }
  2086.     }
  2087.     const CCdregion& cdr = feat.GetData().GetCdregion();
  2088.     if ( cdr.CanGetFrame()  &&  cdr.GetFrame() > CCdregion::eFrame_one ) {
  2089.         x_AddFTableQual("codon_start", NStr::IntToString(cdr.GetFrame()));
  2090.     }
  2091.     ITERATE (CCdregion::TCode_break, it, cdr.GetCode_break()) {
  2092.         string pos = CFlatSeqLoc((*it)->GetLoc(), ctx).GetString();
  2093.         string aa  = "OTHER";
  2094.         switch ((*it)->GetAa().Which()) {
  2095.         case CCode_break::C_Aa::e_Ncbieaa:
  2096.             aa = GetAAName((*it)->GetAa().GetNcbieaa(), true);
  2097.             break;
  2098.         case CCode_break::C_Aa::e_Ncbi8aa:
  2099.             aa = GetAAName((*it)->GetAa().GetNcbi8aa(), false);
  2100.             break;
  2101.         case CCode_break::C_Aa::e_Ncbistdaa:
  2102.             aa = GetAAName((*it)->GetAa().GetNcbistdaa(), false);
  2103.             break;
  2104.         default:
  2105.             break;
  2106.         }
  2107.         x_AddFTableQual("transl_except", "(pos:" + pos + ",aa:" + aa + ")");
  2108.     }
  2109.     const CSeq_id* id = 0;
  2110.     string id_str;
  2111.     if ( prod ) {
  2112.         id = &GetId(prod, eGetId_Best);
  2113.     } else if ( feat.CanGetProduct() ) {
  2114.         try { 
  2115.             id = &GetId(feat.GetProduct(), &ctx.GetScope());
  2116.             if ( id->IsGi() ) {
  2117.                 // get "normal" id 
  2118.             }
  2119.         } catch (CNotUnique&) {
  2120.             id = 0;
  2121.         }
  2122.     }
  2123.     if ( id != 0 ) {
  2124.         if ( id->IsGenbank()  ||  id->IsEmbl()  ||  id->IsDdbj()  ||
  2125.              id->IsTpg()  ||  id->IsTpd()  ||  id->IsTpe()  ||
  2126.              id->IsOther() ||
  2127.              (id->IsLocal()  &&  !ctx.Config().SuppressLocalId()) ) {
  2128.             id_str = id->GetSeqIdString(true);
  2129.         } else if ( id->IsGi() ) {
  2130.             id_str = id->AsFastaString();
  2131.         }
  2132.         x_AddFTableQual("protein_id", id_str);
  2133.     }
  2134. }
  2135. void CFeatureItem::x_AddFTableProtQuals(const CSeq_feat& prot) const
  2136. {
  2137.     if ( !prot.GetData().IsProt() ) {
  2138.         return;
  2139.     }
  2140.     const CProt_ref& pref = prot.GetData().GetProt();
  2141.     ITERATE (CProt_ref::TName, it, pref.GetName()) {
  2142.         if ( !it->empty() ) {
  2143.             x_AddFTableQual("product", *it);
  2144.         }
  2145.     }
  2146.     if ( pref.CanGetDesc()  &&  !pref.GetDesc().empty() ) {
  2147.         x_AddFTableQual("prot_desc", pref.GetDesc());
  2148.     }
  2149.     ITERATE (CProt_ref::TActivity, it, pref.GetActivity()) {
  2150.         if ( !it->empty() ) {
  2151.             x_AddFTableQual("function", *it);
  2152.         }
  2153.     }
  2154.     ITERATE (CProt_ref::TEc, it, pref.GetEc()) {
  2155.         if ( !it->empty() ) {
  2156.             x_AddFTableQual("EC_number", *it);
  2157.         }
  2158.     }
  2159.     if ( prot.CanGetComment()  &&  !prot.GetComment().empty() ) {
  2160.         x_AddFTableQual("prot_note", prot.GetComment());
  2161.     }
  2162. }
  2163. void CFeatureItem::x_AddFTableRegionQuals(const CSeqFeatData::TRegion& region) const
  2164. {
  2165.     if ( !region.empty() ) {
  2166.         x_AddFTableQual("region", region);
  2167.     }
  2168. }
  2169. void CFeatureItem::x_AddFTableBondQuals(const CSeqFeatData::TBond& bond) const
  2170. {
  2171.     size_t bondidx = static_cast<size_t>(bond);
  2172.     if ( bondidx == static_cast<size_t>(CSeqFeatData::eBond_other) ) {
  2173.         bondidx = 5;
  2174.     }
  2175.     if ( bondidx > 0  &&  bondidx < 6 ) {
  2176.         x_AddFTableQual("bond_type", s_BondList[bondidx]);
  2177.     }
  2178. }
  2179. void CFeatureItem::x_AddFTableSiteQuals(const CSeqFeatData::TSite& site) const
  2180. {
  2181.     size_t siteidx = static_cast<size_t>(site);
  2182.     if ( siteidx == static_cast<size_t>(CSeqFeatData::eSite_other) ) {
  2183.         siteidx = 26;
  2184.     }
  2185.     if ( siteidx > 0  &&  siteidx < 27 ) {
  2186.         x_AddFTableQual("site_type", s_SiteList[siteidx]);
  2187.     }
  2188. }
  2189. void CFeatureItem::x_AddFTablePsecStrQuals(const CSeqFeatData::TPsec_str& psec_str) const
  2190. {
  2191.     size_t idx = static_cast<size_t>(psec_str);
  2192.     if ( idx > 0  &&  idx < 3 ) {
  2193.         x_AddFTableQual("sec_str_type", s_PsecStrText[idx]);
  2194.     }
  2195. }
  2196. void CFeatureItem::x_AddFTablePsecStrQuals(const CSeqFeatData::THet& het) const
  2197. {
  2198.     if ( !het.Get().empty() ) {
  2199.         x_AddFTableQual("heterogen", het.Get());
  2200.     }
  2201. }
  2202. static const string s_GetSubtypeString(const COrgMod::TSubtype& subtype)
  2203. {
  2204.     switch ( subtype ) {
  2205.         case COrgMod::eSubtype_strain:           return "strain";
  2206.         case COrgMod::eSubtype_substrain:        return "substrain";
  2207.         case COrgMod::eSubtype_type:             return "type";
  2208.         case COrgMod::eSubtype_subtype:          return "subtype";
  2209.         case COrgMod::eSubtype_variety:          return "variety";
  2210.         case COrgMod::eSubtype_serotype:         return "serotype";
  2211.         case COrgMod::eSubtype_serogroup:        return "serogroup";
  2212.         case COrgMod::eSubtype_serovar:          return "serovar";
  2213.         case COrgMod::eSubtype_cultivar:         return "cultivar";
  2214.         case COrgMod::eSubtype_pathovar:         return "pathovar";
  2215.         case COrgMod::eSubtype_chemovar:         return "chemovar";
  2216.         case COrgMod::eSubtype_biovar:           return "biovar";
  2217.         case COrgMod::eSubtype_biotype:          return "biotype";
  2218.         case COrgMod::eSubtype_group:            return "group";
  2219.         case COrgMod::eSubtype_subgroup:         return "subgroup";
  2220.         case COrgMod::eSubtype_isolate:          return "isolate";
  2221.         case COrgMod::eSubtype_common:           return "common";
  2222.         case COrgMod::eSubtype_acronym:          return "acronym";
  2223.         case COrgMod::eSubtype_dosage:           return "dosage";
  2224.         case COrgMod::eSubtype_nat_host:         return "nat_host";
  2225.         case COrgMod::eSubtype_sub_species:      return "sub_species";
  2226.         case COrgMod::eSubtype_specimen_voucher: return "specimen_voucher";
  2227.         case COrgMod::eSubtype_authority:        return "authority";
  2228.         case COrgMod::eSubtype_forma:            return "forma";
  2229.         case COrgMod::eSubtype_forma_specialis:  return "dosage";
  2230.         case COrgMod::eSubtype_ecotype:          return "ecotype";
  2231.         case COrgMod::eSubtype_synonym:          return "synonym";
  2232.         case COrgMod::eSubtype_anamorph:         return "anamorph";
  2233.         case COrgMod::eSubtype_teleomorph:       return "teleomorph";
  2234.         case COrgMod::eSubtype_breed:            return "breed";
  2235.         case COrgMod::eSubtype_gb_acronym:       return "gb_acronym";
  2236.         case COrgMod::eSubtype_gb_anamorph:      return "gb_anamorph";
  2237.         case COrgMod::eSubtype_gb_synonym:       return "gb_synonym";
  2238.         case COrgMod::eSubtype_old_lineage:      return "old_lineage";
  2239.         case COrgMod::eSubtype_old_name:         return "old_name";
  2240.         case COrgMod::eSubtype_other:            return "note";
  2241.         default:                                 return kEmptyStr;
  2242.     }
  2243.     return kEmptyStr;
  2244. }
  2245. static const string s_GetSubsourceString(const CSubSource::TSubtype& subtype)
  2246. {
  2247.     switch ( subtype ) {
  2248.         case CSubSource::eSubtype_chromosome: return "chromosome";
  2249.         case CSubSource::eSubtype_map: return "map";
  2250.         case CSubSource::eSubtype_clone: return "clone";
  2251.         case CSubSource::eSubtype_subclone: return "subclone";
  2252.         case CSubSource::eSubtype_haplotype: return "haplotype";
  2253.         case CSubSource::eSubtype_genotype: return "genotype";
  2254.         case CSubSource::eSubtype_sex: return "sex";
  2255.         case CSubSource::eSubtype_cell_line: return "cell_line";
  2256.         case CSubSource::eSubtype_cell_type: return "cell_type";
  2257.         case CSubSource::eSubtype_tissue_type: return "tissue_type";
  2258.         case CSubSource::eSubtype_clone_lib: return "clone_lib";
  2259.         case CSubSource::eSubtype_dev_stage: return "dev_stage";
  2260.         case CSubSource::eSubtype_frequency: return "frequency";
  2261.         case CSubSource::eSubtype_germline: return "germline";
  2262.         case CSubSource::eSubtype_rearranged: return "rearranged";
  2263.         case CSubSource::eSubtype_lab_host: return "lab_host";
  2264.         case CSubSource::eSubtype_pop_variant: return "pop_variant";
  2265.         case CSubSource::eSubtype_tissue_lib: return "tissue_lib";
  2266.         case CSubSource::eSubtype_plasmid_name: return "plasmid_name";
  2267.         case CSubSource::eSubtype_transposon_name: return "transposon_name";
  2268.         case CSubSource::eSubtype_insertion_seq_name: return "insertion_seq_name";
  2269.         case CSubSource::eSubtype_plastid_name: return "plastid_name";
  2270.         case CSubSource::eSubtype_country: return "country";
  2271.         case CSubSource::eSubtype_segment: return "segment";
  2272.         case CSubSource::eSubtype_endogenous_virus_name: return "endogenous_virus_name";
  2273.         case CSubSource::eSubtype_transgenic: return "transgenic";
  2274.         case CSubSource::eSubtype_environmental_sample: return "environmental_sample";
  2275.         case CSubSource::eSubtype_isolation_source: return "isolation_source";
  2276.         case CSubSource::eSubtype_other: return "note";
  2277.         default: return kEmptyStr;
  2278.     }
  2279.     return kEmptyStr;
  2280. }
  2281. void CFeatureItem::x_AddFTableBiosrcQuals(const CBioSource& src) const
  2282. {
  2283.     if ( src.CanGetOrg() ) {
  2284.         const CBioSource::TOrg& org = src.GetOrg();
  2285.         if ( org.CanGetTaxname()  &&  !org.GetTaxname().empty() ) {
  2286.             x_AddFTableQual("organism", org.GetTaxname());
  2287.         }
  2288.         if ( org.CanGetOrgname() ) {
  2289.             ITERATE (COrgName::TMod, it, org.GetOrgname().GetMod()) {
  2290.                 if ( (*it)->CanGetSubtype() ) {
  2291.                     string str = s_GetSubtypeString((*it)->GetSubtype());
  2292.                     if ( str.empty() ) {
  2293.                         continue;
  2294.                     }
  2295.                     if ( (*it)->CanGetSubname()  &&  !(*it)->GetSubname().empty() ) {
  2296.                         str += (*it)->GetSubname();
  2297.                     }
  2298.                     x_AddFTableQual(str);
  2299.                 }
  2300.             }
  2301.         }
  2302.     }
  2303.     ITERATE (CBioSource::TSubtype, it, src.GetSubtype()) {
  2304.         if ( (*it)->CanGetSubtype() ) {
  2305.             string str = s_GetSubsourceString((*it)->GetSubtype());
  2306.             if ( str.empty() ) {
  2307.                 continue;
  2308.             }
  2309.             if ( (*it)->CanGetName() ) {
  2310.                 str += (*it)->GetName();
  2311.             }
  2312.             x_AddFTableQual(str);
  2313.         }
  2314.     }
  2315. }
  2316. /////////////////////////////////////////////////////////////////////////////
  2317. //   Source Feature
  2318. /////////////////////////////////////////////////////////////////////////////
  2319. void CSourceFeatureItem::x_AddQuals(CBioseqContext& ctx)
  2320. {
  2321.     const CSeqFeatData& data = m_Feat->GetData();
  2322.     _ASSERT(data.IsOrg()  ||  data.IsBiosrc());
  2323.     // add various generic qualifiers...
  2324.     x_AddQual(eSQ_mol_type,
  2325.               new CFlatMolTypeQVal(ctx.GetBiomol(), ctx.GetMol()));
  2326.     if (m_Feat->IsSetComment()) {
  2327.         x_AddQual(eSQ_seqfeat_note, new CFlatStringQVal(m_Feat->GetComment()));
  2328.     }
  2329.     if (m_Feat->IsSetTitle()) {
  2330.         x_AddQual(eSQ_label, new CFlatLabelQVal(m_Feat->GetTitle()));
  2331.     }
  2332.     if (m_Feat->IsSetCit()) {
  2333.         x_AddQual(eSQ_citation, new CFlatPubSetQVal(m_Feat->GetCit()));
  2334.     }
  2335.     if (m_Feat->IsSetDbxref()) {
  2336.         x_AddQual(eSQ_org_xref, new CFlatXrefQVal(m_Feat->GetDbxref()));
  2337.     }
  2338.     // add qualifiers from biosource fields
  2339.     x_AddQuals(data.GetBiosrc(), ctx);
  2340. }
  2341. static ESourceQualifier s_OrgModToSlot(const COrgMod& om)
  2342. {
  2343.     switch ( om.GetSubtype() ) {
  2344. #define CASE_ORGMOD(x) case COrgMod::eSubtype_##x:  return eSQ_##x;
  2345.         CASE_ORGMOD(strain);
  2346.         CASE_ORGMOD(substrain);
  2347.         CASE_ORGMOD(type);
  2348.         CASE_ORGMOD(subtype);
  2349.         CASE_ORGMOD(variety);
  2350.         CASE_ORGMOD(serotype);
  2351.         CASE_ORGMOD(serogroup);
  2352.         CASE_ORGMOD(serovar);
  2353.         CASE_ORGMOD(cultivar);
  2354.         CASE_ORGMOD(pathovar);
  2355.         CASE_ORGMOD(chemovar);
  2356.         CASE_ORGMOD(biovar);
  2357.         CASE_ORGMOD(biotype);
  2358.         CASE_ORGMOD(group);
  2359.         CASE_ORGMOD(subgroup);
  2360.         CASE_ORGMOD(isolate);
  2361.         CASE_ORGMOD(common);
  2362.         CASE_ORGMOD(acronym);
  2363.         CASE_ORGMOD(dosage);
  2364.     case COrgMod::eSubtype_nat_host:  return eSQ_spec_or_nat_host;
  2365.         CASE_ORGMOD(sub_species);
  2366.         CASE_ORGMOD(specimen_voucher);
  2367.         CASE_ORGMOD(authority);
  2368.         CASE_ORGMOD(forma);
  2369.         CASE_ORGMOD(forma_specialis);
  2370.         CASE_ORGMOD(ecotype);
  2371.         CASE_ORGMOD(synonym);
  2372.         CASE_ORGMOD(anamorph);
  2373.         CASE_ORGMOD(teleomorph);
  2374.         CASE_ORGMOD(breed);
  2375.         CASE_ORGMOD(gb_acronym);
  2376.         CASE_ORGMOD(gb_anamorph);
  2377.         CASE_ORGMOD(gb_synonym);
  2378.         CASE_ORGMOD(old_lineage);
  2379.         CASE_ORGMOD(old_name);
  2380. #undef CASE_ORGMOD
  2381.     case COrgMod::eSubtype_other:  return eSQ_orgmod_note;
  2382.     default:                       return eSQ_none;
  2383.     }
  2384. }
  2385. void CSourceFeatureItem::x_AddQuals(const COrg_ref& org, CBioseqContext& ctx) const
  2386. {
  2387.     string taxname, common;
  2388.     if ( org.IsSetTaxname() ) {
  2389.         taxname = org.GetTaxname();
  2390.     }
  2391.     if ( taxname.empty()  &&  ctx.Config().NeedOrganismQual() ) {
  2392.         taxname = "unknown";
  2393.         if ( org.IsSetCommon() ) {
  2394.             common = org.GetCommon();
  2395.         }
  2396.     }
  2397.     if ( !taxname.empty() ) {
  2398.         x_AddQual(eSQ_organism, new CFlatStringQVal(taxname));
  2399.     }
  2400.     if ( !common.empty() ) {
  2401.         x_AddQual(eSQ_common_name, new CFlatStringQVal(common));
  2402.     }
  2403.     if ( org.CanGetOrgname() ) {
  2404.         ITERATE (COrgName::TMod, it, org.GetOrgname().GetMod()) {
  2405.             ESourceQualifier slot = s_OrgModToSlot(**it);
  2406.             if (slot != eSQ_none) {
  2407.                 x_AddQual(slot, new CFlatOrgModQVal(**it));
  2408.             }
  2409.         }
  2410.     }
  2411.     if ( !WasDesc() ) {
  2412.         x_AddQual(eSQ_unstructured, new CFlatStringListQVal(org.GetMod()));
  2413.     }
  2414.     if ( org.IsSetDb() ) {
  2415.         x_AddQual(eSQ_db_xref, new CFlatXrefQVal(org.GetDb()));
  2416.     }
  2417. }
  2418. static ESourceQualifier s_SubSourceToSlot(const CSubSource& ss)
  2419. {
  2420.     switch (ss.GetSubtype()) {
  2421. #define DO_SS(x) case CSubSource::eSubtype_##x:  return eSQ_##x;
  2422.         DO_SS(chromosome);
  2423.         DO_SS(map);
  2424.         DO_SS(clone);
  2425.         DO_SS(subclone);
  2426.         DO_SS(haplotype);
  2427.         DO_SS(genotype);
  2428.         DO_SS(sex);
  2429.         DO_SS(cell_line);
  2430.         DO_SS(cell_type);
  2431.         DO_SS(tissue_type);
  2432.         DO_SS(clone_lib);
  2433.         DO_SS(dev_stage);
  2434.         DO_SS(frequency);
  2435.         DO_SS(germline);
  2436.         DO_SS(rearranged);
  2437.         DO_SS(lab_host);
  2438.         DO_SS(pop_variant);
  2439.         DO_SS(tissue_lib);
  2440.         DO_SS(plasmid_name);
  2441.         DO_SS(transposon_name);
  2442.         DO_SS(insertion_seq_name);
  2443.         DO_SS(plastid_name);
  2444.         DO_SS(country);
  2445.         DO_SS(segment);
  2446.         DO_SS(endogenous_virus_name);
  2447.         DO_SS(transgenic);
  2448.         DO_SS(environmental_sample);
  2449.         DO_SS(isolation_source);
  2450. #undef DO_SS
  2451.     case CSubSource::eSubtype_other:  return eSQ_subsource_note;
  2452.     default:                          return eSQ_none;
  2453.     }
  2454. }
  2455. void CSourceFeatureItem::x_AddQuals(const CBioSource& src, CBioseqContext& ctx) const
  2456. {
  2457.     // add qualifiers from Org_ref field
  2458.     if ( src.CanGetOrg() ) {
  2459.         x_AddQuals(src.GetOrg(), ctx);
  2460.     }
  2461.     x_AddQual(eSQ_focus, new CFlatBoolQVal(src.IsSetIs_focus()));
  2462.     
  2463.     bool insertion_seq_name = false,
  2464.          plasmid_name = false,
  2465.          transposon_name = false;
  2466.     ITERATE (CBioSource::TSubtype, it, src.GetSubtype()) {
  2467.         ESourceQualifier slot = s_SubSourceToSlot(**it);
  2468.         if ( slot == eSQ_insertion_seq_name ) {
  2469.             insertion_seq_name = true;
  2470.         } else if ( slot == eSQ_plasmid_name ) {
  2471.             plasmid_name = true;
  2472.         } else if ( slot == eSQ_transposon_name ) {
  2473.             transposon_name = true;
  2474.         }
  2475.         if (slot != eSQ_none) {
  2476.             x_AddQual(slot, new CFlatSubSourceQVal(**it));
  2477.         }
  2478.     }
  2479.     // some qualifiers are flags in genome and names in subsource,
  2480.     // print once with name
  2481.     CBioSource::TGenome genome = src.GetGenome();
  2482.     CRef<CFlatOrganelleQVal> organelle(new CFlatOrganelleQVal(genome));
  2483.     if ( (insertion_seq_name  &&  genome == CBioSource::eGenome_insertion_seq)  ||
  2484.          (plasmid_name  &&  genome == CBioSource::eGenome_plasmid)  ||
  2485.          (transposon_name  &&  genome == CBioSource::eGenome_transposon) ) {
  2486.         organelle.Reset();
  2487.     }
  2488.     if ( organelle ) {
  2489.         x_AddQual(eSQ_organelle, organelle);
  2490.     }
  2491.     if ( !WasDesc()  &&  m_Feat->CanGetComment() ) {
  2492.         x_AddQual(eSQ_seqfeat_note, new CFlatStringQVal(m_Feat->GetComment()));
  2493.     }
  2494. }
  2495. void CSourceFeatureItem::x_FormatQuals(CFlatFeature& ff) const
  2496. {
  2497.     ff.SetQuals().reserve(m_Quals.Size());
  2498.     CFlatFeature::TQuals& qvec = ff.SetQuals();
  2499. #define DO_QUAL(x) x_FormatQual(eSQ_##x, #x, qvec)
  2500.     DO_QUAL(organism);
  2501.     DO_QUAL(organelle);
  2502.     DO_QUAL(mol_type);
  2503.     DO_QUAL(strain);
  2504.     x_FormatQual(eSQ_substrain, "sub_strain", qvec);
  2505.     DO_QUAL(variety);
  2506.     DO_QUAL(serotype);
  2507.     DO_QUAL(serovar);
  2508.     DO_QUAL(cultivar);
  2509.     DO_QUAL(isolate);
  2510.     DO_QUAL(isolation_source);
  2511.     x_FormatQual(eSQ_spec_or_nat_host, "specific_host", qvec);
  2512.     DO_QUAL(sub_species);
  2513.     DO_QUAL(specimen_voucher);
  2514.     DO_QUAL(db_xref);
  2515.     x_FormatQual(eSQ_org_xref, "db_xref", qvec);
  2516.     DO_QUAL(chromosome);
  2517.     DO_QUAL(segment);
  2518.     DO_QUAL(map);
  2519.     DO_QUAL(clone);
  2520.     x_FormatQual(eSQ_subclone, "sub_clone", qvec);
  2521.     DO_QUAL(haplotype);
  2522.     DO_QUAL(sex);
  2523.     DO_QUAL(cell_line);
  2524.     DO_QUAL(cell_type);
  2525.     DO_QUAL(tissue_type);
  2526.     DO_QUAL(clone_lib);
  2527.     DO_QUAL(dev_stage);
  2528.     DO_QUAL(frequency);
  2529.     DO_QUAL(germline);
  2530.     DO_QUAL(rearranged);
  2531.     DO_QUAL(transgenic);
  2532.     DO_QUAL(environmental_sample);
  2533.     DO_QUAL(lab_host);
  2534.     DO_QUAL(pop_variant);
  2535.     DO_QUAL(tissue_lib);
  2536.     x_FormatQual(eSQ_plasmid_name,       "plasmid", qvec);
  2537.     x_FormatQual(eSQ_transposon_name,    "transposon", qvec);
  2538.     x_FormatQual(eSQ_insertion_seq_name, "insertion_seq", qvec);
  2539.     DO_QUAL(country);
  2540.     DO_QUAL(focus);
  2541.     if ( !GetContext()->Config().SrcQualsToNote() ) {
  2542.         // some note qualifiers appear as regular quals in GBench or Dump mode
  2543.         x_FormatGBNoteQuals(ff);
  2544.     }
  2545.     DO_QUAL(sequenced_mol);
  2546.     DO_QUAL(label);
  2547.     DO_QUAL(usedin);
  2548.     DO_QUAL(citation);
  2549. #undef DO_QUAL
  2550.     // Format the rest of the note quals (ones that weren't formatted above)
  2551.     // as a single note qualifier
  2552.     x_FormatNoteQuals(ff);
  2553. }
  2554. void CSourceFeatureItem::x_FormatGBNoteQuals(CFlatFeature& ff) const
  2555. {
  2556.     _ASSERT(!GetContext()->Config().SrcQualsToNote());
  2557.     CFlatFeature::TQuals& qvec = ff.SetQuals();
  2558. #define DO_QUAL(x) x_FormatQual(eSQ_##x, #x, qvec)
  2559.     DO_QUAL(type);
  2560.     DO_QUAL(subtype);
  2561.     DO_QUAL(serogroup);
  2562.     DO_QUAL(pathovar);
  2563.     DO_QUAL(chemovar);
  2564.     DO_QUAL(biovar);
  2565.     DO_QUAL(biotype);
  2566.     DO_QUAL(group);
  2567.     DO_QUAL(subgroup);
  2568.     DO_QUAL(common);
  2569.     DO_QUAL(acronym);
  2570.     DO_QUAL(dosage);
  2571.     
  2572.     DO_QUAL(authority);
  2573.     DO_QUAL(forma);
  2574.     DO_QUAL(forma_specialis);
  2575.     DO_QUAL(ecotype);
  2576.     DO_QUAL(synonym);
  2577.     DO_QUAL(anamorph);
  2578.     DO_QUAL(teleomorph);
  2579.     DO_QUAL(breed);
  2580.     
  2581.     DO_QUAL(genotype);
  2582.     x_FormatQual(eSQ_plastid_name, "plastid", qvec);
  2583.     
  2584.     x_FormatQual(eSQ_endogenous_virus_name, "endogenous_virus", qvec);
  2585.     x_FormatQual(eSQ_zero_orgmod, "?", qvec);
  2586.     x_FormatQual(eSQ_one_orgmod,  "?", qvec);
  2587.     x_FormatQual(eSQ_zero_subsrc, "?", qvec);
  2588. #undef DO_QUAL
  2589. }
  2590. void CSourceFeatureItem::x_FormatNoteQuals(CFlatFeature& ff) const
  2591. {
  2592.     CFlatFeature::TQuals qvec;
  2593.     bool add_period = false;
  2594. #define DO_NOTE(x) x_FormatNoteQual(eSQ_##x, #x, qvec, add_period)
  2595.     if (m_WasDesc) {
  2596.         x_FormatNoteQual(eSQ_seqfeat_note, "note", qvec, add_period);
  2597.         DO_NOTE(orgmod_note);
  2598.         DO_NOTE(subsource_note);
  2599.     } else {
  2600.         DO_NOTE(unstructured);
  2601.     }
  2602.     if ( GetContext()->Config().SrcQualsToNote() ) {
  2603.         DO_NOTE(type);
  2604.         DO_NOTE(subtype);
  2605.         DO_NOTE(serogroup);
  2606.         DO_NOTE(pathovar);
  2607.         DO_NOTE(chemovar);
  2608.         DO_NOTE(biovar);
  2609.         DO_NOTE(biotype);
  2610.         DO_NOTE(group);
  2611.         DO_NOTE(subgroup);
  2612.         DO_NOTE(common);
  2613.         DO_NOTE(acronym);
  2614.         DO_NOTE(dosage);
  2615.         
  2616.         DO_NOTE(authority);
  2617.         DO_NOTE(forma);
  2618.         DO_NOTE(forma_specialis);
  2619.         DO_NOTE(ecotype);
  2620.         DO_NOTE(synonym);
  2621.         DO_NOTE(anamorph);
  2622.         DO_NOTE(teleomorph);
  2623.         DO_NOTE(breed);
  2624.         
  2625.         DO_NOTE(genotype);
  2626.         x_FormatNoteQual(eSQ_plastid_name, "plastid", qvec, add_period);
  2627.         
  2628.         x_FormatNoteQual(eSQ_endogenous_virus_name, "endogenous_virus", qvec, add_period);
  2629.     }
  2630.     x_FormatNoteQual(eSQ_common_name, "common", qvec, add_period);
  2631.     if ( GetContext()->Config().SrcQualsToNote() ) {
  2632.         x_FormatNoteQual(eSQ_zero_orgmod, "?", qvec, add_period);
  2633.         x_FormatNoteQual(eSQ_one_orgmod,  "?", qvec, add_period);
  2634.         x_FormatNoteQual(eSQ_zero_subsrc, "?", qvec, add_period);
  2635.     }
  2636. #undef DO_NOTE
  2637.     string notestr;
  2638.     const string* suffix = &kEmptyStr;
  2639.     if ( GetSource().CanGetGenome()  &&  
  2640.         GetSource().GetGenome() == CBioSource::eGenome_extrachrom ) {
  2641.         static const string kEOL = "n";
  2642.         notestr += "extrachromosomal";
  2643.         suffix = &kEOL;
  2644.     }
  2645.     CFlatFeature::TQuals::const_iterator last = qvec.end();
  2646.     CFlatFeature::TQuals::const_iterator end = last--;
  2647.     CFlatFeature::TQuals::const_iterator it = qvec.begin();
  2648.     for ( ; it != end; ++it ) {
  2649.         string note = (*it)->GetValue();
  2650.         if ( NStr::EndsWith(note, ".")  &&  !NStr::EndsWith(note, "...") ) {
  2651.             if ( !add_period ) {
  2652.                 note.erase(note.length() - 1);
  2653.             }
  2654.         }
  2655.         const string& prefix = *suffix + (*it)->GetPrefix();
  2656.         JoinNoRedund(notestr, prefix, note);
  2657.         suffix = &(*it)->GetSuffix();
  2658.     }
  2659.     if ( !notestr.empty() ) {
  2660.         CRef<CFormatQual> note(new CFormatQual("note", notestr));
  2661.         ff.SetQuals().push_back(note);
  2662.     }
  2663. }
  2664. CSourceFeatureItem::CSourceFeatureItem
  2665. (const CBioSource& src,
  2666.  TRange range,
  2667.  CBioseqContext& ctx)
  2668.     : CFeatureItemBase(*new CSeq_feat, ctx),
  2669.       m_WasDesc(true)
  2670. {
  2671.     CSeq_feat& feat = const_cast<CSeq_feat&>(*m_Feat);
  2672.     feat.SetData().SetBiosrc(const_cast<CBioSource&>(src));
  2673.     if ( range.IsWhole() ) {
  2674.         feat.SetLocation().SetWhole(*ctx.GetPrimaryId());
  2675.     } else {
  2676.         CSeq_interval& ival = feat.SetLocation().SetInt();
  2677.         ival.SetFrom(range.GetFrom());
  2678.         ival.SetTo(range.GetTo());
  2679.         ival.SetId(*ctx.GetPrimaryId());
  2680.     }
  2681.     x_GatherInfo(ctx);
  2682. }
  2683. void CSourceFeatureItem::x_FormatQual
  2684. (ESourceQualifier slot,
  2685.  const string& name,
  2686.  CFlatFeature::TQuals& qvec,
  2687.  bool& add_period,
  2688.  IFlatQVal::TFlags flags) const
  2689. {
  2690.     pair<TQCI, TQCI> range = const_cast<const TQuals&>(m_Quals).GetQuals(slot);
  2691.     for (TQCI it = range.first;  it != range.second;  ++it) {
  2692.         const IFlatQVal* qual = it->second;
  2693.         qual->Format(qvec, name, *GetContext(),
  2694.                      flags | IFlatQVal::fIsSource);
  2695.         const CFlatOrgModQVal* orgmod = dynamic_cast<const CFlatOrgModQVal*>(qual);
  2696.         const CFlatSubSourceQVal* subsource = dynamic_cast<const CFlatSubSourceQVal*>(qual);
  2697.         add_period = add_period  ||  (orgmod != 0)  ||  (subsource != 0);
  2698.     }
  2699. }
  2700. END_SCOPE(objects)
  2701. END_NCBI_SCOPE
  2702. /*
  2703. * ===========================================================================
  2704. *
  2705. * $Log: feature_item.cpp,v $
  2706. * Revision 1000.2  2004/06/01 19:44:14  gouriano
  2707. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.26
  2708. *
  2709. * Revision 1.26  2004/05/26 14:57:54  shomrat
  2710. * removed non-preferred variants ribosome slippage, trans splicing, alternate processing, and non-consensus splice site
  2711. *
  2712. * Revision 1.25  2004/05/21 21:42:54  gorelenk
  2713. * Added PCH ncbi_pch.hpp
  2714. *
  2715. * Revision 1.24  2004/05/19 14:47:19  shomrat
  2716. * Check for illegal qualifiers in RELEASE mode
  2717. *
  2718. * Revision 1.23  2004/05/08 12:12:00  dicuccio
  2719. * Use best ID representation for protein products
  2720. *
  2721. * Revision 1.22  2004/05/07 15:22:39  shomrat
  2722. * Added qualifiers add Seq-id filters
  2723. *
  2724. * Revision 1.21  2004/05/06 19:41:00  ucko
  2725. * Kill unwanted definition of ff as a macro, if present (as on Mac OS 10.3)
  2726. *
  2727. * Revision 1.20  2004/05/06 17:49:59  shomrat
  2728. * Fixed feature formatting
  2729. *
  2730. * Revision 1.19  2004/04/22 15:56:47  shomrat
  2731. * Changes in context
  2732. *
  2733. * Revision 1.18  2004/04/13 16:46:39  shomrat
  2734. * Changes due to GBSeq format
  2735. *
  2736. * Revision 1.17  2004/04/12 16:17:27  vasilche
  2737. * Fixed '=' <-> '==' typo.
  2738. *
  2739. * Revision 1.16  2004/04/07 14:27:15  shomrat
  2740. * Added methods forFTable format
  2741. *
  2742. * Revision 1.15  2004/03/31 16:00:12  ucko
  2743. * C(Source)FeatureItem::x_FormatQual: make sure to call the const
  2744. * version of GetQuals to fix WorkShop build errors.
  2745. *
  2746. * Revision 1.14  2004/03/30 20:27:09  shomrat
  2747. * Separated quals container from feature class
  2748. *
  2749. * Revision 1.13  2004/03/25 20:37:41  shomrat
  2750. * Use handles
  2751. *
  2752. * Revision 1.12  2004/03/18 15:37:57  shomrat
  2753. * Fixes to note qual formatting
  2754. *
  2755. * Revision 1.11  2004/03/10 21:30:18  shomrat
  2756. * + product tRNA qual; limit Seq-is types for product ids
  2757. *
  2758. * Revision 1.10  2004/03/10 16:22:18  shomrat
  2759. * Fixed product-id qualifiers
  2760. *
  2761. * Revision 1.9  2004/03/08 21:02:18  shomrat
  2762. * + Exception quals gathering; fixed product id gathering
  2763. *
  2764. * Revision 1.8  2004/03/08 15:45:46  shomrat
  2765. * Added pseudo qualifier
  2766. *
  2767. * Revision 1.7  2004/03/05 18:44:48  shomrat
  2768. * fixes to qualifiers collection and formatting
  2769. *
  2770. * Revision 1.6  2004/02/19 18:07:26  shomrat
  2771. * HideXXXFeat() => HideXXXFeats()
  2772. *
  2773. * Revision 1.5  2004/02/11 22:50:35  shomrat
  2774. * override GetKey
  2775. *
  2776. * Revision 1.4  2004/02/11 16:56:42  shomrat
  2777. * changes in qualifiers gathering and formatting
  2778. *
  2779. * Revision 1.3  2004/01/14 16:12:20  shomrat
  2780. * uncommenetd code
  2781. *
  2782. * Revision 1.2  2003/12/18 17:43:33  shomrat
  2783. * context.hpp moved
  2784. *
  2785. * Revision 1.1  2003/12/17 20:20:52  shomrat
  2786. * Initial Revision (adapted from flat lib)
  2787. *
  2788. * Revision 1.10  2003/10/17 20:58:41  ucko
  2789. * Don't assume coding-region features have their "product" fields set.
  2790. *
  2791. * Revision 1.9  2003/10/16 20:21:53  ucko
  2792. * Fix a copy-and-paste error in CFeatureItem::x_AddQuals
  2793. *
  2794. * Revision 1.8  2003/10/08 21:11:12  ucko
  2795. * Add a couple of accessors to CFeatureItemBase for the GFF/GTF formatter.
  2796. *
  2797. * Revision 1.7  2003/07/22 18:04:13  dicuccio
  2798. * Fixed access of unset optional variables
  2799. *
  2800. * Revision 1.6  2003/06/02 16:06:42  dicuccio
  2801. * Rearranged src/objects/ subtree.  This includes the following shifts:
  2802. *     - src/objects/asn2asn --> arc/app/asn2asn
  2803. *     - src/objects/testmedline --> src/objects/ncbimime/test
  2804. *     - src/objects/objmgr --> src/objmgr
  2805. *     - src/objects/util --> src/objmgr/util
  2806. *     - src/objects/alnmgr --> src/objtools/alnmgr
  2807. *     - src/objects/flat --> src/objtools/flat
  2808. *     - src/objects/validator --> src/objtools/validator
  2809. *     - src/objects/cddalignview --> src/objtools/cddalignview
  2810. * In addition, libseq now includes six of the objects/seq... libs, and libmmdb
  2811. * replaces the three libmmdb? libs.
  2812. *
  2813. * Revision 1.5  2003/04/24 16:15:58  vasilche
  2814. * Added missing includes and forward class declarations.
  2815. *
  2816. * Revision 1.4  2003/03/21 18:49:17  ucko
  2817. * Turn most structs into (accessor-requiring) classes; replace some
  2818. * formerly copied fields with pointers to the original data.
  2819. *
  2820. * Revision 1.3  2003/03/11 15:37:51  kuznets
  2821. * iterate -> ITERATE
  2822. *
  2823. * Revision 1.2  2003/03/10 22:01:36  ucko
  2824. * Change SLegalImport::m_Name from string to const char* (needed by MSVC).
  2825. *
  2826. * Revision 1.1  2003/03/10 16:39:09  ucko
  2827. * Initial check-in of new flat-file generator
  2828. *
  2829. *
  2830. * ===========================================================================
  2831. */