// 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 Googletest
#include <gtest/gtest.h>

// std
#include <memory>
#include <string>

// Include Bpplib
#include <Bpp/Phyl/Tree/PhyloTree.h>

// Include containers
#include <treerecs/algorithms/NeighborJoining.h>
#include <treerecs/tools/Statistics.h>
#include <treerecs/containers/Grid.h>
#include <treerecs/containers/Table.h>
#include <treerecs/containers/GeneMap.h>

// Include handlers, tools
#include <treerecs/tools/SpeciesGeneMapper.h>
#include <treerecs/tools/IO/IO.h>
#include <treerecs/tools/utils.h>
#include <treerecs/tools/IO/RecPhyloTreeToSVG.h>
#include <treerecs/tools/treeReconciliation/TreeReconciliationConductor.h>

// Include examples paths
#include "examples_paths.h"

using namespace treerecs;

/*!
 * @class RecPhyloTreeToSVG_tests
 * @brief Test RecPhyloTreeToSVG methods
 */
class RecPhyloTreeToSVG_tests: public testing::Test {
protected:
  virtual void SetUp() {

    speciestree = IO::readTreeFile(multipolytomy_examples_path
                                   + "species_tree.txt",
                                   TextFormat ::newick, false, false, false);
    genetrees = IO::readTreesFile(multipolytomy_examples_path
                                  + "gene_tree.txt",
                                  TextFormat ::newick, true, false);

    genetrees = {genetrees.front()};

    map = SpeciesGeneMapper::map(genetrees.begin(), genetrees.end(),
                                 *speciestree, MappingMethod::TREES).front();

    SpeciesGeneMapper::updateInnerNodeMapping(map, *genetrees.front(),
                                              *speciestree);
  }

  virtual void TearDown() {}

  std::shared_ptr<bpp::PhyloTree> speciestree;
  std::vector<std::shared_ptr<bpp::PhyloTree>> genetrees;
  SpeciesGeneMap map;
};

TEST_F(RecPhyloTreeToSVG_tests, speciesTreeLayoutTest) {
  TreeReconciliationConductor reconciliator;
  auto reconciled_trees_ = reconciliator.operator()(
      *genetrees.front(), *speciestree, map,
      0, false, 2, 1, 0.5, true, true, 1, false, false, true, false, false, false);
  std::vector<std::shared_ptr<bpp::PhyloTree>> reconciled_trees;
  reconciled_trees.reserve(reconciled_trees_.size());

  std::vector<SpeciesGeneMap> reconciled_maps;
  reconciled_maps.reserve(reconciled_trees_.size());

  unsigned long total_ndup = 0;
  unsigned long total_nloss = 0;
  for(auto rtree: reconciled_trees_){
    reconciled_trees.push_back(rtree.genetree());
    reconciled_maps.push_back(rtree.map());
    total_ndup += rtree.ndup();
    total_nloss += rtree.nloss();
  }

  // Generate the SVG document.
  svg::Document doc_svg = RecPhyloTreeToSVG::createDocument(
      reconciled_trees.begin(),
      reconciled_trees.end(), *speciestree,
      reconciled_maps.begin());

  // Then read document to check the right number of duplications (rect)
  // and losses (using leaves)
  std::string doc_str = doc_svg.toString();

  ASSERT_EQ(utils::count(doc_str, "rect"), total_ndup);
  ASSERT_EQ(utils::count(doc_str, LOSS_STR_FLAG), total_nloss);
}
