
#include "hlavicka.h"
//#include "ac.C"
//#include "ac.h"
#define Max_frequency 16383

Aktual& Aktual::operator= (const Aktual& arg){
  this->pocet_stavov=arg.pocet_stavov;
  delete[] this->P_stavov;
  this->P_stavov=new Cislo[pocet_stavov];
  for(int i=0;i<pocet_stavov;i++) this->P_stavov[i]=arg.P_stavov[i];
  return (*this);
}

policko::policko(const policko& arg){
 // cerr << "pop "<< arg.second.P_stavov << endl;
  first=Cislo(arg.first);
  second=Aktual(arg.second);
};
policko::policko(const Cislo& c, const Aktual& a):first(c),second(a){};
//policko::~policko(){delete &second;}
policko::policko():first(0),second(){};

policko& policko::operator= (const policko& arg){
   this->first=Cislo(arg.first);
   this->second=Aktual(arg.second);
  return (*this);
}

Aktual::Aktual(Cislo* moj,int p):pocet_stavov(p),P_stavov(0){
  //pocet_stavov=p;
  P_stavov=moj;
//  cerr << "novyA2 " << P_stavov << " " << this << endl;
}

Aktual::Aktual(const Aktual& arg):pocet_stavov(arg.pocet_stavov),P_stavov(0){
  /*this->pocet_stavov=arg.pocet_stavov;
  Cislo* moj=new Cislo[this->pocet_stavov];
  for( int stav=0;stav<this->pocet_stavov;stav++) moj[stav]=arg[stav];
  this->P_stavov=new Cislo[pocet_stavov];*/
  P_stavov=new Cislo[pocet_stavov];
  for(int i=0;i<pocet_stavov;i++) this->P_stavov[i]=Cislo(arg.P_stavov[i]);
//  cerr << "novyA " << P_stavov << " " << this << endl;
}

Aktual::Aktual(const Aktual* arg){
  pocet_stavov=arg->pocet_stavov;
  P_stavov=new Cislo[pocet_stavov];
  for(int i=0;i<pocet_stavov;i++) P_stavov[i]=Cislo(arg->P_stavov[i]);
//  cerr << "novyA3 " << P_stavov << " " << this << endl;
}

Aktual::Aktual(int p){
  pocet_stavov=p;
  P_stavov=new Cislo[p];
  for(int i=0;i<pocet_stavov;i++) P_stavov[i]=Cislo(double(1/pocet_stavov));
}

Aktual::Aktual(){
  pocet_stavov=0;
  P_stavov=0;
//  cerr << "LKLK "<< this << "   ";
}
Aktual::~Aktual(){
 // if(P_stavov!=0){ cerr << "mazem sa tvoj A >P " << P_stavov[2].normal() << endl;}
// cerr << "muhaha "<< P_stavov <<"  "  << this << endl;
 delete[] P_stavov;
// cerr << "haha" << endl;
}

/*Aktual::Cislo operator[] (const int p){
  return Cislo(P_stavov[p]);
}*/

/*
tu bude definovana trieda pre Markovovsky model, ktory musi obsahovat:
1, pravdepodobnosti prechodov medzi stavmi
2, rad stavu
3, pravdepodobnosti emisie pismena pre kazdy stav na zaklade predch. vypisanej sekvencie
mozno 4, aktual - struktura obsahujuca pole "aktualnych" P stavov a predchadzajucu vypisanu sekvenciu

model bude mat tieto funkcie:
1, pre danu dlzku komprimovanej sekvencie vypoc. vsetky P vypisov sekvencii tejto dlzky, vrati ich ako mapu
map<sekvencia,pair<P,aktual> >

pozn.
pre zrychlenie vypoctu  si to predpocita pre danu dlzku a potom len pre kazdy stav prenasobi
momentalnym aktualom, tj. pre kazdy stav to predpocita ako by sme v nom boli s P 1 zvlast a potom ked
dostane aktual, to prenasobi a scita po stavoch
TODO pri predpocitani treba vyriesit, ze nepoznam predchadzajucu vypisanu sekvenciu
tj. robit pre vsetky sekvencie dlzky najvacsieho radu, urobit z toho velke pole cohosi a potom vybrat podla
sekvencie na vstupe spravnu polozku a pracovat s nou


2, konstruktor z *ifstream

3, funkciu na nastavenie dlzky predpocitavanej sekvencie a predpocitanie sekvencii tejto dlzky
*/




