/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <mia/internal/autotest.hh>
#include <mia/2d/timestep/fluid.hh>
#include <mia/2d/transformmock.hh>

NS_USE(fluid_timestep_2d);
NS_MIA_USE;

class C2DDummyTransformation: public C2DTransformMock
{
       virtual C2DTransformation *clone() const
       {
              return new C2DDummyTransformation();
       }
       virtual bool save(const std::string& /*filename*/, const std::string& /*type*/) const
       {
              return false;
       }

       virtual P2DTransformation upscale(const C2DBounds& /*size*/) const
       {
              return P2DTransformation(new C2DDummyTransformation());
       }
       virtual void add(const C2DTransformation& /*a*/)
       {
       }

       virtual void update(float /*step*/, const C2DFVectorfield& /*a*/)
       {
       }
       virtual size_t degrees_of_freedom() const
       {
              return 0;
       }
       virtual void set_identity()
       {
       }
       virtual C2DFMatrix derivative_at(int /*x*/, int /*y*/) const
       {
              return C2DFMatrix(C2DFVector(1, 0), C2DFVector(0, 1));
       }
       virtual float get_max_transform() const
       {
              return 0.0f;
       }
       virtual const C2DBounds& get_size() const
       {
              static C2DBounds s(0, 0);
              return s;
       }
       virtual float pertuberate(C2DFVectorfield& v) const
       {
              C2DFVector v12(1, 2);
              transform(v.begin(), v.end(), v.begin(), [&v12](const C2DFVector & v) {
                     return v + C2DFVector(1, 2);
              });
              return v(0, 0).norm();
       }
       virtual C2DFVector apply(const C2DFVector& x) const
       {
              return x;
       }
       virtual C2DFVector operator () (const C2DFVector& x) const
       {
              return x;
       }
       virtual float get_jacobian(const C2DFVectorfield& v, float delta) const
       {
              return  v(0, 0).norm() / delta;
       }
       P2DImage apply(const C2DImage& image, const C2DInterpolatorFactory& /*ipf*/) const
       {
              return P2DImage(image.clone());
       }

       float divergence() const
       {
              return 0.0;
       }
       float curl() const
       {
              return 0.0;
       }

};

struct TimestepFixture {
       TimestepFixture();

       C2DBounds size;
       C2DFluidRegTimeStep plugin;
       C2DFVectorfield infield;
       C2DFVectorfield outfield;
};

TimestepFixture::TimestepFixture():
       size(1, 1),
       plugin(0.5f, 1.5f),
       infield(size),
       outfield(size)
{
       infield(0, 0) = C2DFVector(2.0, 2.0);
       outfield(0, 0) =  C2DFVector(1.0, 0.0);
}

BOOST_FIXTURE_TEST_CASE( fluid_timestep_2d_calculate_pertuberation, TimestepFixture )
{
       C2DDummyTransformation dummy;
       BOOST_CHECK_EQUAL(plugin.calculate_pertuberation(infield, dummy), 5.0f);
       BOOST_CHECK_EQUAL(infield(0, 0), C2DFVector(3.0, 4.0));
}


BOOST_FIXTURE_TEST_CASE( fluid_timestep_2d_regrid, TimestepFixture )
{
       C2DDummyTransformation dummy;
       BOOST_CHECK(plugin.has_regrid());
       BOOST_CHECK(!plugin.regrid_requested(dummy, infield, 3.0));
       BOOST_CHECK(plugin.regrid_requested(dummy, infield, 12.0));
       BOOST_CHECK(plugin.regrid_requested(dummy, outfield, 3.0));
}
