/* $Id: SeqFeatData.cpp 667634 2023-05-18 17:44:07Z vasilche $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
 *               National Center for Biotechnology Information
 *
 *  This software/database is a "United States Government Work" under the
 *  terms of the United States Copyright Act.  It was written as part of
 *  the author's official duties as a United States Government employee and
 *  thus cannot be copyrighted.  This software/database is freely available
 *  to the public for use. The National Library of Medicine and the U.S.
 *  Government have not placed any restriction on its use or reproduction.
 *
 *  Although all reasonable efforts have been taken to ensure the accuracy
 *  and reliability of the software and data, the NLM and the U.S.
 *  Government do not and cannot warrant the performance or results that
 *  may be obtained by using this software or data. The NLM and the U.S.
 *  Government disclaim all warranties, express or implied, including
 *  warranties of performance, merchantability or fitness for any particular
 *  purpose.
 *
 *  Please cite the author in any work or product based on this material.
 *
 * ===========================================================================
 *
 * Author:  .......
 *
 * File Description:
 *   .......
 *
 * Remark:
 *   This code was originally generated by application DATATOOL
 *   using specifications from the ASN data definition file
 *   'seqfeat.asn'.
 */

// standard includes

// generated includes
#include <ncbi_pch.hpp>
#include <objects/seqfeat/SeqFeatData.hpp>
#include <objects/seqfeat/RNA_ref.hpp>
#include <objects/seqfeat/Imp_feat.hpp>
#include <objects/seq/Pubdesc.hpp>
#include <objects/general/User_object.hpp>
#include <objects/seqfeat/Prot_ref.hpp>
#include <objects/seqfeat/Gb_qual.hpp>

#include <algorithm>
#include <util/static_map.hpp>
#include <cassert>

// generated classes

BEGIN_NCBI_SCOPE

BEGIN_objects_SCOPE // namespace ncbi::objects::

// constructor
CSeqFeatData::CSeqFeatData(void)
{
    InvalidateCache();
}


struct SImportEntry {
    const char*            m_Name;
    CSeqFeatData::ESubtype m_Subtype;

    bool operator<(const SImportEntry& e) const {
        return strcmp(m_Name, e.m_Name) < 0;
    }
};

// NOTE: these must stay in ASCIIbetical order!
static const SImportEntry kImportTable[] = {
    { "-10_signal",          CSeqFeatData::eSubtype_10_signal },
    { "-35_signal",          CSeqFeatData::eSubtype_35_signal },
    { "3'UTR",               CSeqFeatData::eSubtype_3UTR },
    { "3'clip",              CSeqFeatData::eSubtype_3clip },
    { "5'UTR",               CSeqFeatData::eSubtype_5UTR },
    { "5'clip",              CSeqFeatData::eSubtype_5clip },
    { "CAAT_signal",         CSeqFeatData::eSubtype_CAAT_signal },
    { "C_region",            CSeqFeatData::eSubtype_C_region },
    { "D-loop",              CSeqFeatData::eSubtype_D_loop },
    { "D_segment",           CSeqFeatData::eSubtype_D_segment },
    { "GC_signal",           CSeqFeatData::eSubtype_GC_signal },
    { "Imp_CDS",             CSeqFeatData::eSubtype_Imp_CDS },
    { "J_segment",           CSeqFeatData::eSubtype_J_segment },
    { "LTR",                 CSeqFeatData::eSubtype_LTR },
    { "N_region",            CSeqFeatData::eSubtype_N_region },
    { "RBS",                 CSeqFeatData::eSubtype_RBS },
    { "STS",                 CSeqFeatData::eSubtype_STS },
    { "S_region",            CSeqFeatData::eSubtype_S_region },
    { "TATA_signal",         CSeqFeatData::eSubtype_TATA_signal },
    { "V_region",            CSeqFeatData::eSubtype_V_region },
    { "V_segment",           CSeqFeatData::eSubtype_V_segment },
    { "allele",              CSeqFeatData::eSubtype_allele },
    { "assembly_gap",        CSeqFeatData::eSubtype_assembly_gap },
    { "attenuator",          CSeqFeatData::eSubtype_attenuator },
    { "centromere",          CSeqFeatData::eSubtype_centromere },
    { "conflict",            CSeqFeatData::eSubtype_conflict },
    { "enhancer",            CSeqFeatData::eSubtype_enhancer },
    { "exon",                CSeqFeatData::eSubtype_exon },
    { "gap",                 CSeqFeatData::eSubtype_gap },
    { "iDNA",                CSeqFeatData::eSubtype_iDNA },
    { "import",              CSeqFeatData::eSubtype_imp },
    { "intron",              CSeqFeatData::eSubtype_intron },
    { "mat_peptide",         CSeqFeatData::eSubtype_mat_peptide },
    { "misc_RNA",            CSeqFeatData::eSubtype_misc_RNA },
    { "misc_binding",        CSeqFeatData::eSubtype_misc_binding },
    { "misc_difference",     CSeqFeatData::eSubtype_misc_difference },
    { "misc_feature",        CSeqFeatData::eSubtype_misc_feature },
    { "misc_recomb",         CSeqFeatData::eSubtype_misc_recomb },
    { "misc_signal",         CSeqFeatData::eSubtype_misc_signal },
    { "misc_structure",      CSeqFeatData::eSubtype_misc_structure },
    { "mobile_element",      CSeqFeatData::eSubtype_mobile_element },
    { "modified_base",       CSeqFeatData::eSubtype_modified_base },
    { "mutation",            CSeqFeatData::eSubtype_mutation },
    { "old_sequence",        CSeqFeatData::eSubtype_old_sequence },
    { "operon",              CSeqFeatData::eSubtype_operon },
    { "oriT",                CSeqFeatData::eSubtype_oriT },
    { "polyA_signal",        CSeqFeatData::eSubtype_polyA_signal },
    { "polyA_site",          CSeqFeatData::eSubtype_polyA_site },
    { "precursor_RNA",       CSeqFeatData::eSubtype_precursor_RNA },
    { "prim_transcript",     CSeqFeatData::eSubtype_prim_transcript },
    { "primer_bind",         CSeqFeatData::eSubtype_primer_bind },
    { "promoter",            CSeqFeatData::eSubtype_promoter },
    { "propeptide",          CSeqFeatData::eSubtype_propeptide },
    { "protein_bind",        CSeqFeatData::eSubtype_protein_bind },
    { "regulatory",          CSeqFeatData::eSubtype_regulatory },
    { "rep_origin",          CSeqFeatData::eSubtype_rep_origin },
    { "repeat_region",       CSeqFeatData::eSubtype_repeat_region },
    { "repeat_unit",         CSeqFeatData::eSubtype_repeat_unit },
    { "satellite",           CSeqFeatData::eSubtype_satellite },
    { "sig_peptide",         CSeqFeatData::eSubtype_sig_peptide },
    { "site_ref",            CSeqFeatData::eSubtype_site_ref },
    { "source",              CSeqFeatData::eSubtype_source },
    { "stem_loop",           CSeqFeatData::eSubtype_stem_loop },
    { "telomere",            CSeqFeatData::eSubtype_telomere },
    { "terminator",          CSeqFeatData::eSubtype_terminator },
    { "transit_peptide",     CSeqFeatData::eSubtype_transit_peptide },
    { "unsure",              CSeqFeatData::eSubtype_unsure },
    { "variation",           CSeqFeatData::eSubtype_variation },
    { "virion",              CSeqFeatData::eSubtype_virion }
};

static const SImportEntry* const kImportTableEnd
    = kImportTable + sizeof(kImportTable)/sizeof(kImportTable[0]);

// Feat info table
typedef SStaticPair<CSeqFeatData::E_Choice, CSeqFeatData::SFeatDataInfo> TInfoPair;

