#ifndef _MAKESG_H
#define _MAKESG_H


#include <map>
#include <stack>

using namespace std;     

class MakeSG{

stack<StackElem> stacktmp;      // stack uchovavajici prvky pokud dojde k rozvetveni
queue<int> M;                   // mnozina M
queue<int> M2;                  // mnozina M'
int* srovPole;                  // pole srovnani rozvetveni
char* s;                        // init kodovani
queue<int> Te;                  //mnozina Te
int done ;                      // boolean hodnota pro while
Stg* stg;                       // ukazatel na STG
SG* sg;                         // ukazatel na SG

public:

MakeSG(Stg* st,SG* s){
stg = st;
sg = s;
done = false;
//makeSrovPole();   
}


//-----------------------------------------------------------------------------      

~MakeSG(){
if(!stacktmp.empty()) cout  <<"CHYBA";
while(!M2.empty()) M2.pop();
while(!M.empty()) M.pop();
while(!Te.empty()) Te.pop();
//delete [] s;
//delete []srovPole;
done = 0;
sg = 0;
stg = 0;

}


//-----------------------------------------------------------------------------      
// priprava Te mnoziny na zasobnik
void merg(queue<int> &S){
int citac = 0;
int v = S.size();
for(int i = 0;i < v;++i){
citac = 0;
for(int j = 0;j < stg->pocetPlace;++j){
if(S.front() == srovPole[j])
++citac; 
        
}
if(citac == 1)
S.push(S.front());

S.pop();

}

}


//-----------------------------------------------------------------------------      
// srovnani na rozvetveni
void makeSrovPole(){
srovPole = new int[stg->pocetPlace];
for(int i = 0;i < stg->pocetPlace;++i)
srovPole[i] = stg->place[i]->indexTran;
}



//-----------------------------------------------------------------------------      
/*
void T(queue<int> Test){
while(!Test.empty()){
cout << Test.front() << " ";     
Test.pop();
}
cout << endl;
}
*/

//-----------------------------------------------------------------------------      
// fce naplni mnzinu M misty s tokeny
void doM(){
for(int i = 0; i < stg->pocetPlace;i++)     
if((stg->place[i])->token == '1'){M.push(i);}
}


//-----------------------------------------------------------------------------      
//fce - vytvori mnozinu Te z odpovidajicich prechodu 
void makeTe(){
queue<int> tmpTe;
int tmp;
for(int i = 0;i < int(M.size());++i)     
{
tmp = M.front();
M.pop();
M.push(tmp);
int x = stg->place[tmp]->indexTran;
tmpTe.push(x);
}


map<int,int> mymap;
map<int,int>::iterator it;

while(!tmpTe.empty()){
mymap[tmpTe.front()] = 1;
tmpTe.pop();
}

for(it = mymap.begin(); it != mymap.end(); it++)
tmpTe.push(it->first);

Te = tmpTe;


}


//-----------------------------------------------------------------------------      
// sjednoti mista a vztvori stav v SG
void doS(){
queue<int> tmp = M;
 
sg->sg[sg->pocet] = new SGelem;
sg->sg[sg->pocet]->pole = new int[int(tmp.size())];
sg->sg[sg->pocet]->lenPole = tmp.size();
sg->sg[sg->pocet]->num = 0;

for(int i = 0;i < sg->sg[sg->pocet]->lenPole;++i)
{
sg->sg[sg->pocet]->pole[i] = tmp.front();
tmp.pop();
}

sg->sg[sg->pocet]->code = new char[strlen(s)];
strcpy(sg->sg[sg->pocet++]->code,s);
}



//-----------------------------------------------------------------------------      
// porovnama mnozinu M s novimi tokeny na prozdnou
int comperM(int t){

queue<int> tmp;
while(!M.empty()){
if(stg->place[M.front()]->indexTran != t)
tmp.push(M.front());
M.pop(); 
}

M = tmp;
while(!tmp.empty()){
for(int i = 0;i < stg->tran[t]->numOfip;++i )
if(stg->tran[t]->indexPlace[i] == tmp.front()) return 1;
tmp.pop();
}

return 0;

}

void sjednoceni(int t){
M2 = M;

for(int i = 0;i < stg->tran[t]->numOfip;++i ){
M2.push(stg->tran[t]->indexPlace[i]);
}     
}


//-----------------------------------------------------------------------------      
// zmena zakodovacihu stavu pro stavy SG podle zneny signalu
void changCode(int t){
int ind = stg->tran[t]->stavInd;
int rf =  stg->tran[t]->riseOrFall;
if(rf == '+') s[ind] = '1';
else if (rf == '-') s[ind] = '0';    
}

//-----------------------------------------------------------------------------      
// vytvoreni prechodu mezi misty v SG, prechod se prirazuje do stavu ze ktereho vychazi
void transition(int m1,int t,int m2){

if(sg->sg[m1]->num == 0){
sg->sg[m1]->t = new int[1  ];
sg->sg[m1]->t[0] = stg->tran[t]->stavInd;
sg->sg[m1]->p = new int[1];
sg->sg[m1]->p[0] = m2;
++sg->sg[m1]->num;
}else{
int* tmp1 = sg->sg[m1]->t;
int* tmp2 = sg->sg[m1]->p;
sg->sg[m1]->t = new int[++sg->sg[m1]->num];
sg->sg[m1]->p = new int[sg->sg[m1]->num];
for(int i = 0;i < sg->sg[m1]->num -1 ;++i){
sg->sg[m1]->t[i] = tmp1[i];
sg->sg[m1]->p[i] = tmp2[i];
}
sg->sg[m1]->t[sg->sg[m1]->num -1] = stg->tran[t]->stavInd;
sg->sg[m1]->p[sg->sg[m1]->num -1] = m2;

delete [] tmp1;
delete [] tmp2;

}

};

//----------------------------------------------------------------------------
//select(Te)
int selectTe(queue<int>& TeSel){
 
int testplace = 0;
int testtoken = 0;
int t = -1;
int velikost = TeSel.size();

for(int d = 0; d <  velikost; d++ )
{

t = TeSel.front();
TeSel.pop();


for(int i = 0; i < stg->pocetPlace;i++){

if((stg->place[i])->indexTran == t){
testplace++;
if((stg->place[i])->token == '1')
testtoken++;
}
}

if( testplace == testtoken )  break;

t = -1;
testplace = 0;
testtoken = 0;

TeSel.push(t);


}

return t;

}


//-----------------------------------------------------------------------------      
// posouva tokeny v STG
void changToken(int t){
int testplace = 0;
int testtoken = 0;

for(int i = 0; i < stg->pocetPlace;i++){

if((stg->place[i])->indexTran == t){
testplace++;
if((stg->place[i])->token == '1')
testtoken++;
}

}     

if(testplace == testtoken){
for(int i = 0; i < stg->pocetPlace;i++)     
if((stg->place[i])->token == '1')
if((stg->place[i])->indexTran == t)
{(stg->place[i])->token = '0';break;}


int tm; 
for(int i = 0; i < stg->tran[t]->numOfip;i++){     
tm = stg->tran[t]->indexPlace[i]; 
if(tm >= stg->pocetPlace) cout << "vet";
stg->place[tm]->token = '1';
}
}
}

//-----------------------------------------------------------------------------      
// kotrola zda mnozina prave vybranich mist netvori jiz stav se stejnou mnozinou mist v SG
int isIndcludeS( ){
queue<int> tmp = M2;              // zasobnik do tmp            
int* tmp2 = new int[tmp.size()];  // init vector stejny jak zasobnik
int* tmp3 = new int[tmp.size()];
//prekopirovani do vectoru
int l = 0;

while(!tmp.empty()){              
tmp2[l] = tmp.front();
tmp3[l] = tmp.front();

l++;
tmp.pop();
}

int test = 0;


for(int i = 0;i < sg->pocet; ++i){



if(sg->sg[i]->lenPole == l){
for(int j = 0;j < l;++j)
for(int k = 0;k < l;++k){
int t1 = tmp2[j];
int t2 = sg->sg[i]->pole[k];
if( t1 == t2 ){
test++;  tmp2[j] = -1; 

}
}
}

if(test)
for(int iii = 0;iii < l;++iii)
tmp2[iii] = tmp3[iii];

if(sg->sg[i]->lenPole == test  )
{delete [] tmp3;delete [] tmp2; return i;}
else {test = 0; }

}
delete [] tmp3;
delete [] tmp2;
return -1;
}


//-----------------------------------------------------------------------------      
// fce samotne prohledavani grafu vychazejici z matematickeho modelu transformace
int find_SG(){
int m;
int tmpind = 0;
sg->pocet = 0;
int t;

doM();

int i = stg->sizeCode;
s = new char[i];
strcpy(s,stg->initCode);
s[i]='\0';
makeTe();
doS();


while(!done){                                   


//t = Te.front();                                
//Te.pop();                                            
t = selectTe(Te);

if(t != -1){
                                  
if(!Te.empty()){                                   
//cout << t << " ";
//T(Te);
//merg(Te);

if(!(Te.empty())){ 

StackElem se;
se.index = tmpind;
se.poleTe = new int[Te.size()];
se.lenP = Te.size();
queue<int> tmp = Te;
int ii = 0;
while(!tmp.empty()) {
se.poleTe[ii++] = tmp.front();
tmp.pop();
}
stacktmp.push(se);    
ii = 0;                                                //    
}  
}

changToken(t);

if(comperM(t)){
std::cout << "STG is not safe"; 
system("PAUSE");
exit(1);
}

sjednoceni(t);           
changCode(t);             
}


if(((m = isIndcludeS()) == -1 ) && t != -1){//podminka

int indtmp = sg->pocet;
M = M2;
doS();

transition(tmpind,t,indtmp);


tmpind = sg->pocet - 1;


makeTe();

//cout << sg->pocet;
     
}
else{
if((strcmp(sg->sg[m]->code,s)) && t != -1){
std::cout << "Iconsistent state assignem" << endl;
system("PAUSE");
exit(1);
}

// ----------------stack empty------------
if(!stacktmp.empty()){
if(t != -1) transition(tmpind,t,m);
StackElem se;
se = stacktmp.top(); 
tmpind = se.index;



while(!Te.empty()) Te.pop();
for(int i = 0;i < se.lenP;++i) 
Te.push(se.poleTe[i]);



while(!M.empty()) M.pop();
for(int i = 0;i < sg->sg[tmpind]->lenPole;++i){ 
M.push(sg->sg[tmpind]->pole[i]);
}

//vsem tokenz na 0
for(int i = 0; i < stg->pocetPlace;i++)     
(stg->place[i])->token = '0';

// nastavit tokeny
int tmpp;
int delka = M.size();
for(int i = 0; i < delka;i++){
tmpp = M.front();
(stg->place[tmpp])->token = '1';
M.pop();
M.push(tmpp);
}



for(int i = 0;i < stg->sizeCode;++i) 
s[i] = sg->sg[tmpind]->code[i];

delete [] se.poleTe;
stacktmp.pop();



}else{if(t != -1) transition(tmpind,t,m); done = 1;  return 0;
}

}           

} 
  return 0;   
}      
      
};

#endif
