/*****************************************************************************
*
*	Type definitions for various database formats
*
*	Osamu Gotoh, ph.D.	(-2001)
*	Saitama Cancer Center Research Institute
*	818 Komuro, Ina-machi, Saitama 362-0806, Japan
*
*	Osamu Gotoh, Ph.D.	(2001-2013)
*	National Institute of Advanced Industrial Science and Technology
*	Computational Biology Research Center (CBRC)
*	2-41-6 Aomi, Koutou-ku, Tokyo 135-0064, Japan
*
*	Osamu Gotoh, Ph.D.      (2003-)
*	Department of Intelligence Science and Technology
*	Graduate School of Informatics, Kyoto University
*	Yoshida Honmachi, Sakyo-ku, Kyoto 606-8501, Japan
*
*	Copyright(c) Osamu Gotoh <<o.gotoh@aist.go.jp>>
*****************************************************************************/

#ifndef  _DBS_
#define  _DBS_

#ifndef _COMM
#define _COMM	';'
#endif 

static	const	char 	SEQ_EXT[] = ".seq";
static	const	char 	IDX_EXT[] = ".idx";
static	const	char 	HED_EXT[] = ".hed";
static	const	char 	GRP_EXT[] = ".grp";
static	const	char 	ENT_EXT[] = ".ent";
static	const	char 	ODR_EXT[] = ".odr";
static	const	char 	BKA_EXT[] = ".bka";
static	const	char 	BKN_EXT[] = ".bkn";
static	const	char 	BKP_EXT[] = ".bkp";
static	const	char	LUN_EXT[] = ".lun";
static	const	char	LUP_EXT[] = ".lup";
static	const	char	LXN_EXT[] = ".lxn";
static	const	char	LXP_EXT[] = ".lxp";
#if USE_ZLIB
static	const	char	SGZ_EXT[] = ".seq.gz";
static	const	char	AGZ_EXT[] = ".bka.gz";
static	const	char	NGZ_EXT[] = ".bkn.gz";
static	const	char	PGZ_EXT[] = ".bkp.gz";
static	const	char	LNZ_EXT[] = ".lun.gz";
static	const	char	LPZ_EXT[] = ".lup.gz";
#endif

#ifndef	DBS_DIR
#define	DBS_DIR		"#alndbs_dir#"
#endif

#ifndef	DBS_SDIR
#define	DBS_SDIR	"#alndbs_dir#"
#endif

#ifndef ALN_DBS
#define	ALN_DBS		"ALN_DBS"
#endif

#ifndef ALN_SDBS
#define	ALN_SDBS	"ALN_SDBS"
#endif

static	const	char	DBSID = '$';
static	const	int	MAX_DBS = 2;
static	const	int	ENTLEN = 14;
static	const	CHAR	SEQ_DELIM = 0x00;
static	const	int	MAXCODE = 21;
static	const	int	NTESTC = 1000;
static	const	long	magicver21 = 1117114721;

struct SeqDb {
	int	FormID;		/* ID of Database Format    */
	int	defmolc;	/* Default moleclur type    */
const	char*	DbName;
const	char*	EntLabel;	/* Entry	*/
const	char*	DefLabel;	/* Definition	*/
const	char*	AccLabel;	/* Accession	*/
const	char*	KeyLabel;	/* Key Word	*/
const	char*	SouLabel;	/* Source	*/
const	char*	RefLabel;	/* Reference	*/
const	char*	AutLabel;	/* Reference Authors	*/
const	char*	TitLabel;	/* Reference Title	*/
const	char*	JouLabel;	/* Reference Journal	*/
const	char*	ComLabel;	/* Comments	*/
const	char*	FeaLabel;	/* Feature Table	*/
const	char*	SeqLabel;	/* Begining of Sequence	*/
const	char*	EndLabel;	/* End of an Entry	*/
const	char*	SeqHead;	/* Head line on Seqence	*/
const	char*	SeqForm;	/* Format for Left Margin*/
	int	SeqBlkNo;	/* No. of Blocks	*/
	int	SeqBlkSz;	/* Size of a Block	*/
	int	SeqBlkSp;	/* Size of an Inter-Block space	*/
	INT	ContSpc;	/* Continue Space	*/
	int	is_DbEntry(const char* str) const;
	int	is_DbEnd(const char* str) const;
	int	is_DbOrigin(const char* str) const;
	long	dbnextentry(FILE* fd, char* ps) const;
};

