/*
 * tracing.h
 *
 *  Created on: 2017. 11. 20.
 *      Author: zeroshoo
 */

/**
 * Ark CDC Tracing File Contoller.
 *
 * This is a arkcdc tracing file contller library
 *
 * @file tracing.h
 */

#ifndef INCLUDE_TRACING_H_
#define INCLUDE_TRACING_H_

#include <stdio.h>

#include <msgpack.h>

#include <stdbool.h>
#include <qlibc/qlibc.h>

#include "arkinternal.h"

#ifdef __linux__
#include <linux/limits.h>
#endif

#define LEN_PATHSIZE            256
#define LEN_ALIAS               32
#define LEN_VERSION             16
#define LEN_TIMESTAMP           24
#define LEN_DSN                 64

#define LEN_OSNAME              16
#define LEN_HOSTNAME            16
#define LEN_KERNEL_RELEASE      32
#define LEN_KERNEL_VERSION      40
#define LEN_ARCHITECTURE        32

#define LEN_DBNAME              16
#define LEN_INSTANCE_NAME       16
#define LEN_DBBANNER            384
#define LEN_DBVERSION           64

#define LEN_ROWID               24
#define LEN_TRANSACTION_ID    	20

#define LEN_SCHEMA			   	30
#define LEN_OBJECT    			128

#define LEN_MAX_REGULAR			4000

#define ARKCDC_NULL     0xFF00FF00

#define TEST_TRACING_FILE	"test.trc"

#define DBTYPE_ORACLE		0x08
#define DBTYPE_MSSQL		0x35
#define DBTYPE_MYSQL		0x37
#define DBTYPE_CUBRID		0x46
#define DBTYPE_TIBERO		0x71
#define DBTYPE_ALTIBASE		0x41
#define DBTYPE_POSTGRESQL	0x90
#define DBTYPE_UNKNOWN		0xFF

#define DBTYPE_STRING_ORACLE		"ORACLE"
#define DBTYPE_STRING_MSSQL			"SQLServer"
#define DBTYPE_STRING_MYSQL			"Mysql"
#define DBTYPE_STRING_CUBRID		"Cubrid"
#define DBTYPE_STRING_TIBERO		"Tibero"
#define DBTYPE_STRING_ALTIBASE		"Altibase"
#define DBTYPE_STRING_POSTGRESQL	"Postgresql"
#define DBTYPE_STRING_UNKNOWN		"Unknown"

#define COL_BEFORE				0x01
#define COL_AFTER				0x02

#define COL_TYPE_UNKNOWN		0x00

#define COL_TYPE_NUMERIC		0x01

#define COL_TYPE_STRING			0x11

#define COL_TYPE_DATE			0x21
#define COL_TYPE_TIMESTAMP		0x22
#define COL_TYPE_TIMESTAMP_TZ	0x23
#define COL_TYPE_TIMESTAMP_TZR  0x24
#define COL_TYPE_TIMESTAMP_LTZ  0x25
#define COL_TYPE_INTERVAL_YM	0x30
#define COL_TYPE_INTERVAL_DS	0x31

#define COL_TYPE_ROWID			0x60

#define COL_TYPE_LARGE			0x80

#define RECORD_TYPE_DML         0x01
#define RECORD_TYPE_DDL         0x02

#define RECORD_TYPE_DML_UNKNOWN			0x00
#define RECORD_TYPE_DML_DELETE          0x01
#define RECORD_TYPE_DML_INSERT          0x02
#define RECORD_TYPE_DML_UPDATE          0x03
#define RECORD_TYPE_DML_UPDATE_PK       0x07

#define RECORD_TYPE_DDL_UNKNOWN			0x00
#define RECORD_TYPE_DDL_CREATE_TABLE	0x01
#define RECORD_TYPE_DDL_ALTER_TABLE		0x02
#define RECORD_TYPE_DDL_DROP_TABLE		0x03
#define RECORD_TYPE_DDL_RENAME_TABLE	0x04
#define RECORD_TYPE_DDL_TRUNCATE_TABLE	0x05

#define TRACING_READONLY		0x01
#define TRACING_READWRTIE		0x03

#define MODESTR_READWRTIE		"r+b"
#define MODESTR_WRTIE			"w+b"
#define MODESTR_READONLY		"rb"

#define TRACING_UMASK			0644

#define TRACING_VERSOION		"1.0.0.3"

#define TRACING_FILEFORMAT		"%s/%s_%06d.trc"

typedef struct acscn
{
	uint32_t high;
	uint32_t wrap;
	uint32_t base;
} ACDSN;

///File Structure 정의
// Tracing Meta info
// 512 bytes
typedef struct _st_tracing_meta
{
	uint16_t version;			/* !< tracing version */
	uint8_t pad1[2];
	uint8_t pad2[4];
	uint32_t cksum;
    char alias[LEN_ALIAS];
    uint8_t pad3[16];
    char filename[LEN_PATHSIZE];
    uint8_t pad4[196];
} tracing_meta;

