#ifndef EMPATHY_IR_DECOMPOSE_H
#define EMPATHY_IR_DECOMPOSE_H

namespace empathy::ir
{
    template< typename T >
    struct LiteralSpec
    {
        using type = T;

        template< typename TT >
        LiteralSpec( TT&& val ) : m_val( forward< TT >( val ) )
        {}

        T m_val;
    };

    template< typename T >
    auto Lit( T&& val );

    template< typename T >
    struct Val
    {
        using type = T;
    };

    template< typename T >
    struct IsLiteralSpec : public false_type
    {};

    template< typename T >
    struct IsLiteralSpec< LiteralSpec< T > > : public true_type
    {};

    template< typename... T >
    struct VecDecompositionReturnTypeBuilder
    {};

    template< typename... TU >
    struct VecDecompositionReturnTypeBuilder< tuple< TU... > >
    {
        using type = tuple< TU... >;
    };

    template< typename... TU, typename HS, typename... TS >
    struct VecDecompositionReturnTypeBuilder< tuple< TU... >, HS, TS... >
    {
        using type = conditional_t< IsLiteralSpec< HS >::value,
            typename VecDecompositionReturnTypeBuilder< tuple< TU... >, TS... >::type,
            typename VecDecompositionReturnTypeBuilder< tuple< TU..., typename HS::type >, TS... >::type
        >;
    };

    template< typename... S >
    struct VectorSpec
    {
        using type = typename VecDecompositionReturnTypeBuilder< tuple<>, S... >::type;

        template< typename... T >
        VectorSpec( T&&... specs ) :
            m_specs( forward< T >( specs )... )
        {}

        tuple< S... > m_specs;
    };

    template< typename... S >
    auto Vec( S&&... specs );

    template< typename T >
    bool Decompose( const Term& t, const LiteralSpec< T >& spec );

    template< typename T >
    optional< reference_wrapper< const T > > Decompose( const Term& t, const Val< T >& spec );

    template< typename... S >
    optional< typename VectorSpec< S... >::type > Decompose( const Term& t, const VectorSpec< S... >& spec );
}

#endif
