#include "hlavicka.h"
typedef priority_queue<ukaz,vector<ukaz>, greater<ukaz> > halda_vrcholov;


int main(int argc,char** argv){// 1. param je subor s Modelom 
//2. param je po kolko pismen sa koduje
//3. param je subor s abecedou
//4. ci komprimuje

ifstream subor(argv[1], ifstream::in);

Model M(&subor); //nacita model zo suboru kt. meno dostane ako parameter  
subor.close();
cerr << endl << " Po konstrukciii" << endl;
int dlzka_kod_post;//po kolko sa bude kodovat
istringstream stm;
stm.str(argv[2]);
stm >> dlzka_kod_post;
cerr << dlzka_kod_post << endl;
int kom;
{
  istringstream stm2;
  stm2.str(argv[4]);
  stm2 >> kom;
}
cerr << kom << endl;
cerr << "ahoj " << kom << endl;
bool komprimuj=(kom==1);
cerr << "ahoj" << endl;
//M.vypis_sa();
//return 0;
//M.napln();
M.predpocitaj(dlzka_kod_post);
//M.vypis_sa();
cerr << "ahoj" << endl;
M.reset();
cerr << "ahoj" << endl;
//return 0;
if(komprimuj){
  cerr << "komprimujem" << endl;
  /*
  -nacitavam pismena kym nemam dost
  -ked mam dost nacitanych,vypocitam cislo sekvencie (moze sa to robit aj priebezne, ale naco?)
  -pokial som nezacal komprimovat, zapisem # a nastavim ze som zacal
  -necham postavit stromcek a najdem kod sekvencie
  -nastavim novy Aktual a pokracujem v nacitavani
  -pokial nacitam nieco, co sa nekoduje, zakodujem koniec sekvencie a doplnim nulami
  -co pride, pisem na vystup (komprimovatelne znaky pisem az ked nacitam iny) kym opat nenacitam dost a potom zapisem # a zacnem komprimovat
  */
  
  //TODO nacitanie abecedy
  kod_abeceda kod;
  dek_abeceda dek;
  ifstream subor_kod_abeceda(argv[3],ifstream::in);
  char p;
  int c;
  while(subor_kod_abeceda >> p >> c){
    kod.insert(make_pair(p,c));
  }
  subor_kod_abeceda.close();
  cerr << "abeceda nacitana" << endl;    
  unsigned char pismeno;
  int pocet_pismen=M.pocet();
  vv_bool vystup;
  vv_sek vstup(dlzka_kod_post,pocet_pismen,&kod,&dek);
  cerr << "vsetko pripravene na nacitavanie" << endl;   
  // M.vypis_sa();
  cerr << dlzka_kod_post << " " << pocet_pismen << endl;
  
  
  while(cin >> pismeno){    
    if(vstup.ber(pismeno)){//vrati true ak ma dost na zapis sekvencie
      long sekvencia=vstup.daj();
      // cerr << "idem spracovat sekvenciu "<< sekvencia << endl;
      halda_vrcholov vrcholy=	M.vrat(sekvencia);
      vrchol* v=urob_stromcek_zdola(vrcholy,sekvencia);//tu budem mat ulozeni smernik na vrchol kt. koduje danu sekvenciu, ohodnotim pocas stavby stromceka
      vector<bool> kod=koduj(v);//zavola aj desktruktor
      vystup.pis(kod);
      //  cerr << "spracovana" << endl;
    }
    if(vstup.koniec()){//ukonci vypis komprimovanej sekvencie a nastavi boolovu hodnotu v vstup na false
      //pouzije sa ked vstup nacita "nieco" skarede a potrebuje ukoncit komprimovaciu
      if(vstup.zacal()){
	halda_vrcholov vrcholy=M.vrat(0);
	vrchol* v=urob_stromcek_koniec(vrcholy);// tu budem mat smernik na vrchol kodujuci ukoncenie komprimacie
	vector<bool> kod=koduj(v);
	M.reset();
	vystup.pis(kod);//zapise
	vystup.ukonci_vystup();//doplni nulami a vyprazdni frontu
      }
      vstup.ukonci();//vypise co mal nacitane a nakoniec vypise znak ktory vo vstup "cakal" na ukoncenie komprimovacieho vystupu
    }
  }
  cerr << "idem ukoncit kodovanie genomu " << endl;
  if(vstup.zacal()){
    halda_vrcholov vrcholy=M.vrat(0);
    cerr << "este1" << endl;
    vrchol* v=urob_stromcek_koniec(vrcholy);// tu budem mat smernik na vrchol kodujuci ukoncenie komprimacie
    cerr << "este2" << endl;
    cerr << v << endl;
    vector<bool> kod=koduj(v);
    M.reset();
    vystup.pis(kod);//zapise
    vystup.ukonci_vystup();//doplni nulami a vyprazdni frontu
  }
}else{
  unsigned char pismeno;
  int pocet_pismen=M.pocet();
  ifstream subor_kod_abeceda(argv[3],ifstream::in);
  kod_abeceda kod;
  dek_abeceda dek;
  char p;
  int c;
  while(subor_kod_abeceda >> c >> p){
    dek.insert(make_pair(c,p));
  }
  
  vv_sek vystup(dlzka_kod_post,pocet_pismen,&kod,&dek);
  bool dekod=false;
  halda_vrcholov vrcholy;
  vrchol* v=0;
  vrchol* zmaz=0;
  while(cin >> pismeno){
    if(!dekod){//ak este nedekoduje
      if(pismeno=='#'){ 
	dekod=true;
	vrcholy=M.nova();
	v=urob_stromcek_zhora(vrcholy);
	zmaz=v;
      }
      else cout << pismeno;
    }else{
      bool este=true;
      for(int i=0;i<8;i++){
	if(este){
	  //najprv zide a potom testuje, ci nie je v liste
	  bool pom=((pismeno & 128)==128);
	  pismeno=(pismeno << 1);
	  if(pom){//chod do praveho syna
	    v=v->p_syn();
	  }else{//inak do laveho
	    v=v->l_syn();
	  }
	  //cerr << "som v : " << v << endl;
	  if(v->som()){
	    //long sek=v->sekvencia();
	    /*ak je list:
	    1, vypis sekvenciu
	    2, nastav novy Aktual
	    3, urob novy stromcek
	    */
	    if(v->koncim()){
	      cerr << "koncim" << endl;
	      este=false;
	      M.reset();
	      if (zmaz==0) cerr << "main.C 147" << endl;
	      zmaz->zmaz();
	      delete zmaz;
	      dekod=false;
	    }else{
	      long sekv=v->sekvencia();
	      vystup.pis(sekv);
	      M.novy_A(sekv);
	      vrcholy=M.nova();
	      v=urob_stromcek_zhora(vrcholy);
	      if (zmaz==0) cerr << "main.C 156" << endl;
	      zmaz->zmaz();
	      delete zmaz;
	      zmaz=v;
	    }
	  }
	}
      }
      
    }
  }
  cerr << "Ukoncene bez spadnutia. Hurra!" << endl;
}
return 0;
}