#ifndef GREEDYPACKING_H_
#define GREEDYPACKING_H_

#include <queue>
#include <vector>
#include <gp-bnb/graph.hpp>
#include <gp-bnb/incremental_bfs.hpp>
#include <gp-bnb/partition.hpp>
#include <iostream>


class greedy_packing{
public:
    /** @brief Initializes a greedy-packing instance 
     *  @param Graph to be partitioned
     *  @param iBFS instance to be used
     *  @param bool, if bound with flow should be used
     */
    greedy_packing(graph& g, incremental_bfs& ibfs, bool with_flow);

    /** @brief executes the GP algortihm
     */
    void run();

    /** @brief resets the already partitioned sets a and b
     *  @param vector of nodes in set a
     *  @param vector of nodes in set b
     */
    void reset(std::vector<node_id>& a, std::vector<node_id>& b);

    /** @brief executes the forced assignments algorithm 
     *  @param node for which we decide the next branch
     *  @return pair of bool and int where bool represents if node
     *          was in trivial block or not
     *          int: new upper bound if we would branch
     */
    partition::subgraph forced_assignment(node_id node, unsigned int best);

    /** @brief return the bound after execution  
     *  @return packing-bound
     */
    int get_max_flow() const{
        return flow_ + bound;
    };

private:

    void bfs();

    graph& graph_;

    //partial partition into blocks a and b
    //x is block with the neighbors of B
    std::vector<node_id>* a_;
    std::vector<node_id>* b_;
    std::vector<node_id> x_;
    std::vector<int> in_part;

    incremental_bfs& i_bfs;

    bool with_flow_, swapped;

    std::vector<std::vector<node_id>> partitioning;

    std::queue<node_id> q;

    std::vector<bool>* flow_edges_;

    std::vector<bool> visited;

    unsigned int a_count, max_a, flow_, bound;
};

#endif /* GREEDY_PACKING_H_ */