#include <iostream>                /* C++ iostream            C++98/11 */
#include <string>
#include <vector>

#define SAMPLE_TIME_MIN_N_SEC 128

/* FADIII START */

#define HIST_NUM_BINS 10
#define IS_CONDOR_ONLY 0

inline struct timespec getTimespecNow (void) {
	struct timespec now;
	return now;
}

/* FADIII END */

struct Histogram {
	u_int32_t sample_time;
	u_int8_t mode;
	struct timespec last_update;
	u_int8_t last_bin_updated;
	std::vector<size_t> histogram_bins;
	size_t hist_type;
	virtual ~Histogram() {}
	Histogram() : sample_time(0), mode(0), last_bin_updated(0), histogram_bins(HIST_NUM_BINS, 0), hist_type(4096) {
		last_update = getTimespecNow();	
	}
	virtual void clear() {
		for (size_t i = 0; i < HIST_NUM_BINS; i++) {
			histogram_bins[i] = 0;
		}
	}
	virtual void updateForTimeInterval() {}
	virtual void updateCurrentBin(size_t value) = 0;
protected:
// Common function for both SB and Port Counter histograms, that will be called from each instance according to its own prm arguments
	size_t getCurrentBin(size_t value, size_t bin_size, size_t first_bin_threshold) {
		size_t upper_bound = first_bin_threshold, lower_bound = 0;
		int index = 0;
		while ((index < (HIST_NUM_BINS - 1)) && (value > lower_bound)) {
			if (value < upper_bound) {
				break;
			}
			++index;
			lower_bound = upper_bound;
			if (mode) {
				upper_bound = first_bin_threshold + ((2 << (index - 1)) * bin_size);
			}
			else {
				upper_bound = first_bin_threshold + (index * bin_size);
			}
		}
		return index;
	}
};

struct SharedBufferHistogram : public Histogram {
	bool enabled;
	bool is_bind;
	size_t local_port;
	size_t hist_parameter;
	size_t hist_min_value;
	size_t hist_max_value;
	SharedBufferHistogram() : Histogram(), enabled(false), is_bind(true), local_port(0), hist_parameter(0), hist_min_value(0), hist_max_value(0) {}
	virtual ~SharedBufferHistogram() {}

	virtual void updateForTimeInterval(size_t global_sample_time) {
		double diff = 0;//CalculateTimeDiff(&last_update); //FADIII
		u_int64_t num_of_intervals = diff / ((2 << (IS_CONDOR_ONLY ? global_sample_time : sample_time)) * SAMPLE_TIME_MIN_N_SEC);
		last_update = getTimespecNow();
		histogram_bins[last_bin_updated] += num_of_intervals;
	}

	virtual void updateCurrentBin(size_t value) {
		size_t index = Histogram::getCurrentBin(value, (hist_max_value - hist_min_value) / (mode ? 255 : 8), hist_min_value);
		histogram_bins[index]++;
		last_bin_updated = index;
	}
};

struct PortCounterHistogram : public Histogram {
	enum PortHistogramBindGroup {
		CRC_Errors,
		Packet_Received_Size,
		Buffer_Overflow_Packet_PG,
		Packet_Received_PG,
		Bytes_Received_Ok,
		Packet_Transmit_Ok_TC,
		PAUSE_Transmit_Prio,
		ARN_Transmit,
		Packet_Transmit_ECN_TC,
		Receive_PAUSE_Duration_Prio,
		Transmit_Cong_TC
	};
	static constexpr size_t CounterHistogramInfinite = 0xffffff;
	size_t first_bin_threshold;
	size_t bin_size;
	int hist_repeat_num;
	size_t current_counter_value;
	size_t min_watermark;
	size_t max_watermark;
	PortCounterHistogram() : Histogram(), first_bin_threshold(0), bin_size(0), hist_repeat_num(0), current_counter_value(0), min_watermark(0xffffffffffffffff), max_watermark(0) {}
	virtual ~PortCounterHistogram() {}
	virtual void updateCurrentBin(size_t value) {
		if (hist_repeat_num <= 0) {
			return;
		}
		size_t diff = 0; // FADIII: CalculateTimeDiff(&last_update);
		if (diff < sample_time) {
			current_counter_value += value;
		}
		else {
			std::cout << "Selected bin=" << getCurrentBin(current_counter_value, bin_size, first_bin_threshold) << std::endl;
			histogram_bins[getCurrentBin(current_counter_value, bin_size, first_bin_threshold)]++;
			if (hist_repeat_num != CounterHistogramInfinite) {
				hist_repeat_num -= (diff / sample_time);
			}
			diff -= sample_time;
			if (diff > sample_time) {
				histogram_bins[0] += diff / sample_time;
			}
			current_counter_value = value;
			last_update = getTimespecNow();
			min_watermark = std::min(value, min_watermark);
			max_watermark = std::max(value, max_watermark);
		}
	}
	static size_t packet_length_to_hist_type(size_t length) {
		length >>= 6;
		size_t reps = 0;
		while (length) {
			length >>= 1;
			reps++;
		}
		return reps;
	}
	virtual void updateForTimeInterval() {
		updateCurrentBin(current_counter_value);
		current_counter_value = 0;
		double diff = 0; //FADIII: CalculateTimeDiff(&last_update);
		u_int64_t num_of_intervals = 1;
		if (sample_time != 0) {
			num_of_intervals = diff / (sample_time * SAMPLE_TIME_MIN_N_SEC);
		}
		histogram_bins[0] += num_of_intervals;
		last_update = getTimespecNow();
	}
	virtual void clear() {
		Histogram::clear();
		first_bin_threshold = 0;
		bin_size = 0;
		hist_repeat_num = 0;
		current_counter_value = 0;
		min_watermark = 0xffffffffffffffff;
		max_watermark = 0;
	}
};

int main() {
	std::cout << "fadi" << std::endl;
}