#define FEAT_INFO_PAIR(type, subtype, key_full, key_gb)                 \
    { CSeqFeatData::e_##type,                                           \
            { CSeqFeatData::eSubtype_##subtype, key_full, key_gb } }

static const TInfoPair kInfoPairs[] = {
    FEAT_INFO_PAIR(Gene, gene, "Gene", "gene"),
    FEAT_INFO_PAIR(Org, org, "Org", "source"),
    FEAT_INFO_PAIR(Cdregion, cdregion, "CDS", "CDS"),
    FEAT_INFO_PAIR(Pub, pub, "Cit", "misc_feature"),
    FEAT_INFO_PAIR(Seq, seq, "Xref", "misc_feature"),
    FEAT_INFO_PAIR(Region, region, "Region", "misc_feature"),
    FEAT_INFO_PAIR(Comment, comment, "Comment", "misc_feature"),
    FEAT_INFO_PAIR(Bond, bond, "Bond", "misc_feature"),
    FEAT_INFO_PAIR(Rsite, rsite, "Rsite", "misc_feature"),
    FEAT_INFO_PAIR(User, user, "User", "misc_feature"),
    FEAT_INFO_PAIR(Txinit, txinit, "TxInit", "promoter"),
    FEAT_INFO_PAIR(Num, num, "Num", "misc_feature"),
    FEAT_INFO_PAIR(Psec_str, psec_str, "SecStr", "SecStr"),
    FEAT_INFO_PAIR(Non_std_residue, non_std_residue, "NonStdRes", "NonStdRes"),
    FEAT_INFO_PAIR(Het, het, "Het", "Het"),
    FEAT_INFO_PAIR(Biosrc, biosrc, "Src", "source"),
    FEAT_INFO_PAIR(Clone, clone, "CloneRef", "misc_feature"),
    FEAT_INFO_PAIR(Variation, variation_ref, "Variation", "variation")
};

typedef CStaticPairArrayMap<CSeqFeatData::E_Choice,
                            CSeqFeatData::SFeatDataInfo> TInfoMap;
DEFINE_STATIC_ARRAY_MAP(TInfoMap, sc_InfoPairs, kInfoPairs);


// e_Prot info table
typedef SStaticPair<CProt_ref::EProcessed, CSeqFeatData::SFeatDataInfo> TProtInfoPair;

#define PROT_INFO_PAIR(proc, subtype, key_full, key_gb)                 \
    { CProt_ref::eProcessed_##proc,                                     \
            { CSeqFeatData::eSubtype_##subtype, key_full, key_gb } }

static const TProtInfoPair kProtInfoPairs[] = {
    PROT_INFO_PAIR(preprotein, preprotein, "Prot", "proprotein"),
    PROT_INFO_PAIR(mature, mat_peptide_aa, "Prot", "mat_peptide"),
    PROT_INFO_PAIR(signal_peptide, sig_peptide_aa, "Prot", "sig_peptide"),
    PROT_INFO_PAIR(transit_peptide, transit_peptide_aa, "Prot", "transit_peptide"),
    PROT_INFO_PAIR(propeptide, propeptide_aa, "Prot", "propeptide")
};

typedef CStaticPairArrayMap<CProt_ref::EProcessed,
                            CSeqFeatData::SFeatDataInfo> TProtInfoMap;
DEFINE_STATIC_ARRAY_MAP(TProtInfoMap, sc_ProtInfoPairs, kProtInfoPairs);


// e_Site info table
typedef SStaticPair<CSeqFeatData::ESite, CSeqFeatData::SFeatDataInfo> TSiteInfoPair;

#define SITE_INFO_PAIR(site, subtype, key_full, key_gb)                 \
    { CSeqFeatData::eSite_##site,                                       \
            { CSeqFeatData::eSubtype_##subtype, key_full, key_gb } }

static const TSiteInfoPair kSiteInfoPairs[] = {
    SITE_INFO_PAIR(binding, site, "Site", "misc_binding"),
    SITE_INFO_PAIR(metal_binding, site, "Site", "misc_binding"),
    SITE_INFO_PAIR(lipid_binding, site, "Site", "misc_binding"),
    SITE_INFO_PAIR(np_binding, site, "Site", "protein_bind"),
    SITE_INFO_PAIR(dna_binding, site, "Site", "primer_bind"),
    SITE_INFO_PAIR(signal_peptide, site, "Site", "sig_peptide"),
    SITE_INFO_PAIR(transit_peptide, site, "Site", "transit_peptide")
};

typedef CStaticPairArrayMap<CSeqFeatData::ESite,
                            CSeqFeatData::SFeatDataInfo> TSiteInfoMap;
DEFINE_STATIC_ARRAY_MAP(TSiteInfoMap, sc_SiteInfoPairs, kSiteInfoPairs);


// e_Rna info table
typedef SStaticPair<CRNA_ref::EType, CSeqFeatData::SFeatDataInfo> TRnaInfoPair;

#define RNA_INFO_PAIR(rna, subtype, key_full, key_gb)                   \
    { CRNA_ref::eType_##rna,                                            \
            { CSeqFeatData::eSubtype_##subtype, key_full, key_gb } }

static const TRnaInfoPair kRnaInfoPairs[] = {
    RNA_INFO_PAIR(premsg, preRNA, "precursor_RNA", "precursor_RNA"),
    RNA_INFO_PAIR(mRNA, mRNA, "mRNA", "mRNA"),
    RNA_INFO_PAIR(tRNA, tRNA, "tRNA", "tRNA"),
    RNA_INFO_PAIR(rRNA, rRNA, "rRNA", "rRNA"),
    RNA_INFO_PAIR(snRNA, snRNA, "snRNA", "snRNA"),
    RNA_INFO_PAIR(scRNA, scRNA, "scRNA", "scRNA"),
    RNA_INFO_PAIR(snoRNA, snoRNA, "snoRNA", "snoRNA"),
    RNA_INFO_PAIR(ncRNA, ncRNA, "ncRNA", "ncRNA"),
    RNA_INFO_PAIR(tmRNA, tmRNA, "tmRNA", "tmRNA")
};

typedef CStaticPairArrayMap<CRNA_ref::EType,
                            CSeqFeatData::SFeatDataInfo> TRnaInfoMap;
DEFINE_STATIC_ARRAY_MAP(TRnaInfoMap, sc_RnaInfoPairs, kRnaInfoPairs);


void CSeqFeatData::x_InitFeatDataInfo(void) const
{
    m_FeatDataInfo.m_Key_gb = "misc_feature"; // ???
    m_FeatDataInfo.m_Key_full = "???";
    switch (Which()) {
    case e_Prot:
        {
            TProtInfoMap::const_iterator it =
                sc_ProtInfoPairs.find(GetProt().GetProcessed());
            if (it != sc_ProtInfoPairs.end()) {
                m_FeatDataInfo = it->second;
            }
            else {
                m_FeatDataInfo.m_Subtype = eSubtype_prot;
                m_FeatDataInfo.m_Key_full = "Prot";
                m_FeatDataInfo.m_Key_gb = "Protein";
            }
            break;
        }
    case e_Site: // Is this correct, or are these encoded as Imp?
        {
            TSiteInfoMap::const_iterator it = sc_SiteInfoPairs.find(GetSite());
            if (it != sc_SiteInfoPairs.end()) {
                m_FeatDataInfo = it->second;
            }
            else {
                m_FeatDataInfo.m_Subtype = eSubtype_site;
                m_FeatDataInfo.m_Key_full = "Site";
                m_FeatDataInfo.m_Key_gb = "misc_feature";
            }
            break;
        }
    case e_Rna:
        {
            CRNA_ref_Base::TType rna_type = GetRna().GetType();
            TRnaInfoMap::const_iterator it =
                sc_RnaInfoPairs.find(rna_type);
            if (it != sc_RnaInfoPairs.end()) {
                m_FeatDataInfo = it->second;
            }
            else {
                bool can_get_name = (GetRna().CanGetExt()
                                    &&  GetRna().GetExt().IsName());
                const string& ext_name = (can_get_name
                                        ? GetRna().GetExt().GetName()
                                        : kEmptyStr);
                if (ext_name == "ncRNA") {
                    m_FeatDataInfo.m_Subtype = eSubtype_ncRNA;
                    m_FeatDataInfo.m_Key_full = "ncRNA";
                } else if (ext_name == "tmRNA") {
                    m_FeatDataInfo.m_Subtype = eSubtype_tmRNA;
                    m_FeatDataInfo.m_Key_full = "tmRNA";
                } else {
                    m_FeatDataInfo.m_Subtype = eSubtype_otherRNA;
                    bool other = GetRna().GetType() == CRNA_ref::eType_other;
                    m_FeatDataInfo.m_Key_full = other ? "RNA" : "misc_RNA";
                }
                m_FeatDataInfo.m_Key_gb = "misc_RNA";
            }
            break;
        }
    case e_Imp:
    {
        const string& key    = GetImp().GetKey();
        SImportEntry  key2   = { key.c_str(), eSubtype_imp };
        const SImportEntry* result = lower_bound(kImportTable,
                                                 kImportTableEnd,
                                                 key2);
        if ( result == kImportTableEnd ||
             strcmp(key2.m_Name, result->m_Name) ) {
            m_FeatDataInfo.m_Subtype = eSubtype_imp;
        } else {
            m_FeatDataInfo.m_Subtype = result->m_Subtype;
        }
        m_FeatDataInfo.m_Key_gb = key.c_str(); // "Imp"?;
        m_FeatDataInfo.m_Key_full = key.c_str();
        break;
    }
    default:
        {
            TInfoMap::const_iterator it = sc_InfoPairs.find(Which());
            if (it != sc_InfoPairs.end()) {
                m_FeatDataInfo = it->second;
            }
            else {
                m_FeatDataInfo.m_Subtype = eSubtype_bad;
                m_FeatDataInfo.m_Key_full = "???";
                m_FeatDataInfo.m_Key_gb = "misc_feature"; // ???
            }
        }
    }
}


// destructor
CSeqFeatData::~CSeqFeatData(void)
{
}


// ASCII representation of subtype (GenBank feature key, e.g.)
string CSeqFeatData::GetKey(EVocabulary vocab) const
{
    if (m_FeatDataInfo.m_Subtype == eSubtype_any) {
        x_InitFeatDataInfo();
    }
    return (vocab == eVocabulary_genbank) ?
        m_FeatDataInfo.m_Key_gb : m_FeatDataInfo.m_Key_full;
}


CSeqFeatData::ESubtype CSeqFeatData::GetSubtype(void) const
{
    if (m_FeatDataInfo.m_Subtype == eSubtype_any) { // unknown
        x_InitFeatDataInfo();
    }
    return m_FeatDataInfo.m_Subtype;
}


void CSeqFeatData::Assign(const CSerialObject& source,
                          ESerialRecursionMode how)
{
    InvalidateCache();
    Tparent::Assign(source, how);
}


void CSeqFeatData::PostRead(void) const
{
    InvalidateCache();
}


DEFINE_STATIC_MUTEX(sx_InitTablesMutex);


typedef vector<CSeqFeatData::E_Choice> TSubtypesTable;
static CSafeStatic<TSubtypesTable> sx_SubtypesTable;
static atomic<bool> sx_SubtypesTableInitialized;

CSeqFeatData::E_Choice CSeqFeatData::GetTypeFromSubtype(ESubtype subtype)
{
    if ( !sx_SubtypesTableInitialized.load(memory_order_acquire) ) {
        s_InitSubtypesTable();
    }
    return (*sx_SubtypesTable)[subtype];
}

MAKE_TWOWAY_CONST_MAP(sm_FeatKeys, ct::tagStrNocase, CSeqFeatData::ESubtype,
{
    {  "-10_signal",         CSeqFeatData::eSubtype_10_signal           },
    {  "-35_signal",         CSeqFeatData::eSubtype_35_signal           },
    {  "3'UTR",              CSeqFeatData::eSubtype_3UTR                },
    {  "3'clip",             CSeqFeatData::eSubtype_3clip               },
    {  "5'UTR",              CSeqFeatData::eSubtype_5UTR                },
    {  "5'clip",             CSeqFeatData::eSubtype_5clip               },
    {  "Bond",               CSeqFeatData::eSubtype_bond                },
    {  "CAAT_signal",        CSeqFeatData::eSubtype_CAAT_signal         },
    {  "CDS",                CSeqFeatData::eSubtype_cdregion            },
    {  "C_region",           CSeqFeatData::eSubtype_C_region            },
    {  "Cit",                CSeqFeatData::eSubtype_pub                 },
    {  "CloneRef",           CSeqFeatData::eSubtype_clone               },
    {  "Comment",            CSeqFeatData::eSubtype_comment             },
    {  "D-loop",             CSeqFeatData::eSubtype_D_loop              },
    {  "D_segment",          CSeqFeatData::eSubtype_D_segment           },
    {  "GC_signal",          CSeqFeatData::eSubtype_GC_signal           },
    {  "Het",                CSeqFeatData::eSubtype_het                 },
    {  "J_segment",          CSeqFeatData::eSubtype_J_segment           },
    {  "LTR",                CSeqFeatData::eSubtype_LTR                 },
    {  "N_region",           CSeqFeatData::eSubtype_N_region            },
    {  "NonStdRes",          CSeqFeatData::eSubtype_non_std_residue     },
    {  "Num",                CSeqFeatData::eSubtype_num                 },
    {  "Protein",            CSeqFeatData::eSubtype_prot                },
    {  "RBS",                CSeqFeatData::eSubtype_RBS                 },
    {  "REFERENCE",          CSeqFeatData::eSubtype_pub                 },
    {  "Region",             CSeqFeatData::eSubtype_region              },
    {  "Rsite",              CSeqFeatData::eSubtype_rsite               },
    {  "STS",                CSeqFeatData::eSubtype_STS                 },
    {  "S_region",           CSeqFeatData::eSubtype_S_region            },
    {  "SecStr",             CSeqFeatData::eSubtype_psec_str            },
    {  "Site",               CSeqFeatData::eSubtype_site                },
    {  "Site-ref",           CSeqFeatData::eSubtype_site_ref            },
    {  "Src",                CSeqFeatData::eSubtype_biosrc              },
    {  "TATA_signal",        CSeqFeatData::eSubtype_TATA_signal         },
    {  "TxInit",             CSeqFeatData::eSubtype_txinit              },
    {  "User",               CSeqFeatData::eSubtype_user                },
    {  "V_region",           CSeqFeatData::eSubtype_V_region            },
    {  "V_segment",          CSeqFeatData::eSubtype_V_segment           },
    {  "VariationRef",       CSeqFeatData::eSubtype_variation_ref       },
    {  "Xref",               CSeqFeatData::eSubtype_seq                 },
    {  "assembly_gap",       CSeqFeatData::eSubtype_assembly_gap        },
    {  "attenuator",         CSeqFeatData::eSubtype_attenuator          },
    {  "centromere",         CSeqFeatData::eSubtype_centromere          },
    {  "conflict",           CSeqFeatData::eSubtype_conflict            },
    {  "enhancer",           CSeqFeatData::eSubtype_enhancer            },
    {  "exon",               CSeqFeatData::eSubtype_exon                },
    {  "gap",                CSeqFeatData::eSubtype_gap                 },
    {  "gene",               CSeqFeatData::eSubtype_gene                },
    {  "iDNA",               CSeqFeatData::eSubtype_iDNA                },
    {  "intron",             CSeqFeatData::eSubtype_intron              },
    {  "mRNA",               CSeqFeatData::eSubtype_mRNA                },
    {  "mat_peptide",        CSeqFeatData::eSubtype_mat_peptide_aa      },
    {  "mat_peptide_nt",     CSeqFeatData::eSubtype_mat_peptide         },
    {  "misc_RNA",           CSeqFeatData::eSubtype_otherRNA            },
    {  "misc_binding",       CSeqFeatData::eSubtype_misc_binding        },
    {  "misc_difference",    CSeqFeatData::eSubtype_misc_difference     },
    {  "misc_feature",       CSeqFeatData::eSubtype_misc_feature        },
    {  "misc_recomb",        CSeqFeatData::eSubtype_misc_recomb         },
    {  "misc_signal",        CSeqFeatData::eSubtype_misc_signal         },
    {  "misc_structure",     CSeqFeatData::eSubtype_misc_structure      },
    {  "mobile_element",     CSeqFeatData::eSubtype_mobile_element      },
    {  "modified_base",      CSeqFeatData::eSubtype_modified_base       },
    {  "ncRNA",              CSeqFeatData::eSubtype_ncRNA               },
    {  "old_sequence",       CSeqFeatData::eSubtype_old_sequence        },
    {  "operon",             CSeqFeatData::eSubtype_operon              },
    {  "oriT",               CSeqFeatData::eSubtype_oriT                },
    {  "polyA_signal",       CSeqFeatData::eSubtype_polyA_signal        },
    {  "polyA_site",         CSeqFeatData::eSubtype_polyA_site          },
    {  "precursor_RNA",      CSeqFeatData::eSubtype_preRNA              },
    {  "prim_transcript",    CSeqFeatData::eSubtype_prim_transcript     },
    {  "primer_bind",        CSeqFeatData::eSubtype_primer_bind         },
    {  "promoter",           CSeqFeatData::eSubtype_promoter            },
    {  "propeptide",         CSeqFeatData::eSubtype_propeptide_aa       },
    {  "propeptide_nt",      CSeqFeatData::eSubtype_propeptide          },
    {  "proprotein",         CSeqFeatData::eSubtype_preprotein          },
    {  "protein_bind",       CSeqFeatData::eSubtype_protein_bind        },
    {  "rRNA",               CSeqFeatData::eSubtype_rRNA                },
    {  "regulatory",         CSeqFeatData::eSubtype_regulatory          },
    {  "rep_origin",         CSeqFeatData::eSubtype_rep_origin          },
    {  "repeat_region",      CSeqFeatData::eSubtype_repeat_region       },
    {  "repeat_unit",        CSeqFeatData::eSubtype_repeat_unit         },
    {  "satellite",          CSeqFeatData::eSubtype_satellite           },
    {  "scRNA",              CSeqFeatData::eSubtype_scRNA               },
    {  "sig_peptide",        CSeqFeatData::eSubtype_sig_peptide_aa      },
    {  "sig_peptide_nt",     CSeqFeatData::eSubtype_sig_peptide         },
    {  "snRNA",              CSeqFeatData::eSubtype_snRNA               },
    {  "snoRNA",             CSeqFeatData::eSubtype_snoRNA              },
    {  "source",             CSeqFeatData::eSubtype_biosrc              },
    {  "stem_loop",          CSeqFeatData::eSubtype_stem_loop           },
    {  "tRNA",               CSeqFeatData::eSubtype_tRNA                },
    {  "telomere",           CSeqFeatData::eSubtype_telomere            },
    {  "terminator",         CSeqFeatData::eSubtype_terminator          },
    {  "tmRNA",              CSeqFeatData::eSubtype_tmRNA               },
    {  "transit_peptide",    CSeqFeatData::eSubtype_transit_peptide_aa  },
    {  "transit_peptide_nt", CSeqFeatData::eSubtype_transit_peptide     },
    {  "unsure",             CSeqFeatData::eSubtype_unsure              },
    {  "variation",          CSeqFeatData::eSubtype_variation           },
    {  "virion",             CSeqFeatData::eSubtype_virion              }
})

CSeqFeatData::ESubtype CSeqFeatData::SubtypeNameToValue(CTempString sName)
{
    auto it = sm_FeatKeys.first.find(sName);
    if (it == sm_FeatKeys.first.end())
        return eSubtype_bad;

    if (sName == "pre_RNA")
        return eSubtype_preRNA;

    return it->second;
}

CTempString CSeqFeatData::SubtypeValueToName(CSeqFeatData::ESubtype eSubtype)
{
    auto it = sm_FeatKeys.second.find(eSubtype);
    if (it == sm_FeatKeys.second.end())
        return kEmptyStr;

    return it->second;
}

bool CSeqFeatData::CanHaveGene(CSeqFeatData::ESubtype subtype) 
{
    switch(subtype) {
    case eSubtype_assembly_gap:
    case eSubtype_biosrc:
    case eSubtype_centromere:
    case eSubtype_gap:
    case eSubtype_operon:
    case eSubtype_rep_origin:
    case eSubtype_telomere:
        return false;
    default:
        break;
    }
    return true;
}

namespace
{
    static constexpr CSeqFeatData::TLegalQualifiers empty_quals{};
}

const CSeqFeatData::TQualifiers& CSeqFeatData::GetMandatoryQualifiers(ESubtype subtype)
{
    MAKE_CONST_MAP(sx_MandatoryQuals, CSeqFeatData::ESubtype, CSeqFeatData::TQualifiers,
        {
        {eSubtype_conflict,       {eQual_citation}},
        {eSubtype_misc_binding,   {eQual_bound_moiety}},
        {eSubtype_modified_base,  {eQual_mod_base}},
        {eSubtype_old_sequence,   {eQual_citation}},
        {eSubtype_protein_bind,   {eQual_bound_moiety}},
        {eSubtype_source,         {eQual_organism}},
        {eSubtype_gap,            {eQual_estimated_length}},
        {eSubtype_operon,         {eQual_operon}},
        // although INSDC indicates that mol_type should be mandatory on
        // source subtype, we do not do so since there are legacy
        // records for which a mol_type could cause loss of information.
        {eSubtype_ncRNA,          {eQual_ncRNA_class}},
        {eSubtype_mobile_element, {eQual_mobile_element_type}},
        {eSubtype_assembly_gap,   {eQual_estimated_length, eQual_gap_type}},
        {eSubtype_regulatory,     {eQual_regulatory_class}},
        });

    auto iter = sx_MandatoryQuals.find(subtype);
    if (iter == sx_MandatoryQuals.end()) {
        return empty_quals;
    }
    return iter->second;
}


#ifdef _DEBUG
struct SSubtypeInfo {
    CSeqFeatData::E_Choice m_Type;
    CSeqFeatData::ESubtype m_Subtype;
    int m_Value;
    const char* m_Name;
};
#define SUBTYPE_INFO(type, subtype, value)  \
    { CSeqFeatData::type, CSeqFeatData::subtype, value, #subtype }
static const SSubtypeInfo s_subtype_info[] = {
    SUBTYPE_INFO(           e_not_set,                   eSubtype_bad,   0),
    SUBTYPE_INFO(              e_Gene,                  eSubtype_gene,   1),
    SUBTYPE_INFO(               e_Org,                   eSubtype_org,   2),
    SUBTYPE_INFO(          e_Cdregion,              eSubtype_cdregion,   3),
    SUBTYPE_INFO(              e_Prot,                  eSubtype_prot,   4),
    SUBTYPE_INFO(              e_Prot,            eSubtype_preprotein,   5),
    SUBTYPE_INFO(              e_Prot,        eSubtype_mat_peptide_aa,   6),
    SUBTYPE_INFO(              e_Prot,        eSubtype_sig_peptide_aa,   7),
    SUBTYPE_INFO(              e_Prot,    eSubtype_transit_peptide_aa,   8),
    SUBTYPE_INFO(               e_Rna,                eSubtype_preRNA,   9),
    SUBTYPE_INFO(               e_Rna,                  eSubtype_mRNA,  10),
    SUBTYPE_INFO(               e_Rna,                  eSubtype_tRNA,  11),
    SUBTYPE_INFO(               e_Rna,                  eSubtype_rRNA,  12),
    SUBTYPE_INFO(               e_Rna,                 eSubtype_snRNA,  13),
    SUBTYPE_INFO(               e_Rna,                 eSubtype_scRNA,  14),
    SUBTYPE_INFO(               e_Rna,                eSubtype_snoRNA,  15),
    SUBTYPE_INFO(               e_Rna,              eSubtype_otherRNA,  16),
    SUBTYPE_INFO(               e_Pub,                   eSubtype_pub,  17),
    SUBTYPE_INFO(               e_Seq,                   eSubtype_seq,  18),
    SUBTYPE_INFO(               e_Imp,                   eSubtype_imp,  19),
    SUBTYPE_INFO(               e_Imp,                eSubtype_allele,  20),
    SUBTYPE_INFO(               e_Imp,            eSubtype_attenuator,  21),
    SUBTYPE_INFO(               e_Imp,              eSubtype_C_region,  22),
    SUBTYPE_INFO(               e_Imp,           eSubtype_CAAT_signal,  23),
    SUBTYPE_INFO(               e_Imp,               eSubtype_Imp_CDS,  24),
    SUBTYPE_INFO(               e_Imp,              eSubtype_conflict,  25),
    SUBTYPE_INFO(               e_Imp,                eSubtype_D_loop,  26),
    SUBTYPE_INFO(               e_Imp,             eSubtype_D_segment,  27),
    SUBTYPE_INFO(               e_Imp,              eSubtype_enhancer,  28),
    SUBTYPE_INFO(               e_Imp,                  eSubtype_exon,  29),
    SUBTYPE_INFO(               e_Imp,             eSubtype_EC_number,  30),
    SUBTYPE_INFO(               e_Imp,             eSubtype_GC_signal,  31),
    SUBTYPE_INFO(               e_Imp,                  eSubtype_iDNA,  32),
    SUBTYPE_INFO(               e_Imp,                eSubtype_intron,  33),
    SUBTYPE_INFO(               e_Imp,             eSubtype_J_segment,  34),
    SUBTYPE_INFO(               e_Imp,                   eSubtype_LTR,  35),
    SUBTYPE_INFO(               e_Imp,           eSubtype_mat_peptide,  36),
    SUBTYPE_INFO(               e_Imp,          eSubtype_misc_binding,  37),
    SUBTYPE_INFO(               e_Imp,       eSubtype_misc_difference,  38),
    SUBTYPE_INFO(               e_Imp,          eSubtype_misc_feature,  39),
    SUBTYPE_INFO(               e_Imp,           eSubtype_misc_recomb,  40),
    SUBTYPE_INFO(               e_Imp,              eSubtype_misc_RNA,  41),
    SUBTYPE_INFO(               e_Imp,           eSubtype_misc_signal,  42),
    SUBTYPE_INFO(               e_Imp,        eSubtype_misc_structure,  43),
    SUBTYPE_INFO(               e_Imp,         eSubtype_modified_base,  44),
    SUBTYPE_INFO(               e_Imp,              eSubtype_mutation,  45),
    SUBTYPE_INFO(               e_Imp,              eSubtype_N_region,  46),
    SUBTYPE_INFO(               e_Imp,          eSubtype_old_sequence,  47),
    SUBTYPE_INFO(               e_Imp,          eSubtype_polyA_signal,  48),
    SUBTYPE_INFO(               e_Imp,            eSubtype_polyA_site,  49),
    SUBTYPE_INFO(               e_Imp,         eSubtype_precursor_RNA,  50),
    SUBTYPE_INFO(               e_Imp,       eSubtype_prim_transcript,  51),
    SUBTYPE_INFO(               e_Imp,           eSubtype_primer_bind,  52),
    SUBTYPE_INFO(               e_Imp,              eSubtype_promoter,  53),
    SUBTYPE_INFO(               e_Imp,          eSubtype_protein_bind,  54),
    SUBTYPE_INFO(               e_Imp,                   eSubtype_RBS,  55),
    SUBTYPE_INFO(               e_Imp,         eSubtype_repeat_region,  56),
    SUBTYPE_INFO(               e_Imp,           eSubtype_repeat_unit,  57),
    SUBTYPE_INFO(               e_Imp,            eSubtype_rep_origin,  58),
    SUBTYPE_INFO(               e_Imp,              eSubtype_S_region,  59),
    SUBTYPE_INFO(               e_Imp,             eSubtype_satellite,  60),
    SUBTYPE_INFO(               e_Imp,           eSubtype_sig_peptide,  61),
    SUBTYPE_INFO(               e_Imp,                eSubtype_source,  62),
    SUBTYPE_INFO(               e_Imp,             eSubtype_stem_loop,  63),
    SUBTYPE_INFO(               e_Imp,                   eSubtype_STS,  64),
    SUBTYPE_INFO(               e_Imp,           eSubtype_TATA_signal,  65),
    SUBTYPE_INFO(               e_Imp,            eSubtype_terminator,  66),
    SUBTYPE_INFO(               e_Imp,       eSubtype_transit_peptide,  67),
    SUBTYPE_INFO(               e_Imp,                eSubtype_unsure,  68),
    SUBTYPE_INFO(               e_Imp,              eSubtype_V_region,  69),
    SUBTYPE_INFO(               e_Imp,             eSubtype_V_segment,  70),
    SUBTYPE_INFO(               e_Imp,             eSubtype_variation,  71),
    SUBTYPE_INFO(               e_Imp,                eSubtype_virion,  72),
    SUBTYPE_INFO(               e_Imp,                 eSubtype_3clip,  73),
    SUBTYPE_INFO(               e_Imp,                  eSubtype_3UTR,  74),
    SUBTYPE_INFO(               e_Imp,                 eSubtype_5clip,  75),
    SUBTYPE_INFO(               e_Imp,                  eSubtype_5UTR,  76),
    SUBTYPE_INFO(               e_Imp,             eSubtype_10_signal,  77),
    SUBTYPE_INFO(               e_Imp,             eSubtype_35_signal,  78),
    SUBTYPE_INFO(               e_Imp,                   eSubtype_gap,  79),
    SUBTYPE_INFO(               e_Imp,                eSubtype_operon,  80),
    SUBTYPE_INFO(               e_Imp,                  eSubtype_oriT,  81),
    SUBTYPE_INFO(               e_Imp,              eSubtype_site_ref,  82),
    SUBTYPE_INFO(            e_Region,                eSubtype_region,  83),
    SUBTYPE_INFO(           e_Comment,               eSubtype_comment,  84),
    SUBTYPE_INFO(              e_Bond,                  eSubtype_bond,  85),
    SUBTYPE_INFO(              e_Site,                  eSubtype_site,  86),
    SUBTYPE_INFO(             e_Rsite,                 eSubtype_rsite,  87),
    SUBTYPE_INFO(              e_User,                  eSubtype_user,  88),
    SUBTYPE_INFO(            e_Txinit,                eSubtype_txinit,  89),
    SUBTYPE_INFO(               e_Num,                   eSubtype_num,  90),
    SUBTYPE_INFO(          e_Psec_str,              eSubtype_psec_str,  91),
    SUBTYPE_INFO(   e_Non_std_residue,       eSubtype_non_std_residue,  92),
    SUBTYPE_INFO(               e_Het,                   eSubtype_het,  93),
    SUBTYPE_INFO(            e_Biosrc,                eSubtype_biosrc,  94),
    SUBTYPE_INFO(               e_Rna,                 eSubtype_ncRNA,  95),
    SUBTYPE_INFO(               e_Rna,                 eSubtype_tmRNA,  96),
    SUBTYPE_INFO(             e_Clone,                 eSubtype_clone,  97),
    SUBTYPE_INFO(         e_Variation,         eSubtype_variation_ref,  98),
    SUBTYPE_INFO(               e_Imp,        eSubtype_mobile_element,  99),
    SUBTYPE_INFO(               e_Imp,            eSubtype_centromere, 100),
    SUBTYPE_INFO(               e_Imp,              eSubtype_telomere, 101),
    SUBTYPE_INFO(               e_Imp,          eSubtype_assembly_gap, 102),
    SUBTYPE_INFO(               e_Imp,            eSubtype_regulatory, 103),
    SUBTYPE_INFO(               e_Imp,            eSubtype_propeptide, 104),
    SUBTYPE_INFO(              e_Prot,         eSubtype_propeptide_aa, 105),
    SUBTYPE_INFO(           e_not_set,                   eSubtype_max, 106),
    SUBTYPE_INFO(           e_not_set,                   eSubtype_any, 255)
};
static const size_t s_subtype_count =
    sizeof(s_subtype_info)/sizeof(s_subtype_info[0]);
#endif


void CSeqFeatData::s_InitSubtypesTable(void)
{
    if (sx_SubtypesTableInitialized.load(memory_order_acquire)) {
        return;
    }
    CMutexGuard guard(sx_InitTablesMutex);
    if (sx_SubtypesTableInitialized.load(memory_order_acquire)) {
        return;
    }
    TSubtypesTable& table = *sx_SubtypesTable;
    table.assign(eSubtype_any + 1, e_not_set);

    table[eSubtype_gene] = e_Gene;
    table[eSubtype_org] = e_Org;
    table[eSubtype_cdregion] = e_Cdregion;
    table[eSubtype_pub] = e_Pub;
    table[eSubtype_seq] = e_Seq;
    table[eSubtype_region] = e_Region;
    table[eSubtype_comment] = e_Comment;
    table[eSubtype_bond] = e_Bond;
    table[eSubtype_site] = e_Site;
    table[eSubtype_rsite] = e_Rsite;
    table[eSubtype_user] = e_User;
    table[eSubtype_txinit] = e_Txinit;
    table[eSubtype_num] = e_Num;
    table[eSubtype_psec_str] = e_Psec_str;
    table[eSubtype_non_std_residue] = e_Non_std_residue;
    table[eSubtype_het] = e_Het;
    table[eSubtype_biosrc] = e_Biosrc;
    table[eSubtype_clone] = e_Clone;
    table[eSubtype_variation_ref] = e_Variation;
    for (int sub = eSubtype_prot; sub <= eSubtype_transit_peptide_aa; ++sub) {
        table[ESubtype(sub)] = e_Prot;
    }
    for (int sub = eSubtype_preRNA; sub <= eSubtype_otherRNA; ++sub) {
        table[ESubtype(sub)] = e_Rna;
    }
    table[eSubtype_ncRNA] = e_Rna;
    table[eSubtype_tmRNA] = e_Rna;
    for (int sub = eSubtype_imp; sub <= eSubtype_site_ref; ++sub) {
        table[ESubtype(sub)] = e_Imp;
    }
    for ( const SImportEntry* p = kImportTable; p != kImportTableEnd; ++p ) {
        table[p->m_Subtype] = e_Imp;
    }
    table[eSubtype_propeptide] = e_Imp;
    table[eSubtype_propeptide_aa] = e_Prot;

    sx_SubtypesTableInitialized.store(true, memory_order_release);

#ifdef _DEBUG
    if ( false ) { // print new definition of s_subtype_info[]
        NcbiCout << "static const SSubtypeInfo s_subtype_info[] = {\n";
        for ( size_t i = 0; i < s_subtype_count; ++i ) {
            const SSubtypeInfo& info = s_subtype_info[i];
            string type = SelectionName(GetTypeFromSubtype(info.m_Subtype));
            if ( type == "not set" ) {
                type = "not_set";
            }
            else {
                type[0] = toupper(type[0]);
                NStr::ReplaceInPlace(type, "-", "_");
            }
            type = "e_"+type;
            NcbiCout << "    SUBTYPE_INFO("
                     << setw(20) << type << ", "
                     << setw(30) << info.m_Name << ", "
                     << setw(3) << info.m_Subtype << ")";
            if ( i != s_subtype_count-1 ) NcbiCout << ",";
            NcbiCout << "\n";
        }
        NcbiCout << "};" << NcbiEndl;
    }
    // check if type/subtype values didn't change
    for ( size_t i = 0; i < s_subtype_count; ++i ) {
        const SSubtypeInfo& info = s_subtype_info[i];
        _ASSERT(info.m_Type == GetTypeFromSubtype(info.m_Subtype));
    }
#endif    
}

const CSeqFeatData::TSubTypeQualifiersMap& CSeqFeatData::s_GetLegalQualMap() noexcept
{
    MAKE_CONST_MAP(legal_quals_proxy, ESubtype, TLegalQualifiers,
        {
{ eSubtype_gene, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_nomenclature,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_phenotype,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_trans_splicing,
           eQual_usedin,
} },

//{ eSubtype_org, {
//},

{ eSubtype_cdregion, {
           eQual_EC_number,
           eQual_allele,
           eQual_artificial_location,
           eQual_citation,
           eQual_coded_by,
           eQual_codon,
           eQual_codon_start,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gdb_xref,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_partial,
           eQual_product,
           eQual_protein_id,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_ribosomal_slippage,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_transl_except,
           eQual_transl_table,
           eQual_translation,
           eQual_usedin,
} },

{ eSubtype_prot, {
           eQual_EC_number,
           eQual_UniProtKB_evidence,
           eQual_allele,
           eQual_calculated_mol_wt,
           eQual_citation,
           eQual_db_xref,
           eQual_derived_from,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_name,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_protein_id,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_preprotein, {
           eQual_EC_number,
           eQual_allele,
           eQual_calculated_mol_wt,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_name,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_protein_id,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_mat_peptide_aa, {
           eQual_EC_number,
           eQual_allele,
           eQual_calculated_mol_wt,
           eQual_citation,
           eQual_db_xref,
           eQual_derived_from,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_name,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_protein_id,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_sig_peptide_aa, {
           eQual_EC_number,
           eQual_allele,
           eQual_calculated_mol_wt,
           eQual_citation,
           eQual_db_xref,
           eQual_derived_from,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_name,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_protein_id,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_transit_peptide_aa, {
           eQual_allele,
           eQual_calculated_mol_wt,
           eQual_citation,
           eQual_db_xref,
           eQual_derived_from,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_name,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_protein_id,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_preRNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

{ eSubtype_mRNA, {
           eQual_allele,
           eQual_artificial_location,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_partial,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_transcript_id,
           eQual_usedin,
} },

{ eSubtype_tRNA, {
           eQual_allele,
           eQual_anticodon,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

{ eSubtype_rRNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_snRNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_scRNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_snoRNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

//a.k.a.misc_RNA
{ eSubtype_otherRNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_ncRNA_class,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

//{ eSubtype_pub, {
//},

//{ eSubtype_seq, {
//},

//{ eSubtype_imp, {
//},

//{ eSubtype_allele, {
//},

{ eSubtype_attenuator, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_phenotype,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_usedin,
} },

{ eSubtype_C_region, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_CAAT_signal, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_usedin,
} },

{ eSubtype_Imp_CDS, {
           eQual_EC_number,
           eQual_allele,
           eQual_artificial_location,
           eQual_citation,
           eQual_codon,
           eQual_codon_start,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_product,
           eQual_protein_id,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_transl_except,
           eQual_transl_table,
           eQual_translation,
           eQual_usedin,
} },

{ eSubtype_conflict, {
           eQual_allele,
           eQual_citation,
           eQual_compare,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_replace,
           eQual_usedin,
} },

{ eSubtype_D_loop, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_usedin,
} },

{ eSubtype_D_segment, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_enhancer, {
           eQual_allele,
           eQual_bound_moiety,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_exon, {
           eQual_EC_number,
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_partial,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

{ eSubtype_GC_signal, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_usedin,
} },

{ eSubtype_iDNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_intron, {
           eQual_allele,
           eQual_citation,
           eQual_cons_splice,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_partial,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

{ eSubtype_J_segment, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_LTR, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_mat_peptide, {
           eQual_EC_number,
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_misc_binding, {
           eQual_allele,
           eQual_bound_moiety,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_usedin,
} },

{ eSubtype_misc_difference, {
           eQual_allele,
           eQual_citation,
           eQual_clone,
           eQual_compare,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_phenotype,
           eQual_replace,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_misc_feature, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_feat_class,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_phenotype,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_SO_type,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_misc_recomb, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_recombination_class,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_misc_RNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_product,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_misc_signal, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_phenotype,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_misc_structure, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_modified_base, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_mod_base,
           eQual_note,
           eQual_old_locus_tag,
           eQual_usedin,
} },

//{ eSubtype_mutation, {
//},

{ eSubtype_N_region, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_old_sequence, {
           eQual_allele,
           eQual_citation,
           eQual_compare,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_replace,
           eQual_usedin,
} },

{ eSubtype_polyA_signal, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_usedin,
} },

{ eSubtype_polyA_site, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_usedin,
} },

{ eSubtype_precursor_RNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_derived_from,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_product,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

{ eSubtype_prim_transcript, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_primer_bind, {
           eQual_PCR_conditions,
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_promoter, {
           eQual_allele,
           eQual_bound_moiety,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_phenotype,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_protein_bind, {
           eQual_allele,
           eQual_bound_moiety,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_RBS, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_repeat_region, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_insertion_seq,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_mobile_element,
           eQual_note,
           eQual_old_locus_tag,
           eQual_partial,
           eQual_rpt_family,
           eQual_rpt_type,
           eQual_rpt_unit,
           eQual_rpt_unit_range,
           eQual_rpt_unit_seq,
           eQual_satellite,
           eQual_standard_name,
           eQual_transposon,
           eQual_usedin,
} },

{ eSubtype_repeat_unit, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_rpt_family,
           eQual_rpt_type,
           eQual_rpt_unit,
           eQual_rpt_unit_range,
           eQual_rpt_unit_seq,
           eQual_usedin,
} },

{ eSubtype_rep_origin, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_direction,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_S_region, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_satellite, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_rpt_family,
           eQual_rpt_type,
           eQual_rpt_unit,
           eQual_rpt_unit_range,
           eQual_rpt_unit_seq,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_sig_peptide, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_source, {
           eQual_PCR_primers,
           eQual_altitude,
           eQual_bio_material,
           eQual_cell_line,
           eQual_cell_type,
           eQual_chloroplast,
           eQual_chromoplast,
           eQual_chromosome,
           eQual_citation,
           eQual_clone,
           eQual_clone_lib,
           eQual_collected_by,
           eQual_collection_date,
           eQual_country,
           eQual_cultivar,
           eQual_culture_collection,
           eQual_cyanelle,
           eQual_db_xref,
           eQual_dev_stage,
           eQual_ecotype,
           eQual_environmental_sample,
           eQual_exception,
           eQual_focus,
           eQual_frequency,
           eQual_germline,
           eQual_haplogroup,
           eQual_haplotype,
           eQual_host,
           eQual_identified_by,
           eQual_isolate,
           eQual_isolation_source,
           eQual_kinetoplast,
           eQual_lab_host,
           eQual_label,
           eQual_lat_lon,
           eQual_linkage_group,
           eQual_macronuclear,
           eQual_map,
           eQual_mating_type,
           eQual_metagenome_source,
           eQual_metagenomic,
           eQual_mitochondrion,
           eQual_mol_type,
           eQual_note,
           eQual_organelle,
           eQual_organism,
           eQual_plasmid,
           eQual_pop_variant,
           eQual_proviral,
           eQual_rearranged,
           eQual_segment,
           eQual_sequenced_mol,
           eQual_serotype,
           eQual_serovar,
           eQual_sex,
           eQual_specimen_voucher,
           eQual_strain,
           eQual_submitter_seqid,
           eQual_sub_clone,
           eQual_sub_species,
           eQual_sub_strain,
           eQual_tissue_lib,
           eQual_tissue_type,
           eQual_transgenic,
           eQual_transposon,
           eQual_type_material,
           eQual_usedin,
           eQual_variety,
           eQual_virion,
           eQual_whole_replicon,
} },

{ eSubtype_stem_loop, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_STS, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_TATA_signal, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_usedin,
} },

{ eSubtype_terminator, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_transit_peptide, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_unsure, {
           eQual_allele,
           eQual_citation,
           eQual_compare,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_replace,
           eQual_usedin,
} },

{ eSubtype_V_region, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_V_segment, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_variation, {
           eQual_allele,
           eQual_citation,
           eQual_compare,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_frequency,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_phenotype,
           eQual_product,
           eQual_replace,
           eQual_standard_name,
           eQual_usedin,
} },

//{ eSubtype_virion, {

{ eSubtype_3clip, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

{ eSubtype_3UTR, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

{ eSubtype_5clip, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

{ eSubtype_5UTR, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

{ eSubtype_10_signal, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_35_signal, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_gap, {
           eQual_estimated_length,
           eQual_exception,
           eQual_experiment,
           eQual_inference,
           eQual_map,
           eQual_note,
} },

{ eSubtype_operon, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_inference,
           eQual_label,
           eQual_map,
           eQual_note,
           eQual_operon,
           eQual_phenotype,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_oriT, {
           eQual_allele,
           eQual_bound_moiety,
           eQual_citation,
           eQual_db_xref,
           eQual_direction,
           eQual_exception,
           eQual_experiment,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_rpt_type,
           eQual_rpt_unit,
           eQual_rpt_unit_range,
           eQual_rpt_unit_seq,
           eQual_standard_name,
           eQual_usedin,
} },

//{ eSubtype_site_ref, {
//},

{ eSubtype_region, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_phenotype,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_region_name,
           eQual_SO_type,
           eQual_standard_name,
           eQual_usedin,
} },

//sameasmisc_feature
{ eSubtype_comment, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_phenotype,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

//sameasmisc_feature
{ eSubtype_bond, {
           eQual_allele,
           eQual_bond_type,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_phenotype,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

//sameasmisc_feature
{ eSubtype_site, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_phenotype,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_site_type,
           eQual_standard_name,
           eQual_usedin,
} },

//{ eSubtype_rsite, {
//},

//{ eSubtype_user, {
//},

//{ eSubtype_txinit, {
//},

//{ eSubtype_num, {
//},

//sameasmisc_feature???
{ eSubtype_psec_str, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_phenotype,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_sec_str_type,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_non_std_residue, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_non_std_residue,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_phenotype,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

//sameasmisc_feature
{ eSubtype_het, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_heterogen,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_number,
           eQual_old_locus_tag,
           eQual_phenotype,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_biosrc, {
           eQual_PCR_primers,
           eQual_altitude,
           eQual_bio_material,
           eQual_cell_line,
           eQual_cell_type,
           eQual_chloroplast,
           eQual_chromoplast,
           eQual_chromosome,
           eQual_citation,
           eQual_clone,
           eQual_clone_lib,
           eQual_collected_by,
           eQual_collection_date,
           eQual_country,
           eQual_cultivar,
           eQual_culture_collection,
           eQual_cyanelle,
           eQual_db_xref,
           eQual_dev_stage,
           eQual_ecotype,
           eQual_environmental_sample,
           eQual_exception,
           eQual_focus,
           eQual_frequency,
           eQual_germline,
           eQual_haplogroup,
           eQual_haplotype,
           eQual_host,
           eQual_identified_by,
           eQual_isolate,
           eQual_isolation_source,
           eQual_kinetoplast,
           eQual_lab_host,
           eQual_label,
           eQual_lat_lon,
           eQual_linkage_group,
           eQual_macronuclear,
           eQual_map,
           eQual_mating_type,
           eQual_metagenome_source,
           eQual_metagenomic,
           eQual_mitochondrion,
           eQual_mol_type,
           eQual_note,
           eQual_organelle,
           eQual_organism,
           eQual_plasmid,
           eQual_pop_variant,
           eQual_proviral,
           eQual_rearranged,
           eQual_segment,
           eQual_sequenced_mol,
           eQual_serotype,
           eQual_serovar,
           eQual_sex,
           eQual_specimen_voucher,
           eQual_strain,
           eQual_submitter_seqid,
           eQual_sub_clone,
           eQual_sub_species,
           eQual_sub_strain,
           eQual_tissue_lib,
           eQual_tissue_type,
           eQual_transgenic,
           eQual_transposon,
           eQual_type_material,
           eQual_usedin,
           eQual_variety,
           eQual_virion,
           eQual_whole_replicon,
} },

{ eSubtype_ncRNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_ncRNA_class,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_trans_splicing,
           eQual_usedin,
} },

{ eSubtype_tmRNA, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_product,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_tag_peptide,
           eQual_usedin,
} },

//{ eSubtype_clone, {
//},

{ eSubtype_variation_ref, {
           eQual_allele,
           eQual_citation,
           eQual_compare,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_frequency,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_phenotype,
           eQual_product,
           eQual_replace,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_mobile_element, {
           eQual_allele,
           eQual_citation,
           eQual_db_xref,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_insertion_seq,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_mobile_element_type,
           eQual_note,
           eQual_old_locus_tag,
           eQual_rpt_family,
           eQual_rpt_type,
           eQual_standard_name,
           eQual_transposon,
           eQual_usedin,
} },

{ eSubtype_centromere, {
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_inference,
           eQual_note,
           eQual_standard_name,
} },

{ eSubtype_telomere, {
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_inference,
           eQual_note,
           eQual_rpt_type,
           eQual_rpt_unit_range,
           eQual_rpt_unit_seq,
           eQual_standard_name,
} },

{ eSubtype_assembly_gap, {
           eQual_estimated_length,
           eQual_exception,
           eQual_gap_type,
           eQual_linkage_evidence,
} },

{ eSubtype_regulatory, {
           eQual_allele,
           eQual_bound_moiety,
           eQual_citation,
           eQual_db_xref,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_note,
           eQual_old_locus_tag,
           eQual_operon,
           eQual_phenotype,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_regulatory_class,
           eQual_standard_name,
} },

{ eSubtype_propeptide, {
           eQual_EC_number,
           eQual_allele,
           eQual_calculated_mol_wt,
           eQual_citation,
           eQual_db_xref,
           eQual_derived_from,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_name,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_protein_id,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },

{ eSubtype_propeptide_aa, {
           eQual_EC_number,
           eQual_allele,
           eQual_calculated_mol_wt,
           eQual_citation,
           eQual_db_xref,
           eQual_derived_from,
           eQual_evidence,
           eQual_exception,
           eQual_experiment,
           eQual_function,
           eQual_gene,
           eQual_gene_synonym,
           eQual_inference,
           eQual_label,
           eQual_locus_tag,
           eQual_map,
           eQual_name,
           eQual_note,
           eQual_old_locus_tag,
           eQual_product,
           eQual_protein_id,
           eQual_pseudo,
           eQual_pseudogene,
           eQual_standard_name,
           eQual_usedin,
} },
{ eSubtype_any, TLegalQualifiers::set_range(eQual_allele, eQual_whole_replicon)}
});

    static constexpr TSubTypeQualifiersMap g_legal_quals{legal_quals_proxy};

    return g_legal_quals;
}


const CSeqFeatData::TLegalQualifiers& CSeqFeatData::GetLegalQualifiers(ESubtype subtype)
{
    auto it = s_GetLegalQualMap().find(subtype);
    if (it == s_GetLegalQualMap().end())
        return empty_quals;

    return it->second;
}

bool CSeqFeatData::IsLegalQualifier(ESubtype subtype, EQualifier qual)
{
    auto it = s_GetLegalQualMap().find(subtype);
    if (it == s_GetLegalQualMap().end())
        return false;

    return it->second.test(qual);
}

// this is compile time dual map
// there is no need to pre-sort item in any particular order
// duplicate item will be overriden with latter version, i.e. it permitted to put aliases
MAKE_TWOWAY_CONST_MAP(sc_QualPairs, CSeqFeatData::EQualifier, ct::tagStrNocase,
{
    { CSeqFeatData::eQual_bad, "bad" },
    { CSeqFeatData::eQual_allele, "allele" },
    { CSeqFeatData::eQual_altitude, "altitude" },
    { CSeqFeatData::eQual_anticodon, "anticodon" },
    { CSeqFeatData::eQual_artificial_location, "artificial_location" },
    { CSeqFeatData::eQual_bio_material, "bio_material" },
    { CSeqFeatData::eQual_bond_type, "bond_type" },
    { CSeqFeatData::eQual_bound_moiety, "bound_moiety" },
    { CSeqFeatData::eQual_calculated_mol_wt, "calculated_mol_wt" },
    { CSeqFeatData::eQual_cell_line, "cell_line" },
    { CSeqFeatData::eQual_cell_type, "cell_type" },
    { CSeqFeatData::eQual_chloroplast, "chloroplast" },
    { CSeqFeatData::eQual_chromoplast, "chromoplast" },
    { CSeqFeatData::eQual_chromosome, "chromosome" },
    { CSeqFeatData::eQual_citation, "citation" },
    { CSeqFeatData::eQual_clone, "clone" },
    { CSeqFeatData::eQual_clone_lib, "clone_lib" },
    { CSeqFeatData::eQual_coded_by, "coded_by" },
    { CSeqFeatData::eQual_codon, "codon" },
    { CSeqFeatData::eQual_codon_start, "codon_start" },
    { CSeqFeatData::eQual_collected_by, "collected_by" },
    { CSeqFeatData::eQual_collection_date, "collection_date" },
    { CSeqFeatData::eQual_compare, "compare" },
    { CSeqFeatData::eQual_cons_splice, "cons_splice" },
    { CSeqFeatData::eQual_country, "country" },
    { CSeqFeatData::eQual_cultivar, "cultivar" },
    { CSeqFeatData::eQual_culture_collection, "culture_collection" },
    { CSeqFeatData::eQual_cyanelle, "cyanelle" },
    { CSeqFeatData::eQual_db_xref, "db_xref" },
    { CSeqFeatData::eQual_derived_from, "derived_from" },
    { CSeqFeatData::eQual_dev_stage, "dev_stage" },
    { CSeqFeatData::eQual_direction, "direction" },
    { CSeqFeatData::eQual_EC_number, "EC_number" },
    { CSeqFeatData::eQual_ecotype, "ecotype" },
    { CSeqFeatData::eQual_environmental_sample, "environmental_sample" },
    { CSeqFeatData::eQual_estimated_length, "estimated_length" },
    { CSeqFeatData::eQual_evidence, "evidence" },
    { CSeqFeatData::eQual_exception, "exception" },
    { CSeqFeatData::eQual_experiment, "experiment" },
    { CSeqFeatData::eQual_feat_class, "feat_class" },
    { CSeqFeatData::eQual_focus, "focus" },
    { CSeqFeatData::eQual_frequency, "frequency" },
    { CSeqFeatData::eQual_function, "function" },
    { CSeqFeatData::eQual_gap_type, "gap_type" },
    { CSeqFeatData::eQual_gdb_xref, "gdb_xref" },
    { CSeqFeatData::eQual_gene, "gene" },
    { CSeqFeatData::eQual_gene_synonym, "gene_synonym" },
    { CSeqFeatData::eQual_germline, "germline" },
    { CSeqFeatData::eQual_haplogroup, "haplogroup" },
    { CSeqFeatData::eQual_haplotype, "haplotype" },
    { CSeqFeatData::eQual_heterogen, "heterogen" },
    { CSeqFeatData::eQual_host, "specific_host" }, // this is supported
    { CSeqFeatData::eQual_host, "host" },          // the second will override previous
    { CSeqFeatData::eQual_identified_by, "identified_by" },
    { CSeqFeatData::eQual_inference, "inference" },
    { CSeqFeatData::eQual_insertion_seq, "insertion_seq" },
    { CSeqFeatData::eQual_isolate, "isolate" },
    { CSeqFeatData::eQual_isolation_source, "isolation_source" },
    { CSeqFeatData::eQual_kinetoplast, "kinetoplast" },
    { CSeqFeatData::eQual_lab_host, "lab_host" },
    { CSeqFeatData::eQual_label, "label" },
    { CSeqFeatData::eQual_lat_lon, "lat_lon" },
    { CSeqFeatData::eQual_linkage_evidence, "linkage_evidence" },
    { CSeqFeatData::eQual_linkage_group, "linkage_group" },
    { CSeqFeatData::eQual_locus_tag, "locus_tag" },
    { CSeqFeatData::eQual_macronuclear, "macronuclear" },
    { CSeqFeatData::eQual_map, "map" },
    { CSeqFeatData::eQual_mating_type, "mating_type" },
    { CSeqFeatData::eQual_metagenome_source, "metagenome_source" },
    { CSeqFeatData::eQual_metagenomic, "metagenomic" },
    { CSeqFeatData::eQual_mitochondrion, "mitochondrion" },
    { CSeqFeatData::eQual_mobile_element, "mobile_element" },
    { CSeqFeatData::eQual_mobile_element_type, "mobile_element_type" },
    { CSeqFeatData::eQual_mod_base, "mod_base" },
    { CSeqFeatData::eQual_mol_type, "mol_type" },
    { CSeqFeatData::eQual_name, "name" },
    { CSeqFeatData::eQual_nomenclature, "nomenclature" },
    { CSeqFeatData::eQual_non_std_residue, "non_std_residue" },
    { CSeqFeatData::eQual_ncRNA_class, "ncRNA_class" },
    { CSeqFeatData::eQual_note, "note" },
    { CSeqFeatData::eQual_number, "number" },
    { CSeqFeatData::eQual_old_locus_tag, "old_locus_tag" },
    { CSeqFeatData::eQual_operon, "operon" },
    { CSeqFeatData::eQual_organelle, "organelle" },
    { CSeqFeatData::eQual_organism, "organism" },
    { CSeqFeatData::eQual_partial, "partial" },
    { CSeqFeatData::eQual_PCR_conditions, "PCR_conditions" },
    { CSeqFeatData::eQual_PCR_primers, "PCR_primers" },
    { CSeqFeatData::eQual_phenotype, "phenotype" },
    { CSeqFeatData::eQual_plasmid, "plasmid" },
    { CSeqFeatData::eQual_pop_variant, "pop_variant" },
    { CSeqFeatData::eQual_product, "product" },
    { CSeqFeatData::eQual_protein_id, "protein_id" },
    { CSeqFeatData::eQual_proviral, "proviral" },
    { CSeqFeatData::eQual_pseudo, "pseudo" },
    { CSeqFeatData::eQual_pseudogene, "pseudogene" },
    { CSeqFeatData::eQual_rearranged, "rearranged" },
    { CSeqFeatData::eQual_recombination_class, "recombination_class" },
    { CSeqFeatData::eQual_region_name, "region_name" },
    { CSeqFeatData::eQual_regulatory_class, "regulatory_class" },
    { CSeqFeatData::eQual_replace, "replace" },
    { CSeqFeatData::eQual_ribosomal_slippage, "ribosomal_slippage" },
    { CSeqFeatData::eQual_rpt_family, "rpt_family" },
    { CSeqFeatData::eQual_rpt_type, "rpt_type" },
    { CSeqFeatData::eQual_rpt_unit, "rpt_unit" },
    { CSeqFeatData::eQual_rpt_unit_range, "rpt_unit_range"  },
    { CSeqFeatData::eQual_rpt_unit_seq, "rpt_unit_seq"  },
    { CSeqFeatData::eQual_satellite, "satellite" },
    { CSeqFeatData::eQual_sec_str_type, "sec_str_type" },
    { CSeqFeatData::eQual_segment, "segment" },
    { CSeqFeatData::eQual_sequenced_mol, "sequenced_mol" },
    { CSeqFeatData::eQual_serotype, "serotype" },
    { CSeqFeatData::eQual_serovar, "serovar" },
    { CSeqFeatData::eQual_sex, "sex" },
    { CSeqFeatData::eQual_site_type, "site_type" },
    { CSeqFeatData::eQual_SO_type, "SO_type" },
    { CSeqFeatData::eQual_specimen_voucher, "specimen_voucher" },
    { CSeqFeatData::eQual_standard_name, "standard_name" },
    { CSeqFeatData::eQual_strain, "strain" },
    { CSeqFeatData::eQual_submitter_seqid, "submitter_seqid" },
    { CSeqFeatData::eQual_sub_clone, "sub_clone" },
    { CSeqFeatData::eQual_sub_species, "sub_species" },
    { CSeqFeatData::eQual_sub_strain, "sub_strain" },
    { CSeqFeatData::eQual_tag_peptide, "tag_peptide" },
    { CSeqFeatData::eQual_tissue_lib, "tissue_lib" },
    { CSeqFeatData::eQual_tissue_type, "tissue_type" },
    { CSeqFeatData::eQual_trans_splicing, "trans_splicing" },
    { CSeqFeatData::eQual_transcript_id, "transcript_id" },
    { CSeqFeatData::eQual_transgenic, "transgenic" },
    { CSeqFeatData::eQual_translation, "translation" },
    { CSeqFeatData::eQual_transl_except, "transl_except" },
    { CSeqFeatData::eQual_transl_table, "transl_table" },
    { CSeqFeatData::eQual_transposon, "transposon" },
    { CSeqFeatData::eQual_type_material, "type_material" },
    { CSeqFeatData::eQual_UniProtKB_evidence, "UniProtKB_evidence" },
    { CSeqFeatData::eQual_usedin, "usedin" },
    { CSeqFeatData::eQual_variety, "variety" },
    { CSeqFeatData::eQual_virion, "virion" },
    { CSeqFeatData::eQual_whole_replicon, "whole_replicon" }
})

CTempString CSeqFeatData::GetQualifierAsString(EQualifier qual)
{
    auto iter = sc_QualPairs.first.find(qual);
    if (iter == sc_QualPairs.first.end())
        return kEmptyStr;
    else
        return iter->second;
}

CSeqFeatData::EQualifier CSeqFeatData::GetQualifierType(CTempString qual)
{
    auto iter = sc_QualPairs.second.find(qual);
    if (iter != sc_QualPairs.second.end())
        return iter->second;

    return CSeqFeatData::eQual_bad;
}

 std::pair<CSeqFeatData::EQualifier, CTempString> CSeqFeatData::GetQualifierTypeAndValue(CTempString qual)
{
    auto iter = sc_QualPairs.second.find(qual);
    if (iter != sc_QualPairs.second.end())
    {
        CTempString value = iter->first;
        return { iter->second, value };
    }

    return { CSeqFeatData::eQual_bad, kEmptyStr };
}

namespace
{
#define ADD_XREF_PAIR(x, y) {CSeqFeatData::eSubtype_ ## x, CSeqFeatData::eSubtype_ ## y },

    template<typename _Ty, size_t _Width>
    class  TPairsMatrix
    {    
    public:
        static constexpr size_t width = _Width;
        using TBitset = ct::const_bitset<width, _Ty>;
        using table_t = ct_const_array<TBitset, width>;

        using init_t = std::pair<_Ty, _Ty>;
        using non_empty_pair = std::pair<_Ty, TBitset>;

        template<size_t N>
        constexpr TPairsMatrix(const init_t(&init)[N])
        {
            using row_t = ct_const_array<char, width>;
            using init_matrix_t = ct_const_array<row_t, width>;

            init_matrix_t matrix{};
            for (const auto& rec : init)
            {
                matrix[rec.first][rec.second] = '1';
                matrix[rec.second][rec.first] = '1';
            }
            m_table = assemble_table(matrix, std::make_index_sequence<width>{});
            size_t last = 0;
            for (size_t i = 0; i < width; ++i)
            {
                if (!m_table[i].empty())
                    m_non_empty_indices[last++] = i;
            }
            m_non_empty_count = last;
        }

        constexpr size_t NonEmptyCount() const
        {
            return m_non_empty_count;
        }

        template<size_t N>
        static bool Check(const ct_const_array<non_empty_pair, N>& in, _Ty v1, _Ty v2)
        {
            auto it = std::lower_bound(in.begin(), in.end(), v1, [](auto left, auto right)
            {
                return left.first < right;
            });
            if (it != in.end())
            {
                return it->second.test(v2);
            }
            return false;
        }
        static bool Check(const table_t& table, _Ty v1, _Ty v2)
        {
            return table[v1].test(v2);
        }
        // returns ordered collection of non_empty bitsets, suitable for binary search
        template<size_t N>
        constexpr auto select_bitsets() const 
        {
            return select_bitsets(std::make_index_sequence<N>{});
        }
        // returns all bitsets, suitable for constant-time lookups
        constexpr auto get_bitsets() const
        {
            return m_table;
        }
    protected:
        template<typename _Matrix, size_t...Ints>
        static constexpr auto assemble_table(const _Matrix& init, std::index_sequence<Ints...>)
            -> table_t
        {
            return { { TBitset{init[Ints]} ... } };
        }
        template<size_t I>
        constexpr non_empty_pair make_row() const
        {
            return { _Ty(m_non_empty_indices[I]), m_table[m_non_empty_indices[I]] };
        }
        template<size_t...Ints>
        constexpr auto select_bitsets(std::index_sequence<Ints...>) const
            -> ct_const_array<non_empty_pair, sizeof...(Ints) >
        {
            return { { make_row<Ints>() ... } };
        }

        table_t m_table{};
        ct_const_array<size_t, width> m_non_empty_indices{};
        size_t  m_non_empty_count{ 0 };
    };
    using CAssembleSubTypePairs = TPairsMatrix<CSeqFeatData::ESubtype, CSeqFeatData::eSubtype_max>;

    static constexpr CAssembleSubTypePairs::init_t g_allowed_pairs[] = {
     ADD_XREF_PAIR(ncRNA, preRNA)
     ADD_XREF_PAIR(S_region, mRNA)
     ADD_XREF_PAIR(gene, preRNA)
     ADD_XREF_PAIR(J_segment, gene)
     ADD_XREF_PAIR(exon, tmRNA)
     ADD_XREF_PAIR(N_region, exon)
     ADD_XREF_PAIR(V_region, cdregion)
     ADD_XREF_PAIR(intron, preRNA)
     ADD_XREF_PAIR(V_segment, preRNA)
     ADD_XREF_PAIR(otherRNA, polyA_signal)
     ADD_XREF_PAIR(S_region, exon)
     ADD_XREF_PAIR(gene, tmRNA)
     ADD_XREF_PAIR(otherRNA, preRNA)
     ADD_XREF_PAIR(exon, preRNA)
     ADD_XREF_PAIR(5UTR, intron)
     ADD_XREF_PAIR(mRNA, tmRNA)
     ADD_XREF_PAIR(3UTR, intron)
     ADD_XREF_PAIR(5UTR, preRNA)
     ADD_XREF_PAIR(otherRNA, polyA_site)
     ADD_XREF_PAIR(N_region, cdregion)
     ADD_XREF_PAIR(N_region, gene)
     ADD_XREF_PAIR(V_region, mRNA)
     ADD_XREF_PAIR(V_segment, mRNA)
     ADD_XREF_PAIR(cdregion, mRNA)
     ADD_XREF_PAIR(gene, ncRNA)
     ADD_XREF_PAIR(C_region, mRNA)
     ADD_XREF_PAIR(exon, tRNA)
     ADD_XREF_PAIR(gene, mRNA)
     ADD_XREF_PAIR(exon, misc_RNA)
     ADD_XREF_PAIR(ncRNA, polyA_signal)
     ADD_XREF_PAIR(3UTR, preRNA)
     ADD_XREF_PAIR(preRNA, rRNA)
     ADD_XREF_PAIR(exon, mRNA)
     ADD_XREF_PAIR(gene, rRNA)
     ADD_XREF_PAIR(intron, otherRNA)
     ADD_XREF_PAIR(V_segment, cdregion)
     ADD_XREF_PAIR(N_region, preRNA)
     ADD_XREF_PAIR(J_segment, preRNA)
     ADD_XREF_PAIR(5UTR, exon)
     ADD_XREF_PAIR(gene, polyA_site)
     ADD_XREF_PAIR(preRNA, tRNA)
     ADD_XREF_PAIR(polyA_signal, preRNA)
     ADD_XREF_PAIR(D_segment, cdregion)
     ADD_XREF_PAIR(V_region, preRNA)
     ADD_XREF_PAIR(cdregion, tmRNA)
     ADD_XREF_PAIR(N_region, intron)
     ADD_XREF_PAIR(V_region, exon)
     ADD_XREF_PAIR(5UTR, gene)
     ADD_XREF_PAIR(gene, tRNA)
     ADD_XREF_PAIR(TATA_signal, gene)
     ADD_XREF_PAIR(D_segment, mRNA)
     ADD_XREF_PAIR(tRNA, tmRNA)
     ADD_XREF_PAIR(V_segment, exon)
     ADD_XREF_PAIR(V_segment, intron)
     ADD_XREF_PAIR(cdregion, gene)
     ADD_XREF_PAIR(mRNA, preRNA)
     ADD_XREF_PAIR(gene, otherRNA)
     ADD_XREF_PAIR(enhancer, gene)
     ADD_XREF_PAIR(misc_RNA, polyA_signal)
     ADD_XREF_PAIR(ncRNA, polyA_site)
     ADD_XREF_PAIR(intron, rRNA)
     ADD_XREF_PAIR(35_signal, gene)
     ADD_XREF_PAIR(misc_RNA, preRNA)
     ADD_XREF_PAIR(10_signal, gene)
     ADD_XREF_PAIR(preRNA, tmRNA)
     ADD_XREF_PAIR(intron, ncRNA)
     ADD_XREF_PAIR(misc_RNA, polyA_site)
     ADD_XREF_PAIR(5UTR, mRNA)
     ADD_XREF_PAIR(J_segment, cdregion)
     ADD_XREF_PAIR(C_region, cdregion)
     ADD_XREF_PAIR(intron, misc_RNA)
     ADD_XREF_PAIR(TATA_signal, preRNA)
     ADD_XREF_PAIR(exon, ncRNA)
     ADD_XREF_PAIR(3UTR, gene)
     ADD_XREF_PAIR(S_region, preRNA)
     ADD_XREF_PAIR(exon, rRNA)
     ADD_XREF_PAIR(mRNA, regulatory)
     ADD_XREF_PAIR(J_segment, intron)
     ADD_XREF_PAIR(intron, tRNA)
     ADD_XREF_PAIR(S_region, cdregion)
     ADD_XREF_PAIR(V_region, gene)
     ADD_XREF_PAIR(C_region, intron)
     ADD_XREF_PAIR(C_region, exon)
     ADD_XREF_PAIR(D_segment, intron)
     ADD_XREF_PAIR(C_region, preRNA)
     ADD_XREF_PAIR(3UTR, mRNA)
     ADD_XREF_PAIR(intron, mRNA)
     ADD_XREF_PAIR(J_segment, mRNA)
     ADD_XREF_PAIR(mRNA, polyA_site)
     ADD_XREF_PAIR(V_segment, gene)
     ADD_XREF_PAIR(3UTR, exon)
     ADD_XREF_PAIR(V_region, intron)
     ADD_XREF_PAIR(D_segment, exon)
     ADD_XREF_PAIR(J_segment, exon)
     ADD_XREF_PAIR(gene, promoter)
     ADD_XREF_PAIR(D_segment, preRNA)
     ADD_XREF_PAIR(gene, misc_RNA)
     ADD_XREF_PAIR(exon, gene)
     ADD_XREF_PAIR(N_region, mRNA)
     ADD_XREF_PAIR(exon, otherRNA)
     ADD_XREF_PAIR(C_region, gene)
     ADD_XREF_PAIR(S_region, gene)
     ADD_XREF_PAIR(D_segment, gene)
     ADD_XREF_PAIR(gene, polyA_signal)
     ADD_XREF_PAIR(intron, tmRNA)
     ADD_XREF_PAIR(gene, intron)
     ADD_XREF_PAIR(gene, regulatory)
     ADD_XREF_PAIR(mRNA, polyA_signal)
     ADD_XREF_PAIR(polyA_site, preRNA)
     ADD_XREF_PAIR(S_region, intron)
    };

        static constexpr CAssembleSubTypePairs::init_t g_prohibited_pairs[] = {
         ADD_XREF_PAIR(3UTR, promoter)
         ADD_XREF_PAIR(enhancer, rRNA)
         ADD_XREF_PAIR(3UTR, 5UTR)
         ADD_XREF_PAIR(cdregion, cdregion)
         ADD_XREF_PAIR(otherRNA, otherRNA)
         ADD_XREF_PAIR(35_signal, D_segment)
         ADD_XREF_PAIR(polyA_site, regulatory)
         ADD_XREF_PAIR(N_region, promoter)
         ADD_XREF_PAIR(cdregion, regulatory)
         ADD_XREF_PAIR(35_signal, misc_RNA)
         ADD_XREF_PAIR(mRNA, otherRNA)
         ADD_XREF_PAIR(V_region, polyA_signal)
         ADD_XREF_PAIR(35_signal, J_segment)
         ADD_XREF_PAIR(rRNA, rRNA)
         ADD_XREF_PAIR(C_region, otherRNA)
         ADD_XREF_PAIR(TATA_signal, V_segment)
         ADD_XREF_PAIR(ncRNA, regulatory)
         ADD_XREF_PAIR(intron, polyA_site)
         ADD_XREF_PAIR(5UTR, C_region)
         ADD_XREF_PAIR(intron, intron)
         ADD_XREF_PAIR(35_signal, V_segment)
         ADD_XREF_PAIR(5UTR, D_segment)
         ADD_XREF_PAIR(10_signal, S_region)
         ADD_XREF_PAIR(J_segment, tRNA)
         ADD_XREF_PAIR(V_region, promoter)
         ADD_XREF_PAIR(5UTR, rRNA)
         ADD_XREF_PAIR(35_signal, C_region)
         ADD_XREF_PAIR(polyA_signal, tRNA)
         ADD_XREF_PAIR(J_segment, enhancer)
         ADD_XREF_PAIR(cdregion, ncRNA)
         ADD_XREF_PAIR(10_signal, rRNA)
         ADD_XREF_PAIR(J_segment, tmRNA)
         ADD_XREF_PAIR(mRNA, ncRNA)
         ADD_XREF_PAIR(N_region, regulatory)
         ADD_XREF_PAIR(TATA_signal, cdregion)
         ADD_XREF_PAIR(10_signal, polyA_site)
         ADD_XREF_PAIR(10_signal, V_segment)
         ADD_XREF_PAIR(S_region, tmRNA)
         ADD_XREF_PAIR(S_region, misc_RNA)
         ADD_XREF_PAIR(mRNA, tRNA)
         ADD_XREF_PAIR(TATA_signal, exon)
         ADD_XREF_PAIR(10_signal, tRNA)
         ADD_XREF_PAIR(35_signal, cdregion)
         ADD_XREF_PAIR(35_signal, tRNA)
         ADD_XREF_PAIR(cdregion, otherRNA)
         ADD_XREF_PAIR(35_signal, enhancer)
         ADD_XREF_PAIR(10_signal, tmRNA)
         ADD_XREF_PAIR(35_signal, V_region)
         ADD_XREF_PAIR(C_region, C_region)
         ADD_XREF_PAIR(enhancer, promoter)
         ADD_XREF_PAIR(3UTR, tmRNA)
         ADD_XREF_PAIR(D_segment, regulatory)
         ADD_XREF_PAIR(35_signal, otherRNA)
         ADD_XREF_PAIR(otherRNA, regulatory)
         ADD_XREF_PAIR(V_region, V_region)
         ADD_XREF_PAIR(35_signal, rRNA)
         ADD_XREF_PAIR(J_segment, S_region)
         ADD_XREF_PAIR(misc_RNA, ncRNA)
         ADD_XREF_PAIR(V_region, polyA_site)
         ADD_XREF_PAIR(S_region, tRNA)
         ADD_XREF_PAIR(V_segment, rRNA)
         ADD_XREF_PAIR(N_region, misc_RNA)
         ADD_XREF_PAIR(J_segment, misc_RNA)
         ADD_XREF_PAIR(mRNA, mRNA)
         ADD_XREF_PAIR(5UTR, V_segment)
         ADD_XREF_PAIR(N_region, tmRNA)
         ADD_XREF_PAIR(N_region, ncRNA)
         ADD_XREF_PAIR(3UTR, enhancer)
         ADD_XREF_PAIR(TATA_signal, tmRNA)
         ADD_XREF_PAIR(D_segment, tRNA)
         ADD_XREF_PAIR(enhancer, preRNA)
         ADD_XREF_PAIR(D_segment, polyA_site)
         ADD_XREF_PAIR(3UTR, cdregion)
         ADD_XREF_PAIR(ncRNA, rRNA)
         ADD_XREF_PAIR(promoter, tmRNA)
         ADD_XREF_PAIR(N_region, polyA_signal)
         ADD_XREF_PAIR(S_region, otherRNA)
         ADD_XREF_PAIR(35_signal, S_region)
         ADD_XREF_PAIR(10_signal, V_region)
         ADD_XREF_PAIR(misc_RNA, regulatory)
         ADD_XREF_PAIR(C_region, promoter)
         ADD_XREF_PAIR(otherRNA, tRNA)
         ADD_XREF_PAIR(J_segment, promoter)
         ADD_XREF_PAIR(polyA_site, tmRNA)
         ADD_XREF_PAIR(preRNA, promoter)
         ADD_XREF_PAIR(otherRNA, rRNA)
         ADD_XREF_PAIR(10_signal, D_segment)
         ADD_XREF_PAIR(35_signal, promoter)
         ADD_XREF_PAIR(enhancer, tRNA)
         ADD_XREF_PAIR(10_signal, misc_RNA)
         ADD_XREF_PAIR(rRNA, regulatory)
         ADD_XREF_PAIR(10_signal, N_region)
         ADD_XREF_PAIR(5UTR, enhancer)
         ADD_XREF_PAIR(TATA_signal, promoter)
         ADD_XREF_PAIR(D_segment, tmRNA)
         ADD_XREF_PAIR(misc_RNA, otherRNA)
         ADD_XREF_PAIR(D_segment, V_region)
         ADD_XREF_PAIR(35_signal, preRNA)
         ADD_XREF_PAIR(3UTR, otherRNA)
         ADD_XREF_PAIR(polyA_signal, promoter)
         ADD_XREF_PAIR(S_region, regulatory)
         ADD_XREF_PAIR(misc_RNA, misc_RNA)
         ADD_XREF_PAIR(10_signal, cdregion)
         ADD_XREF_PAIR(5UTR, S_region)
         ADD_XREF_PAIR(10_signal, J_segment)
         ADD_XREF_PAIR(ncRNA, otherRNA)
         ADD_XREF_PAIR(otherRNA, tmRNA)
         ADD_XREF_PAIR(cdregion, polyA_signal)
         ADD_XREF_PAIR(J_segment, polyA_site)
         ADD_XREF_PAIR(cdregion, enhancer)
         ADD_XREF_PAIR(J_segment, J_segment)
         ADD_XREF_PAIR(regulatory, tmRNA)
         ADD_XREF_PAIR(S_region, polyA_site)
         ADD_XREF_PAIR(35_signal, tmRNA)
         ADD_XREF_PAIR(D_segment, polyA_signal)
         ADD_XREF_PAIR(35_signal, exon)
         ADD_XREF_PAIR(intron, regulatory)
         ADD_XREF_PAIR(enhancer, enhancer)
         ADD_XREF_PAIR(10_signal, polyA_signal)
         ADD_XREF_PAIR(rRNA, tmRNA)
         ADD_XREF_PAIR(D_segment, ncRNA)
         ADD_XREF_PAIR(N_region, tRNA)
         ADD_XREF_PAIR(cdregion, preRNA)
         ADD_XREF_PAIR(enhancer, regulatory)
         ADD_XREF_PAIR(D_segment, promoter)
         ADD_XREF_PAIR(5UTR, V_region)
         ADD_XREF_PAIR(35_signal, polyA_signal)
         ADD_XREF_PAIR(10_signal, intron)
         ADD_XREF_PAIR(J_segment, polyA_signal)
         ADD_XREF_PAIR(V_region, otherRNA)
         ADD_XREF_PAIR(polyA_site, polyA_site)
         ADD_XREF_PAIR(mRNA, promoter)
         ADD_XREF_PAIR(enhancer, ncRNA)
         ADD_XREF_PAIR(tRNA, tRNA)
         ADD_XREF_PAIR(3UTR, V_region)
         ADD_XREF_PAIR(C_region, S_region)
         ADD_XREF_PAIR(D_segment, S_region)
         ADD_XREF_PAIR(D_segment, N_region)
         ADD_XREF_PAIR(polyA_site, tRNA)
         ADD_XREF_PAIR(C_region, misc_RNA)
         ADD_XREF_PAIR(10_signal, regulatory)
         ADD_XREF_PAIR(35_signal, polyA_site)
         ADD_XREF_PAIR(5UTR, misc_RNA)
         ADD_XREF_PAIR(J_segment, rRNA)
         ADD_XREF_PAIR(5UTR, polyA_site)
         ADD_XREF_PAIR(misc_RNA, tmRNA)
         ADD_XREF_PAIR(C_region, J_segment)
         ADD_XREF_PAIR(V_segment, polyA_signal)
         ADD_XREF_PAIR(V_region, misc_RNA)
         ADD_XREF_PAIR(V_region, regulatory)
         ADD_XREF_PAIR(10_signal, mRNA)
         ADD_XREF_PAIR(misc_RNA, rRNA)
         ADD_XREF_PAIR(TATA_signal, V_region)
         ADD_XREF_PAIR(J_segment, N_region)
         ADD_XREF_PAIR(ncRNA, promoter)
         ADD_XREF_PAIR(S_region, polyA_signal)
         ADD_XREF_PAIR(D_segment, rRNA)
         ADD_XREF_PAIR(polyA_site, rRNA)
         ADD_XREF_PAIR(V_region, tRNA)
         ADD_XREF_PAIR(D_segment, D_segment)
         ADD_XREF_PAIR(J_segment, otherRNA)
         ADD_XREF_PAIR(V_segment, polyA_site)
         ADD_XREF_PAIR(5UTR, otherRNA)
         ADD_XREF_PAIR(exon, exon)
         ADD_XREF_PAIR(exon, intron)
         ADD_XREF_PAIR(promoter, promoter)
         ADD_XREF_PAIR(cdregion, polyA_site)
         ADD_XREF_PAIR(V_region, enhancer)
         ADD_XREF_PAIR(TATA_signal, misc_RNA)
         ADD_XREF_PAIR(TATA_signal, rRNA)
         ADD_XREF_PAIR(3UTR, J_segment)
         ADD_XREF_PAIR(J_segment, regulatory)
         ADD_XREF_PAIR(intron, polyA_signal)
         ADD_XREF_PAIR(C_region, N_region)
         ADD_XREF_PAIR(N_region, enhancer)
         ADD_XREF_PAIR(TATA_signal, enhancer)
         ADD_XREF_PAIR(preRNA, preRNA)
         ADD_XREF_PAIR(3UTR, misc_RNA)
         ADD_XREF_PAIR(C_region, D_segment)
         ADD_XREF_PAIR(V_segment, otherRNA)
         ADD_XREF_PAIR(5UTR, N_region)
         ADD_XREF_PAIR(35_signal, mRNA)
         ADD_XREF_PAIR(3UTR, TATA_signal)
         ADD_XREF_PAIR(V_region, ncRNA)
         ADD_XREF_PAIR(10_signal, preRNA)
         ADD_XREF_PAIR(enhancer, otherRNA)
         ADD_XREF_PAIR(10_signal, exon)
         ADD_XREF_PAIR(3UTR, V_segment)
         ADD_XREF_PAIR(misc_RNA, tRNA)
         ADD_XREF_PAIR(cdregion, exon)
         ADD_XREF_PAIR(10_signal, TATA_signal)
         ADD_XREF_PAIR(5UTR, polyA_signal)
         ADD_XREF_PAIR(tmRNA, tmRNA)
         ADD_XREF_PAIR(5UTR, cdregion)
         ADD_XREF_PAIR(35_signal, 35_signal)
         ADD_XREF_PAIR(TATA_signal, intron)
         ADD_XREF_PAIR(ncRNA, ncRNA)
         ADD_XREF_PAIR(promoter, tRNA)
         ADD_XREF_PAIR(3UTR, ncRNA)
         ADD_XREF_PAIR(35_signal, N_region)
         ADD_XREF_PAIR(N_region, otherRNA)
         ADD_XREF_PAIR(C_region, tRNA)
         ADD_XREF_PAIR(5UTR, 5UTR)
         ADD_XREF_PAIR(N_region, S_region)
         ADD_XREF_PAIR(TATA_signal, regulatory)
         ADD_XREF_PAIR(V_segment, tRNA)
         ADD_XREF_PAIR(ncRNA, tRNA)
         ADD_XREF_PAIR(5UTR, ncRNA)
         ADD_XREF_PAIR(3UTR, S_region)
         ADD_XREF_PAIR(V_segment, regulatory)
         ADD_XREF_PAIR(3UTR, D_segment)
         ADD_XREF_PAIR(35_signal, 5UTR)
         ADD_XREF_PAIR(3UTR, C_region)
         ADD_XREF_PAIR(cdregion, intron)
         ADD_XREF_PAIR(cdregion, rRNA)
         ADD_XREF_PAIR(TATA_signal, TATA_signal)
         ADD_XREF_PAIR(35_signal, intron)
         ADD_XREF_PAIR(N_region, rRNA)
         ADD_XREF_PAIR(35_signal, TATA_signal)
         ADD_XREF_PAIR(mRNA, rRNA)
         ADD_XREF_PAIR(10_signal, 10_signal)
         ADD_XREF_PAIR(C_region, V_segment)
         ADD_XREF_PAIR(rRNA, tRNA)
         ADD_XREF_PAIR(TATA_signal, tRNA)
         ADD_XREF_PAIR(TATA_signal, otherRNA)
         ADD_XREF_PAIR(C_region, rRNA)
         ADD_XREF_PAIR(35_signal, ncRNA)
         ADD_XREF_PAIR(3UTR, N_region)
         ADD_XREF_PAIR(3UTR, polyA_site)
         ADD_XREF_PAIR(S_region, TATA_signal)
         ADD_XREF_PAIR(V_region, V_segment)
         ADD_XREF_PAIR(N_region, N_region)
         ADD_XREF_PAIR(cdregion, promoter)
         ADD_XREF_PAIR(D_segment, J_segment)
         ADD_XREF_PAIR(5UTR, tmRNA)
         ADD_XREF_PAIR(enhancer, exon)
         ADD_XREF_PAIR(S_region, S_region)
         ADD_XREF_PAIR(5UTR, regulatory)
         ADD_XREF_PAIR(enhancer, misc_RNA)
         ADD_XREF_PAIR(exon, polyA_signal)
         ADD_XREF_PAIR(3UTR, rRNA)
         ADD_XREF_PAIR(gene, gene)
         ADD_XREF_PAIR(TATA_signal, polyA_site)
         ADD_XREF_PAIR(enhancer, polyA_site)
         ADD_XREF_PAIR(5UTR, tRNA)
         ADD_XREF_PAIR(enhancer, polyA_signal)
         ADD_XREF_PAIR(D_segment, otherRNA)
         ADD_XREF_PAIR(C_region, polyA_site)
         ADD_XREF_PAIR(J_segment, TATA_signal)
         ADD_XREF_PAIR(polyA_signal, polyA_site)
         ADD_XREF_PAIR(10_signal, enhancer)
         ADD_XREF_PAIR(TATA_signal, ncRNA)
         ADD_XREF_PAIR(promoter, regulatory)
         ADD_XREF_PAIR(S_region, V_segment)
         ADD_XREF_PAIR(S_region, V_region)
         ADD_XREF_PAIR(J_segment, ncRNA)
         ADD_XREF_PAIR(TATA_signal, polyA_signal)
         ADD_XREF_PAIR(C_region, enhancer)
         ADD_XREF_PAIR(ncRNA, tmRNA)
         ADD_XREF_PAIR(D_segment, V_segment)
         ADD_XREF_PAIR(C_region, polyA_signal)
         ADD_XREF_PAIR(polyA_site, promoter)
         ADD_XREF_PAIR(35_signal, regulatory)
         ADD_XREF_PAIR(enhancer, mRNA)
         ADD_XREF_PAIR(preRNA, regulatory)
         ADD_XREF_PAIR(10_signal, 3UTR)
         ADD_XREF_PAIR(10_signal, C_region)
         ADD_XREF_PAIR(polyA_signal, regulatory)
         ADD_XREF_PAIR(C_region, tmRNA)
         ADD_XREF_PAIR(3UTR, polyA_signal)
         ADD_XREF_PAIR(regulatory, regulatory)
         ADD_XREF_PAIR(V_segment, V_segment)
         ADD_XREF_PAIR(10_signal, 35_signal)
         ADD_XREF_PAIR(D_segment, enhancer)
         ADD_XREF_PAIR(V_segment, ncRNA)
         ADD_XREF_PAIR(V_segment, promoter)
         ADD_XREF_PAIR(V_segment, misc_RNA)
         ADD_XREF_PAIR(D_segment, TATA_signal)
         ADD_XREF_PAIR(N_region, V_region)
         ADD_XREF_PAIR(N_region, polyA_site)
         ADD_XREF_PAIR(C_region, ncRNA)
         ADD_XREF_PAIR(5UTR, promoter)
         ADD_XREF_PAIR(C_region, TATA_signal)
         ADD_XREF_PAIR(exon, polyA_site)
         ADD_XREF_PAIR(D_segment, misc_RNA)
         ADD_XREF_PAIR(S_region, rRNA)
         ADD_XREF_PAIR(S_region, ncRNA)
         ADD_XREF_PAIR(S_region, promoter)
         ADD_XREF_PAIR(5UTR, TATA_signal)
         ADD_XREF_PAIR(N_region, TATA_signal)
         ADD_XREF_PAIR(V_region, rRNA)
         ADD_XREF_PAIR(otherRNA, promoter)
         ADD_XREF_PAIR(exon, promoter)
         ADD_XREF_PAIR(polyA_signal, rRNA)
         ADD_XREF_PAIR(V_segment, tmRNA)
         ADD_XREF_PAIR(J_segment, V_region)
         ADD_XREF_PAIR(cdregion, tRNA)
         ADD_XREF_PAIR(enhancer, intron)
         ADD_XREF_PAIR(regulatory, tRNA)
         ADD_XREF_PAIR(C_region, regulatory)
         ADD_XREF_PAIR(polyA_signal, tmRNA)
         ADD_XREF_PAIR(misc_RNA, promoter)
         ADD_XREF_PAIR(J_segment, V_segment)
         ADD_XREF_PAIR(N_region, V_segment)
         ADD_XREF_PAIR(intron, promoter)
         ADD_XREF_PAIR(V_segment, enhancer)
         ADD_XREF_PAIR(10_signal, otherRNA)
         ADD_XREF_PAIR(TATA_signal, mRNA)
         ADD_XREF_PAIR(S_region, enhancer)
         ADD_XREF_PAIR(3UTR, tRNA)
         ADD_XREF_PAIR(V_region, tmRNA)
         ADD_XREF_PAIR(C_region, V_region)
         ADD_XREF_PAIR(3UTR, regulatory)
         ADD_XREF_PAIR(10_signal, ncRNA)
         ADD_XREF_PAIR(10_signal, 5UTR)
         ADD_XREF_PAIR(polyA_signal, polyA_signal)
         ADD_XREF_PAIR(3UTR, 3UTR)
         ADD_XREF_PAIR(35_signal, 3UTR)
         ADD_XREF_PAIR(enhancer, tmRNA)
         ADD_XREF_PAIR(10_signal, promoter)
         ADD_XREF_PAIR(5UTR, J_segment)
         ADD_XREF_PAIR(cdregion, misc_RNA)
         ADD_XREF_PAIR(exon, regulatory)
         ADD_XREF_PAIR(mRNA, misc_RNA)
         ADD_XREF_PAIR(promoter, rRNA)
    };

    // Three steps initialization is still required until C++17 is engaged
    // this doesn't impact performance or memory footprints
    static constexpr CAssembleSubTypePairs g_allowed_init(g_allowed_pairs);
    static constexpr CAssembleSubTypePairs g_prohibited_init(g_prohibited_pairs);

// constant time access tables use 2544 bytes each, regardless of the number of pairs used
// binary search table requires 928 bytes each, and depends on number of pairs used
#if 1 // use tables with constant time access
    static constexpr auto g_allowed_xrefs    = g_allowed_init.get_bitsets();
    static constexpr auto g_prohibited_xrefs = g_prohibited_init.get_bitsets();
#else // or use binary search tables
    static constexpr auto g_allowed_xrefs    = g_allowed_init.select_bitsets<g_allowed_init.NonEmptyCount()>();
    static constexpr auto g_prohibited_xrefs = g_prohibited_init.select_bitsets<g_prohibited_init.NonEmptyCount()>();
#endif

#undef ADD_XREF_PAIR
}

bool CSeqFeatData::AllowXref(CSeqFeatData::ESubtype subtype1, CSeqFeatData::ESubtype subtype2)
{
    return CAssembleSubTypePairs::Check(g_allowed_xrefs, subtype1, subtype2);
}
bool CSeqFeatData::ProhibitXref(CSeqFeatData::ESubtype subtype1, CSeqFeatData::ESubtype subtype2)
{
    return CAssembleSubTypePairs::Check(g_prohibited_xrefs, subtype1, subtype2);
}

/////////////////// end of CSeqFeatData methods


const CFeatList* CSeqFeatData::GetFeatList()
{
    static unique_ptr<CFeatList> theFeatList;

    if ( !theFeatList.get() ) {
        DEFINE_STATIC_MUTEX(s_Mutex);
        CMutexGuard LOCK(s_Mutex);
        if ( !theFeatList.get() ) {
            theFeatList.reset(new CFeatList());
        }
    }
    return theFeatList.get();
}

const CBondList* CSeqFeatData::GetBondList()
{
    static unique_ptr<CBondList> theBondList;

    if ( !theBondList.get() ) {
        DEFINE_STATIC_MUTEX(s_Mutex);
        CMutexGuard LOCK(s_Mutex);
        if ( !theBondList.get() ) {
            theBondList.reset(new CBondList());
        }
    }
    return theBondList.get();
}


const CSiteList* CSeqFeatData::GetSiteList()
{
    static unique_ptr<CSiteList> theSiteList;

    if ( !theSiteList.get() ) {
        DEFINE_STATIC_MUTEX(s_Mutex);
        CMutexGuard LOCK(s_Mutex);
        if ( !theSiteList.get() ) {
            theSiteList.reset(new CSiteList());
        }
    }
    return theSiteList.get();
}

bool CSeqFeatData::IsRegulatory(ESubtype subtype)
{
    const TSubtypeSet & regulatory_subtypes_set = GetSetOfRegulatorySubtypes();
    return (
        regulatory_subtypes_set.find(subtype) !=
        regulatory_subtypes_set.end() );
}


const string & CSeqFeatData::GetRegulatoryClass(ESubtype subtype)
{
    // Special cases where subtype does not translate to its
    // SubtypeValueToName equivalent.
    typedef map<ESubtype, string> TSubtypeToNameMap;

    struct FCreateSubtypeNameMap {
        static TSubtypeToNameMap * Create() {

            // create via the inverse of the GetRegulatoryClass that
            // takes a string
            AutoPtr<TSubtypeToNameMap> p_new_map(new TSubtypeToNameMap);

            const TSubtypeSet & regulatory_subtypes_set =
                GetSetOfRegulatorySubtypes();
            ITERATE(TSubtypeSet, subtype_iter, regulatory_subtypes_set) {
                (*p_new_map)[*subtype_iter] = SubtypeValueToName(*subtype_iter);
            }

            _ASSERT( regulatory_subtypes_set.size() == p_new_map->size() );

            // override for special cases
            typedef SStaticPair<ESubtype, const char *> TSubtypeNameElem; 
            static const TSubtypeNameElem sc_subtype_name_map[] = {
                { CSeqFeatData::eSubtype_polyA_signal, "polyA_signal_sequence"},
                { CSeqFeatData::eSubtype_RBS, "ribosome_binding_site"},
                { CSeqFeatData::eSubtype_TATA_signal, "TATA_box"},
                { CSeqFeatData::eSubtype_35_signal, "minus_35_signal"},
                { CSeqFeatData::eSubtype_10_signal, "minus_10_signal"},
            };

            ITERATE_0_IDX(special_case_idx, ArraySize(sc_subtype_name_map)) {
                const TSubtypeNameElem & subtype_name_elem =
                    sc_subtype_name_map[special_case_idx];
                
                (*p_new_map)[subtype_name_elem.first] =
                    subtype_name_elem.second;
            }

            _ASSERT( regulatory_subtypes_set.size() == p_new_map->size() );
            return p_new_map.release();
        }
    };

    static CSafeStatic<TSubtypeToNameMap> sc_SubtypeToNameMap(
        FCreateSubtypeNameMap::Create);

    if( ! IsRegulatory(subtype) ) {
        return kEmptyStr;
    } else if( subtype == eSubtype_misc_signal ) {
        // this subtype does not have a string equivalent
        return kEmptyStr;
    } else {
        TSubtypeToNameMap::const_iterator find_iter =
            sc_SubtypeToNameMap->find(subtype);
        if( find_iter != sc_SubtypeToNameMap->end() ) {
            return find_iter->second;
        }
    }

    // give up
    return kEmptyStr;
}

CSeqFeatData::ESubtype
CSeqFeatData::GetRegulatoryClass(const string & class_name )
{
    typedef map<string, ESubtype> TNameToSubtypeMap;

    // to avoid getting out of sync, this map is created via the
    // inverse of the subtype-to-name map.
    struct FCreateNameToSubtypeMap {
        static TNameToSubtypeMap * Create() {
            AutoPtr<TNameToSubtypeMap> p_new_map(new TNameToSubtypeMap);

            const TSubtypeSet & regulatory_subtypes_set =
                GetSetOfRegulatorySubtypes();
            ITERATE(TSubtypeSet, subtype_iter, regulatory_subtypes_set) {
                const string & class_name =
                    GetRegulatoryClass(*subtype_iter);
                (*p_new_map)[class_name] = *subtype_iter;
            }

            _ASSERT( p_new_map->size() == regulatory_subtypes_set.size() );
            return p_new_map.release();
        }
    };

    static CSafeStatic<TNameToSubtypeMap> ms_NameToSubtypeMap(
        FCreateNameToSubtypeMap::Create);

    TNameToSubtypeMap::const_iterator find_iter =
        ms_NameToSubtypeMap->find(class_name);
    if( find_iter != ms_NameToSubtypeMap->end() ) {
        return find_iter->second;
    }

    return eSubtype_bad;
}


const vector<string>& CSeqFeatData::GetRegulatoryClassList()
{
    static vector<string> choices = {
        "promoter",
        "ribosome_binding_site",
        "attenuator",
        "CAAT_signal",
        "DNase_I_hypersensitive_site",
        "enhancer",
        "enhancer_blocking_element",
        "GC_signal",
        "imprinting_control_region",
        "insulator",
        "locus_control_region",
        "matrix_attachment_region",
        "minus_10_signal",
        "minus_35_signal",
        "polyA_signal_sequence",
        "recoding_stimulatory_region",
        "recombination_enhancer",
        "replication_regulatory_region",
        "response_element",
        "riboswitch",
        "silencer",
        "TATA_box",
        "terminator",
        "transcriptional_cis_regulatory_region",
        "uORF",
    };

    return choices;
}

bool CSeqFeatData::FixRegulatoryClassValue(string& val)
{
    static vector<string> regulatory_class_values;
    if (regulatory_class_values.empty()) {
        regulatory_class_values = GetRegulatoryClassList();
    }

    string original = val;

    const string* valid_val = NStr::FindNoCase(regulatory_class_values, val);
    if (valid_val != nullptr) {
        val = *valid_val;
    }

    return original != val;
}

const vector<string>& CSeqFeatData::GetRecombinationClassList()
{
    static vector<string> choices = {
        "meiotic",
        "mitotic",
        "non_allelic_homologous",
        "chromosome_breakpoint",
    };

    return choices;
}

bool CSeqFeatData::IsDiscouragedSubtype(ESubtype subtype)
{
    static constexpr TSubtypes discouraged_subtypes {
        eSubtype_10_signal,
        eSubtype_35_signal,
        eSubtype_allele,
        eSubtype_attenuator,
        eSubtype_CAAT_signal,
        eSubtype_conflict,
        eSubtype_enhancer,
        eSubtype_GC_signal,
        eSubtype_LTR,
        eSubtype_misc_binding,
        eSubtype_mutation,
        eSubtype_polyA_signal,
        eSubtype_promoter,
        eSubtype_RBS,
        eSubtype_repeat_unit,
        eSubtype_satellite,
        eSubtype_scRNA,
        eSubtype_site_ref,
        eSubtype_snoRNA,
        eSubtype_snRNA,
        eSubtype_TATA_signal,
        eSubtype_terminator,
        eSubtype_virion,
    };

    if (discouraged_subtypes.test(subtype))
            return true;
    else
            return false;
}

bool CSeqFeatData::IsDiscouragedQual(EQualifier qual)
{
    static constexpr TQualifiers discouraged_quals {
        eQual_insertion_seq,
        eQual_mobile_element,
        eQual_rpt_unit,
        eQual_transposon,
    };

    if (discouraged_quals.test(qual))
        return true;
    else
        return false;
}


//////////////////////////////////////////////////////////////////////////////


struct SFeatListItem {
    CSeqFeatData::E_Choice m_Type;
    CSeqFeatData::ESubtype m_Subtype;
    const char* m_Description;
    const char* m_StorageKey;
};

static const SFeatListItem sc_ConfigItemInit[] = {
    {  CSeqFeatData::e_not_set,  CSeqFeatData::eSubtype_any,   "All",  "Master"  },
    {  CSeqFeatData::e_Gene,     CSeqFeatData::eSubtype_gene,  "Gene", "Gene"  },
    {  CSeqFeatData::e_Org,      CSeqFeatData::eSubtype_org,   "Org",  "Org"  },
    {  CSeqFeatData::e_Cdregion, CSeqFeatData::eSubtype_cdregion,  "CDS",  "CDS"  },

    {  CSeqFeatData::e_Prot,     CSeqFeatData::eSubtype_any,   "Protein, All",  "Prot Master"  },
    {  CSeqFeatData::e_Prot,     CSeqFeatData::eSubtype_prot,  "Protein", "Prot"  },
    {  CSeqFeatData::e_Prot,     CSeqFeatData::eSubtype_preprotein,    "ProProtein", "ProProtein"  },
    {  CSeqFeatData::e_Prot,     CSeqFeatData::eSubtype_mat_peptide_aa,    "Mature Peptide AA", "Mat-Peptide AA"  },
    {  CSeqFeatData::e_Prot,     CSeqFeatData::eSubtype_sig_peptide_aa,    "Signal Peptide AA", "Sig-Peptide AA"  },
    {  CSeqFeatData::e_Prot,     CSeqFeatData::eSubtype_transit_peptide_aa,    "Transit Peptide AA", "Transit-Peptide AA"  },
    {  CSeqFeatData::e_Prot,     CSeqFeatData::eSubtype_propeptide_aa,    "ProPeptide AA", "ProPeptide"  },

    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_any,   "RNA, All" , "RNA Master"  },
    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_preRNA,  "precursor_RNA",   "precursor_RNA"  },
    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_mRNA,  "mRNA", "mRNA"  },
    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_tRNA,  "tRNA", "tRNA"  },
    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_rRNA,  "rRNA", "rRNA"  },
    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_snRNA,  "snRNA", "snRNA"  },
    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_scRNA,  "scRNA", "scRNA"  },
    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_snoRNA,  "sno_RNA", "sno_RNA"  },
    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_ncRNA,  "ncRNA", "ncRNA"  },
    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_tmRNA,  "tmRNA", "tmRNA"  },
    {  CSeqFeatData::e_Rna,     CSeqFeatData::eSubtype_otherRNA,  "misc_RNA",  "misc_RNA"  },

    {  CSeqFeatData::e_Pub,     CSeqFeatData::eSubtype_pub,   "Pub", "Pub"  },
    {  CSeqFeatData::e_Seq,     CSeqFeatData::eSubtype_seq,   "Seq", "Seq"  },

    {  CSeqFeatData::e_Imp,      CSeqFeatData::eSubtype_any,   "Import All", "Import Master"  },

    {  CSeqFeatData::e_Region,   CSeqFeatData::eSubtype_region,    "region",     "region"  },
    {  CSeqFeatData::e_Comment,  CSeqFeatData::eSubtype_comment,    "comment",     "comment"  },
    {  CSeqFeatData::e_Bond,     CSeqFeatData::eSubtype_bond,    "bond",     "bond"  },
    {  CSeqFeatData::e_Site,     CSeqFeatData::eSubtype_site,    "site",     "site"  },
    {  CSeqFeatData::e_Rsite,    CSeqFeatData::eSubtype_rsite,    "rsite",     "rsite"  },
    {  CSeqFeatData::e_User,     CSeqFeatData::eSubtype_user,    "user",     "user"  },
    {  CSeqFeatData::e_Txinit,   CSeqFeatData::eSubtype_txinit,    "txinit",     "txinit"  },
    {  CSeqFeatData::e_Num,      CSeqFeatData::eSubtype_num,    "num",     "num"  },
    {  CSeqFeatData::e_Psec_str, CSeqFeatData::eSubtype_psec_str,    "psec_str",     "psec_str"  },
    {  CSeqFeatData::e_Non_std_residue,     CSeqFeatData::eSubtype_non_std_residue,    "non_std_residue",     "non_std_residue"  },
    {  CSeqFeatData::e_Het,      CSeqFeatData::eSubtype_het,    "het",     "het"  },
    {  CSeqFeatData::e_Biosrc,   CSeqFeatData::eSubtype_biosrc,    "biosrc",     "biosrc"  },
    {  CSeqFeatData::e_Clone,    CSeqFeatData::eSubtype_clone,     "clone",      "clone"  },
    {  CSeqFeatData::e_Variation, CSeqFeatData::eSubtype_variation_ref, "variation",  "variation"  }
};


/**
    CFeatListItem comparator
    to sort the set properly.
*/
bool CFeatListItem::operator<(const CFeatListItem& rhs) const
{
    if (m_Type == rhs.m_Type) {
        // the 'Any' subtype should sort lower than anything else in that type.
        if (m_Subtype == CSeqFeatData::eSubtype_any) {
            return rhs.m_Subtype != CSeqFeatData::eSubtype_any;
        }
        if ( rhs.m_Subtype == CSeqFeatData::eSubtype_any) {
            return false;
        }
        return m_Subtype < rhs.m_Subtype;
    }
    return m_Type < rhs.m_Type;
}


/*****
    CFeatList definitions.
*****/

CFeatList::CFeatList()
{
    x_Init();
}


CFeatList::~CFeatList()
{
}

bool CFeatList::TypeValid(int type, int subtype) const
{
    const_iterator ci_it = m_FeatTypes.find(CFeatListItem(type, subtype, "", ""));
    if (ci_it == m_FeatTypes.end()) {
        return false;
    }
    return true;
}


bool CFeatList::GetItem(int type, int subtype, CFeatListItem& config_item) const
{
    const_iterator ci_it = m_FeatTypes.find(CFeatListItem(type, subtype, "", ""));
    if (ci_it == m_FeatTypes.end()) {
        return false;
    }
    config_item = *ci_it;
    return true;
}


bool CFeatList::GetItemBySubtype(int subtype,  CFeatListItem& config_item) const
{
    TSubtypeMap::const_iterator fm_it = m_FeatTypeMap.find(subtype);
    if (fm_it == m_FeatTypeMap.end()) {
        return false;
    }
    config_item = fm_it->second;
    return true;
}


bool CFeatList::GetItemByDescription(const string& desc, CFeatListItem& config_item) const
{
    const_iterator ci_it = begin();
    for (; ci_it != end(); ++ci_it) {
        if (NStr::EqualNocase(ci_it->GetDescription(), desc)) {
            config_item = *ci_it;
            return true;
        }
    }
    return false;
}


bool CFeatList::GetTypeSubType(const string& desc, int& type, int& subtype) const
{
    CFeatListItem config_item;
    if ( GetItemByDescription(desc, config_item) ) {
        type = config_item.GetType();
        subtype = config_item.GetSubtype();
        return true;
    }
    return false;
}

bool CFeatList::GetItemByKey(const string& key, CFeatListItem& config_item) const
{
    const_iterator ci_it = begin();
    for (; ci_it != end(); ++ci_it) {
        if (ci_it->GetStoragekey() == key) {
            config_item = *ci_it;
            return true;
        }
    }
    return false;
}


string CFeatList::GetDescription(int type, int subtype) const
{
    CFeatListItem config_item;
    if (!GetItem(type, subtype, config_item)) {
        return kEmptyStr;
    }
    return config_item.GetDescription();
}


string CFeatList::GetStoragekey(int type, int subtype) const
{
    CFeatListItem config_item;
    if (!GetItem(type, subtype, config_item)) {
        return kEmptyStr;
    }
    return config_item.GetStoragekey();
}


string CFeatList::GetStoragekey(int subtype) const
{
    CFeatListItem config_item;
    if (!GetItemBySubtype(subtype, config_item)) {
        return kEmptyStr;
    }
    return config_item.GetStoragekey();
}


vector<string> CFeatList::GetStoragekeys(int subtype) const
{
    vector<string> keys;
    keys.push_back(GetStoragekey(CSeqFeatData::e_not_set, CSeqFeatData::eSubtype_any));
    if (subtype != CSeqFeatData::eSubtype_any) {
        CFeatListItem item;
        if (GetItemBySubtype(subtype, item)) {
            CFeatListItem sub_master_item;
            if (GetItem(item.GetType(), CSeqFeatData::eSubtype_any, sub_master_item)) {
                keys.push_back(sub_master_item.GetStoragekey());
            }
            keys.push_back(item.GetStoragekey());
        }
    }

    return keys;
}

void CFeatList::x_Init()
{
    const size_t  config_item_size = sizeof(sc_ConfigItemInit)/sizeof(sc_ConfigItemInit[0]);
    for (size_t i = 0; i < config_item_size; ++i ) {
        CFeatListItem item(sc_ConfigItemInit[i].m_Type,
                           sc_ConfigItemInit[i].m_Subtype,
                           sc_ConfigItemInit[i].m_Description,
                           sc_ConfigItemInit[i].m_StorageKey);
        _VERIFY(m_FeatTypes.insert(item).second);
    }
    
    for (const SImportEntry* iep = kImportTable; iep < kImportTableEnd; ++iep) {
        CFeatListItem item(CSeqFeatData::GetTypeFromSubtype(iep->m_Subtype), 
                           iep->m_Subtype, iep->m_Name, iep->m_Name);
        _VERIFY(m_FeatTypes.insert(item).second);
    }

    ITERATE(CFeatList, it, m_FeatTypes) {
        const CFeatListItem& item = *it;
        int subtype = item.GetSubtype();
        if (subtype != CSeqFeatData::eSubtype_any  ||  item.GetType() == CSeqFeatData::e_not_set) {
            // only enter the main Master item, no other master items.
            // else subtypes are not unique.
            m_FeatTypeMap[subtype] = item;
        }
    }
}


/// return a list of all the feature descriptions for a menu or other control.
void CFeatList::GetDescriptions(vector<string> &descs, bool hierarchical) const
{
    descs.clear();


    ITERATE (TFeatTypeContainer, iter, m_FeatTypes) {
        string  this_desc = iter->GetDescription();

        if (hierarchical) {
            string parent_desc;
            if (iter->GetSubtype() != CSeqFeatData::eSubtype_any) {
                parent_desc = GetDescription(iter->GetType(), CSeqFeatData::eSubtype_any);
            } else if (iter->GetType() != CSeqFeatData::e_not_set) {
                parent_desc = this_desc;
            }

            if ( ! parent_desc.empty()) {
                this_desc = parent_desc + "/" + this_desc;
            }
        }

        descs.push_back(this_desc);
    }
}

string x_SpaceToDash(string str1)
{
    string::size_type pos = 0;
    while ((pos = NStr::Find(str1, " ", pos)) != NCBI_NS_STD::string::npos) {
        str1[pos] = '-';
    }
    return str1;
}

/////////////////////////////////////////////////////////////////////////////

static const CBondList::TBondKey bond_key_to_subtype [] = {
    { "disulfide",  CSeqFeatData::eBond_disulfide  },
    { "other",      CSeqFeatData::eBond_other      },
    { "thioether",  CSeqFeatData::eBond_thioether  },
    { "thiolester", CSeqFeatData::eBond_thiolester },
    { "xlink",      CSeqFeatData::eBond_xlink      }
};
DEFINE_CLASS_STATIC_ARRAY_MAP(CBondList::TBondMap, CBondList::sm_BondKeys, bond_key_to_subtype);

CBondList::CBondList()
{
}


CBondList::~CBondList()
{
}


bool CBondList::IsBondName(string str) const
{
    const_iterator ci_it = sm_BondKeys.find (x_SpaceToDash(str).c_str());
    if (ci_it != sm_BondKeys.end ()) {
        return true;
    } else {
        return false;
    }
}


bool CBondList::IsBondName (string str, CSeqFeatData::EBond& bond_type) const
{
    const_iterator ci_it = sm_BondKeys.find (x_SpaceToDash(str).c_str());
    if (ci_it != sm_BondKeys.end ()) {
        bond_type = ci_it->second;
        return true;
    } else {
        return false;
    }
}


CSeqFeatData::EBond CBondList::GetBondType(string str) const
{
    const_iterator ci_it = sm_BondKeys.find (x_SpaceToDash(str).c_str());
    if (ci_it == sm_BondKeys.end()) {
        NCBI_THROW(CException, eUnknown, "Not a valid bond type!");
    } else {
        return ci_it->second;
    }
}
/////////////////////////////////////////////////////////////////////////////


static const CSiteList::TSiteKey site_key_to_subtype [] = {
    { "acetylation",                 CSeqFeatData::eSite_acetylation                 },
    { "active",                      CSeqFeatData::eSite_active                      },
    { "amidation",                   CSeqFeatData::eSite_amidation                   },
    { "binding",                     CSeqFeatData::eSite_binding                     },
    { "blocked",                     CSeqFeatData::eSite_blocked                     },
    { "cleavage",                    CSeqFeatData::eSite_cleavage                    },
    { "DNA binding",                 CSeqFeatData::eSite_dna_binding                 },
    { "gamma carboxyglutamic acid",  CSeqFeatData::eSite_gamma_carboxyglutamic_acid  },
    { "glycosylation",               CSeqFeatData::eSite_glycosylation               },
    { "hydroxylation",               CSeqFeatData::eSite_hydroxylation               },
    { "inhibit",                     CSeqFeatData::eSite_inhibit                     },
    { "lipid binding",               CSeqFeatData::eSite_lipid_binding               },
    { "metal binding",               CSeqFeatData::eSite_metal_binding               },
    { "methylation",                 CSeqFeatData::eSite_methylation                 },
    { "modified",                    CSeqFeatData::eSite_modified                    },
    { "mutagenized",                 CSeqFeatData::eSite_mutagenized                 },
    { "myristoylation",              CSeqFeatData::eSite_myristoylation              },
    { "nitrosylation",               CSeqFeatData::eSite_nitrosylation               },
    { "np binding",                  CSeqFeatData::eSite_np_binding                  },
    { "other",                       CSeqFeatData::eSite_other                       },
    { "oxidative deamination",       CSeqFeatData::eSite_oxidative_deamination       },
    { "phosphorylation",             CSeqFeatData::eSite_phosphorylation             },
    { "pyrrolidone carboxylic acid", CSeqFeatData::eSite_pyrrolidone_carboxylic_acid },
    { "signal peptide",              CSeqFeatData::eSite_signal_peptide              },
    { "sulfatation",                 CSeqFeatData::eSite_sulfatation                 },
    { "transit peptide",             CSeqFeatData::eSite_transit_peptide             },
    { "transmembrane region",        CSeqFeatData::eSite_transmembrane_region        },
    { "unclassified",                CSeqFeatData::eSite_other                       }
};

DEFINE_CLASS_STATIC_ARRAY_MAP(CSiteList::TSiteMap, CSiteList::sm_SiteKeys, site_key_to_subtype);

CSiteList::CSiteList()
{
}


CSiteList::~CSiteList()
{
}


bool CSiteList::IsSiteName(string str) const
{
    const_iterator ci_it = sm_SiteKeys.find (x_SpaceToDash(str).c_str());
    if (ci_it != sm_SiteKeys.end ()) {
        return true;
    } else {
        return false;
    }
}


bool CSiteList::IsSiteName (string str, CSeqFeatData::ESite& site_type) const
{
    const_iterator ci_it = sm_SiteKeys.find (x_SpaceToDash(str).c_str());
    if (ci_it != sm_SiteKeys.end ()) {
        site_type = ci_it->second;
        return true;
    } else {
        return false;
    }
}


CSeqFeatData::ESite CSiteList::GetSiteType(string str) const
{
    const_iterator ci_it = sm_SiteKeys.find (x_SpaceToDash(str).c_str());
    if (ci_it == sm_SiteKeys.end()) {
        NCBI_THROW(CException, eUnknown, "Not a valid site type!");
    } else {
        return ci_it->second;
    }
}

const CSeqFeatData::TSubtypeSet & 
CSeqFeatData::GetSetOfRegulatorySubtypes(void)
{
    static ESubtype const regulatory_subtypes [] = {
        eSubtype_attenuator,
        eSubtype_CAAT_signal,
        eSubtype_enhancer,
        eSubtype_GC_signal,
        eSubtype_LTR,
        eSubtype_misc_signal,
        eSubtype_polyA_signal,
        eSubtype_promoter,
        eSubtype_RBS,
        eSubtype_TATA_signal,
        eSubtype_terminator,
        eSubtype_10_signal,
        eSubtype_35_signal,
    };

    DEFINE_STATIC_ARRAY_MAP_WITH_COPY(
        TSubtypeSet, sc_RegulatorySubtypes, regulatory_subtypes);

    return sc_RegulatorySubtypes;
}


CSeqFeatData::EFeatureLocationAllowed CSeqFeatData::AllowedFeatureLocation(ESubtype subtype)
{
    EFeatureLocationAllowed rval = eFeatureLocationAllowed_Any;
    switch (subtype) {
        case eSubtype_prot:
        case eSubtype_preprotein:
        case eSubtype_mat_peptide_aa:
        case eSubtype_sig_peptide_aa:
        case eSubtype_transit_peptide_aa:
        case eSubtype_propeptide_aa:
        case eSubtype_bond:
        case eSubtype_psec_str:
        case eSubtype_non_std_residue:
            rval = eFeatureLocationAllowed_ProtOnly;
            break;
        case eSubtype_region:
        case eSubtype_pub:
        case eSubtype_site:
            rval = eFeatureLocationAllowed_Any;
            break;
        case eSubtype_any:
        case eSubtype_bad:
        case eSubtype_max:
            rval = eFeatureLocationAllowed_Error;
            break;
        default:
            rval = eFeatureLocationAllowed_NucOnly;
            break;
    }

    return rval;
}


bool CSeqFeatData::AllowStrandBoth(ESubtype subtype)
{
    bool rval = false;

    switch (subtype) {
        case eSubtype_regulatory:
        case eSubtype_protein_bind:
        case eSubtype_misc_feature:
        case eSubtype_repeat_region:
        case eSubtype_rep_origin:
        case eSubtype_misc_recomb:
        case eSubtype_S_region:
        case eSubtype_centromere:
        case eSubtype_telomere:
        case eSubtype_variation:
        case eSubtype_misc_binding:
        case eSubtype_misc_difference:
        case eSubtype_misc_structure:
        case eSubtype_mobile_element:
        case eSubtype_assembly_gap:
        case eSubtype_LTR:
            rval = true;
            break;
        default:
            rval = false;
            break;
    }

    return rval;
}


bool CSeqFeatData::RequireLocationIntervalsInBiologicalOrder(CSeqFeatData::ESubtype feat_subtype)
{
    bool required = true;
    switch (feat_subtype)
    {
        case CSeqFeatData::eSubtype_pub:
        case CSeqFeatData::eSubtype_het:
        case CSeqFeatData::eSubtype_primer_bind:
        case CSeqFeatData::eSubtype_misc_recomb:
            required = false;
            break;
        default:
            break;
    }
    return required;
}


bool CSeqFeatData::AllowAdjacentIntervals(CSeqFeatData::ESubtype feat_subtype)
{
    bool allowed = false;
    switch (feat_subtype)
    {
    case CSeqFeatData::eSubtype_pub:
    case CSeqFeatData::eSubtype_het:
    case CSeqFeatData::eSubtype_primer_bind:
    case CSeqFeatData::eSubtype_misc_recomb:
        allowed = true;
        break;
    default:
        break;
    }
    return allowed;
}


bool CSeqFeatData::ShouldRepresentAsGbqual (CSeqFeatData::ESubtype feat_subtype, CSeqFeatData::EQualifier qual_type)
{
    // experiment and inference get their own panels
    if (qual_type == CSeqFeatData::eQual_experiment || qual_type == CSeqFeatData::eQual_inference) {
        return false;
    }
    // pseudo and pseudogene are handled separately
    if (qual_type == CSeqFeatData::eQual_pseudogene || qual_type == CSeqFeatData::eQual_pseudo) {
        return false;
    }

    if (qual_type == CSeqFeatData::eQual_product) {
        if (feat_subtype == CSeqFeatData::eSubtype_mat_peptide
            || feat_subtype == CSeqFeatData::eSubtype_sig_peptide
            || feat_subtype == CSeqFeatData::eSubtype_transit_peptide
            || feat_subtype == CSeqFeatData::eSubtype_propeptide
            || feat_subtype == CSeqFeatData::eSubtype_C_region
            || feat_subtype == CSeqFeatData::eSubtype_D_segment
            || feat_subtype == CSeqFeatData::eSubtype_exon
            || feat_subtype == CSeqFeatData::eSubtype_J_segment
            || feat_subtype == CSeqFeatData::eSubtype_misc_feature
            || feat_subtype == CSeqFeatData::eSubtype_N_region
            || feat_subtype == CSeqFeatData::eSubtype_S_region
            || feat_subtype == CSeqFeatData::eSubtype_V_region
            || feat_subtype == CSeqFeatData::eSubtype_V_segment
            || feat_subtype == CSeqFeatData::eSubtype_variation) {
            return true;
        } else {
            return false;
        }
    }

    if (feat_subtype == CSeqFeatData::eSubtype_gene)
    {
        if (  qual_type == CSeqFeatData::eQual_allele ||
              qual_type == CSeqFeatData::eQual_gene_synonym ||
              qual_type == CSeqFeatData::eQual_locus_tag ||
              qual_type == CSeqFeatData::eQual_map
            )
            return true;
        else
            return false;
    }


    if (qual_type == CSeqFeatData::eQual_citation
        || qual_type == CSeqFeatData::eQual_db_xref
        || qual_type == CSeqFeatData::eQual_evidence
        || qual_type == CSeqFeatData::eQual_exception
        || qual_type == CSeqFeatData::eQual_gene
        || qual_type == CSeqFeatData::eQual_gene_synonym
        || qual_type == CSeqFeatData::eQual_insertion_seq
        || qual_type == CSeqFeatData::eQual_label
        || qual_type == CSeqFeatData::eQual_locus_tag
        || qual_type == CSeqFeatData::eQual_note
        || qual_type == CSeqFeatData::eQual_partial
        || qual_type == CSeqFeatData::eQual_product
        || qual_type == CSeqFeatData::eQual_pseudo
        || qual_type == CSeqFeatData::eQual_rpt_unit
        || qual_type == CSeqFeatData::eQual_transposon
        || qual_type == CSeqFeatData::eQual_experiment
        || qual_type == CSeqFeatData::eQual_trans_splicing
        || qual_type == CSeqFeatData::eQual_ribosomal_slippage
        || qual_type == CSeqFeatData::eQual_standard_name
        || qual_type == CSeqFeatData::eQual_usedin) {
        return false;
    }
    if (feat_subtype == CSeqFeatData::eSubtype_cdregion) {
        if (qual_type == CSeqFeatData::eQual_codon_start
            || qual_type == CSeqFeatData::eQual_codon
            || qual_type == CSeqFeatData::eQual_EC_number
            || qual_type == CSeqFeatData::eQual_gdb_xref
            || qual_type == CSeqFeatData::eQual_number
            || qual_type == CSeqFeatData::eQual_protein_id
            //|| qual_type == CSeqFeatData::eQual_transl_except
            || qual_type == CSeqFeatData::eQual_transl_table
            || qual_type == CSeqFeatData::eQual_translation
            || qual_type == CSeqFeatData::eQual_allele
            || qual_type == CSeqFeatData::eQual_translation
            || qual_type == CSeqFeatData::eQual_function
            || qual_type == CSeqFeatData::eQual_old_locus_tag) {
            return false;
        }
    }

   

    if (qual_type == CSeqFeatData::eQual_map 
        && feat_subtype != CSeqFeatData::eSubtype_repeat_region 
        && feat_subtype != CSeqFeatData::eSubtype_gap) {
      return false;
    }
    if (qual_type == CSeqFeatData::eQual_operon
        && feat_subtype != CSeqFeatData::eSubtype_operon) {
        return false;
    }
    return true;    
}


bool CSeqFeatData::ShouldRepresentAsGbqual (CSeqFeatData::ESubtype feat_subtype, const CGb_qual& qual)
{
    if (!qual.IsSetQual()) {
        return false;
    }
    return ShouldRepresentAsGbqual(feat_subtype, CSeqFeatData::GetQualifierType(qual.GetQual()));
}


bool CSeqFeatData::FixImportKey(string& key)
{
    if (NStr::EqualNocase(key, "allele") ||
        NStr::EqualNocase(key, "mutation")) {
        key = "variation";
        return true;
    } else if (NStr::EqualNocase(key, "Import") ||
        NStr::EqualNocase(key, "virion")) {
        key = "misc_feature";
        return true;
    } else if (NStr::EqualNocase(key, "repeat_unit")) {
        key = "repeat_region";
        return true;
    } else if (NStr::EqualNocase(key, "misc_bind")) {
        key = "misc_binding";
        return true;
    }
    const SImportEntry* start = kImportTable;
    while (start < kImportTableEnd) {
        if (NStr::EqualNocase(key, start->m_Name)) {
            if (!NStr::Equal(key, start->m_Name)) {
                key = start->m_Name;
                return true;
            } else {
                return false;
            }
        }
        ++start;
    }
    return false;
}


bool CSeqFeatData::IsLegalProductNameForRibosomalSlippage(
    const string& productName)
{
    static vector<string> matchPhrases{ "IS150 protein InsAB", "PCRF domain-containing protein" };
    static vector<string> containedPhrases{ "transposase", "chain release" };

    for (const auto& phrase: matchPhrases) {
        if (phrase == productName) {
            return true;
        }
    }
    for (const auto& phrase: containedPhrases) {
        if (productName.find(phrase) != string::npos) {
            return true;
        }
    }
    return false;
}


END_objects_SCOPE // namespace ncbi::objects::

END_NCBI_SCOPE

/* Original file checksum: lines: 61, chars: 1894, CRC32: 86fb976 */