Model::~Model(){
  cerr << "Idem mazat Model" << endl;
  delete A;
  delete B;
  if(Predpocitane!=0){
    for(int k=0;k<delitel[max_rad];k++){
  //    cerr << "k " << k << endl;
      for(int i=0;i<pocet_stavov;i++){
//	cerr << "i " << i << "  "; 
	delete[] Predpocitane[k][i];
      }
  //    cerr << endl;
      delete[] Predpocitane[k];
    }
  }
  delete[] Predpocitane;
  for(int i=0;i<pocet_stavov;i++){
    delete[] P_emisii[i];
    delete[] P_prechodov[i];
  }
  delete[] P_emisii;
  delete[] P_prechodov;
  delete[] rad;
  delete[] delitel;
}

  //konstruktor
Model::Model(ifstream* g){//konstruuje Model zo suboru
  predchadzajuca_sq=0;
  Predpocitane=0;
  rad=0;
  delitel=0;
    (*g) >> pocet_stavov >> pocet_pismen >> poc_rozdelenie;
cerr << "Nacital som pocet stavov, pocet pismen, pritomnost pociatocneho rozdelenia " << pocet_stavov << " " << pocet_pismen << " " << poc_rozdelenie << endl;
    rad=new int[pocet_stavov];
cerr << "Nacitavam pociatocne rozdelenie pravdepodobnosti  "<< poc_rozdelenie << endl;
    if (poc_rozdelenie){//ak je, nacita pociatocne rozdelenie P stavov
      double pom;
      Cislo* novy_a=new Cislo[pocet_stavov];
      for(int i=0;i<pocet_stavov;i++){
	(*g) >> pom;
//	cerr << pom << " ";
	novy_a[i]=Cislo(pom);
//	cerr << endl << "zapisal som " << novy_a[i].daj_hod() << endl;
      }
   //   cerr << endl;
      A=new Aktual(novy_a,pocet_stavov);
    }else {
     
      A=new Aktual(pocet_stavov);
    }
    
  
    P_prechodov=new Cislo*[pocet_stavov];
   cerr << "Nacitavam tabulku prechodov" << endl; 
    for(int i=0;i<pocet_stavov;i++){//nacita tabulku prechodov
//      cerr << "stav " << i << endl;
      P_prechodov[i]=new Cislo[pocet_stavov];
      for(int j=0;j<pocet_stavov;j++){
	double pom;
	(*g) >> pom;
//	cerr << pom << " ";
	 P_prechodov[i][j]=Cislo(pom);
      }
   //   cerr << endl;
    }
    //nacita emisne P
    P_emisii=new Cislo*[pocet_stavov];
    max_rad=0;
    cerr << "nacitavam tabulku P emisii " << endl;
    for(int stav=0;stav<pocet_stavov;stav++){
  //    cerr << "stav " << stav << endl;
   //   int z;
      (*g) >> rad[stav];
     
 //     cerr << "rad " << rad[stav] << " " << max_rad<< endl;
      
      if (max_rad<rad[stav]){//ak treba zvacsi rozsah vectoru delitel
	max_rad=rad[stav];
      }
      long pocet_s=pocet_pismen;
      for(int q=0;q<rad[stav];q++) pocet_s=pocet_s*pocet_pismen;
      P_emisii[stav]=new Cislo[pocet_s];
 //     cerr << "P emis "<< rad[stav] << endl;
      for(int s=0;s<pocet_s;s++){
	double pom;
	(*g) >> pom;
//	cerr << pom << " ";
	P_emisii[stav][s]=Cislo(pom);
      }
//      cerr << endl;
      
    }
    
  delitel=new long[max_rad+1];
  delitel[0]=pocet_pismen;
  cerr << pocet_pismen << endl;
  for(int i=0;i<max_rad;i++){ 
    delitel[i+1]=delitel[i]*pocet_pismen;
    cerr << delitel[i] << " " << delitel[i+1] << endl;
  }
  
//cerr << "delitel: " << endl;
//for(int i=0; i<max_rad+1;i++) cerr << delitel[i] << " ";
//cerr << endl << endl;
  
  B=new Aktual(A);
  cerr << "Model nacitany " << endl << endl;
//vypis_sa();  
}//koniec konstruktoru
  
  
void Model::update_model(ac_model* acm,int sym){
//  cerr << "sekvencia: " << predchadzajuca_sq << endl;
  long sekvencia=((predchadzajuca_sq*pocet_pismen)+sym)%delitel[max_rad];
  predchadzajuca_sq=sekvencia;
//  cerr << "sekvencia: " << predchadzajuca_sq << endl;
  policko p=P_sekvencie(sekvencia,B->P_stavov);
  delete B;
  B=new Aktual(p.second);
  Cislo pom[pocet_pismen];
  for(int pismeno=0;pismeno<pocet_pismen;pismeno++){
    long s=((predchadzajuca_sq*pocet_pismen)+pismeno)%delitel[max_rad];
    pom[pismeno]=P_sekvencie(s,B->P_stavov).first;
  //   cerr << pom[pismeno].normal() << endl;
  }
  Cislo sum(0);
  acm->cfreq[acm->nsym] = 0;
  for(int pismeno=pocet_pismen-1;pismeno>=0;pismeno--){
    //TODO upravis acm->cfreq
    sum=sum+pom[pismeno];
    acm->cfreq[pismeno] = int(sum.normal()*Max_frequency);
  //  cerr << "pisem " << acm->cfreq[pismeno] << " " << sum.normal() << endl;
  }
}
  
 
void Model::ac_model_init(ac_model *acm){
  long sekvencia=0;
  predchadzajuca_sq=sekvencia;
  delete B;
  B=new Aktual(*A);
  Cislo pom[pocet_pismen];
  for(int pismeno=0;pismeno<pocet_pismen;pismeno++){
    long s=((predchadzajuca_sq*pocet_pismen)+pismeno)%delitel[max_rad];
    pom[pismeno]=P_sekvencie(s,B->P_stavov).first;
  //  cerr << pom[pismeno].normal() << endl;
  }
  Cislo sum(0);
  acm->cfreq[acm->nsym] = 0;
  for(int pismeno=pocet_pismen-1;pismeno>=0;pismeno--){
    //TODO upravis acm->cfreq
    sum=sum+pom[pismeno];
    acm->cfreq[pismeno] = sum.normal()*Max_frequency;
  }
}
  
  
  
  
  
  
 
 void Model::reset(){//pred kodovanim nastavi Model do vychodzieho stavu
//  cerr << "OK_x"<< endl;
  predchadzajuca_sq=0;
 delete B;
// cerr << "OK_o"<< endl;
  B=new Aktual(A);
 }
 int Model::pocet(){
  return pocet_pismen;
 }
 
  


