/*****************************************************************//**
 * \file   Constraint.h
 * \brief  A generic constraint interface to store the specific constraint wheither it is a branching constraint or a cut constraint.
 *
 * \author Matteo Petris
 * \date   March 2023
 *********************************************************************/
#ifndef SUBSETROWCONSTRAINT_H
#define SUBSETROWCONSTRAINT_H

#include "Constraint.h"

template<class Type>
class SubsetRowConstraint : public Constraint<Type> {

protected:

	vector<int> subset;
	vector<int> subset_bit;
	vector<int> multipliers;
	int gcd;
	string subsetToString;

public:
	/**
	 * Constructor by default.
	 *
	 */
	SubsetRowConstraint() :Constraint<Type>(), subset() {
		this->isVI = true;
	}


	/**
	 * Constructor with the left hand side, the right hand side and the operator of the constraint.
	 *
	 * \param variables_indexes: vector<int>&
	 * \param rhs: double
	 * \param _operator: const string&
	 */
	SubsetRowConstraint(double rhs, const string& _operator, const vector<int>& subset, const vector<int>& subset_bit, const vector<int>& multipliers, const int& gcd, const string& subsetToString, const string& name = "") :
		Constraint<Type>(rhs, _operator, name), subset(subset), subset_bit(subset_bit), multipliers(multipliers), gcd(gcd), subsetToString(subsetToString) {
		this->isVI = true;
	}

	/**
	 * Destructor.
	 *
	 */
	virtual ~SubsetRowConstraint() {
	}

	bool is_vertex_in_subset(const int& word, const int& bit) const {
		return ((this->subset_bit.at(word) & bit) == bit);
	}

	int get_multiplier(const int& vertex_id) const {
		for (int i = 0; i < this->subset.size(); i++) {
			if (this->subset.at(i) == vertex_id) {
				return this->multipliers.at(i);
			}
		}
	}

	/**
	 * Get method of items.
	 *
	 * \return items: const pair<int, int>&
	 */
	const vector<int>& get_subset() const {
		return this->subset;
	}

	const vector<int>& get_subset_bit() const {
		return this->subset_bit;
	}

	const vector<int>& get_multipliers() const {
		return this->multipliers;
	}

	const int& getGCD() const {
		return this->gcd;
	}

	const string& get_subsetToString() const {
		return this->subsetToString;
	}

	string toString() const {
		string mystring = "SUBSETROW\n";
		for (int i = 0; i < this->subset.size(); i++) {
			mystring += "\t" + to_string(this->subset.at(i)) + " ";
		}
		mystring += "\n";
		for (int i = 0; i < this->subset_bit.size(); i++) {
			mystring += "\t" + to_string(this->subset_bit.at(i)) + " ";
		}
		mystring += "\n";
		for (int i = 0; i < this->multipliers.size(); i++) {
			mystring += "\t" + to_string(this->multipliers.at(i)) + " ";
		}
		mystring += "\n\tGCD " + to_string(this->gcd) + "\n";
		//mystring << Constraint<Type>::to_string();
		return mystring;
	}

	/**
	*  \brief	 Get a string for debug output.
	*  \param    out : ostream
	*  \param    constraint : const ArcBranchConstraint<Type>&
	*  \return   The stream with the message ID added : ostream
	*/
	friend ostream& operator<<(ostream& out, const SubsetRowConstraint<Type>& constraint) {
		out << constraint.to_string();
		return out;
	}
};
#endif //SUBSETROWCONSTRAINT_H
