#ifndef functionH
#define functionH

#include "misc.h"
#include "import.h"
#include "pla_elem.h"
#include "export.h"
#include "pupik.h"

using namespace std;

class Function {
    // privatni data
    DdManager *manager;// manazer cuddu
    list<DdNode*> temp;  // seznam pomocnych BDD pro operace
    list<Bdd_elem> bdd_list; // seznam prvku Bdd_elem (strom + jmeno promenne)
    list<Bdd_elem> output_list;// seznam vystupnich Bdd_elem (pro rychlejsi pruchod)
    DdNode *background, *zero; // pomocne promenne pro urceni background a zero hodnoty v bdd
    MStr out_var; // pomocna promenna pro kontrolu aktualni vystupni promenne
    list<PLA_elem *> pla_list; // seznam mintermu a vystupu pro minimalizaci
    PLA_elem *pla; // pomocna promenna pro minimalizaci
    int outputs_num; // pocet vystupu
    long count; // pomocna promenna urcujici pocet termu, ktere se prohledavaji pro minimalizaci
    bool minimize; // priznak - minimalizovat ci ne, tot otazka
    bool subsets;// priznak - pouzit v pupikovi podmnoziny
    
    // privatni metody
    void error();
    DdNode * create_basic_bdd(void);
    DdNode * create_bdd_recursive(MStr, vector<Input_elem> &);
    DdNode * combine_bdds(list<DdNode*> &, int);
    DdNode * combine_bdds_2(list<DdNode*> &, int);
    void create_bdd_list(vector<Input_elem> &);
    void print_bdd(list<Bdd_elem> &);
    void print_inputs(vector<Input_elem> &);
    void print_input_list(vector<Input_elem> &);
    bool is_output(MStr, vector<Input_elem> &);
    DdNode * find_node(MStr, list<Bdd_elem> &);
    int minimize_output(DdNode *, Export *, int);
    void minimize_output_recursive(DdNode *, char *, Export *);
    void minimize_output_pupik(DdNode *, char *, Export *, Pupik *);
    int compare_minterms(char *, char *);
    void merge_minterms(char *, char *);
    int absorp_minterms(char *, char *);
    void print_pla_list(void);
    void print_array(char *, int);

public:
    Function(DdManager *m, bool min, bool sub){ manager = m; count = 0; minimize = min; subsets = sub; outputs_num = 0;};
    ~Function(){};
    list<Bdd_elem> get_bdd_list(void);
    list<PLA_elem *> get_pla_list(void);
    bool run(vector<Input_elem> &, Export *, int);
};

#endif
