#ifndef ME_PROXYPACK_HH_
#define ME_PROXYPACK_HH_

#include "geners/tupleIO.hh"

namespace gs {
    //
    // The class ClassIdComparator must provide a static function
    // "bool compatible(const ClassId& idOnFile, const ClassId& idProxyPack);"
    //
    template<class ClassIdComparator, typename... Args>
    class ProxyPack : public std::tuple<Args...>
    {
    public:
        typedef std::tuple<Args...> Base;

        ProxyPack() : firstRead_(true) {}

        inline explicit ProxyPack(const Args&... args) :
            std::tuple<Args...>(args...), firstRead_(true) {}

        inline ClassId classId() const {return ClassId(*this);}
        static inline const char* classname()
        {
            static std::string name;
            if (name.size() == 0)
            {
                std::ostringstream os;
                os << "gs::ProxyPack<";
                Private::TupleClassIdCycler<
                    Base, std::tuple_size<Base>::value>::collectClassIds(os);
                os << '>';
                name = os.str();
            }
            return name.c_str();
        }
        static inline unsigned version() {return 1;}

        inline bool write(std::ostream& of) const
        {
            return write_item(of, *(static_cast<const Base*>(this)), false);
        }

        static inline bool restore(const ClassId& id, std::istream& is,
                                   ProxyPack* pack)
        {
            // Checking ClassId every time would take too long...
            assert(pack);
            if (pack->firstRead_)
            {
                assert(ClassIdComparator::compatible(id, pack->classId()));
                pack->firstRead_ = false;
                pack->iostack_.reserve(1);
                pack->iostack_.push_back(id);
            }
            return GenericReader<std::istream, std::vector<ClassId>, Base,
                Int2Type<IOTraits<int>::ISTUPLE> >::process(
                    *(static_cast<Base*>(pack)), is, &pack->iostack_, false);
        }

    private:
        bool firstRead_;
        std::vector<ClassId> iostack_;
    };


    // Functions to simplify creation of proxy packs
    template<typename... Args>
    inline ProxyPack<SameClassName, Args...> make_proxy_pack(Args&&... args)
    {
        return ProxyPack<SameClassName, Args...>(args...);
    }
}

#endif // ME_PROXYPACK_HH_