//Extract details
// 512 bytes
typedef struct _st_tracing_extract
{
    char alias[LEN_ALIAS];
    uint8_t pad1[16];
    char version[LEN_VERSION];
    uint8_t pad2[16];
    char begin_timestamp[LEN_TIMESTAMP];
    ACDSN begin_commit_dsn;
    uint8_t pad3[4];
    uint8_t pad4[16];
    char end_timestamp[LEN_TIMESTAMP];
    ACDSN end_commit_dsn;
    uint8_t pad5[4];
    uint8_t pad6[16];
    uint8_t pad7[64];
    uint8_t pad8[256];
} tracing_extract;

//Operating System details
// 512 bytes
typedef struct _st_tracing_os
{
	uint8_t type;
	uint8_t pad1[3];
	uint8_t pad2[12];
    char osname[LEN_OSNAME];						// uname
    char hostname[LEN_HOSTNAME];					// hostname, uname -n
    char kernel_release[LEN_KERNEL_RELEASE];		// uname -r
    char kernel_version[LEN_KERNEL_VERSION];		// uname -v
    uint8_t pad3[8];
    char architecture[LEN_ARCHITECTURE];			// uname -p
    uint8_t pad4[96];
    uint8_t pad5[256];
} tracing_os;

// Soure Database details
// 512 bytes
typedef struct _st_tracing_database
{
    uint8_t type;										// DBTYPE_ORACLE
    uint8_t pad1[3];
    uint8_t version_flag;
    uint8_t pad2[3];
    char db_name[LEN_DBNAME];						// SELECT NAME FROM V$DATABASE
    char instance_name[LEN_INSTANCE_NAME];			// SELECT INSTANCE_NAME FROM V$INSTANCE
    uint8_t pad3[8];
    char version[LEN_DBVERSION];					// SELECT VERSION FROM V$INSTANCE
    uint8_t pad4[8];
    char banner[LEN_DBBANNER];						// SELECT BANNER FROM V$VERSION
    uint8_t pad5[8];
} tracing_database;

//FILE HEADER
typedef struct _st_tracing_file_header
{
	tracing_meta	meta;
    tracing_extract extract;
    tracing_os os;
    tracing_database db;
} tracing_file_header;

//Row Header
typedef struct _st_tracing_record_header
{
	uint8_t command;  // DML, DDL
	uint8_t type;         // 0x01 DELETE, 0x02 INSERT, 0x03 UPDATE, 0x07 UPDATE including PK
    int data_length;
    char timestamp[LEN_TIMESTAMP];
    int sequence;       // RBA
    int block;         // RBA
    int offset;         // RBA
    short tx_index;
    uint8_t tx_continue;
    short col_count;
    char schema[LEN_SCHEMA];
    char object[LEN_OBJECT];
} tracing_record_header;

//data record
typedef struct _st_tracing_record_data
{
	short colno;
	uint8_t flag;					// 0x01 BEFORE, 0x02 AFTER
	short type;					// 0x01 NUMERIC, 0x02 STRING, 0x03 DATE, 0x05 LOB
    uint8_t is_null;
    uint32_t length;
    char str[LEN_MAX_REGULAR];
} tracing_record_data;

//file body Transaction Record
typedef struct _st_tracing_record_transaction
{
    char rowid[LEN_ROWID];
    ACDSN commit_dsn;
    char tx_id[LEN_TRANSACTION_ID];
} tracing_record_transaction;

typedef struct _st_tracing_record
{
    tracing_record_header header;
    tracing_record_data *data;
    tracing_record_transaction transaction;
} tracing_record;

typedef struct _st_tracing_record_bracket
{
	int 		index;
	uint8_t		flag;
	uint8_t		unused;
	uint16_t	length;
	uint32_t	tba;
} tracing_record_bracket;

#define BRACKET_OPENING 40
#define BRACKET_CLOSING 41

typedef struct _st_tracing_record_buffer
{
	tracing_record_bracket 		opener;
	char 		*data;
	tracing_record_bracket 		closer;
} tracing_record_buffer;

typedef struct _st_tracing_status
{
	int 		seqno;
	uint32_t	tba;
} tracing_status;

static ACDSN FFPADDING = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };

int dsncmp(ACDSN *l, ACDSN *r);
uint64_t getHumanToBytes(char *human);
char *get_database_type_to_string(uint8_t _type, char *_stringbuf);
char * trcstrerror(int errnum);

int get_last_tracing_seq(const char *path, const char *alias);

int check_tracing(const char *path);
bool checksum_header(const tracing_file_header *_header);
int check_header(const char *path);

