/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2017 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU Lesser General Public License as published by    *
* the Free Software Foundation; either version 2.1 of the License, or (at     *
* your option) any later version.                                             *
*                                                                             *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
* for more details.                                                           *
*                                                                             *
* You should have received a copy of the GNU Lesser General Public License    *
* along with this program. If not, see <http://www.gnu.org/licenses/>.        *
*******************************************************************************
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#ifndef LINEARSUBSPACE_Hexa2TetraEngine_H
#define LINEARSUBSPACE_Hexa2TetraEngine_H


#include "LinearSubspace/config.h"

#include <sofa/helper/rmath.h>
#include <sofa/helper/OptionsGroup.h>
#include <sofa/core/DataEngine.h>

#include <image/ImageTypes.h>


#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <iostream>
#include <fstream>
#include <limits>



#define LINEARSUBSPACE_Hexa2TetraEngine_EPSILON (1e-5)
#define LINEARSUBSPACE_Hexa2TetraEngine_TERMINAL_DISPLAY    false

#if LINEARSUBSPACE_Hexa2TetraEngine_TERMINAL_DISPLAY
  #define OUT   std::cout
  #define ENDL  std::endl
#else
  #define OUT   sout
  #define ENDL  sendl
#endif


namespace sofa
{
namespace component
{
namespace engine
{

class SOFA_LinearSubspace_API Hexa2TetraEngine : public core::DataEngine
{

public:
    typedef core::DataEngine Inherited;
    SOFA_CLASS(Hexa2TetraEngine, Inherited);

    typedef unsigned int Ref;
    typedef sofa::helper::fixed_array<Ref,8> Hexa;
    typedef sofa::helper::fixed_array<Ref,4> Tetra;

    typedef helper::vector<Hexa> VecHexa;
    typedef helper::vector<Tetra> VecTetra;

    /// Input
    Data<VecHexa> d_hexaIndex;

    /// Output
    Data<VecTetra> d_tetraIndex;

    virtual void init()
    {
        addInput(&d_hexaIndex);

        addOutput(&d_tetraIndex);

        setDirtyValue();
    }

    virtual void reinit()
    {
        setDirtyValue();
    }

    void update()
    {

        helper::ReadAccessor< Data<VecHexa>> hexaIndex_accessor(d_hexaIndex);
        const VecHexa& hexaIndex = hexaIndex_accessor.ref();

        helper::WriteAccessor< Data<VecTetra>> tetraIndex_accessor(d_tetraIndex);
        VecTetra& tetraIndex = tetraIndex_accessor.wref();

        tetraIndex.resize(6*hexaIndex.size());

        helper::fixed_array<Ref, 6> sequence = {1, 5, 4, 7, 3, 2};

        for(uint i=0; i<hexaIndex.size(); ++i)
        {
            for(uint j=0; j<6; ++j)
            {
//                tetraIndex[i*6+j][0] = hexaIndex[i][0];
//                tetraIndex[i*6+j][1] = hexaIndex[i][7];
//                tetraIndex[i*6+j][2] = hexaIndex[i][j+1];
//                tetraIndex[i*6+j][3] = hexaIndex[i][(j+1)%6+1];

                tetraIndex[i*6+j][0] = hexaIndex[i][0];
                tetraIndex[i*6+j][1] = hexaIndex[i][6];
                tetraIndex[i*6+j][2] = hexaIndex[i][sequence[j]];
                tetraIndex[i*6+j][3] = hexaIndex[i][sequence[(j+1)%6]];
            }
        }

        OUT << "Generated " << tetraIndex.size() << " tetrahedra from " << hexaIndex.size() << " hexahedra." << ENDL;

        cleanDirty();
    }

protected:
    Hexa2TetraEngine() : Inherited()
      , d_hexaIndex(initData(&d_hexaIndex, VecHexa(), "hexaIndex", ""))
      , d_tetraIndex(initData(&d_tetraIndex, VecTetra(), "tetraIndex", ""))
    {

    }

    ~Hexa2TetraEngine()
    {

    }

};




}
}
}


#endif