void Model::novy_A(long sekvencia){
   Cislo pom[pocet_stavov];
   for(int stav=0;stav<pocet_stavov;stav++){
     pom[stav]=(*B)[stav]*Predpocitane[predchadzajuca_sq][stav][sekvencia].first;
   }
   halda p[pocet_stavov];
   halda spolu;
   for(int stav=0;stav<pocet_stavov;stav++){
     for(int stav2=0;stav2<pocet_stavov;stav2++){
       Cislo wr=P_prechodov[stav][stav2]*pom[stav];
       p[stav2].push(wr);
       spolu.push(wr);
     }
   }
   Cislo st=sum(spolu);
   Cislo* novy_a=new Cislo[pocet_stavov];
   for(int stav=0;stav<pocet_stavov;stav++){
     novy_a[stav]=sum(p[stav])/st;
   }
   delete B;
   B=new Aktual(novy_a,pocet_stavov);
   //for(int i=0;i<pocet_stavov;i++) cerr << (*B)[i].normal() << " ";
   //cerr << endl;
   predchadzajuca_sq=(predchadzajuca_sq*delitel[dlzka-1]+sekvencia)%delitel[max_rad];
}

void Model::vypis_sa(){
  cerr << "Pole prechodov: " << endl;
  for(int stav1=0;stav1<pocet_stavov;stav1++){
    cerr << "P prechodov zo stavu " << stav1 << endl;
    for(int stav2=0;stav2<pocet_stavov;stav2++) cerr << P_prechodov[stav1][stav2].normal() << " ";
    cerr << endl;
  }
  cerr << "Pravdepodobnosti sekvencii" << endl;
  for(int stav=0;stav<pocet_stavov;stav++){
    cerr << "stav " << stav << endl; 
    for(int sekv=0;sekv<delitel[rad[stav]];sekv++){
      cerr << P_emisii[stav][sekv].normal() << " ";
    }
    cerr << endl;
  }
  cerr << "Zakladny Aktual " << endl;
  for(int stav=0;stav<pocet_stavov;stav++){
    cerr << (*A)[stav].normal() << " ";
  }
  cerr << endl;
  if(Predpocitane!=0){
    cerr << "Predpocitane: " << dlzka << endl << endl;
    for(int k=0;k<delitel[max_rad];k++){
      cerr << "k " << k << endl;
      for(int i=0;i<pocet_stavov;i++){
	cerr << "stav: "<< i << endl;
	for(int j=0;j<delitel[dlzka-1];j++){
	  cerr << Predpocitane[k][i][j].first.normal() << " ";
	}
	cerr << endl;
      }
      cerr<< endl;
    }
  }   
  return;
}






