/* -*- 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/>.
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string>
#include <sstream>
#include <stdexcept>
#include <cassert>

#include <mia/core/file.hh>
#include <mia/core/filter.hh>
#include <mia/core/errormacro.hh>
#include <mia/core/msgstream.hh>
#include <mia/2d/imageio.hh>

NS_BEGIN(IMAGEIO_2D_RAW)

NS_MIA_USE
using namespace std;
using namespace boost;



class CRaw2DImageIO: public C2DImageIOPlugin {
public:
	CRaw2DImageIO();

	friend struct C2DRawImageSaver;

private:
	PData do_load(const string& fname) const;
	bool do_save(const string& fname, const Data& data) const;
	const string do_get_descr() const;
};

CRaw2DImageIO::CRaw2DImageIO():
	C2DImageIOPlugin("raw")
{
	add_supported_type(it_float);
	add_supported_type(it_double);
	add_supported_type(it_sint);
	add_supported_type(it_uint);
	add_supported_type(it_sshort);
	add_supported_type(it_ushort);
	add_supported_type(it_sbyte);
	add_supported_type(it_ubyte);
	add_supported_type(it_bit);

	add_suffix(".raw");
	add_suffix(".RAW");

}

CRaw2DImageIO::PData CRaw2DImageIO::do_load(string const& /*filename*/)const
{
	cvwarn() << "CRaw2DImageIO::do_load:  raw image reading currently not supported\n";
	return CRaw2DImageIO::PData();
}

struct C2DRawImageSaver {
	typedef bool result_type;

	C2DRawImageSaver(CFile& f):
		m_f(f)
	{
	}

	template <typename T>
	result_type operator()(const T2DImage<T>& image) const;
private:
	CFile& m_f;
};


template <typename T>
struct T2DRawImageWriter
{
	static bool apply (const T2DImage<T>& image, FILE *f) {
		return image.size() == fwrite(&image(0,0),sizeof(T), image.size(),  f);
	}
};

template <>
struct T2DRawImageWriter<bool>  {
	static bool apply (const C2DBitImage& image, FILE *f) {
		vector<char> buf(image.size(), 0);
		copy(image.begin(), image.end(), buf.begin());
		return buf.size() == fwrite(&buf[0],1, image.size(),  f);
	}
};


template <typename T>
C2DRawImageSaver::result_type
C2DRawImageSaver::operator()(const T2DImage<T>& image) const
{
	return T2DRawImageWriter<T>::apply(image, m_f);
}

///

bool CRaw2DImageIO::do_save(string const& filename, const C2DImageVector& data) const
{
	cvdebug() << "CRaw2DImageIO::save begin\n";

	COutputFile f(filename);
	if (!f) {
		cverr() << "CRaw2DImageIO::save:unable to open output file:" << filename << "\n";
		return false;
	}

	C2DRawImageSaver saver(f);

	for (C2DImageVector::const_iterator iimg = data.begin(); iimg != data.end(); ++iimg)
		filter(saver, **iimg);

	cvdebug() << "CRaw2DImageIO::save end\n";
	return true;
}

const string  CRaw2DImageIO::do_get_descr()const
{
	return string("RAW 2D-image output support");
}


extern "C" EXPORT CPluginBase *get_plugin_interface()
{
		return new CRaw2DImageIO;
}


NS_END
