#include <iostream>
#include <fstream>
#include <string>
#include "gate.h"

#ifndef _LEXSYMBOL_
#define _LEXSYMBOL_

typedef enum LexSymb {	T_INPUT, T_OUTPUT, T_IDENT, T_NULL, T_COMMA,   // lexikalni symboly
                        T_LPAR, T_RPAR, T_EQUAL,
						T_AND, T_OR, T_NAND, T_NOR, T_XOR, T_XNOR,
						T_BUF, T_INV, T_EOI};


static const int count_key_words = 22;
static const struct {char* slovo; LexSymb symb;} TabKS[] = {		// tabulka lexikalnich symbolu
		{"output", T_OUTPUT},
		{"input",  T_INPUT},
		{"and", T_AND},
		{"or", T_OR},
		{"nand", T_NAND},
		{"nor", T_NOR},
		{"xor", T_XOR},
		{"xnor", T_XNOR},
		{"buf", T_BUF},
		{"buff", T_BUF},
		{"not", T_INV},
		{"OUTPUT", T_OUTPUT},
		{"INPUT",  T_INPUT},
		{"AND", T_AND},
		{"OR", T_OR},
		{"NAND", T_NAND},
		{"NOR", T_NOR},
		{"XOR", T_XOR},
		{"XNOR", T_XNOR},
		{"BUF", T_BUF},
		{"BUFF", T_BUF},
		{"NOT", T_INV},
	};

class LexSymbol {
private:	
	static const unsigned short int MaxLenIdent = 30;					//maximalni delka identifikatoru
	char ident[MaxLenIdent];											//promenna pro uchovani identifikatoru
	int delkaIdent;														//delka identifikatoru
	LexSymb typ;														//typ lexikalniho symbolu

public:
	LexSymbol():typ(T_NULL),delkaIdent(0){};							//konstruktor

	void nastavTyp (LexSymb symb)		{ typ = symb; };				//nastavy typ lexikalniho symbolu
	LexSymb getTyp () const				{ return typ;} ;				//vrati typ lexikalniho symbolu

	void pridejZnak(char zn);											//prida jeden znak do identifikatoru (pokud identifikator neni > MaxLenIdent, pak ignoruje)
	
	char* getIdent()					{ return ident;};				//vrati retezec identifikatoru
	int getDelkaIdent() const			{ return delkaIdent;};			//vrati delku identifikatoru
};

#endif

#ifndef _LEXAN_
#define _LEXAN_

class LexAn {
private:
	char vstup;								// p=pismeno nebo cislice, e=konec vstupu, n=konec radku, m=mezera
	char znak;								// nacteny znak
	char ctiZnak(void);						// vrati dalsi znak ze vstupniho souboru
	std::ifstream fin;						// stream pro cteni ze souboru
	LexSymb klicoveSlovo(char* key);		// vrati klicove slovo, pokud retezec je klicovym slovem, jinak vrati typ T_IDENT

public:
	LexAn (char* nameOfFile);				//konstruktor, prebira nazev vstupniho souboru
	~LexAn ();								//destruktor, zavira otevreny soubor
	LexSymbol getSymbol ();					//vrati dalsi Lexikalni Symbol
	void ctiVstup(void);					//precte dalsi znak ze vstupu
};

#endif

#ifndef _IMPORT_
#define _IMPORT_

// provadi rekurzivni sestup dle LL1 gramatiky
class Import {
private:
	std::map<std::string, Gate*> map_of_gates;			//mapa nactenych hradel, slouzi pri vytvareni vnitrnich hradel (pokud vstupni, vystupni hradlo, tak nevytvarej nove)

	LexSymbol symbol;									//prave nacteny lexikalni symbol
	LexAn lex;											//lexikalni analyzator
	void compare(LexSymb ls);							//srovnani ocekavaneoho lexikalniho symbolu a symbolu na vstupu
	LexSymb show();										//ukaze nasledujici lexikalni symbol

	// funkce pro rekurzivni sestup (inputs_outputs a inner_nodes upraveny na cyklus)
	void inputs_outputs(std::list<Gate*>& _inputs, std::list<Gate*>& _outputs);		//nacita vstupy a vystupy obvodu
	void inner_nodes(std::list<Gate*>& _inner_nodes);								//nacita vnitrni uzly obvodu
	void inputs_of_gate(Gate* gate);												//nacita vstup vnitrniho uzlu
	void rest_inputs_of_gate(Gate* gate);											//nacita zbytek vstupu vnitrniho uzlu
	Type_of_gate type();															//nacita typ hradla

public:
	Import(char* nameOfFile):lex(nameOfFile){};										//konstruktor prebirajici nazev vstupniho souboru															

	void read_circuit(std::list<Gate*>& _inputs,std::list<Gate*>& _outputs, std::list<Gate*>& _inner_nodes); //vstupni funkce pro nacteni obvodu, prebira odkazy na vstupni, vystupni a vnitrni uzly
																											 //po nacteni ze souboru provadi provazani obvodu
};

#endif








