/*****************************************************************//**
 * \file   CutGenerator.h
 * \brief  Reperesents the interface of pricing subproblem algorithm with a virtual pure algorithm to override by inherent classes depending on the choosed algorithm to solve the pricing subproblem.
 *
 * \author talmefta
 * \date   October 2022
 *********************************************************************/
#ifndef CUTGENERATOR_H
#define CUTGENERATOR_H

#include "Header.h"
#include "Node.h"
#include "CutFamilyInformation.h"

static int			   cut_iteration = 0;		/**< Global variable counting the cut iteration where the cutter has been involved.*/
static int			   cut_counter = 0;		    /**< Global variable counting the cut.*/
static double		   separation_time = 0.0;	/**< Global variable counting the total separation time.*/

 /**
  * \class CutGenerator
  * \brief Interface of Chain of responsability design pattern dealing with the choice of the cut generator (cut algorithm) when cutting fractional solutions in branch and price and cut.
  */

template<class RestrictedMasterProblem, class PricingSubProblem, class ColumnGeneration, class ConstraintType>
class CutGenerator {
public:
    /**
     * Virtual destructor.
     *
     */
    virtual ~CutGenerator() {}

    virtual vector<CutFamilyInformation*>& get_information() = 0;

    virtual CutGenerator<RestrictedMasterProblem, PricingSubProblem, ColumnGeneration, ConstraintType>* get_next_cutter() = 0;


    /**
    * \brief Sets the next algorithm operator in the chain of responsibility in the base handler class (here, the CutGeneratorAbstract).
    * \param _next_cutter : CutGenerator< PricingSubProblem>*
    * \return _next_cutter to let us link the algorithms operators in a convenient way (algorithm1->set_next_cutter(handler2)->set_next_cutter(handler3)) : CutGenerator<Instance, ColumnsType, DualVariables>*.
    */
    virtual CutGenerator<RestrictedMasterProblem, PricingSubProblem, ColumnGeneration, ConstraintType>* set_next_cutter(CutGenerator<RestrictedMasterProblem, PricingSubProblem, ColumnGeneration, ConstraintType>* _next_cutter) = 0;

     /**
        * Tries to find cuts to add to the node. Stores the new cuts if any in the node's cut_constraints.
        * \details This method has to be implemented by inherent classes to define how to cut the node.
        *
        * \param node: Node<class RestrictedMasterProblem, class PricingSubProblem, class ColumnGeneration>&
        */
    virtual bool cut(Node<RestrictedMasterProblem, PricingSubProblem, ColumnGeneration, ConstraintType>& node) = 0;

    virtual void reset_found_inequality() = 0;

    //statistics about a family of inequalities

    const int compute_violated_inequalities_number() {
        int number = 0;
        for (auto& cut_family_info : this->get_information()) {
            number += cut_family_info->get_number_violated_cuts();
        }
        return number;
    }

    const double compute_dual_bound_before_first() {
        double db = -1;
        int first_it = ::OMEGA;
        for (auto& cut_family_info : this->get_information()) {
            int it = cut_family_info->get_cut_iteration();
            if (it < first_it) {
                db = cut_family_info->get_dual_bound_before_adding_cuts();
                first_it = it;
            }
        }
        return db;
    }

    const double compute_separation_time() {
        double time = 0.0;
        for (auto& cut_family_info : this->get_information()) {
            time += cut_family_info->get_time();
        }
        return time;
    }

    const double compute_minimal_violation() {
        double min_viol = ::OMEGA;
        for (auto& cut_family_info : this->get_information()) {
            min_viol = min(min_viol, cut_family_info->get_minimum_violation());
        }
        return min_viol;
    }

    const double compute_maximal_violation() {
        double max_viol = -::OMEGA;
        for (auto& cut_family_info : this->get_information()) {
            max_viol = max(max_viol, cut_family_info->get_maximum_violation());
        }
        return max_viol;
    }

};

#endif //CUTGENERATOR_H