#define DIMENSION 4
#define POCET_BIN_VRCHOLOV 16
#define VELKOST_D 24
#define FAKTORIAL_FARIEB 4*3*2

#define POCET_FARIEB DIMENSION
#define POCET_VRCHOLOV POCET_BIN_VRCHOLOV*DIMENSION/2
#define POCET_SUSEDOV 2*(DIMENSION-1)
#define POCET_VRCHOLOV_FARBA POCET_BIN_VRCHOLOV/2
#define MAX_FARIEB 50000
#define MAX_RIESENI 3000

#define MAXN POCET_VRCHOLOV
#define MAXM ((MAXN+WORDSIZE-1)/WORDSIZE)

#include "./global_functions.h"

#ifndef _FACTOR_CUBE_DFS_H
#define	_FACTOR_CUBE_DFS_H

extern "C" {
    
}

class FACTOR_CUBE_DFS {
public:
    FACTOR_CUBE_DFS(int a,int b, int c, int d, int e, int f, int g, int h, int i);
    virtual ~FACTOR_CUBE_DFS();
private:
    int M, vrchol, novy_vrchol, sused, m, pom;
    graph g[MAXN*MAXN], cg[MAXN*MAXN], cgi[MAXN*MAXN];
    nvector lab[MAXN], ptn[MAXN]; //povodne nvector

    int orbits[MAXN];

    set * gv;
    statsblk stats;
    setword workspace[50 * MAXM];

    int nove_vrcholy[POCET_BIN_VRCHOLOV][POCET_BIN_VRCHOLOV];
    int bin_susedia[POCET_BIN_VRCHOLOV][DIMENSION];
    int susedia_napln_def[DIMENSION];
    int default_susedia[POCET_VRCHOLOV][POCET_SUSEDOV];
    int default_ofarbenie[POCET_VRCHOLOV];
    int ofarbenie[POCET_VRCHOLOV];
    int su_ofarbene[POCET_VRCHOLOV];
    int cesta_global[2 * POCET_VRCHOLOV_FARBA - 1];
    int perm_pole_2[2][2];
    int perm_pole_2_fak;
    int perm_pole_3[6][3];
    int perm_pole_3_fak;
    int perm_pole_4[24][4];
    int perm_pole_4_fak;
    int perm_pole_5[120][5];
    int perm_pole_5_fak;
    int perm_pole_6[720][6];
    int perm_pole_6_fak;
    int perm_pole_tmp;
    char binary[DIMENSION];

    struct FAKTORIZACIA {
        unsigned int ofarbenie[POCET_VRCHOLOV];
        unsigned int laby[FAKTORIAL_FARIEB][POCET_VRCHOLOV];
        unsigned int D_tabulka[VELKOST_D * POCET_VRCHOLOV / 4];
    };
    unsigned int faktorizacia_pocet;
    typedef struct FAKTORIZACIA item_faktorizacia;
    item_faktorizacia * faktorizacia[MAX_RIESENI];

    struct OPTION {
        unsigned int SEMI_CHECK; //  1 - SEMI    //  2 - PERF    // 0 - NIC
        unsigned int SEMI_POZICIA_POCAS; //  1 - ZAPNUTE    //  0 - VYPNUTE
        unsigned int SEMI_POZICIA_FARBA_KONIEC; //  1 - ZAPNUTE    //  0 - VYPNUTE
        unsigned int SEMI_POZICIA_OFARBENIE_KONIEC; //  1 - ZAPNUTE    //  0 - VYPNUTE     // totok dorobit
        unsigned int VYPIS; //  1 - zapnuty //  0 - vypnuty
        unsigned int NAUTY; //  1 - zapnuty //  0 - vypnuty
        unsigned int NAUTY_POZICIA_FARBA_KONIEC; //  1 - na konci kazdej farby   2 - na konci ofarbenia
        unsigned int NAUTY_POZICIA_OFARBENIE_KONIEC;
        unsigned int NAUTY_D_TABULKA;
    } option;

    int zapis_iba_do_labu;
    permutation lab_farby_level[POCET_FARIEB][MAX_FARIEB][POCET_VRCHOLOV];
    int lab_farby_level_pocet[POCET_FARIEB];
    int ofarbenie_global[POCET_FARIEB][MAX_FARIEB][POCET_VRCHOLOV];
    int ofarbenie_global_pocet[POCET_FARIEB];
    int farby_level[DIMENSION - 1][MAX_FARIEB][POCET_VRCHOLOV_FARBA];
    int pocet_farieb_level[DIMENSION - 1];

    void najdi_faktorizaciu(int cesta[2 * POCET_VRCHOLOV_FARBA - 1], int su_ofarbene_lokal[POCET_VRCHOLOV], int ofarbenie_lokal[POCET_VRCHOLOV], int farby_level_lokal[DIMENSION - 1][MAX_FARIEB][POCET_VRCHOLOV_FARBA], int pocet_farieb_level_lokal[DIMENSION - 1]);
    int check_P1F(int vrchol, unsigned int level_lokal, int ofarbenie_lokal[POCET_VRCHOLOV]);
    int check_P1F_koniec(int vrchol, unsigned int level_lokal, int ofarbenie_lokal[POCET_VRCHOLOV]);
    int check_level_P1F(unsigned int vrchol, unsigned int level_lokal_first, unsigned int level_lokal_akt, int ofarbenie_lokal[POCET_VRCHOLOV]);
    int check_P1F_rot(int vrchol, unsigned int level_lokal, int ofarbenie_lokal[POCET_VRCHOLOV]);
    void vyrataj_D_tabulku(int akt_faktorizacia);
    int RunNautyPocas(int level_nauty, int su_ofarbene_lokal[POCET_VRCHOLOV], int ofarbenie_lokal[POCET_VRCHOLOV], graph g_lokal[MAXN*MAXN], graph cg_lokal[MAXN*MAXN], graph cgi_lokal[MAXN*MAXN]);

    void NaplnDefault();
    void najdiSusedovDec(int bod_dec);
    int byte_to_binary(int x);
    int binary_to_decimal(char * bod_bin1);
    inline int myPow(int x, int p);
    void visit(int *Value, int N, int k);
    void print(const int *v, const int size);
};

#endif	/* _FACTOR_CUBE_DFS_H */

