#if !defined(__CDALIGNPROC_BASE__)
#define __CDALIGNPROC_BASE__

#if defined(__DB_OFFLINE__)
#include "basedata.hpp"
#include "structifx.hpp"
#else
#include <shlu2/DataUtils/basedata.hpp>
#include <StructIfx/structifx.hpp>
#endif
#if defined(_MT)
#include <corelib/ncbimtx.hpp>
#endif
#include <map>
#include <array>


constexpr const char * NODOMPROT = "Protein with no known domain";
constexpr const SeqLen_t MAX_NA_LEN = 200000;
constexpr const double SFHIT_THRESHOLD = 0.2;




// -- For Refseq curation
struct TCDDHitInfo
{
	PssmId_t pssmid;
	std::string acxn;
	SeqPos_t hitstart;
	SeqPos_t hitstop;
	SeqPos_t pssmstart;
	SeqPos_t pssmstop;
	double evalue;
	int score;
	double bitscore;
	double cutoffscore;
	bool ispartial;
	bool ismulti;
};



// -- base class
class CCdAlignProcessor
{
public:
	// -- sorting facilities
	struct TDomAlignFacility
	{
		TDomSeqAlignment *pAlign;
		size_t ulIdx;
		
		// -- added 12/03/2013 for sorting modification
		const TDomain *pCdInfo;
		size_t ulGapsIdx;
		
		
		TDomAlignFacility(void): pAlign(nullptr), ulIdx(0), pCdInfo(nullptr), ulGapsIdx(std::string::npos) {};
	};
	
	struct TDomAlignOrderByEValue
	{
		bool operator () (const TDomAlignFacility &p1, const TDomAlignFacility &p2)
		{
			if (p1.pAlign->m_dEValue < p2.pAlign->m_dEValue) return true;
			else if (p1.pAlign->m_dEValue > p2.pAlign->m_dEValue) return false;
			else return (p1.pAlign->m_dBitScore > p2.pAlign->m_dBitScore);
		}
	};
	
	// -- return seuqence length, for convenience
	static SeqLen_t SortReadingFrames(const std::vector<TDomSeqAlignment> &rSrc, std::vector<size_t> rfIndice[READINGFRAME::TOTAL_RFS], SeqLen_t qlen);
	
	CCdAlignProcessor(const TDomClusterIndexIfx *dom_src = nullptr): m_mtxDomClusterIdx(), m_pDomSrc(dom_src) {} ;
	
	
	virtual ~CCdAlignProcessor(void) {};
	
	inline
	const TDomClusterIndexIfx * GetMap(void) const {return m_pDomSrc;}
	
	
	//virtual const TDomain* FindCdInfo(unsigned int pssmid) const = 0;
	//virtual const TShluClusterInfo* FindClusterInfo(int clusterid) const = 0;
	
	
	// -- just a public interface for calculation
	//void Calculate(TShluCdQuery &rTarget, std::map<unsigned int, TDomain> &missed) const;
	
	// -- two set of calculated std::vector<TDomSeqAlignment> merged together, recalculate the four index sets. 
	// -- TDomSeqAlignment fields are assumed to be calculated/filled already so no need to calculate again
	// -- only need to calculate m_bRep and m_iRegionIdx
	//void MergeCalc(std::vector<TDomSeqAlignment> &aligns, TShluAlignIndice &dst, std::map<unsigned int, TDomain> &missed) const;
	//void MergeCalc(std::vector<TDomSeqAlignment> &aligns, const std::vector<size_t> &selIdx, TShluAlignIndice &dst, std::map<unsigned int, TDomain> &missed) const;
	void Calculate(std::vector<TDomSeqAlignment> &aligns, const std::vector<size_t> &selIdx, TDomSeqAlignIndex &dst, std::vector<PssmId_t> &missed, const int * stdmax = nullptr, size_t nmax = 0) const;
	void Calculate(std::vector<TDomSeqAlignment> &aligns, TDomSeqAlignIndex &dst, std::vector<PssmId_t> &missed, const int * stdmax = nullptr, size_t nmax = 0) const;
		
	
	// -- two set of calculated std::vector<TShluCdAlignInfo> merged together, recalculate the four index sets. 
	// -- TDomSeqAlignment fields are assumed to be calculated/filled already so no need to calculate again
	// -- only need to calculate m_bRep and m_iRegionIdx
	// -- and by the time to call MergeCalc, all missed pssmid should be there.
	void MergeCalc(std::vector<TDomSeqAlignment> &aligns, const std::vector<size_t> &selIdx, TDomSeqAlignIndex &dst, const int * stdmax = nullptr, size_t nmax = 0) const;
		
