// Copyright (C) 2018  INRIA
//
// Treerecs is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// Treerecs 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#include <gtest/gtest.h>

#include <string>

#include <treerecs/tools/SupportTools.h>
#include <TreerecsCliUtils.h>
#include <TreerecsParameters.h>

using namespace treerecs;

using std::string;

class SupportTools_test: public testing::Test {
 protected:
  virtual void SetUp() {}

  virtual void TearDown() {}
};

class TreerecsParameters_ : public TreerecsParameters {
 public:
  TreerecsParameters_() = default;
};

TEST_F(SupportTools_test, ConvertThresholdInputsToDoubles_simple) {
  std::unique_ptr<TreerecsParameters> params(new TreerecsParameters_());
  params->thresholds_inputs.push_back("68.2");
  std::vector<double> sorted_supports {25.0, 50.0, 68.1, 68.2, 68.3, 95.0};

  auto thresholds = ConvertThresholdInputsToDoubles(params, sorted_supports);
  decltype(thresholds) expected_thresholds {68.2};

  EXPECT_EQ(thresholds, expected_thresholds);
  EXPECT_EQ(params->strict_support_thresholds, true);
}

TEST_F(SupportTools_test, ConvertThresholdInputsToDoubles_multiple) {
  std::unique_ptr<TreerecsParameters> params(new TreerecsParameters_());
  params->thresholds_inputs.push_back("30.0");
  params->thresholds_inputs.push_back("68.2");
  std::vector<double> sorted_supports {25.0, 50.0, 68.1, 68.2, 68.3, 95.0};

  auto thresholds = ConvertThresholdInputsToDoubles(params, sorted_supports);
  decltype(thresholds) expected_thresholds {30.0,68.2};

  EXPECT_EQ(thresholds, expected_thresholds);
  EXPECT_EQ(params->strict_support_thresholds, true);
}

TEST_F(SupportTools_test, ConvertThresholdInputsToDoubles_epsilon) {
  std::unique_ptr<TreerecsParameters> params(new TreerecsParameters_());
  params->thresholds_inputs.push_back("68.2+epsilon");
  std::vector<double> sorted_supports {25.0, 50.0, 68.1, 68.2, 68.3, 95.0};

  auto thresholds = ConvertThresholdInputsToDoubles(params, sorted_supports);
  decltype(thresholds) expected_thresholds {68.2};

  EXPECT_EQ(thresholds, expected_thresholds);
  EXPECT_EQ(params->strict_support_thresholds, false);
}

TEST_F(SupportTools_test, ConvertThresholdInputsToDoubles_e) {
  std::unique_ptr<TreerecsParameters> params(new TreerecsParameters_());
  params->thresholds_inputs.push_back("68.2+e");
  std::vector<double> sorted_supports {25.0, 50.0, 68.1, 68.2, 68.3, 95.0};

  auto thresholds = ConvertThresholdInputsToDoubles(params, sorted_supports);
  decltype(thresholds) expected_thresholds {68.2};

  EXPECT_EQ(thresholds, expected_thresholds);
  EXPECT_EQ(params->strict_support_thresholds, false);
}

TEST_F(SupportTools_test, ConvertThresholdInputsToDoubles_multiple_epsilon) {
  std::unique_ptr<TreerecsParameters> params(new TreerecsParameters_());
  params->thresholds_inputs.push_back("50.0+e");
  params->thresholds_inputs.push_back("68.2+e");
  std::vector<double> sorted_supports {25.0, 50.0, 68.1, 68.2, 68.3, 95.0};

  decltype(ConvertThresholdInputsToDoubles(params, sorted_supports)) thresholds;
  EXPECT_NO_THROW(thresholds =
      ConvertThresholdInputsToDoubles(params, sorted_supports));
  decltype(thresholds) expected_thresholds {50.0, 68.2};

  EXPECT_EQ(thresholds, expected_thresholds);
  EXPECT_EQ(params->strict_support_thresholds, false);
}

TEST_F(SupportTools_test, ConvertThresholdInputsToDoubles_incoherent_epsilon) {
  std::unique_ptr<TreerecsParameters> params(new TreerecsParameters_());
  params->thresholds_inputs.push_back("50.0");
  params->thresholds_inputs.push_back("68.2+e");
  std::vector<double> sorted_supports {25.0, 50.0, 68.1, 68.2, 68.3, 95.0};

  EXPECT_THROW(ConvertThresholdInputsToDoubles(params, sorted_supports),
               malformed_cmd);

  params->thresholds_inputs.clear();
  params->thresholds_inputs.push_back("50.0+e");
  params->thresholds_inputs.push_back("68.2");

  EXPECT_THROW(ConvertThresholdInputsToDoubles(params, sorted_supports),
               malformed_cmd);
}
