#ifndef __TAB_DATA__H__
#define __TAB_DATA__H__

#include <mutex>
#include <optional>
#include <string>
#include <vector>

#include "tab_data.h"

using namespace std;

/* stores information about the column widths in tab mode */
class TabData {
public:
	TabData() : _countdown(0) {}
	/* observe the width of a column */
	virtual void observe_col(size_t num, size_t width) {
		unique_lock<mutex> ul(_m);
		if (num >= _sizes.size()) {
			_sizes.resize(num + 1);
		}
		auto vals = _sizes[num];
		if (width > vals.first) {
			vals.second = vals.first;
			vals.first = width;
		} else if (width > vals.second) {
			vals.second = width;
		}
		_sizes[num] = vals;
	}

	virtual void maybe_evict() {
		if (_countdown == 0) {
			for (size_t i = 0; i < _sizes.size(); ++i) {
				_sizes[i].first = _sizes[i].second;
				_sizes[i].second = 0;
			}
			_countdown = 5;
		} else {
			--_countdown;
		}
	}

	/* returns the width afforded to column number num */
	virtual size_t width(size_t num) const {
		unique_lock<mutex> ul(_m);
		if (num < _sizes.size()) {
			const auto& vals = _sizes[num];
			// if the longest col is 50% more than the second
			// longest, just use the second longest
			if (vals.second && vals.second * 1.5 < vals.first)
				return vals.second;
			return vals.first;
		}
		return 0;
	}

	virtual void clear() {
		unique_lock<mutex> ul(_m);
		_sizes.clear();
	}

protected:
	// used for random eviction so long cells that aren't reseen go away
	size_t _countdown;
	// column number to the largest and second largest width observed
	vector<pair<size_t, size_t>> _sizes;
	// thread safety
	mutable mutex _m;
};

#endif  // __TAB_DATA__H__