	// -- mode: TDataModes::EIndex, rf: readingframe index , 0-5
	
	void ExtractDomains(const TDomAnnot &rProcessed, std::vector< const TDomain* > &doms, std::vector< const TCluster* > &fams, int mode, int rfidx = 0) const;
	void ExtractDomains(const std::list<TDomAnnot> &rProcessed, std::vector< const TDomain* > &doms, std::vector< const TCluster* > &fams, int mode, int rfidx = 0) const;
	
	//Please make sure pssmids and clstids are non-dup.
	// -- extract doms and their superfamilies
	void ExtractDomains(const std::vector<PssmId_t> &pssmids, std::vector< const TDomain* > &doms, std::vector< const TCluster* > &fams) const;
	void ExtractClusters(const std::vector<ClusterId_t> &clstids, std::vector< const TCluster* > &fams) const;
	
	
protected:
#if defined(_MT)
	mutable ncbi::CRWLock m_mtxDomClusterIdx;
#endif
	const TDomClusterIndexIfx *m_pDomSrc;
	
	virtual void x_LoadMissingDomains(const std::vector<PssmId_t> &missed) const {};
	// -- added missed pssmid collector, for those not in dart but in cdtrack
	
	
	
	
	
	
	
	
	
	
	//void x_Calculate(std::vector<TDomSeqAlignment> &aligns, TShluAlignIndice &dst, std::map<unsigned int, TDomain> &missed) const;
	
	
	// -- take seqid, return pssmid (pseudo or not)
	
	//virtual unsigned int x_CollectDomain(const ncbi::objects::CSeq_id &rCdSeqId, int iFlags) = 0;
	
	
	//static void LoadCuratedClusterInfo(void);
	//static void MergeCuratedClusterInfo(std::map<int, TShluClusterInfo> & tgt);
	//static std::map<int, TCuratedClusterInfo> m_mapCuratedClusterInfo;
};

struct _TArchNameCols
{
	std::string name;
	std::string label;
	std::string nameevds;
	std::string labelevds;
	
	_TArchNameCols(void):
		name(k_strEmptyString), label(k_strEmptyString), nameevds(k_strEmptyString), labelevds(k_strEmptyString) {};
	void clear(void);
};

// -- 4/26/2024 - create name for superfamily architectures
void CreateSuperFamArchName(const TDomClusterIndexIfx &domInfo, const TDomSeqAlignIndex &indice, const std::vector<TDomSeqAlignment> &aligns, _TArchNameCols &cols, std::string &remark);

void CreateSpArchName(const TDomClusterIndexIfx &domInfo, const TDomSeqAlignIndex &indice, const std::vector<TDomSeqAlignment> &aligns, _TArchNameCols &cols, std::string &remark);


// -- without applying threshold
void CreateArchStrings0(const TDomClusterIndexIfx &domInfo, const std::vector<size_t> &conciseIdx, const std::vector<TDomSeqAlignment> &aligns, std::string &archStr, std::string &spArchStr);
// -- with applying threshold
void CreateArchStrings1(const TDomClusterIndexIfx &domInfo, const std::vector<size_t> &conciseIdx, const std::vector<TDomSeqAlignment> &aligns, std::string &archStr, std::string &spArchStr, double sfHitThold = SFHIT_THRESHOLD);
//  -- currently set to CreateArchStrings0
void CreateArchStrings(const TDomClusterIndexIfx &domInfo, const std::vector<size_t> &conciseIdx, const std::vector<TDomSeqAlignment> &aligns, std::string &archStr, std::string &spArchStr);



#endif
