#include "bench_parser.h"
#include <time.h>

class TVnitrni;
class TVnejsi;
class THradlo;

class THotove_hradlo {
  public:
	int pocet;  // na kolik vstupu de vystup
	TVnejsi *hradlo;  // ukazatel na hotove hradlo
};

class Collapsing {
#ifdef DEBUG
	int casAnd,casOr,casEsp,casAbs;
	int pocAnd,pocOr,pocEsp,pocAbs;
#endif
#ifdef STATE
	int pocVnor;
#endif
	int INPUT;
	char *arg[5];  // argumenty prikazove radky
	BenchParserClient *data;
	BenchParser *b;
//	std::string soubor2;
	string *vstupy;
	TVnejsi* minim_hradlo(std::string hradlo, bool negace = false);
	void absorpce(TVnejsi* nove, int* novy_soucin);
	TVnejsi* minim(TVnejsi* nove);
  public:
	Collapsing(int ac,char *a[]){
		data = new BenchParserClient;
		b = new BenchParser(data);
		b->run(a[1]);
		//soubor2 = soubor.substr(0,soubor.find_first_of('.')) + ".pla";
		arg[1] = "result.pla";
		arg[2] = "-1";  // pri kolika a vice hradlech se pouzije Espresso
		arg[3] = "false";  // zda se pouzije Espresso na vysledek
		arg[4] = "true";  // zda se pouzije absorpce
		switch (ac) {
			case 6: arg[4] = a[5];
			case 5: arg[2] = a[4];
			case 4: arg[3] = a[3];
			case 3: arg[1] = a[2];
				break;
		}
	}
	void minimalize();
};

class TVnitrni {
  public:
    char *vnitrni2;
	int pocet_neg, pocet_norm,inp;
#ifdef ALL_ABS
	TVnitrni() {}
#endif
	TVnitrni(int input) {
		inp = input;
		vnitrni2 = new char[input];
		for (int i=0; i<input; i++) vnitrni2[i]=0;
		pocet_neg = pocet_norm = 0;
	}
	~TVnitrni() {
		delete[] vnitrni2;
	}
};

class TVnejsi {
  public:
	TVnitrni **vnejsi;
	int clenu;
	TVnejsi() {
		clenu = 10;
		vnejsi = new TVnitrni*[clenu];
		for (int i=0; i<clenu; i++) vnejsi[i] = NULL;
	}
	TVnejsi(int clen) {
		clenu = clen;
		vnejsi = new TVnitrni*[clenu];
		for (int i=0; i<clenu; i++) vnejsi[i] = NULL;
	}
	TVnejsi(TVnejsi& kopie) {  // kopirovaci konstruktor
		clenu = kopie.clenu;
		vnejsi = new TVnitrni*[kopie.clenu];
		int j,ii = kopie.vnejsi[0]->inp;
		for (int i=0; i<kopie.clenu; i++) {//vnejsi[i] = kopie.vnejsi[i];
			vnejsi[i] = new TVnitrni(ii);
			for (j=0; j<ii; j++) vnejsi[i]->vnitrni2[j] = kopie.vnejsi[i]->vnitrni2[j];
		}
	}
	~TVnejsi() {
		for (int i=0; i<clenu; i++) if (vnejsi[i] != NULL) delete vnejsi[i];
		delete[] vnejsi;
	}
	void Zvetsi(){  // pokud nedostacuje velikost pole ukazatelu na TVnitrni, tak se zdvojnasobi
		int i;
		TVnitrni **pom;
		pom = new TVnitrni*[clenu*2];
		for (i=0; i<clenu-1; i++) pom[i] = vnejsi[i];
		for (i=clenu-1, clenu *=2; i<clenu; i++) pom[i] = NULL;
		delete vnejsi;
		vnejsi = pom;
	}
};

class THradlo {
  public:
	TVnejsi **hradlo;
	int poc_vst;
	THradlo(int pocet_vstupu) {
		poc_vst = pocet_vstupu;
		hradlo = new TVnejsi*[pocet_vstupu];
		for (int i=0; i<pocet_vstupu; i++) hradlo[i]=NULL;
	}
	~THradlo() {
		for (int i=0; i<poc_vst; i++) delete hradlo[i];
		delete[] hradlo;
	}
};

