#if !defined(__SEG_SET__)
#define __SEG_SET__

#include "cacheops.hpp"
#if defined(__DB_OFFLINE__)
#include "structifx.hpp"
#include "normbase.hpp"
#else
#include <StructIfx/structifx.hpp>
#include <shlu2/BasicUtils/normbase.hpp>
#endif
#include <list>
#include <vector>
#include <algorithm>
struct TSeg_base: public Cacheable
{
	struct TResiduePos
	{
		SeqPos_t curr, ori;
		TResiduePos(SeqPos_t c = 0, SeqPos_t o = 0): curr(c), ori(o) {};
	};
	
	SeqPos_t from;
	SeqPos_t to;
	
	// -- The ori_from should always be pointing to the position on original sequence that corresponding to the "from" of the current mapped position. Pay attention to negative strand proteins, the ori_from should be the coordinate of the C'- residue of thesegment on original. Any mapping should keep this relationship unchanged. 
	SeqPos_t ori_from;
	
	bool operator == (const TSeg_base& other) const;
	
	TSeg_base(SeqPos_t f = 0, SeqPos_t t = 0): from(f), to(t), ori_from(f) {};
	bool IsValid(void) const;
	
	bool LeftTo(const TSeg_base& rSrcSeg) const {return (to < rSrcSeg.from - 1);} 
	bool RightTo(const TSeg_base& rSrcSeg) const {return (from > rSrcSeg.to + 1);}
	bool LeftTouch(const TSeg_base& rSrcSeg) const {return (to == rSrcSeg.from - 1);}
	bool RightTouch(const TSeg_base& rSrcSeg) const {return (from == rSrcSeg.to + 1);}
	bool MoreLeft(const TSeg_base& rSrcSeg) const {return (from < rSrcSeg.from);}
	bool MoreRight(const TSeg_base& rSrcSeg) const {return (to > rSrcSeg.to);}
	bool Overlap(const TSeg_base& rSrcSeg) const {return ((from >= rSrcSeg.from && from <= rSrcSeg.to) || (rSrcSeg.from >= from && rSrcSeg.from <= to));}
	bool Touch(const TSeg_base& rSrcSeg) const {return (LeftTouch(rSrcSeg) || RightTouch(rSrcSeg));}
    
    virtual void SaveToCache(CDataCache &dc) const override;
    virtual void RestoreFromCache(CDataCache &dc) override;
};



// -- sort from left most to right
struct TSegSortLeft
{
	bool operator () (const TSeg_base* s1, const TSeg_base* s2);
};

// -- sort from long to short segs, so short segs will be drawn later than long segs
struct TSegSortLength
{
	bool operator () (const TSeg_base* s1, const TSeg_base* s2);
};


template <typename SEGTYPE>
class CSegSetTmpl: public Cacheable
{
	friend class TSeqAlignment;
public:
	typedef SEGTYPE TSeg;
	typedef std::list<SEGTYPE> TSegs;	
	
	
	CSegSetTmpl(void): m_iFactor(1), m_lstContainer(), m_ulGapThreshold(k_SeqLen_Max) {};
	CSegSetTmpl(const std::vector<SeqPos_t>& starts, const std::vector<SeqLen_t>& lens);	//always set ofs to zero! so must use slave coordinates.
	virtual ~CSegSetTmpl(void) {};
	
	//this must be a normal segs: align from left to right
	void SetData(const std::vector<SeqPos_t>& starts, const std::vector<SeqLen_t>& lens);	//always set ofs to zero! so must use slave coordinates.
	void SetData(const std::vector<SeqPos_t> &residues);

	bool operator == (const CSegSetTmpl& other) const;
	
	// -- status
	bool IsEmpty(void) const {return m_lstContainer.empty();}
	int GetTransFactor(void) const {return m_iFactor;}
	
	// -- manipulate. 
	// -- any operation, the ori_from and ori_to are calculated based on target segment. src segs ori information are discarded.
	void AddSeg(SeqPos_t f, SeqPos_t t);	//  
	void AddSeg(const SEGTYPE& seg);
	
	void Clear(void) {m_lstContainer.clear();}
	
	void Merge(const CSegSetTmpl& src);
	void Cross(const CSegSetTmpl& src);
	void Clip(const CSegSetTmpl& src);
	void Inv(SeqPos_t from, SeqPos_t to);	//inverse against a total range

	SeqPos_t GetLeft(void) const;
	SeqPos_t GetRight(void) const;
	//SeqPos_t GetLeftOfs(void) const;
	//SeqPos_t GetRightOfs(void) const;
	SeqPos_t GetTotalResidues(void) const;
	

	void GetOverall(SEGTYPE &target, SeqPos_t &ori_to) const;	//ori-to is calculated from the last segment factor is 1 or 3 -- if Pr2na
	SeqPos_t GetOriTo(typename TSegs::const_iterator citer, SeqPos_t pos = -1) const;
	SeqPos_t GetOriTo(void) const;
	const TSegs& GetSegs(void) const {return m_lstContainer;}
	// -- gapThreshold is AA residue counts. Will automatically convert to NA (if applicable) counts in the result
	void GetGaps(CSegSetTmpl<SEGTYPE> &dst) const;
	//void GetSimplePosMap(std::vector<TResiduePos> &dst) const;
	//void GetOriSimplePosMap(std::vector<TResiduePos> &dst) const;
	void GetTranslatedPosMap(size_t aaSeqLen, std::vector<TSeg_base::TResiduePos> &dst) const;
	virtual int GetCompleteSize(void) const {return -1;}
    
    virtual void SaveToCache(CDataCache &dc) const override;
    virtual void RestoreFromCache(CDataCache &dc) override;
	
protected:
	// -- the actual container
	//factor: when map protein to na, it is 3, otherwise it is 1. sign denotes the direction, it is mainly
	// -- responsible to calculate ori_to from ori_from of each segment.
	int m_iFactor;
	
	TSegs m_lstContainer;
public:
	SeqLen_t m_ulGapThreshold;

};


typedef CSegSetTmpl<TSeg_base> CSegSet;

#include "impl/segset_impl.hpp"
#endif
