
// Copyright 2019 Shlomi Steinberg
// 

#pragma once

#include <array>
#include <cstddef>
#include <algorithm>

#include "glm.hpp"

template <typename T, size_t S>
class spectrum {
	using storage_t = std::array<T, S>;

	storage_t s;

public:
	constexpr spectrum() noexcept : spectrum(T(0)) {};
	constexpr spectrum(T v) noexcept { for (auto &sv : s) sv = v; };
	spectrum(const spectrum &) = default;
	spectrum(spectrum &&) noexcept = default;
	spectrum &operator=(const spectrum &) = default;
	spectrum &operator=(spectrum &&) noexcept = default;

	constexpr auto begin() noexcept { return s.begin(); }
	constexpr auto begin() const noexcept { return s.begin(); }
	constexpr auto cbegin() const noexcept { return s.cbegin(); }
	constexpr auto rbegin() noexcept { return s.rbegin(); }
	constexpr auto rbegin() const noexcept { return s.rbegin(); }
	constexpr auto end() noexcept { return s.end(); }
	constexpr auto end() const noexcept { return s.end(); }
	constexpr auto cend() const noexcept { return s.cend(); }
	constexpr auto rend() noexcept { return s.rend(); }
	constexpr auto rend() const noexcept { return s.rend(); }

	auto& operator[](size_t idx) noexcept { return s[idx]; }
	auto& operator[](size_t idx) const noexcept { return s[idx]; }

	const auto size() const noexcept { return S; }
};

template <typename T, size_t S>
spectrum<T,S>& operator+=(spectrum<T,S> &lhs, const spectrum<T,S> &rhs) noexcept { for (size_t s=0;s<S;++s) lhs[s]+=rhs[s]; return lhs; }
template <typename T, size_t S>
spectrum<T,S>& operator-=(spectrum<T,S> &lhs, const spectrum<T,S> &rhs) noexcept { for (size_t s=0;s<S;++s) lhs[s]-=rhs[s]; return lhs; }
template <typename T, size_t S>
spectrum<T,S> operator+(const spectrum<T,S> &lhs, const spectrum<T,S> &rhs) noexcept { spectrum<T,S> out = lhs; for (size_t s=0;s<S;++s) out[s]=lhs[s]+rhs[s]; return out; }
template <typename T, size_t S>
spectrum<T,S> operator-(const spectrum<T,S> &lhs, const spectrum<T,S> &rhs) noexcept { spectrum<T,S> out = lhs; for (size_t s=0;s<S;++s) out[s]=lhs[s]+rhs[s]; return out; }

template <typename T, size_t S>
spectrum<T,S>& operator*=(spectrum<T,S> &lhs, T rhs) noexcept { for (size_t s=0;s<S;++s) lhs[s]*=rhs; return lhs; }
template <typename T, size_t S>
spectrum<T,S>& operator/=(spectrum<T,S> &lhs, T rhs) noexcept { for (size_t s=0;s<S;++s) lhs[s]/=rhs; return lhs; }
template <typename T, size_t S>
spectrum<T,S> operator*(const spectrum<T,S> &lhs, T rhs) noexcept { spectrum<T,S> out = lhs; std::for_each(out.begin(), out.end(), [&](auto &l){ l*=rhs; }); return out; }
template <typename T, size_t S>
spectrum<T,S> operator*(T lhs, const spectrum<T,S> &rhs) noexcept { spectrum<T,S> out = rhs; std::for_each(out.begin(), out.end(), [&](auto &l){ l*=lhs; }); return out; }
template <typename T, size_t S>
spectrum<T,S> operator/(const spectrum<T,S> &lhs, T rhs) noexcept { spectrum<T,S> out = lhs; std::for_each(out.begin(), out.end(), [&](auto &l){ l/=rhs; }); return out; }
