#ifndef INTERPOLATOR_H
#define INTERPOLATOR_H

#include <vector>
#include <algorithm>


namespace K {

	/**
	 * this class allows adding values with some sort of key.
	 * hereafter it is possible to interpolate between two values
	 * using a provided key.
	 */
	template <typename Key, typename Value> class Interpolator {

		/** combine key and value within one struct */
		struct KeyedEntry {
			Key key;
			Value val;
			KeyedEntry(const Key key, const Value& val) : key(key), val(val) {;}
		};

	public:

		/** all entries within the interpolator */
		std::vector<KeyedEntry> values;

	public:

		/** add a new timed entry */
		void add(const Key key, const Value& val) {
			values.push_back(KeyedEntry(key, val));
		}

		/** get the interpolated value for the given key */
		Value get(const Key key) const {
			auto comp = [] (const Key& key, const KeyedEntry& e) {return key < e.key;};
			auto it = std::upper_bound(values.begin(), values.end(), key, comp);		// first element > key
			const KeyedEntry eH = *it;								// greater than key
			const KeyedEntry eL = *(--it);							// smaller than key
			const Key diff = eH.key - eL.key;						// distance between upper and lower bound
			const float vL = float(eH.key - key) / float(diff);		// influence factor for the smaller one
			const float vH = float(key - eL.key) / float(diff);		// influence factor for the larger one
			return (eH.val * vH) + (eL.val * vL);					// interpolate
		}

		/** ensure the first key starts at 0 */
		void makeRelative() {
			const Key firstKey = values[0].key;
			for (KeyedEntry& e : values) {e.key -= firstKey;}
		}

	};

}

#endif // INTERPOLATOR_H
