//////////////////////////////////////////////////////////////////
// Multiscale fixed size long term rotating log file
// Author: Marijn Weehuizen
//////////////////////////////////////////////////////////////////


#define HOUR_COUNT (600)			// 400 samples is 33.33 minutes
#define HOUR_SAMPLE (10)			// Sample every 10 seconds
#define DAY_COUNT (550)				// 400 samples is 33.33 hours
#define DAY_SAMPLE (5*60)			// Sample every 5 minutes
#define WEEK_COUNT (550)			// 400 samples is 8.33 days
#define WEEK_SAMPLE (30*60)			// Sample every 30 minutes
#define MONTH_COUNT (550)			// 400 samples is 33.33 days
#define MONTH_SAMPLE (2*60*60)		// Sample every 2 hours
#define YEAR_COUNT  (550)			// 1 sample / day, 366 days, 2 years
#define YEAR_SAMPLE (24*60*60)		// Sample every 24 hours

#define HOUR_WINDOW (4)				// High res samples valid if collecteed 10s +/- 4s ago
#define DAY_WINDOW (60)				// Day samples valid if collecteed 5*60s +/- 60s ago


enum COUNTER_TYPES { PERF_CTR, PERF_AVG, PERF_INSTANT };

enum SAMPLE_TYPES { MLOG_HOUR, MLOG_DAY, MLOG_WEEK, MLOG_MONTH, MLOG_YEAR};

extern char *SAMPLE_TEXT[];

typedef struct _HISTORY {
    time_t time;
    unsigned long  in, out, percent, inmax, outmax;
} HISTORY;

typedef struct _HISTORY_DETAIL {
    time_t time;
    double in, out, inmax, outmax;
} HISTORY_DETAIL;


typedef struct _MLOG_INDEX {
	HISTORY *precent;
	HISTORY *poldest;
	HISTORY *pstart;
	HISTORY *pend;
} MLOG_INDEX;

typedef struct _MLOG{
	int type;				// not currently used
	int samplemode;			// highres / normal sampling frequency
	int debugfill;			// debug fill for checking multiresolution averaging
	HISTORY_DETAIL *last1;	// last sample point (for normalising)
	HISTORY_DETAIL *last2;	// second to last sample point (for normalising)
	MLOG_INDEX index[5];	// index to the data buffer
	HISTORY_DETAIL data_recent[2];
	HISTORY data[HOUR_COUNT + DAY_COUNT + WEEK_COUNT + MONTH_COUNT + YEAR_COUNT + 1];
} MLOG;

// Main external interface
MLOG *mlog_new ();
int mlog_addvalue(MLOG *pL, time_t now, double value, int dodebug);
int mlog_load (MLOG **hL, char* file, int debugfill, int type);
int mlog_save (MLOG *pL, char* file);
int mlog_fillgraphbufer(MLOG *pL, int graphtime, int scale, HISTORY*bf, int maxx, int maxy, double yscale, int cutoff);
unsigned long mlog_lastvalue(MLOG *pL);
int	mlog_getscale(char* type);
int mlog_setsamplemode(int mode);
int mlog_resample(MLOG *pL, int mode);
int mlog_getsamplemode();
int mlog_getsampleperiod();
void mlog_setdebug(int debug);

int mlog_locate_invalid_data(MLOG *pL, unsigned long limit, time_t *invalid_start, time_t *invalid_end, int *count);
int mlog_reset_invalid_data(MLOG *pL, time_t reset_start, time_t reset_end, int *changes);
int mlog_validate_data2(MLOG *pL, time_t reset_start, time_t reset_end, int *changes);
int mlog_rescale_data2(MLOG *pL, double rescale, int *changes);


// Internal helper functions
int mlog_test();
int mlog_debugsave(MLOG *pL, char* file);
void mlog_writevalue(MLOG *pL, FILE* fo,char* s, HISTORY *p, int scale);
void mlog_writevalue_detail(MLOG *pL, FILE* fo,char* s, HISTORY_DETAIL *p, int scale);
int mlog_addvalue_core(MLOG *pL, int scale, HISTORY_DETAIL *newvalue, int dodebug);


extern int SAMPLE_PERIOD[];

#define  DEBUG_COUNTER	0xFFFFFF00
#define  DEBUG_TYPE		0x000000FF
#define  DEBUG_FILL		0x00000001
#define	 DEBUG_RAMP		0x00000002
#define  DEBUG_STEADY	0x00000004

#define TRUNC_ULONG(x) (x)>ULONG_MAX ? ULONG_MAX : (x)

#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
