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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: reference_item.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 19:45:23  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.18
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: reference_item.cpp,v 1000.2 2004/06/01 19:45:23 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. *   flat-file generator -- bibliographic references
  39. *
  40. * ===========================================================================
  41. */
  42. #include <ncbi_pch.hpp>
  43. #include <corelib/ncbistd.hpp>
  44. #include <serial/iterator.hpp>
  45. #include <util/static_set.hpp>
  46. #include <objects/biblio/biblio__.hpp>
  47. #include <objects/general/Name_std.hpp>
  48. #include <objects/general/Person_id.hpp>
  49. #include <objects/medline/Medline_entry.hpp>
  50. #include <objects/pub/Pub.hpp>
  51. #include <objects/pub/Pub_equiv.hpp>
  52. #include <objects/pub/Pub_set.hpp>
  53. #include <objects/seqloc/Patent_seq_id.hpp>
  54. #include <objects/seq/Bioseq.hpp>
  55. #include <objects/seq/Seqdesc.hpp>
  56. #include <objects/seqfeat/Seq_feat.hpp>
  57. #include <objects/seqfeat/SeqFeatData.hpp>
  58. #include <objects/biblio/Imprint.hpp>
  59. #include <objmgr/util/sequence.hpp>
  60. #include <algorithm>
  61. #include <objtools/format/text_ostream.hpp>
  62. #include <objtools/format/formatter.hpp>
  63. #include <objtools/format/items/reference_item.hpp>
  64. #include <objtools/format/context.hpp>
  65. #include "utils.hpp"
  66. BEGIN_NCBI_SCOPE
  67. BEGIN_SCOPE(objects)
  68. USING_SCOPE(sequence);
  69. /////////////////////////////////////////////////////////////////////////////
  70. //
  71. // LessEqual - predicate class for sorting references
  72. class LessEqual
  73. {
  74. public:
  75.     LessEqual(bool serial_first, bool is_refseq);
  76.     bool operator()(const CRef<CReferenceItem>& ref1, const CRef<CReferenceItem>& ref2);
  77. private:
  78.     bool m_SerialFirst;
  79.     bool m_IsRefSeq;
  80. };
  81. /////////////////////////////////////////////////////////////////////////////
  82. void CReferenceItem::FormatAffil(const CAffil& affil, string& result)
  83. {
  84.     if (affil.IsStr()) {
  85.         result = affil.GetStr();
  86.     } else {
  87.         result.erase();
  88.         const CAffil::C_Std& std = affil.GetStd();
  89.         if (std.IsSetDiv()) {
  90.             result = std.GetDiv();
  91.         }
  92.         if (std.IsSetAffil()) {
  93.             if (!result.empty()) {
  94.                 result += ", ";
  95.             }
  96.             result += std.GetAffil();
  97.         }
  98.         if (std.IsSetStreet()) {
  99.             if (!result.empty()) {
  100.                 result += ", ";
  101.             }
  102.             result += std.GetStreet();
  103.         }
  104.         if (std.IsSetCity()) {
  105.             if (!result.empty()) {
  106.                 result += ", ";
  107.             }
  108.             result += std.GetCity();
  109.         }
  110.         if (std.IsSetSub()) {
  111.             if (!result.empty()) {
  112.                 result += ", ";
  113.             }
  114.             result += std.GetSub();
  115.         }
  116.         if (std.IsSetPostal_code()) {
  117.             if (!result.empty()) {
  118.                 result += " ";
  119.             }
  120.             result += std.GetPostal_code();
  121.         }
  122.         if (std.IsSetCountry()) {
  123.             if (!result.empty()) {
  124.                 result += ", ";
  125.             }
  126.             result += std.GetCountry();
  127.         }
  128.     }
  129. }
  130. static void s_FixPages(string& pages)
  131. {
  132.     // Restore redundant leading digits of the second number if needed
  133.     SIZE_TYPE digits1 = pages.find_first_not_of("0123456789");
  134.     if ( digits1 != NPOS) {
  135.         SIZE_TYPE hyphen = pages.find('-', digits1);
  136.         if ( hyphen != NPOS ) {
  137.             SIZE_TYPE digits2 = pages.find_first_not_of("0123456789",
  138.                 hyphen + 1);
  139.             digits2 -= hyphen + 1;
  140.             if ( digits2 < digits1 ) {
  141.                 // lengths of the tail portions
  142.                 SIZE_TYPE len1 = hyphen + digits2 - digits1;
  143.                 SIZE_TYPE len2 = pages.size() - hyphen - 1;
  144.                 int x = NStr::strncasecmp(&pages[digits1 - digits2],
  145.                     &pages[hyphen + 1],
  146.                     min(len1, len2));
  147.                 if ( x > 0  ||  (x == 0  &&  len1 >= len2) ) {
  148.                     // complain?
  149.                 } else {
  150.                     pages.insert(hyphen + 1, pages, 0,
  151.                         digits1 - digits2);
  152.                 }
  153.             }
  154.         }
  155.     }
  156. }
  157. CReferenceItem::CReferenceItem(const CSeqdesc& desc, CBioseqContext& ctx) :
  158.     CFlatItem(&ctx), m_PMID(0), m_MUID(0), m_Category(eUnknown), m_Serial(0),
  159.     m_JustUids(false), m_Prepub(CImprint::ePrepub_other)
  160. {
  161.     _ASSERT(desc.IsPub());
  162.     
  163.     x_SetObject(desc.GetPub());
  164.     m_Pubdesc.Reset(&(desc.GetPub()));
  165.     if ( ctx.GetMapper() != 0 ) {
  166.         m_Loc.Reset(ctx.GetMapper()->Map(ctx.GetLocation()));
  167.     } else {
  168.         m_Loc.Reset(&ctx.GetLocation());
  169.     }
  170.     x_GatherInfo(ctx);
  171. }
  172. CReferenceItem::CReferenceItem(const CSeq_feat& feat, CBioseqContext& ctx) :
  173.     CFlatItem(&ctx), m_PMID(0), m_MUID(0), m_Category(eUnknown), m_Serial(0),
  174.     m_JustUids(false), m_Prepub(CImprint::ePrepub_other)
  175. {
  176.     _ASSERT(feat.GetData().IsPub());
  177.     x_SetObject(feat);
  178.     m_Pubdesc.Reset(&(feat.GetData().GetPub()));
  179.     if ( ctx.GetMapper() != 0 ) {
  180.         m_Loc.Reset(ctx.GetMapper()->Map(feat.GetLocation()));
  181.     } else {
  182.         m_Loc.Reset(&(feat.GetLocation()));
  183.     }
  184. }
  185. CReferenceItem::CReferenceItem
  186. (const CPubdesc& pub,
  187.  CBioseqContext& ctx,
  188.  const CSeq_loc* loc) :
  189.     CFlatItem(&ctx), m_Pubdesc(&pub), m_Loc(loc), m_PMID(0), m_MUID(0),
  190.     m_Category(eUnknown), m_Serial(0), m_JustUids(false),
  191.     m_Prepub(CImprint::ePrepub_other)
  192. {
  193.     x_SetObject(pub);
  194.     if ( !m_Loc ) {
  195.         m_Loc.Reset(&ctx.GetLocation());
  196.     }
  197.     if ( ctx.GetMapper() != 0 ) {
  198.         m_Loc.Reset(ctx.GetMapper()->Map(*m_Loc));
  199.     }
  200.     x_GatherInfo(ctx);
  201. }
  202. void CReferenceItem::SetLoc(const CConstRef<CSeq_loc>& loc)
  203. {
  204.     m_Loc = loc;
  205. }
  206. static void s_MergeDuplicates
  207. (CReferenceItem::TReferences& refs,
  208.  CBioseqContext& ctx)
  209. {
  210.     if ( refs.size() < 2 ) {
  211.         return;
  212.     }
  213.     CReferenceItem::TReferences::iterator curr = refs.begin();
  214.     CReferenceItem::TReferences::iterator prev = curr;
  215.     while ( curr != refs.end() ) {
  216.         if ( !*curr ) {
  217.             curr = refs.erase(curr);
  218.             if ( curr == refs.end() ) {
  219.                 break;
  220.             }
  221.         }
  222.         _ASSERT(*curr);
  223.         bool remove = false;
  224.         bool merge  = true;
  225.         const CReferenceItem& curr_ref = **curr;
  226.         if ( curr_ref.JustUids() ) {
  227.             remove = true;
  228.         } else {
  229.             // EMBL patent records do not need author or title - A29528.1
  230.             // do not allow no author reference to appear by itself - U07000.1
  231.             if ( !(ctx.IsEMBL()  &&  ctx.IsPatent())  &&
  232.                  curr_ref.GetAuthors() == 0 ) {
  233.                 remove = true;
  234.                 merge = false;
  235.             }
  236.         }
  237.         if ( (prev != curr)  &&  prev->NotEmpty() ) {
  238.             const CReferenceItem& prev_ref = **prev;
  239.             if ( curr_ref.GetPMID() == prev_ref.GetPMID()  &&  curr_ref.GetPMID() != 0 ) {
  240.                 remove = true;
  241.             }
  242.             if ( remove  &&
  243.                  prev_ref.GetReftype() == CPubdesc::eReftype_seq  &&
  244.                  curr_ref.GetReftype() != CPubdesc::eReftype_seq ) {
  245.                 // real range trumps sites
  246.                 merge = false;
  247.             }
  248.             if ( prev_ref.GetLoc() == 0 ) {
  249.                 merge = false;
  250.             }
  251.         } else {
  252.             merge = false;
  253.         }
  254.         if ( remove ) {
  255.             CConstRef<CSeq_loc> merged_loc;
  256.             if ( merge  &&  (curr_ref.GetLoc() != 0) ) {
  257.                 merged_loc.Reset(SeqLocMerge(ctx.GetHandle(),
  258.                     *(*prev)->GetLoc(), *curr_ref.GetLoc(), fFuseAbutting));
  259.             }
  260.             (*prev)->SetLoc(merged_loc);
  261.             curr = refs.erase(curr);
  262.             if ( curr == refs.end() ) {
  263.                 break;
  264.             }
  265.         } else {
  266.             prev = curr;
  267.             ++curr;
  268.         }
  269.     }
  270. }
  271. void CReferenceItem::Rearrange(TReferences& refs, CBioseqContext& ctx)
  272. {
  273.     {{
  274.         sort(refs.begin(), refs.end(), LessEqual(false, ctx.IsRefSeq()));
  275.     }}
  276.     {{
  277.         // merge duplicate references
  278.         s_MergeDuplicates(refs, ctx);
  279.     }}
  280.     {{
  281.         // !!! add submit reference
  282.     }}
  283.     {{
  284.         // re-sort, take serial number into consideration.
  285.         sort(refs.begin(), refs.end(), LessEqual(true, ctx.IsRefSeq()));
  286.     }}
  287.     
  288.     // assign final serial numbers
  289.     size_t size = refs.size();
  290.     for ( size_t i = 0;  i < size; ++i ) {
  291.         refs[i]->m_Serial = i + 1;
  292.     }
  293. }
  294. void CReferenceItem::Format
  295. (IFormatter& formatter,
  296.  IFlatTextOStream& text_os) const
  297. {
  298.     formatter.FormatReference(*this, text_os);
  299. }
  300. bool CReferenceItem::Matches(const CPub_set& ps) const
  301. {
  302.     if ( !ps.IsPub() ) {
  303.         return false;
  304.     }
  305.     ITERATE (CPub_set::TPub, it, ps.GetPub()) {
  306.         if ( x_Matches(**it) ) {
  307.             return true;
  308.         }
  309.     }
  310.     return false;
  311. }
  312. bool CReferenceItem::x_Matches(const CPub& pub) const
  313. {
  314.     switch ( pub.Which() ) {
  315.     case CPub::e_Muid:
  316.         return pub.GetMuid() == GetMUID();
  317.     case CPub::e_Pmid:
  318.         return pub.GetPmid() == GetPMID();
  319.     case CPub::e_Equiv:
  320.         ITERATE (CPub::TEquiv::Tdata, it, pub.GetEquiv().Get()) {
  321.             if ( x_Matches(**it) ) {
  322.                 return true;
  323.             }
  324.         }
  325.         break;
  326.     default:
  327.         {
  328.             if ( !m_UniqueStr.empty() ) {
  329.                 string unique;
  330.                 pub.GetLabel(&unique, CPub::eContent, true);
  331.                 size_t len = unique.length();
  332.                 if ( len > 0  &&  unique[len - 1] == '>' ) {
  333.                     --len;
  334.                 }
  335.                 len = min(len , m_UniqueStr.length());
  336.                 unique.resize(len);
  337.                 if ( NStr::StartsWith(m_UniqueStr, unique, NStr::eNocase) ) {
  338.                     return true;
  339.                 }
  340.             }
  341.         break;
  342.         }
  343.     }
  344.     return false;
  345. }
  346. void CReferenceItem::x_GatherInfo(CBioseqContext& ctx)
  347. {
  348.     if ( !m_Pubdesc->CanGetPub() ) {
  349.         x_SetSkip();
  350.     }
  351.     if ( ctx.GetSubmitBlock() != 0 ) {
  352.         m_Title = "Direct Submission";
  353.         m_Category = eSubmission;
  354.     }
  355.     CPub_equiv::Tdata::const_iterator last = m_Pubdesc->GetPub().Get().end()--;
  356.     ITERATE (CPub_equiv::Tdata, it, m_Pubdesc->GetPub().Get()) {
  357.         x_Init(**it, ctx);
  358.         // set unique str
  359.         // skip over just serial number
  360.         if ( (*it)->IsGen()  &&  it != last ) {
  361.             const CCit_gen& gen = (*it)->GetGen();
  362.             if ( !gen.CanGetCit()  ||
  363.                  !NStr::StartsWith(gen.GetCit(), "BackBone id_pub", NStr::eNocase) ) {
  364.                 if ( !gen.CanGetCit()  &&
  365.                       !gen.CanGetJournal()  &&
  366.                       !gen.CanGetDate()  &&
  367.                       gen.CanGetSerial_number()  &&
  368.                       gen.GetSerial_number() > 0 ) {
  369.                      continue;
  370.                 }
  371.             }
  372.         }
  373.         if ( m_UniqueStr.empty() ) {
  374.             (*it)->GetLabel(&m_UniqueStr, CPub::eContent, true);
  375.         }
  376.     }
  377.     x_CleanData();
  378.     // gather Genbank specific fields (formats: Genbank, GBSeq, DDBJ)
  379.     if ( ctx.IsGenbankFormat() ) {
  380.         x_GatherRemark(ctx);
  381.     }
  382. }
  383.  
  384. void CReferenceItem::x_Init(const CPub& pub, CBioseqContext& ctx)
  385. {
  386.     switch (pub.Which()) {
  387.     case CPub::e_Gen:
  388.         x_Init(pub.GetGen(), ctx);
  389.         break;
  390.     case CPub::e_Sub:
  391.         x_Init(pub.GetSub(), ctx);
  392.         break;
  393.     case CPub::e_Medline:
  394.         x_Init(pub.GetMedline(), ctx);
  395.         break;
  396.     case CPub::e_Muid:
  397.         if ( m_MUID == 0 ) {
  398.             m_MUID = pub.GetMuid();
  399.             m_Category = ePublished;
  400.         }
  401.         break;
  402.     case CPub::e_Article:
  403.         x_Init(pub.GetArticle(), ctx);
  404.         break;
  405.     case CPub::e_Journal:
  406.         x_Init(pub.GetJournal(), ctx);
  407.         break;
  408.     case CPub::e_Book:
  409.         x_Init(pub.GetBook(), ctx);
  410.         break;
  411.     case CPub::e_Proc:
  412.         x_Init(pub.GetProc().GetBook(), ctx);
  413.         break;
  414.     case CPub::e_Patent:
  415.         x_Init(pub.GetPatent(), ctx);
  416.         break;
  417.     case CPub::e_Man:
  418.         x_Init(pub.GetMan(), ctx);
  419.         break;
  420.     case CPub::e_Equiv:
  421.         ITERATE (CPub_equiv::Tdata, it, pub.GetEquiv().Get()) {
  422.             x_Init(**it, ctx);
  423.         }
  424.         break;
  425.     case CPub::e_Pmid:
  426.         if ( m_PMID == 0 ) {
  427.             m_PMID = pub.GetPmid();
  428.             m_Category = ePublished;
  429.         }
  430.         break;
  431.     default:
  432.         break;
  433.     }
  434. }
  435. void CReferenceItem::x_Init(const CCit_gen& gen, CBioseqContext& ctx)
  436. {
  437.     // serial
  438.     if ( gen.CanGetSerial_number()  &&  m_Serial == 0 ) {
  439.         m_Serial = gen.GetSerial_number();
  440.     }
  441.     // title
  442.     if ( m_Title.empty() ) {
  443.         if ( gen.CanGetTitle()  &&  !gen.GetTitle().empty() ) {
  444.             m_Title = gen.GetTitle();
  445.         } else {
  446.             if ( gen.CanGetCit()  &&  !gen.GetCit().empty() ) {
  447.                 const string& cit = gen.GetCit();
  448.                 SIZE_TYPE pos = NStr::Find(cit, "Title="");
  449.                 if ( pos != NPOS ) {
  450.                     pos += 7;
  451.                     SIZE_TYPE end = cit.find_first_of('"', pos);
  452.                     m_Title = cit.substr(pos, end - pos);
  453.                 }
  454.             }
  455.         }
  456.     }
  457.     
  458.     // Journal
  459.     x_SetJournal(gen, ctx);
  460.     
  461.     // Authors
  462.     if ( gen.CanGetAuthors() ) {
  463.         x_AddAuthors(gen.GetAuthors());
  464.     }
  465.     // MUID
  466.     if ( gen.CanGetMuid()  &&  m_MUID == 0 ) {
  467.         m_MUID = gen.GetMuid();
  468.     }
  469.     
  470.     // PMID
  471.     if ( gen.CanGetPmid()  &&  m_PMID == 0 ) {
  472.         m_PMID = gen.GetPmid();
  473.     }
  474.     // Volume
  475.     if ( gen.CanGetVolume()  &&  m_Volume.empty() ) {
  476.         m_Volume = gen.GetVolume();
  477.     }
  478.     // Issue
  479.     if ( gen.CanGetIssue()  &&  m_Issue.empty() ) {
  480.         m_Issue = gen.GetIssue();
  481.     }
  482.     // Pages
  483.     if ( gen.CanGetPages()  &&  m_Pages.empty() ) {
  484.         m_Pages = gen.GetPages();
  485.         s_FixPages(m_Pages);
  486.     }
  487.     // Date
  488.     if ( gen.CanGetDate()  &&  !m_Date ) {
  489.         m_Date = &gen.GetDate();
  490.     }
  491. }
  492. void CReferenceItem::x_Init(const CCit_sub& sub, CBioseqContext& ctx)
  493. {
  494.     // Title
  495.     m_Title = "Direct Submission";
  496.     // Authors
  497.     x_AddAuthors(sub.GetAuthors());
  498.     if ( sub.GetAuthors().CanGetAffil() ) {
  499.         FormatAffil(sub.GetAuthors().GetAffil(), m_Journal);
  500.     }
  501.     // Date
  502.     if ( sub.CanGetDate() ) {
  503.         m_Date = &sub.GetDate();
  504.     } else {
  505.         // complain?
  506.         if ( sub.CanGetImp() ) {
  507.             m_Date = &sub.GetImp().GetDate();
  508.         }
  509.     }
  510.     m_Category = eSubmission;
  511. }
  512. void CReferenceItem::x_Init(const CMedline_entry& mle, CBioseqContext& ctx)
  513. {
  514.     m_Category = ePublished;
  515.     if ( mle.CanGetUid()  &&  m_MUID == 0 ) {
  516.         m_MUID = mle.GetUid();
  517.     }
  518.     if ( !m_Date ) {
  519.         m_Date = &mle.GetEm();
  520.     }
  521.     if ( mle.CanGetPmid()  &&  m_PMID == 0 ) {
  522.         m_PMID = mle.GetPmid();
  523.     }
  524.     if ( mle.CanGetCit() ) {
  525.         x_Init(mle.GetCit(), ctx);
  526.     }
  527. }
  528. void CReferenceItem::x_Init(const CCit_art& art, CBioseqContext& ctx)
  529. {
  530.     // Title
  531.     if ( art.CanGetTitle()  &&  !art.GetTitle().Get().empty() ) {
  532.         m_Title = art.GetTitle().GetTitle();
  533.     }
  534.     // Authors
  535.     if ( art.CanGetAuthors() ) {
  536.         x_AddAuthors(art.GetAuthors());
  537.     }
  538.     // Journal
  539.     switch ( art.GetFrom().Which() ) {
  540.     case CCit_art::C_From::e_Journal:
  541.         x_Init(art.GetFrom().GetJournal(), ctx);
  542.         break;
  543.     case CCit_art::C_From::e_Book:
  544.         x_Init(art.GetFrom().GetBook(), ctx, true);
  545.         break;
  546.     case CCit_art::C_From::e_Proc:
  547.         x_Init(art.GetFrom().GetProc().GetBook(), ctx, true);
  548.         break;
  549.     default:
  550.         break;
  551.     }
  552.     if ( art.CanGetIds() ) {
  553.         ITERATE (CArticleIdSet::Tdata, it, art.GetIds().Get()) {
  554.             switch ( (*it)->Which() ) {
  555.             case CArticleId::e_Pubmed:
  556.                 if ( m_PMID == 0 ) {
  557.                     m_PMID = (*it)->GetPubmed();
  558.                 }
  559.                 break;
  560.             case CArticleId::e_Medline:
  561.                 if ( m_MUID == 0 ) {
  562.                     m_MUID = (*it)->GetMedline();
  563.                 }
  564.                 break;
  565.             default:
  566.                 break;
  567.             }
  568.         }
  569.     }
  570. }
  571. void CReferenceItem::x_Init(const CCit_jour& jour, CBioseqContext& ctx)
  572. {
  573.     x_SetJournal(jour.GetTitle(), ctx);
  574.     x_AddImprint(jour.GetImp(), ctx);
  575. }
  576. void CReferenceItem::x_Init
  577. (const CCit_book& book,
  578.  CBioseqContext& ctx,
  579.  bool for_art)
  580. {
  581.     if ( !for_art ) {
  582.         if ( book.CanGetImp() ) {
  583.             x_AddImprint(book.GetImp(), ctx);
  584.         }
  585.         if ( book.CanGetTitle()  &&  !book.GetTitle().Get().empty() ) {
  586.             m_Journal = book.GetTitle().GetTitle();
  587.         }
  588.         if ( m_Authors.Empty()  &&  book.CanGetAuthors() ) {
  589.             x_AddAuthors(book.GetAuthors());
  590.         }
  591.     }  else if ( book.CanGetTitle()  &&  book.CanGetImp() ) {
  592.         m_Book.Reset(&book);
  593.         x_AddImprint(book.GetImp(), ctx);
  594.     }
  595. }
  596. void CReferenceItem::x_Init(const CCit_pat& pat, CBioseqContext& ctx)
  597. {
  598.     bool embl = ctx.Config().IsFormatEMBL();
  599.     m_Category = ePublished;
  600.     m_Title = pat.GetTitle();
  601.     x_AddAuthors(pat.GetAuthors());
  602.     m_Journal = (embl ? "Patent number " : "Patent: ") + pat.GetCountry() + ' ';
  603.     if ( pat.CanGetNumber()  &&  !pat.GetNumber().empty() ) {
  604.         m_Journal += pat.GetNumber();
  605.     } else if ( pat.CanGetApp_number()  &&  !pat.GetApp_number().empty() ) {
  606.         m_Journal += pat.GetApp_number();
  607.     }
  608.     if ( pat.CanGetDoc_type()  &&  !pat.GetDoc_type().empty() ) {
  609.         m_Journal += '-';
  610.         m_Journal += pat.GetDoc_type();
  611.     }
  612.     CPatent_seq_id::TSeqid seqid = 0;
  613.     ITERATE (CBioseq::TId, it, ctx.GetBioseqIds()) {
  614.         if ((*it)->IsPatent()) {
  615.             seqid = (*it)->GetPatent().GetSeqid();
  616.         }
  617.     }
  618.     if ( seqid > 0 ) {
  619.         m_Journal += embl ? '/' : ' ';
  620.         m_Journal += NStr::IntToString(seqid);
  621.         if ( embl ) {
  622.             m_Journal += ", ";
  623.         }
  624.     } else {
  625.         m_Journal += ' ';
  626.     }
  627.     if ( pat.CanGetDate_issue() ) {
  628.         m_Journal += ' ';
  629.         DateToString(pat.GetDate_issue(), m_Journal);
  630.     } else if ( pat.CanGetApp_date() ) {
  631.         m_Journal += ' ';
  632.         DateToString(pat.GetApp_date(), m_Journal);
  633.     }
  634.     m_Journal += (embl ? '.' : ';');
  635. }
  636. void CReferenceItem::x_Init(const CCit_let& man, CBioseqContext& ctx)
  637. {
  638.     x_Init(man.GetCit(), ctx);
  639.     if (man.CanGetType()  &&  man.GetType() == CCit_let::eType_thesis) {
  640.         const CImprint& imp = man.GetCit().GetImp();
  641.         if ( !m_Journal.empty() ) {
  642.             m_Title = m_Journal;
  643.             m_Journal.erase();
  644.         }
  645.         m_Journal = "Thesis (";
  646.         imp.GetDate().GetDate(&m_Journal, "%Y");
  647.         m_Journal += ')';
  648.         if (imp.CanGetPrepub()
  649.             &&  imp.GetPrepub() == CImprint::ePrepub_in_press) {
  650.             m_Journal += ", In press";
  651.         }
  652.         if (imp.CanGetPub()) {
  653.             string affil;
  654.             FormatAffil(imp.GetPub(), affil);
  655.             replace(affil.begin(), affil.end(), '"', ''');
  656.             m_Journal += ' ' + affil;
  657.         }
  658.         m_Date.Reset();
  659.     }
  660. }
  661. void CReferenceItem::x_AddAuthors(const CAuth_list& auth_list)
  662. {
  663.     m_Authors.Reset(&auth_list);
  664.     if ( !auth_list.CanGetNames() ) return;
  665.     
  666.     // also populate the consortium (if available)
  667.     if ( !m_Consortium.empty() ) return;
  668.     const CAuth_list::TNames& names = auth_list.GetNames();
  669.     
  670.     if ( names.IsStd() ) {
  671.         ITERATE (CAuth_list::TNames::TStd, it, names.GetStd()) {
  672.             const CAuthor& auth = **it;
  673.             if ( auth.CanGetName()  &&  
  674.                  auth.GetName().IsConsortium() ) {
  675.                 m_Consortium = auth.GetName().GetConsortium();
  676.                 break;
  677.             }
  678.         }
  679.     }
  680. }
  681. void CReferenceItem::x_SetJournal(const CTitle& title, CBioseqContext& ctx)
  682. {
  683.     // Only GenBank/EMBL/DDBJ require ISO JTA in ENTREZ/RELEASE modes.
  684.     bool require_iso_jta = ctx.Config().CitArtIsoJta();
  685.     if ( !ctx.IsGED()  &&  !ctx.IsTPA() ) {
  686.         require_iso_jta = false;
  687.     }
  688.     // always use iso_jta title if present
  689.     const CTitle::C_E* ttl = 0;
  690.     ITERATE (CTitle::Tdata, it, title.Get()) {
  691.         if ( (*it)->IsIso_jta() ) {
  692.             ttl = *it;
  693.             break;
  694.         }
  695.     }
  696.     bool electronic_journal = false;
  697.     if ( ttl == 0 ) {
  698.         ttl = title.Get().front();
  699.         if ( ttl != 0  &&  ttl->IsName() ) {
  700.             if ( NStr::StartsWith(ttl->GetName(), "(er)", NStr::eNocase) ) {
  701.                 electronic_journal = true;
  702.             }
  703.         }
  704.         if ( require_iso_jta  &&  !electronic_journal ) {
  705.             return;
  706.         }
  707.         m_Journal = title.GetTitle();
  708.     } else {
  709.         m_Journal = ttl->GetIso_jta();
  710.     }
  711. }
  712. void CReferenceItem::x_SetJournal(const CCit_gen& gen, CBioseqContext& ctx)
  713. {
  714.     if ( !gen.CanGetCit()  &&  !gen.CanGetJournal()  &&  !gen.CanGetDate()  &&
  715.          gen.CanGetSerial_number()  &&  gen.GetSerial_number() != 0 ) {
  716.         return;
  717.     }
  718.     if ( !gen.CanGetJournal()  &&
  719.           gen.CanGetCit()  &&  
  720.           NStr::StartsWith(gen.GetCit(), "unpublished", NStr::eNocase) ) {
  721.         const string& cit = gen.GetCit();
  722.         if ( ctx.Config().NoAffilOnUnpub() ) {
  723.             m_Category = eUnpublished;
  724.             m_Journal = "Unpublished";
  725.             return;
  726.         }
  727.         if ( gen.CanGetAuthors()  &&  gen.GetAuthors().CanGetAffil() ) {
  728.             string affil;
  729.             (gen.GetAuthors().GetAffil(), affil);
  730.             if ( !affil.empty() ) {
  731.                 m_Category = eUnpublished;
  732.                 m_Journal = "Unpublished " + affil;
  733.                 return;
  734.             }
  735.         }
  736.         m_Journal = cit;
  737.         return;
  738.     }
  739.     
  740.     string result, in_press;
  741.     if ( gen.CanGetJournal() ) {
  742.         x_SetJournal(gen.GetJournal(), ctx);
  743.         result = m_Journal;
  744.     }
  745.     if ( gen.CanGetCit() ) {
  746.         const string& cit = gen.GetCit();
  747.         SIZE_TYPE pos = NStr::FindNoCase(cit, "Journal="");
  748.         if ( pos != NPOS ) {
  749.             result = cit.substr(pos + 9);
  750.         } else if ( NStr::StartsWith(cit, "submitted", NStr::eNocase)  ||
  751.                     NStr::StartsWith(cit, "unpublished", NStr::eNocase) ) {
  752.             if ( !ctx.Config().DropBadCitGens()  ||  !result.empty() ) {
  753.                 in_press = cit;
  754.             } else {
  755.                 in_press = "Unpublished";
  756.             }
  757.         } else if ( NStr::StartsWith(cit, "Online Publication", NStr::eNocase)  ||
  758.                     NStr::StartsWith(cit, "Published Only in DataBase", NStr::eNocase) ) {
  759.             in_press = cit;
  760.         } else if ( !ctx.Config().DropBadCitGens()  &&  result.empty() ) {
  761.             result = cit;
  762.         }
  763.     }
  764.     if ( !result.empty() ) {
  765.         SIZE_TYPE pos = result.find_first_of("="");
  766.         if ( pos != NPOS ) {
  767.             result.erase(pos);
  768.         }
  769.     }
  770.     
  771.     m_Journal = result;
  772.     if ( !in_press.empty() ) {
  773.         m_Journal += ' ';
  774.         m_Journal += in_press;
  775.     }
  776. }
  777. void CReferenceItem::x_AddImprint(const CImprint& imp, CBioseqContext& ctx)
  778. {
  779.     if ( !m_Date ) {
  780.         m_Date.Reset(&imp.GetDate());
  781.     }
  782.     if ( imp.IsSetVolume()  &&  !imp.GetVolume().empty()  ) {
  783.         m_Volume = imp.GetVolume();
  784.         if ( imp.IsSetPart_sup()  &&  !imp.GetPart_sup().empty() ) {
  785.             m_Volume += " (" + imp.GetPart_sup() + ")";
  786.         }
  787.     }
  788.     
  789.     if ( imp.IsSetIssue()  &&  !imp.GetIssue().empty() ) {
  790.         m_Issue = imp.GetIssue();
  791.         if ( imp.IsSetPart_supi()  &&  !imp.GetPart_supi().empty() ) {
  792.             m_Issue += " (" + imp.GetPart_supi() + ")";
  793.         }
  794.     }
  795.     if ( imp.IsSetPages()  &&  !imp.GetPages().empty() ) {
  796.         m_Pages = imp.GetPages();
  797.         s_FixPages(m_Pages);
  798.     }
  799.     if ( imp.IsSetPrepub() ) {
  800.         m_Prepub = imp.GetPrepub();
  801.         m_Category = 
  802.             m_Prepub != CImprint::ePrepub_in_press ? eUnpublished : ePublished;
  803.     } else {
  804.         m_Category = ePublished;
  805.     }
  806. }
  807. void CReferenceItem::GetAuthNames
  808. (list<string>& authors,
  809.  const CAuth_list* alp)
  810. {   
  811.     authors.clear();
  812.     if ( alp == 0 ) {
  813.         return;
  814.     }
  815.     const CAuth_list::TNames& names = alp->GetNames();
  816.     switch ( names.Which() ) {
  817.     case CAuth_list::TNames::e_Std:
  818.         ITERATE (CAuth_list::TNames::TStd, it, names.GetStd()) {
  819.             if ( !(*it)->CanGetName() ) {
  820.                 continue;
  821.             }
  822.             const CPerson_id& pid = (*it)->GetName();
  823.             string name;
  824.             pid.GetLabel(&name, CPerson_id::eGenbank);
  825.             authors.push_back(name);
  826.         }
  827.         break;
  828.         
  829.     case CAuth_list::TNames::e_Ml:
  830.         authors.insert(authors.end(),
  831.             names.GetMl().begin(), names.GetMl().end());
  832.         break;
  833.         
  834.     case CAuth_list::TNames::e_Str:
  835.         authors.insert(authors.end(),
  836.             names.GetStr().begin(), names.GetStr().end());
  837.         break;
  838.         
  839.     default:
  840.         break;
  841.     }
  842. }
  843. string CReferenceItem::GetAuthString(const CAuth_list* alp)
  844. {
  845.     list<string> authors;
  846.     if ( alp == 0 ) {
  847.         authors.push_back(".");
  848.     } else {
  849.         GetAuthNames(authors, alp);
  850.     }
  851.     CNcbiOstrstream auth_line;
  852.     list<string>::const_iterator last = --(authors.end());
  853.     string separator = kEmptyStr;
  854.     bool first = true;
  855.     ITERATE(list<string>, it, authors) {
  856.         if ( it == last ) {
  857.             separator = " and ";
  858.         }
  859.         auth_line << (first ? kEmptyStr : separator) << *it;
  860.         separator = ", ";
  861.         first = false;
  862.     }
  863.     return CNcbiOstrstreamToString(auth_line);
  864. }
  865. void CReferenceItem::x_CleanData(void)
  866. {
  867.     // !!!
  868.     // remove spaces from title etc.
  869. }
  870. /////////////////////////////////////////////////////////////////////////////
  871. //
  872. // Genbank Format Specific
  873. // these must be in "ASCIIbetical" order; beware of the fact that
  874. // closing quotes sort after spaces.
  875. static const string sc_RemarkText[] = {
  876.   "full automatic",
  877.   "full staff_entry",
  878.   "full staff_review",
  879.   "simple automatic",
  880.   "simple staff_entry",
  881.   "simple staff_review",
  882.   "unannotated automatic",
  883.   "unannotated staff_entry",
  884.   "unannotated staff_review"
  885. };
  886. static const CStaticArraySet<string> sc_Remarks(sc_RemarkText, sizeof(sc_RemarkText));
  887. void CReferenceItem::x_GatherRemark(CBioseqContext& ctx)
  888. {
  889.     list<string> l;
  890.     // comment
  891.     if ( m_Pubdesc->IsSetComment()  &&  !m_Pubdesc->GetComment().empty() ) {
  892.         const string& comment = m_Pubdesc->GetComment();
  893.         
  894.         if ( sc_Remarks.find(comment) == sc_Remarks.end() ) {
  895.             l.push_back(comment);
  896.         }
  897.     }
  898.     // for GBSeq format collect remarks only from comments.
  899.     if ( ctx.Config().IsFormatGBSeq() ) {
  900.         if ( !l.empty() ) {
  901.             m_Remark = l.front();
  902.         }
  903.         return;
  904.     }
  905.     // GIBBSQ
  906.     CSeq_id::TGibbsq gibbsq = 0;
  907.     ITERATE (CBioseq::TId, it, ctx.GetBioseqIds()) {
  908.         if ( (*it)->IsGibbsq() ) {
  909.             gibbsq = (*it)->GetGibbsq();
  910.         }
  911.     }
  912.     if ( gibbsq > 0 ) {
  913.         static const string str1 = 
  914.             "GenBank staff at the National Library of Medicine created this entry [NCBI gibbsq ";
  915.         static const string str2 = "] from the original journal article.";
  916.         l.push_back(str1 + NStr::IntToString(gibbsq) + str2);
  917.         // Figure
  918.         if ( m_Pubdesc->IsSetFig()  &&  !m_Pubdesc->GetFig().empty()) {
  919.             l.push_back("This sequence comes from " + m_Pubdesc->GetFig());
  920.         }
  921.         // Poly_a
  922.         if ( m_Pubdesc->IsSetPoly_a()  &&  m_Pubdesc->GetPoly_a() ) {
  923.         l.push_back("Polyadenylate residues occurring in the figure were 
  924.             omitted from the sequence.");
  925.         }
  926.         // Maploc
  927.         if ( m_Pubdesc->IsSetMaploc()  &&  !m_Pubdesc->GetMaploc().empty()) {
  928.             l.push_back("Map location: " + m_Pubdesc->GetMaploc());
  929.         }
  930.     }
  931.     
  932.     if ( m_Pubdesc->CanGetPub() ) {
  933.         ITERATE (CPubdesc::TPub::Tdata, it, m_Pubdesc->GetPub().Get()) {
  934.             if ( (*it)->IsArticle() ) {
  935.                 if ( (*it)->GetArticle().GetFrom().IsJournal() ) {
  936.                     const CCit_jour& jour = 
  937.                         (*it)->GetArticle().GetFrom().GetJournal();
  938.                     if ( jour.IsSetImp() ) {
  939.                         const CCit_jour::TImp& imp = jour.GetImp();
  940.                         if ( imp.IsSetRetract() ) {
  941.                             const CCitRetract& ret = imp.GetRetract();
  942.                             if ( ret.IsSetType()  &&
  943.                                 ret.GetType() == CCitRetract::eType_in_error  &&
  944.                                 ret.IsSetExp()  &&
  945.                                 !ret.GetExp().empty() ) {
  946.                                 l.push_back("Erratum:[" + ret.GetExp() + "]");
  947.                             }
  948.                         }
  949.                     }
  950.                 }
  951.             } else if ( (*it)->IsSub() ) {
  952.                 const CCit_sub& sub = (*it)->GetSub();
  953.                 if ( sub.IsSetDescr()  &&  !sub.GetDescr().empty() ) {
  954.                     l.push_back(sub.GetDescr());
  955.                 }
  956.             }
  957.         }
  958.     }
  959.     m_Remark = NStr::Join(l, "n");
  960. }
  961. /////////////////////////////////////////////////////////////////////////////
  962. //
  963. // Reference Sorting
  964. static size_t s_CountFields(const CDate& date)
  965. {
  966.     _ASSERT(date.IsStd());
  967.     const CDate::TStd& std = date.GetStd();
  968.     size_t count = 0;
  969.     if ( std.IsSetYear() ) {
  970.         ++count;
  971.     }
  972.     if ( std.IsSetMonth() ) {
  973.         ++count;
  974.     }
  975.     if ( std.IsSetDay() ) {
  976.         ++count;
  977.     }
  978.     if ( std.IsSetHour() ) {
  979.         ++count;
  980.     }
  981.     if ( std.IsSetMinute() ) {
  982.         ++count;
  983.     }
  984.     if ( std.IsSetSecond() ) {
  985.         ++count;
  986.     }
  987.     return count;
  988. }
  989. LessEqual::LessEqual(bool serial_first, bool is_refseq) :
  990.     m_SerialFirst(serial_first), m_IsRefSeq(is_refseq)
  991. {}
  992. bool LessEqual::operator()
  993. (const CRef<CReferenceItem>& ref1,
  994.  const CRef<CReferenceItem>& ref2)
  995. {
  996.     if ( m_SerialFirst  &&  ref1->GetSerial() != ref2->GetSerial() ) {
  997.         return ref1->GetSerial() < ref2->GetSerial();
  998.     }
  999.     // sort by category (published / unpublished / submission)
  1000.     if ( ref1->GetCategory() != ref2->GetCategory() ) {
  1001.         return ref1->GetCategory() < ref2->GetCategory();
  1002.     }
  1003.     // sort by date:
  1004.     // - publications with date come before those without one.
  1005.     // - more specific dates come before less specific ones.
  1006.     // - older publication comes first (except RefSeq).
  1007.     const CDate* d1 = ref1->GetDate();
  1008.     const CDate* d2 = ref2->GetDate();
  1009.     if ( (d1 != 0)  &&  (d2 == 0) ) {
  1010.         return true;
  1011.     } else if ( (d1 == 0)  &&  (d2 != 0) ) {
  1012.         return false;
  1013.     }
  1014.     if ( (d1 != 0)  &&  (d2 != 0) ) {
  1015.         CDate::ECompare status = ref1->GetDate()->Compare(*ref2->GetDate());
  1016.         if ( status == CDate::eCompare_unknown  &&
  1017.              d1->IsStd()  &&  d2->IsStd() ) {
  1018.             // one object is more specific than the other.
  1019.             size_t s1 = s_CountFields(*d1);
  1020.             size_t s2 = s_CountFields(*d2);
  1021.             return m_IsRefSeq ? s1 > s2 : s1 < s2;
  1022.         } else if ( status != CDate::eCompare_same ) {
  1023.             return m_IsRefSeq ? (status == CDate::eCompare_after) :
  1024.                                 (status == CDate::eCompare_before);
  1025.         }
  1026.     }
  1027.     // dates are the same, or both missing.
  1028.     
  1029.     // distinguish by uids (swap order for RefSeq)
  1030.     if ( ref1->GetPMID() != 0  &&  ref2->GetPMID() != 0  &&
  1031.          !(ref1->GetPMID() == ref2->GetPMID()) ) {
  1032.         return m_IsRefSeq ? (ref1->GetPMID() > ref2->GetPMID()) :
  1033.             (ref1->GetPMID() < ref2->GetPMID());
  1034.     }
  1035.     if ( ref1->GetMUID() != 0  &&  ref2->GetMUID() != 0  &&
  1036.          !(ref1->GetMUID() == ref2->GetMUID()) ) {
  1037.         return m_IsRefSeq ? (ref1->GetMUID() > ref2->GetMUID()) :
  1038.             (ref1->GetMUID() < ref2->GetMUID());
  1039.     }
  1040.     // just uids goes last
  1041.     if ( (ref1->GetPMID() != 0  &&  ref2->GetPMID() != 0)  ||
  1042.          (ref1->GetMUID() != 0  &&  ref2->GetMUID() != 0) ) {
  1043.         if ( ref1->JustUids()  &&  !ref2->JustUids() ) {
  1044.             return true;
  1045.         } else if ( !ref1->JustUids()  &&  ref2->JustUids() ) {
  1046.             return false;
  1047.         }
  1048.     }
  1049.     if ( ref1->GetReftype() != CPubdesc::eReftype_seq ) {
  1050.         return true;
  1051.     } else if ( ref2->GetReftype() != CPubdesc::eReftype_seq ) {
  1052.         return false;
  1053.     }
  1054.     
  1055.     // next use AUTHOR string
  1056.     string auth1 = CReferenceItem::GetAuthString(ref1->GetAuthors());
  1057.     string auth2 = CReferenceItem::GetAuthString(ref2->GetAuthors());
  1058.     int comp = NStr::CompareNocase(auth1, auth2);
  1059.     if ( comp != 0 ) {
  1060.         return comp < 0;
  1061.     }
  1062.     // !!! unique string ???
  1063.     if ( !m_SerialFirst ) {
  1064.         return ref1->GetSerial() < ref2->GetSerial();
  1065.     }
  1066.     return true;
  1067. }
  1068. END_SCOPE(objects)
  1069. END_NCBI_SCOPE
  1070. /*
  1071. * ===========================================================================
  1072. *
  1073. * $Log: reference_item.cpp,v $
  1074. * Revision 1000.2  2004/06/01 19:45:23  gouriano
  1075. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.18
  1076. *
  1077. * Revision 1.18  2004/05/21 21:42:54  gorelenk
  1078. * Added PCH ncbi_pch.hpp
  1079. *
  1080. * Revision 1.17  2004/05/20 17:11:45  ucko
  1081. * Reset strings with erase() rather than clear(), which isn't 100% portable.
  1082. *
  1083. * Revision 1.16  2004/05/20 13:47:54  shomrat
  1084. * Fixed Pub-set match
  1085. *
  1086. * Revision 1.15  2004/05/15 13:22:45  ucko
  1087. * Sort sc_RemarkText, and note the requirement.
  1088. *
  1089. * Revision 1.14  2004/05/14 13:15:25  shomrat
  1090. * Fixed use of CStaticArraySet
  1091. *
  1092. * Revision 1.13  2004/05/06 17:59:30  shomrat
  1093. * Handle duplicate references
  1094. *
  1095. * Revision 1.12  2004/04/27 15:14:04  shomrat
  1096. * Added logic for partial range formatting
  1097. *
  1098. * Revision 1.11  2004/04/22 15:56:30  shomrat
  1099. * Changes in context
  1100. *
  1101. * Revision 1.10  2004/04/13 16:49:36  shomrat
  1102. * GBSeq format changes
  1103. *
  1104. * Revision 1.9  2004/03/26 17:26:34  shomrat
  1105. * Set category to unpublished where needed
  1106. *
  1107. * Revision 1.8  2004/03/18 15:44:21  shomrat
  1108. * Fixes to REFERENCE formatting
  1109. *
  1110. * Revision 1.7  2004/03/10 16:21:17  shomrat
  1111. * Fixed reference sorting, Added REMARK gathering
  1112. *
  1113. * Revision 1.6  2004/03/05 18:42:59  shomrat
  1114. * Set category to Published if title exist
  1115. *
  1116. * Revision 1.5  2004/02/24 17:24:27  vasilche
  1117. * Added missing include <Pub.hpp>
  1118. *
  1119. * Revision 1.4  2004/02/11 22:55:44  shomrat
  1120. * use IsModeRelease method
  1121. *
  1122. * Revision 1.3  2004/02/11 17:00:46  shomrat
  1123. * minor changes to Matches method
  1124. *
  1125. * Revision 1.2  2003/12/18 17:43:36  shomrat
  1126. * context.hpp moved
  1127. *
  1128. * Revision 1.1  2003/12/17 20:24:12  shomrat
  1129. * Initial Revision (adapted from flat lib)
  1130. *
  1131. *
  1132. * ===========================================================================
  1133. */