//***************************************************************************
//* Copyright (c) 2015 Saint Petersburg State University
//* Copyright (c) 2011-2014 Saint Petersburg Academic University
//* All Rights Reserved
//* See file LICENSE for details.
//***************************************************************************

#pragma once

#include "redundant_contig_remover.hpp"
#include "equal_path_deletion_correction.hpp"

using namespace debruijn_graph;

namespace dipspades {

class IterativeLoopCorrector : public AbstractContigCorrector{

    size_t k_value_;

    VertexPathIndex &index_;
    size_t max_loop_len_;
    size_t min_lcs_length_;
    size_t max_tail_length_;
    CorrectionResult res;

public:
    IterativeLoopCorrector(Graph &g, size_t k_value, VertexPathIndex &index, size_t max_loop_len,
            size_t min_lcs_length, size_t max_tail_length) :
        AbstractContigCorrector(g), k_value_(k_value), index_(index),
        max_loop_len_(max_loop_len), min_lcs_length_(min_lcs_length),
        max_tail_length_(max_tail_length) {
    }

    ContigStoragePtr Correct(ContigStoragePtr contigs) {
        {
            INFO("Equal path remover starts");
            index_.Initialize(contigs);
            EqualPathDeletionCorrector equal_path_remover(g_, index_);
            contigs = equal_path_remover.Correct(contigs);
            res.redundancy_map = equal_path_remover.Result().redundancy_map;
            index_.Clear();
            INFO(std::to_string(contigs->Size()) + " contigs will be used further");
        }

        INFO("Iterative loop corrector starts");
        {
            INFO("Only exact match iteration with parameters:");
            INFO("\tMaximal loop length - " + std::to_string(max_loop_len_));
            INFO("\tMinimal lcs length - " + std::to_string(min_lcs_length_));
            INFO("\tMaximal tail length - 0");

            index_.Initialize(contigs);
            LoopBulgeDeletionCorrector loop_corr(g_, k_value_,
                    max_loop_len_, 0, min_lcs_length_, index_);
            contigs = loop_corr.Correct(contigs);
            auto old_map = res.redundancy_map;
            auto new_map = loop_corr.Results().redundancy_map;
            RedundancyMapMerger<size_t> map_merger;
            res.redundancy_map = map_merger.MergeTwoMaps(old_map, new_map);
            index_.Clear();
            INFO(std::to_string(contigs->Size()) + " contigs will be used further");
        }

        {
            INFO("Tails allowing match iteration with parameters:");
            INFO("\tMaximal loop length - " + std::to_string(max_loop_len_));
            INFO("\tMinimal lcs length - " + std::to_string(min_lcs_length_));
            INFO("\tMaximal tail length - " + std::to_string(max_tail_length_));
            index_.Initialize(contigs);
            LoopBulgeDeletionCorrector loop_corr(g_, k_value_,
                    max_loop_len_, max_tail_length_, min_lcs_length_, index_);
            contigs = loop_corr.Correct(contigs);
            auto old_map = res.redundancy_map;
            auto new_map = loop_corr.Results().redundancy_map;
            RedundancyMapMerger<size_t> map_merger;
            res.redundancy_map = map_merger.MergeTwoMaps(old_map, new_map);
            index_.Clear();
            INFO(std::to_string(contigs->Size()) + " contigs will be used further");
        }
        INFO("Iterative loop corrector ends");
        return contigs;
    }

    MappingContigPtr Correct(MappingContigPtr contig){
        return contig;
    }

    CorrectionResult Results(){
        return res;
    }
};

}
