#pragma once

#include "gp_config.hpp"

#include "gp/algorithms/repeat.hpp"

namespace gp {
	template<typename T>
	T lerp(T input, T low, T high) {
		return low + (high - low) * input;
	}
	template<typename T>
	T lextrap(T input, T low, T high) {
		return (input - low) / (high - low);
	}

	template<typename T, size_t fixed_passes = 16>
	T fixed_sqrt(T value) {
		gp_config::assertion(value >= 0, "trying to compute square root of negative number");
		if(value == 0) return 0;
		T ret = value / 2;
		T tmp;

		gp::repeat(fixed_passes, [&](){
			tmp = ret;
			ret = (value / tmp + tmp) / 2;
		});

		return ret;
	}

	template<typename T, size_t cap_passes = 16>
	T epsilon_sqrt(T value) {
		gp_config::assertion(value >= 0, "trying to compute square root of negative number");
		if(value == 0) return 0;
		T ret = value / 2;
		T tmp;
		constexpr T epsilon = gp_config::rendering::epsilon;
		size_t cnt = 0;
		while(
			!(
				(ret+epsilon)*ret > value
				&& (ret-epsilon)*ret < value
			)
			&& cnt < cap_passes
		){
			tmp = ret;
			ret = (value / tmp + tmp) / 2;
			++cnt;
		};

		return ret;
	}

	template<typename T, size_t cap_passes = 16>
	T stable_sqrt(T value) {
		gp_config::assertion(value >= 0, "trying to compute square root of negative number");
		if(value == 0) return 0;
		T ret = value / 2;
		T tmp;
		while(ret != tmp){
			tmp = ret;
			ret = (value / tmp + tmp) / 2;
		};

		return ret;
	}
}