#include <iostream>

using namespace std;

#include "metastack.hpp"
#include "metastr.hpp"

//the try out
//for loop a certain amount
//push number in that loop
//then pop them all
//all in meta



template <typename IT>
struct PRINT{
    typedef STACK<int> ST;
    static inline void EXEC()
    {
        cout << ST::EXEC<IT>() << endl;
    }
};

template <typename IT>
struct PRINT2{
    static inline void EXEC()
    {
        for (int i=0;i<IT::SIZE();i++)
            cout << IT::PEEK(i);
        cout << endl;
    }
};

//functor
template <int n>
struct functor{
    static inline int EXEC()
    {
        return n;
    }
};

template <template <int> class E>
struct callback{
    static inline int EXEC()
    {
        return E<0>::EXEC();
    }
};

//if

template <int N>
struct IF{
    static inline int EXEC()
    {
    }
};

template <>
struct IF<0>{
    static inline int EXEC()
    {
    }
};

//IDEA

//subclass with template
template <int A>
struct ADD{
    template <int B>
    struct WITH{
        static inline int EXEC()
        {
            return A+B;
        }
    };
};

//vector

template <typename T>
struct VECTOR2D{

    template <T _X, T _Y>
    struct VECTOR{
        static inline T X()
        {
            return _X;
        }
        static inline T Y()
        {
            return _Y;
        }
    };
    
    template <typename A, typename B>
    struct ADD{
        static inline T X()
        {
            return A::X() + B::X();
        }
        static inline T Y()
        {
            return A::Y() + B::Y();
        }
    };
    
    template <typename A, typename B>
    struct SUB{
        static inline T X()
        {
            return A::X() + B::X();
        }
        static inline T Y()
        {
            return A::Y() + B::Y();
        }
    };

    template <typename A, T B>
    struct SCALE{
        static inline T X()
        {
            return A::X() + B;
        }
        static inline T Y()
        {
            return A::Y() + B;
        }
    };
};


//test
extern const char hello[] = "hello world";
extern const char add[] = "the";

int main()
{
    typedef STACK<int> ST;
    typedef ST::PUSH<10,NIL> un;
    PRINT<un>::EXEC();
    typedef ST::PUSH<5,un> deux;
    PRINT<deux>::EXEC();
    typedef ST::PUSH<3,deux> trois;
    PRINT<trois>::EXEC();
    typedef ST::POP<trois> quatre;
    PRINT<quatre>::EXEC();
    typedef ST::PUSH<6, quatre> cinq;
    PRINT<cinq>::EXEC();
    typedef ST::POP<cinq> six;
    PRINT<six>::EXEC();
    typedef ST::POP<six> sept;
    PRINT<sept>::EXEC();

    typedef STRING::STR<hello,11> one;
    PRINT2<one>::EXEC();
    typedef STRING::SUB<one,0,5> two;
    PRINT2<two>::EXEC();
    typedef STRING::SUB<one,5,11> three;
    PRINT2<three>::EXEC();
    typedef STRING::STR<add,3> the;
    typedef STRING::INSERT<one,6,6,the> four;
    PRINT2<four>::EXEC();
    typedef STRING::INSERT<two,6,6,the> five;
    PRINT2<five>::EXEC();
    typedef STRING::INSERT<five,9,9,three> sixe;
    PRINT2<sixe>::EXEC();


    
    char array[sixe::SIZE()];
    STRING::REDUCE<sixe>(array);
    cout << array << endl;

    return 0;
}
