#ifndef __DAV_OUT_FILTER_H__
#define __DAV_OUT_FILTER_H__

#define MAX_DELAY	5000000 // 5 sec
//#define SOC_BUFF	196607
//#define BANDWIDTH_LIMIT	1048576
//#define SOC_BUFF	262144
#define SOC_BUFF	393216
//#define SOC_BUFF	524288
#define MIN_SLEEP	50000
#define NUM_SUM		20
#define SKIP_NUM	1

#define PARSE_FILLBUFF	1
#define PARSE_GETHERING	2
#define PARSE_LIMIT		3

//#define AC_TCP		(ac->tc_percent[atoi(ai.szTCClassID)])
//#define AC_TCS		(ac->tc_session[atoi(ai.szTCClassID)])
#define SET_CID		cid = 0
#define AC_TCP		(ac->tc_percent)
#define AC_TCS		(ac->tc_session)


#ifdef __OPENDAV_BAND_CONTROL__
#define BC_START \
	apr_time_t past = 0, now = apr_time_now(), logged = 0, mode_time = 0;	\
	apr_time_t to_sleep_percent = 0, to_sleep_fixed = 0, to_sleep = 0, to_sleep_current = 0; \
	unsigned long long total_amount = 0, reflesh_amount = 0, first_limit = 0; \
	struct account_cache *ac;	\
	unsigned long long snapbps = 0, snaplen = 0, snaptime = 0; \
	unsigned long long maxbps = 0, maxlen = 0, maxtime = 0; \
	int gether_num = 0, mode = PARSE_FILLBUFF; \
	int __rv = 0, cid; \
	\
	acct_info ai;	\
	__rv = at_split(r->user, &ai);	\
	DBG0("BC_START debugging #111");\
	mode_time = apr_time_now(); \
	DBG0("BC_START debugging #22");\
	\
	if (__rv == -1) {	\
	DBG0("BC_START debugging #33");\
		ac = NULL;	\
	} else if (__rv == -2) {	\
	DBG0("BC_START debugging #44");\
		ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,	\
				"BC_START: user id format not match (%s)", r->user);	\
		ac = NULL;	\
	} else {	\
	DBG0("BC_START debugging #55");\
		ac = dav_shared_ac_get_by_tranid(ai.szVolumeID);	\
	} \
	DBG0("BC_START debugging #66");\
	SET_CID; 

/*
//		if (ac) {	\
			ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,	\
					"BC_START: ac: %d%%, %d bps",	\
					AC_TCP, AC_TCS);	\
		}	\
	}
*/


#define BC_CORE(slen) \
	total_amount += slen;	\
	if (ac && (AC_TCP > 0 || AC_TCS > 0)) {	\
		reflesh_amount += slen; \
		if ((gether_num > 0 ? reflesh_amount > (SOC_BUFF * 2) : reflesh_amount > SOC_BUFF) && mode == PARSE_FILLBUFF) { \
			mode = PARSE_GETHERING; \
			gether_num = 0; \
			snaplen = 0; \
			snaptime = 0; \
		} \
		now = apr_time_now();		\
		if (logged == 0 || logged != now / 1000000) {	\
			logged = 0;	\
		}	\
		if (now > past && mode == PARSE_LIMIT && first_limit != 0) {		\
			apr_time_t __past = past; \
			if (first_limit) { __past = mode_time; \
				first_limit = reflesh_amount; } \
			to_sleep_percent = 0;	\
			to_sleep_fixed = 0;	\
			if (AC_TCP > 0 && snapbps > 0 && AC_TCP < 10000) {	\
				to_sleep_percent = \
					(apr_time_t)((1000000 * (double)(slen + first_limit)) / \
								 ((snapbps * AC_TCP) / 10000));	\
				\
				if (to_sleep_percent < (now - __past)) 	\
					to_sleep_percent = 0;	\
				else	\
					to_sleep_percent -= (now - __past); \
			}	\
			if (AC_TCS > 0) {	\
				to_sleep_fixed =	\
					(apr_time_t)((1000000 * (double)(slen + first_limit)) / AC_TCS);	\
				if (to_sleep_fixed < (now - __past)) 	\
					to_sleep_fixed = 0;	\
				else	\
					to_sleep_fixed -= (now - __past); \
			}	\
	\
			if (to_sleep_percent > to_sleep_fixed)	\
				to_sleep += to_sleep_percent;	\
			else {	\
				to_sleep += to_sleep_fixed;	\
			} \
			first_limit = 0; \
			\
		}		\
        if (to_sleep > MAX_DELAY) to_sleep = MAX_DELAY;	\
		if (mode == PARSE_GETHERING) { \
			snaplen += slen; \
			snaptime += (now - past); \
			gether_num++; \
			if (gether_num >= NUM_SUM) { \
				if( snaptime > 0 ) \
					snapbps = (snaplen * 1000000 / snaptime); \
				 if( maxtime > 0 ) \
					maxbps = (maxlen * 1000000 / maxtime); \
				mode = PARSE_LIMIT; \
				first_limit = reflesh_amount; \
			} \
		} \
		if (mode == PARSE_FILLBUFF) { \
			maxlen += slen; \
			maxtime += (now - past); \
		} \
		if (to_sleep > MIN_SLEEP) {	\
			int sleep_vector = (to_sleep / MIN_SLEEP);	\
			apr_time_t after_sleep; \
			\
			to_sleep -= MIN_SLEEP * sleep_vector;	\
			apr_sleep(MIN_SLEEP * sleep_vector);	\
			after_sleep = apr_time_now();	\
			\
			to_sleep_current = (after_sleep - now - (MIN_SLEEP * sleep_vector));	\
			to_sleep -= to_sleep_current; \
			\
			past = after_sleep; \
		} else {  \
			past = now; \
		} \
		\
		if (mode == PARSE_LIMIT && first_limit <= 0) { \
			reflesh_amount = 0; \
			mode = PARSE_FILLBUFF; \
			mode_time = past; \
			maxlen = 0; \
			maxtime = 0; \
		} \
	}

