#include "tap.hpp"

#include "tuple/type.hpp"

#include <typeindex>

template <typename T>
struct int_mapper
{
    typedef int type;
};


int
main (void)
{
    cruft::TAP::logger tap;

    {
        using tuple_t = std::tuple<float,int,void>;
        tap.expect_eq (cruft::tuple::type::index<tuple_t,int>::value, 1u, "tuple index extraction");
    }

    {
        using tuple_t = std::tuple<float,int,void>;
        tap.expect (
            std::is_same_v<
                cruft::tuple::type::nth_t<tuple_t,1>,
                int
            >,
            "tuple type indexing with 'nth'"
        );
    }

    {
#if !defined(NO_RTTI)
        auto tuple = std::make_tuple (1u, 1, 1.f, 1.);
        std::vector<std::type_index> expected {
            std::type_index (typeid (1u)),
            std::type_index (typeid (1)),
            std::type_index (typeid (1.f)),
            std::type_index (typeid (1.))
        };

        std::vector<std::type_index> actual;
        cruft::tuple::type::each<decltype(tuple)> ([&actual] (auto i) {
            actual.push_back (typeid (typename decltype(i)::type));
        });

        tap.expect_eq (actual, expected, "type iteration");
#else
        tap.skip ("type iteration because no-rtti");
#endif
    }

    {
        using pair_t = std::pair<int,float>;
        using tuple_t = std::tuple<int,float>;

        tap.expect (std::is_same_v<cruft::tuple::type::entuple_t<pair_t>, tuple_t>, "entuple a pair");
    }

    {
        using a = std::pair<int,float>;
        using b = std::tuple<char>;
        using c = std::tuple<int,float,char>;

        tap.expect (std::is_same_v<
            cruft::tuple::type::cat_t<a,b>, c
        >, "concatenate pair and tuple");
    }


    {
        using original_t = std::tuple<int,char,float,int,double,int>;
        using removed_t = std::tuple<char,float,double>;

        tap.expect (std::is_same_v<
            cruft::tuple::type::remove_t<int,original_t>,
            removed_t
        >, "removed int from tuple");
    }

    {
        using original_t = std::tuple<int,float,float,char,double,char>;
        using unique_t = std::tuple<int,float,char,double>;

        tap.expect (std::is_same_v<
            cruft::tuple::type::unique_t<original_t>,
            unique_t
        >, "removed duplicates from tuple");
    }

    {

        using src_t = std::tuple<std::string>;
        using dst_t = typename cruft::tuple::type::map<src_t, int_mapper>::type;

        tap.expect (std::is_same<dst_t, std::tuple<int>>::value, "tuple type mapping");
    }

    return tap.status ();
}