// Copyright (C) 2016 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#ifndef MULTIVARIATEBASISGENERS_H
#define MULTIVARIATEBASISGENERS_H
#include "geners/GenericIO.hh"
#include "StOpt/regression/MultiVariateBasis.h"
#include "StOpt/core/utils/eigenGeners.h"


/** \file MultiVariateBasisGeners.h
 *  \brief Define non intrusive serialization with random access
*  \author Xavier Warin
*/

gs_specialize_template_id_T(StOpt::MultiVariateBasis, 1, 0);
gs_declare_template_external_T(StOpt::MultiVariateBasis);

// The most arcane part is to specialize the behavior of the two
// template classes at the heart of the serialization facility:
// gs::GenericWriter and gs::GenericReader.
//
namespace gs
{
template <class Stream, class State, class A>
struct GenericWriter<Stream, State, StOpt::MultiVariateBasis<A>,
           Int2Type<IOTraits<int>::ISEXTERNAL> >
{
    inline static bool process(const StOpt::MultiVariateBasis<A> &p_multi, Stream &os,
                               State *, const bool processClassId)
    {
        // If necessary, serialize the class id
        static const ClassId current(ClassId::makeId<StOpt::MultiVariateBasis<A> >());
        const bool status = processClassId ? current.write(os) : true;

        // Serialize object data if the class id was successfully
        // written out
        if (status)
        {
            write_item(os, p_multi.getNumberOfVariates());
            write_item(os, p_multi.getNumberOfFunctions());
            Eigen::ArrayXXi tensor = p_multi.getTensorFull().array();
            write_item(os, tensor);
            write_item(os, p_multi.getTensorSparse());
            write_item(os, p_multi.getIsReduced());
            write_item(os, p_multi.getCenter());
            write_item(os, p_multi.getScale());
        }

        // Return "true" on success, "false" on failure
        return status && !os.fail();
    }
};

template <class Stream, class State, class A>
struct GenericReader<Stream, State, StOpt::MultiVariateBasis<A>,
           Int2Type<IOTraits<int>::ISEXTERNAL> >
{
    inline static bool readIntoPtr(StOpt::MultiVariateBasis<A> *&ptr, Stream &is,
                                   State *st, const bool processClassId)
    {
        // Make sure that the serialized class id is consistent with
        // the current one
        static const ClassId current(ClassId::makeId<StOpt::MultiVariateBasis<A> >());
        const ClassId &stored = processClassId ? ClassId(is, 1) : st->back();

        // Check that the name is consistent. Do not check for the
        // consistency of the complete id because we want to be able
        // to read different versions of classes A and B.
        current.ensureSameName(stored);

        std::unique_ptr<int> numberOfVariates = read_item<int>(is);
        std::unique_ptr<int> numberOfFunctions = read_item<int>(is);
        typedef   Eigen::Array< int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> rowArrayXi;
        std::unique_ptr<rowArrayXi >  tensorFull = read_item<rowArrayXi>(is);
        std::unique_ptr<StOpt::RowSparseMatrix> tensorSparse = read_item<StOpt::RowSparseMatrix>(is);
        std::unique_ptr<bool> isReduced = read_item<bool>(is);
        std::unique_ptr<Eigen::ArrayXd> center = read_item<Eigen::ArrayXd>(is);
        std::unique_ptr<Eigen::ArrayXd> scale = read_item<Eigen::ArrayXd>(is);
        if (ptr == 0)
            ptr = new StOpt::MultiVariateBasis<A>(*numberOfVariates, *numberOfFunctions, tensorFull->matrix(), *tensorSparse, *isReduced, *center, *scale);
        else
            *ptr = StOpt::MultiVariateBasis<A>(*numberOfVariates, *numberOfFunctions, tensorFull->matrix(), *tensorSparse, *isReduced, *center, *scale);
        return true;
    }

    inline static bool process(StOpt::MultiVariateBasis<A> &s, Stream &is,
                               State *st, const bool processClassId)
    {
        // Simply convert reading by reference into reading by pointer
        StOpt::MultiVariateBasis<A> *ps = &s;
        return readIntoPtr(ps, is, st, processClassId);
    }
};
}

#endif /*  MULTIVARIATEBASISGENERS_H */