struct DbsRec20 {
	char	entry[ENTLEN];
	CHAR	master;
	CHAR	subset;
	long	recnbr;
	long	srcptr;
	long	seqptr;
	long	seqlen;
};

struct DbsRec25 {
	long	seqptr;
	long	seqlen;
	size_t	entptr;
};

struct DbsRec {
	long	seqptr;
	long	seqlen;
	size_t	entptr;
};

struct DbsGrp {
	long	seqptr;
	long	recnbr;
};

class DbsDt {
friend	class	MakeBlk;
friend	class	SrchBlk;
	char*	pseq;
	CHAR*	dbsseq;
	Strlist*	grplbl;
	bool	comment;
	DbsRec*	recidx;
	int*	gsiidx;
	DbsRec20*	recidx20;
	INT*	recodr;
	char*	entry;
	int*	gsipool;
	DbsRec*	bisearch(const char* key) const;
	void	readseq(const char* fn);
	size_t	readgrp(FILE* fgrp);
	void	readidx20(FILE* fd, const char* fn);
	DbsRec*	readidx(FILE* fidx, const char* fn);
	void	readentry(FILE* fent, const char* fn);
	void	readodr(FILE* fodr, const char* fn);
public:
const	char*	dbsid;
	SeqDb*  curdb;
	FILE*	fseq;
	DbsGrp* dbsgrp;
	int     numgrp;
	INT	numidx;
	void	clean();
	DbsDt(int c = 0, int molc = UNKNOWN);
	DbsDt(const char* form);
	~DbsDt();
	int	grpno(DbsGrp* grp) const {return (grp - dbsgrp);}
	int	recno(const DbsRec* rec) const {return (rec - recidx);}
	DbsGrp*	finddbsgrp(const char* name) const;
	DbsRec*	findcode(const char* code) const;
	DbsRec*	dbsrec(INT pos) const {return (pos < numidx? recidx + pos: 0);}
	DbsRec*	dbsrec(const DbsRec* rec = 0) const {return (recidx + (rec? recodr[recno(rec)]: 0));}
	int	guessmolc() const;
	CHAR*	dbseq(DbsRec* rec = 0) const {return (dbsseq + (rec? rec->seqptr: 0));}
	char*	entname(const DbsRec* rec = 0) const {return (entry + (rec? rec->entptr: 0));}
	char*	entname(int recno) const {return (entry + recidx[recno].entptr);}
	int*	gsient(int recno) const {return (gsiidx? gsipool + gsiidx[recno]: 0);}
	int	gsisize(int recno) const {return (gsiidx? gsiidx[recno + 1] - gsiidx[recno]:0);}
	char*	fsrcname(int sub) const {return ((*grplbl)[sub]);}
	FILE*	dbsfopen() const {return (dbsseq? 0: fopen(pseq, "r"));}
	void	prepare(size_t entry_space, size_t num, size_t seq_space, size_t gsi_space = 0);
	void	prepare(Strlist& sname, int num, size_t space, size_t gsi_space = 0);
	int	seqloc(CHAR* ps) const {return (ps - dbsseq);}
	int	entloc(char* pe) const {return (pe - entry);}
	int	gsiloc(int* pg) const {return (pg - gsipool);}
	void	makodr();
};

enum DBs {GenBank, EMBL, Swiss, TFDS, NBRF, ProDB, 
		FASTA, MSF, PIR, NEXUS, Bare, EndOfDB = Bare};

extern	DbsDt*	dbs_dt[];
extern	SeqDb	SeqDBs[];

extern	SeqDb*	setform(int c);
extern	void	setdefdbf(DbsDt* dbf);
extern	void	EraDbsDt();
extern	char*	path2dbf(char* str, const char* fn, const char* ext = 0);
extern	bool	space_digit(const char* ps);
extern	const	char*	finddbfpath(const char* fn, const char* ext = 0);
extern	SeqDb*	whichdb(const char* ps);

template <typename file_t>
char* dbs_header(char* str, file_t fin)
{
	char*	ps = str;
	while (*ps == _LCOMM || space_digit(ps))
	    if (!fin || !(ps = fgets(str, MAXL, fin)))
		return (0);
	return (ps);
}

template <typename file_t>
SeqDb*	whichdb(char* ps, file_t fd = 0)
{
	if (fd) ps = dbs_header(ps, fd);
	return (whichdb(ps));
}

#endif
