// Copyright (C) 2016 EDF
// All Rights Reserved
// This code is published under the GNU Lesser General Public License (GNU LGPL)
#ifndef GLOBALREGRESSIONGENERS_H
#define GLOBALREGRESSIONGENERS_H
/* #include "geners/GenericIO.hh" */
#include <geners/AbsReaderWriter.hh>
#include "StOpt/regression/BaseRegressionGeners.h"
#include "StOpt/regression/MultiVariateBasisGeners.h"
#include "StOpt/regression/GlobalRegression.h"
#include "StOpt/core/utils/Polynomials1D.h"

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

// Concrete reader/writer for class GlobalRegression
// Note publication of GlobalRegression as "wrapped_type".
template< class ClassFunc1D>
struct GlobalRegressionGeners: public gs::AbsReaderWriter<StOpt::BaseRegression>
{
    typedef StOpt::BaseRegression wrapped_base;
    typedef StOpt::GlobalRegression<ClassFunc1D > wrapped_type;

    // Methods that have to be overridden from the base
    bool write(std::ostream &p_of, const wrapped_base &p_base, bool p_dumpId) const override
    {
        // If necessary, write out the class id
        const bool status = p_dumpId ? wrappedClassId().write(p_of) : true;
        // Write the object data out
        if (status)
        {
            const wrapped_type  &w = dynamic_cast<const wrapped_type &>(p_base);
            gs::write_item(p_of, w.getBZeroDate());
            gs::write_item(p_of, w.getBasis());
            gs::write_item(p_of, w.getMeanX());
            gs::write_item(p_of, w.getEtypX());
            gs::write_item(p_of, w.getSvdMatrix());
            gs::write_pod(p_of, w.getBRotationAndRescale());
        }
        // Return "true" on success
        return status && !p_of.fail();
    }
    wrapped_type *read(const gs::ClassId &p_id, std::istream &p_in) const override
    {
        // Validate the class id. You might want to implement
        // class versioning here.
        wrappedClassId().ensureSameId(p_id);
        std::unique_ptr<bool> bZeroDate = gs::read_item<bool>(p_in);
        std::unique_ptr<StOpt::MultiVariateBasis<ClassFunc1D> > basis = gs::read_item< StOpt::MultiVariateBasis<ClassFunc1D> >(p_in);
        std::unique_ptr< Eigen::ArrayXd> meanX = gs::read_item<  Eigen::ArrayXd>(p_in);
        std::unique_ptr< Eigen::ArrayXd> etypX = gs::read_item<  Eigen::ArrayXd>(p_in);
        std::unique_ptr< Eigen::MatrixXd> svdMatrix = gs::read_item<  Eigen::MatrixXd>(p_in);
        bool bRotationAndRescale = false;
        gs::read_pod(p_in, &bRotationAndRescale);
        // Check that the stream is in a valid state
        if (p_in.fail()) throw gs::IOReadFailure("In BIO::read: input stream failure");
        return new wrapped_type(*bZeroDate, *basis, *meanX, *etypX, *svdMatrix, &bRotationAndRescale);
    }

    // The class id for GlobalRegression  will be needed both in the "read" and "write"
    // methods. Because of this, we will just return it from one static
    // function.
    static const gs::ClassId &wrappedClassId()
    {
        static const gs::ClassId wrapId(gs::ClassId::makeId<wrapped_type>());
        return wrapId;
    }
};

gs_specialize_class_id(StOpt::GlobalRegression< StOpt::Hermite>, 1)
gs_declare_type_external(StOpt::GlobalRegression< StOpt::Hermite>)
gs_associate_serialization_factory(StOpt::GlobalRegression< StOpt::Hermite>, StaticSerializationFactoryForBaseRegression)
gs_specialize_class_id(StOpt::GlobalRegression< StOpt::Canonical>, 1)
gs_declare_type_external(StOpt::GlobalRegression< StOpt::Canonical>)
gs_associate_serialization_factory(StOpt::GlobalRegression< StOpt::Canonical>, StaticSerializationFactoryForBaseRegression)
gs_specialize_class_id(StOpt::GlobalRegression< StOpt::Tchebychev>, 1)
gs_declare_type_external(StOpt::GlobalRegression< StOpt::Tchebychev>)
gs_associate_serialization_factory(StOpt::GlobalRegression< StOpt::Tchebychev>, StaticSerializationFactoryForBaseRegression)


#endif /*  GLOBALREGRESSIONGENERS */