/*
//		if (logged == 0 || logged != now / 1000000) {	\
			logged = now / 1000000;	\
		} \

//		if (logged == 0) {	\
			double bps = total_amount / ((now - start) / 1000000.); \
			ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,	\
					"BC_CORE S %lld (%.2f %cbps / snap %.2f %cbps)", to_sleep,	\
					(bps > 1024 * 1024 ? bps / 1024. / 1024. : bps / 1024.),	\
					(bps > 1024 * 1024 ? 'M' : 'K'),	\
					(snapbps > 1024 * 1024 ? snapbps / 1024. / 1024. : snapbps / 1024.),	\
					(snapbps > 1024 * 1024 ? 'M' : 'K'));	\
		}	\

//		if (logged == 0) {	\
			ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,	\
					"BC_CORE B ac %d%% P %lld / F %lld",	\
					AC_TCP, to_sleep_percent, to_sleep_fixed);	\
		}	\

//				if (logged == 0) {	\
					ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,	\
							"BC_CORE F %lld (%d/%d) / %lld",	\
							to_sleep_fixed, (int)slen, (int)AC_TCS, (now - __past));	\
				}	\
				\

//				if (logged == 0) {	\
					ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,	\
							"BC_CORE P %lld (%d/%d->%d) / %lld",	\
							to_sleep_percent, (int)slen, (int)snapbps, (int)((snapbps * AC_TCP) / 10000), (now - __past));	\
				}	\

//			ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,	\
					" -- %d: time %lld len %ld", \
					gether_num, (now - past), slen); \

//					if (logged == 0) {	\
						ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,	\
								" -- %d: time %lld/%lld len %lld", \
								_bc_i, (bs[_bc_i].now - bs[_bc_i].past), bs[_bc_i].curr, \
								bs[_bc_i].size); \
					} \

//			ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,	\
//					"BC_CORE: to_sleep: %d", to_sleep);	\


//				if (maxbps == 0 || to_sleep_current > 0) maxbps = snapbps; \
				to_sleep_current = 0; \
*/

#define BC_FINISH

/*
//	{	\
			double bps = total_amount / ((now - start) / 1000000.); \
			ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,	\
					"BC_FINISH2 %lld (%.2f %cbps)", to_sleep,	\
					(bps > 1024 * 1024 ? bps / 1024. / 1024. : bps / 1024.),	\
					(bps > 1024 * 1024 ? 'M' : 'K'));	\
	}
*/

#else
#define BC_START
#define BC_CORE(slen)
#define BC_FINISH
#endif

#endif // __DAV_OUT_FILTER_H___