#ifdef __cplusplus
extern "C" {
#endif

typedef struct actracer_t	actracer_t;
typedef struct actloader_t	actloader_t;

#define ACTRC_OPT_THREADSAFE  0x01
#define ACTRC_OPT_FLUSH        0x02

/* public functions */
extern actracer_t *actracer(const char *_alias, const char *_dirpath,
		const long int _rotateoffset, const int _rotateinterval, const int _options);

extern actloader_t *actloader(const char *_alias, const char *_dirpath, const int _options);

//extern  int     *_TrcErrno( void );
//#define trcerrno   (*_TrcErrno())

#ifndef trcerrno
extern int trcerrno;
#endif

#define TEACCESS	1001		/* Trace file Permission denied */
#define TENOTSFILE	1002		/* Trace status open fail */
#define TEWRONGRBA	1003		/* Wrong trace file block address */
#define TENOENT		1004		/* No such trace file or directory */
#define TENOTRCFILE	1005		/* No such trace file or directory */
#define TEPERM		1006		/* Trace operation not permitted */
#define TEWRONGHEAD	1007		/* Wrong trace file header block */
#define TENOCURRENT 1008		/* Trace file is not current file */

//#define	TENOMEM		12			/* MEMORY ALLOCATE FAIL */



/**
 * actracer_t structure object structure
 */
struct actracer_t {
    /* encapsulated member functions */
	bool (*save_header) (actracer_t *self, tracing_file_header * _header);
	bool (*load_header) (actracer_t *self, tracing_file_header *_header);
	void (*set_os) (actracer_t *self, tracing_os * os);
	void (*set_db) (actracer_t *self, tracing_database *db);
	void (*set_extract) (actracer_t *self, ACDSN *commit_dsn, char *timestamp);
    bool (*append_record) (actracer_t *self, tracing_record * _rec);

    bool (*force_close) (actracer_t *trc, ACDSN *commit_dsn, char *timestamp);

//    bool (*ts_clear) (actracer_t *trc);

    bool (*tflush) (actracer_t *trc);
    void (*tfree) (actracer_t *trc);

    /* private variables - do not access directly */
    void *mutex;  /*!< activated if compiled with --enable-threadsafe */

    char alias[LEN_ALIAS]; /*!< alias */

    tracing_file_header header;

    char tracedir[PATH_MAX]; /*!< trace file directory path */

    char fileprefix[PATH_MAX]; /*!< file naming prefix */
    char filepath[PATH_MAX];    /*!< generated system path of tracing file */
    FILE *fp;           /*!< file pointer of tracing file path */

    int rotateinterval; /*!< traing file will be rotate in this interval seconds */
    int nextrotate;  /*!< next rotate universal time, seconds */

    uint64_t rotateoffset; /*!< traing file will be rotate in this size */
    bool trcflush;   /*!< flag for immediate flushing */

    uint32_t index;

    tracing_status ts;
//    char statuspath[PATH_MAX];    /*!< generated system path of tracing status file */
//    FILE *tsfp;           /*!< file pointer of tracing status file */
//    int tsfd;           /*!< file pointer of tracing status file */

    //    FILE *outfp;    /*!< stream pointer for duplication */
    //    bool outflush;  /*!< flag for immediate flushing for duplicated stream */
};

/**
 * actloader_t structure object structure
 */
struct actloader_t {
    /* encapsulated member functions */
	bool (*load_header) (actloader_t *self, tracing_file_header * _header);
	long int (*get_next_record) (actloader_t *self, tracing_record * _rec);
	long int (*get_next_record_with_buffer) (actloader_t *self, tracing_record * _rec, tracing_record_buffer *_buffer);
//    long int (*set_scn) (actloader_t *self, ACDSN *_dsn);

    long int (*search_file_scn) (actloader_t *tl, ACDSN *_dsn);

    long int (*seek_position) (actloader_t *tl, long int _position);
    long int (*seek_record) (actloader_t *tl, long int _rec_num);
    long int (*seek_scn) (actloader_t *tl, ACDSN *_dsn);

//    bool (*ts_clear) (actloader_t *trc);

    void (*tfree) (actloader_t *trc);

    bool is_current;

    /* private variables - do not access directly */
    void *mutex;  /*!< activated if compiled with --enable-threadsafe */

    char alias[LEN_ALIAS]; /*!< alias */

    tracing_file_header header;

    char tracedir[PATH_MAX]; /*!< trace file directory path */

    char filepath[PATH_MAX];    /*!< generated system path of tracing file */
    FILE *fp;           		/*!< file pointer of tracing file path */

    uint32_t index;

    tracing_status ts;
//	char statuspath[PATH_MAX];    /*!< generated system path of tracing status file */
//	FILE *tsfp;           /*!< file pointer of tracing status file */
};

#ifdef __cplusplus
}
#endif

#endif /* INCLUDE_TRACING_H_ */
