/* -*- 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/core/product_base.hh>
#include <mia/core/cmdlineparser.hh>
#include <mia/core/handler.hh>
#include <mia/core/factory.hh>
#include <mia/core/handler.cxx>
#include <mia/core/plugin_base.cxx>


using namespace std;
NS_MIA_BEGIN

class CProductMock : public CProductBase
{
public:
       typedef CProductMock plugin_type;
       typedef CProductMock plugin_data;

       static const char *data_descr;
       static const char *type_descr;
       CProductMock(const char *s): m_value(s)
       {
       };
private:
       string m_value;
};

const char *CProductMock::type_descr = "mock";
const char *CProductMock::data_descr = "product";

class CFactoryMock: public TFactory<CProductMock>
{
public:
       CFactoryMock(): TFactory<CProductMock>("lala") {}

       typedef shared_ptr<CProductMock> ProductPtr;

       CProductMock *do_create() const
       {
              return new CProductMock("teststring");
       }
       const std::string do_get_descr() const
       {
              return "test mock";
       }
};

class CFactoryMockPluginHandler : public TFactoryPluginHandler<CFactoryMock>
{
public:
       CFactoryMockPluginHandler()
       {
              auto is_added = add_plugin(TFactoryPluginHandler<CFactoryMock>::PInterface(new CFactoryMock()));
              assert(is_added);
       }
};

template<> const  char *const
TPluginHandler<CFactoryMock>::m_help = "just a mock";

typedef THandlerSingleton<CFactoryMockPluginHandler> CFactoryHandlerMock;

FACTORY_TRAIT(CFactoryHandlerMock);

BOOST_AUTO_TEST_CASE( test_a_factory_option )
{
       CFactoryHandlerMock::ProductPtr product;
       PCmdOption option = make_opt(product, "lola", "lala", 'l', "Some help");
       option->set_value("lala");
       option->post_set();
       BOOST_REQUIRE(product);
       BOOST_CHECK_EQUAL(product->get_init_string(), "lala");
       //option->set_value(NULL);
       //	BOOST_CHECK(!product);
       BOOST_CHECK_EQUAL(option->get_value_as_string(), "lala");
}

const SProgramDescription general_help = {
       {pdi_group, "Test"},
       {pdi_short, "Test factory option"},
       {pdi_description, "This program tests the command line parser."}
};


BOOST_AUTO_TEST_CASE( test_a2_factory_option )
{
       CFactoryHandlerMock::ProductPtr product;
       PCmdOption option = make_opt(product, "lala", "lila", 'l', "Some help");
       CCmdOptionList olist(general_help);
       olist.add(option);
       vector<const char *> cmdline(1);
       cmdline[0] = "testprogram";
       BOOST_CHECK_EQUAL(olist.parse(cmdline.size(), &cmdline[0]), CCmdOptionList::hr_no);
       BOOST_REQUIRE(product);
       BOOST_CHECK_EQUAL(product->get_init_string(), "lala");
       //option->set_value(NULL);
       //	BOOST_CHECK(!product);
       BOOST_CHECK_EQUAL(option->get_value_as_string(), "lala");
}

BOOST_AUTO_TEST_CASE( test_string_factory_hint_check_valide)
{
       string value;
       PCmdOption popt(make_opt(value, "string", 's', "a string option",
                                CCmdOptionFlags::validate, &CFactoryHandlerMock::instance() ));
       BOOST_CHECK_NO_THROW(popt->set_value("lala:stuff=no"));
}

BOOST_AUTO_TEST_CASE( test_string_factory_hint_check_fail)
{
       string value;
       PCmdOption popt(make_opt(value, "string", 's', "a string option",
                                CCmdOptionFlags::validate, &CFactoryHandlerMock::instance() ));
       BOOST_CHECK_THROW(popt->set_value("lalo:stuff=no"), invalid_argument);
}


BOOST_AUTO_TEST_CASE( test_a2_factory_option_unique )
{
       CFactoryHandlerMock::UniqueProduct product;
       PCmdOption option = make_opt(product, "lala", "lila", 'l', "Some help");
       CCmdOptionList olist(general_help);
       olist.add(option);
       vector<const char *> cmdline(1);
       cmdline[0] = "testprogram";
       BOOST_CHECK_EQUAL(olist.parse(cmdline.size(), &cmdline[0]), CCmdOptionList::hr_no);
       BOOST_REQUIRE(product);
       BOOST_CHECK_EQUAL(product->get_init_string(), "lala");
       //option->set_value(NULL);
       //	BOOST_CHECK(!product);
       BOOST_CHECK_EQUAL(option->get_value_as_string(), "lala");
}


BOOST_AUTO_TEST_CASE( test_another_factory_option )
{
       auto product = 	CFactoryHandlerMock::instance().produce("lala");
       BOOST_CHECK_EQUAL(product->get_init_string(), "lala");
       PCmdOption option = make_opt(product, "lola", "lala", 'l', "Some help");
       BOOST_CHECK_EQUAL(option->get_value_as_string(), "lala");
}

NS_MIA_END