priority_queue<ukaz,vector<ukaz>, greater<ukaz> > Model::vrat(long sekvencia){
   priority_queue<ukaz,vector<ukaz>, greater<ukaz> > moja;
   for(long s=0;s<delitel[dlzka-1];s++){
     
     halda P_sekvencie;
      for(int stav=0;stav<pocet_stavov;stav++){
	P_sekvencie.push(Predpocitane[predchadzajuca_sq][stav][s].first*(*B)[stav]);
      }
      Cislo w=sum(P_sekvencie);
      vrchol* q=new vrchol(w,s);
      ukaz s(q);
      moja.push(s);
   }
   //novy Aktual
   Cislo pom[pocet_stavov];
   
   for(int stav=0;stav<pocet_stavov;stav++){
    // cerr << "deedfce" <<  B->P_stavov[stav].normal() << "  " << predchadzajuca_sq << " " << stav << " " << sekvencia <<endl;
     pom[stav]=B->P_stavov[stav]*Predpocitane[predchadzajuca_sq][stav][sekvencia].first;
   }
   halda p[pocet_stavov];
   halda spolu;
   for(int stav=0;stav<pocet_stavov;stav++){
     for(int stav2=0;stav2<pocet_stavov;stav2++){
       Cislo wr=P_prechodov[stav][stav2]*pom[stav];
       p[stav2].push(wr);
       spolu.push(wr);
     }
   }
   Cislo st=sum(spolu);
   Cislo* novy_a=new Cislo[pocet_stavov];
   for(int stav=0;stav<pocet_stavov;stav++){
     novy_a[stav]=sum(p[stav])/st;
   }
   delete B;
   B=new Aktual(novy_a,pocet_stavov);
   vrchol* v1=new vrchol();
//cerr << endl << " TOTOTOTOTO " << v1 << " " << v1->koncim() << endl << endl;
   ukaz s2(v1);
   moja.push(s2);//vlozi vrchol kodujuci koniec sekvencie   
   predchadzajuca_sq=(predchadzajuca_sq*delitel[dlzka-1]+sekvencia)%delitel[max_rad];
//cerr << "nova sekvencia je " << predchadzajuca_sq << endl;
   return moja;
 }
 

 
  


priority_queue<ukaz,vector<ukaz>, greater<ukaz> > Model::nova(){
  priority_queue<ukaz,vector<ukaz>, greater<ukaz> > moja;
  for(long s=0;s<delitel[dlzka-1];s++){
    halda P_sekvencie;
    for(int stav=0;stav<pocet_stavov;stav++){
      P_sekvencie.push(Predpocitane[predchadzajuca_sq][stav][s].first*(*B)[stav]);
    }
    vrchol* g=new vrchol(sum(P_sekvencie),s);
    ukaz s(g);
    moja.push(s);
  }
  //novy Aktual
  vrchol* v1=new vrchol();
  ukaz s(v1);
  moja.push(s);//vlozi vrchol kodujuci koniec sekvencie
  return moja;
}














