/* -*- 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/core/export_handler.hh>


#include <mia/core/plugin_base.hh>
#include <mia/core/handler.hh>

#include <mia/core/plugin_base.cxx>
#include <mia/core/handler.cxx>

#include <mia/3d/2dimagefifofilter.hh>
#include <mia/core/fifofilter.cxx>

NS_MIA_BEGIN

const char *image2d_stack::data_descr = "2dstack";

C2DImageFifoFilter::C2DImageFifoFilter(size_t fill, size_t min_fill, size_t read_start):
       TFifoFilter<P2DImage>(fill, min_fill, read_start)
{
}

C3DImage *C2DImageFifoFilter::create_buffer(const C2DBounds& slice_sice, size_t depth, EPixelType type)
{
       const C3DBounds size(slice_sice.x, slice_sice.y, depth);

       switch (type) {
       case it_bit:
              return new T3DImage<bool>(size);

       case it_sbyte:
              return new T3DImage<signed char>(size);

       case it_ubyte:
              return new T3DImage<unsigned char>(size);

       case it_sshort:
              return new T3DImage<signed short>(size);

       case it_ushort:
              return new T3DImage<unsigned short>(size);

       case it_sint:
              return new T3DImage<signed int>(size);

       case it_uint:
              return new T3DImage<unsigned int>(size);
#ifdef HAVE_INT64

       case it_slong:
              return new T3DImage<signed long>(size);

       case it_ulong:
              return new T3DImage<unsigned long>(size);
#endif

       case it_float:
              return new T3DImage<float>(size);

       case it_double:
              return new T3DImage<double>(size);

       default:
              assert("unkown image type requested");
              return NULL;
       }
}

typedef TFifoFilterSink<P2DImage> C2DImageFifoFilterSink;
template class TFifoFilterSink<P2DImage>;

C2DFifoFilterPlugin::C2DFifoFilterPlugin(char const *const  name):
       TFactory<C2DImageFifoFilter>(name)
{
}

bool C2DFifoFilterPlugin::call_test(const CImageStack& in_data, const CImageStack& test_data,
                                    C2DImageFifoFilter& filter) const
{
       TRACE("C2DFifoFilterPlugin::call_test");
       C2DImageFifoFilterSink::Pointer sink(new C2DImageFifoFilterSink());
       filter.append_filter(sink);

       for (CImageStack::const_iterator i = in_data.begin();
            i != in_data.end(); ++i)
              filter.push(*i);

       filter.finalize();
       C2DImageFifoFilterSink::result_type r = sink->result();

       if (r.size() != test_data.size()) {
              cvfail() << "Expected " << test_data.size()  << " slices, got " << r.size() << "\n";
              return false;
       }

       bool result = true;

       for (size_t i = 0; i < r.size(); ++i) {
              if (r[i]->get_pixel_type() != test_data[i]->get_pixel_type()) {
                     cvfail() << "Pixel type\n";
                     return false;
              }

              if (r[i]->get_size() != test_data[i]->get_size()) {
                     cvfail() << "Size\n";
                     return false;
              }

              if (*r[i] != *test_data[i]) {
                     cvfail() << "Data\n";
                     cvdebug() << "Failed slice: " << i << "\n";
                     CImageComparePrinter printer;
                     mia::filter(printer, *r[i], *test_data[i]);
                     result = false;
              }
       }

       return result;
}


template <> const char   *const
TPluginHandler<C2DFifoFilterPlugin>::m_help =
       "These filters work on a stack of 2D images in a 3D manner by interpreting the images of the stack "
       "as slices of a 3D image. For spacial filters with a fixed filter width that is small compared to "
       "the number of slices the filter is applied in a true 3D manner. "
       "For other filters, that would normally require to work on the whole image domain at once, the "
       "image filter is only applied to a subset of the images at a time which results in a quasi-3D processing "
       " that may require additional post-processing.";


template class TPlugin<image2d_stack, filter_type>;
template class TFifoFilter<P2DImage>;
template class TFactory<C2DImageFifoFilter>;
template class TFactoryPluginHandler<C2DFifoFilterPlugin>;
//template class TPluginHandler<TFactory<C2DImageFifoFilter, image2d_stack, filter_type> >;
template class TPluginHandler<C2DFifoFilterPlugin>;
template class THandlerSingleton<TFactoryPluginHandler<C2DFifoFilterPlugin>>;

NS_MIA_END
