//---------------------------------------------------------------------------
#include <stdio.h>  // printf
#include <stdlib.h> // atoi, random
#include <string.h>
#include <time.h>
#include <sys\timeb.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <math.h>

#include "tboolfnct.h"
#include "boom.h"
#include "tpfnct.h"

#define POCET_POKUSU_OUTPUT 1
#define DELKA_NAZVU_STAVU 16
#define VYPIS_CASU
//#define LADICI_HLASENI
//#define VYPIS_TERMU
//#define VYPIS_CHYBEJICICH_TERMU
//#define VYPIS_NAHOD
#define random(n)	(rand()%(n))

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

class THash_Polozka
{
public:
  TPfnct * fnct;                // Budu pouzivat Tpfcnt fyzicky z TBoolfcnt kvuli mistu.
  THash_Polozka * next;
  THash_Polozka();
private:
};

class THash_Seznam_Polozek
{
public:
  THash_Seznam_Polozek* next;
  long index;  // index do Thash_Tabulka->tabulka[]  -- kvuli DeleteTerm. pokud budem mazat prvni, tak abychom mohli zmenit primo tabulka[]
  THash_Seznam_Polozek();
  ~THash_Seznam_Polozek();
};

class THash_Tabulka
{
public:
  long pocet;
  int bitu;
  long polozek;

private:
  THash_Polozka **tabulka;
  void Push(TPfnct * ff,long kam);
  TBoolFnct *parent;
  void AddItemPrivate(TPfnct * ff, int pozice, long kam);
  THash_Seznam_Polozek* Vrat_SeznamPrivate(TPfnct * ff,THash_Seznam_Polozek* pol, int pozice,long kde);  // Vrati ukazatel na seznam kam (by patril)/patri term ff.

public:
  THash_Tabulka(int bits,TBoolFnct *parent);
  ~THash_Tabulka();
  THash_Polozka* VratPolozkuZTabulky(long index);
  void THash_Tabulka::UlozPolozkuDoTabulky(THash_Polozka *pol,long index);
  void AddItem(TPfnct * ff);
  THash_Seznam_Polozek* Vrat_Seznam(TPfnct * ff);  // Vrati ukazatel na seznam kam (by patril)/patri term ff.
  void DeleteTerm(TPfnct *ff);
  void Print();
};


class GenerateInfo
{
public:
  int bits;
  char *onmpla;
  char *onminf;
  int iv;
  int ov;
  int t;
  int mask;
  int type;  // 0 fd 1 fr
  double idc;      // prumerny
  double odc;
  double idt;
  double odt;
  double sidc;     // prvni term
  double sodc;
  double sidt;
  double sodt;
  double glidc;    // posledni term
  double glodc;
  double glidt;
  double glodt;
  int filt;
  int dupl;
  int timeout;
  int pocet_output;   // pocet navic opakovanych zkousek outputu pri generovani
  THash_Tabulka *hashtab;
  TBoolFnct *fn;
  int *tab;   // tabulka s idc,idt,idf,odc,odt,odf pro kazdy term. Pro pocitani granularity.
  void Print();
  void PrintOdchylka(GenerateInfo *gi);
  GenerateInfo(int terms);
  ~GenerateInfo();
};
GenerateInfo::GenerateInfo(int terms)
{
  int i;
  this->tab = (int *) malloc(sizeof(long) * 6 * terms);  // alokuju pole
  for (i=0;i<terms;i++)
  {
    this->tab[i*6]=this->tab[i*6+1]=this->tab[i*6+2]=this->tab[i*6+3]=this->tab[i*6+4]=this->tab[i*6+5]=0;
  }
}

GenerateInfo::~GenerateInfo()
{
  delete this->tab;
}


void GenerateInfo::Print()
{
  printf("Vstupu: %4d Vystupu: %4d Termu: %4d\n",this->iv,this->ov,this->t);
  printf("Prumerne rozlozeni:\n");
  printf("Vstupni %% dont-care: %3.0f Vystupni %% dont-care: %3.0f\n",this->idc,this->odc);
  printf("Vstupni %% '1':       %3.0f Vystupni %% '1':       %3.0f\n",this->idt,this->odt);
  printf("Vstupni %% '0':       %3.0f Vystupni %% '0':       %3.0f\n",100-this->idt,100-this->odt);
  printf("Linearni rozlozeni:\n");
  printf("Vstupni %% dc : %3.0f - %3.0f Vystupni %% dc : %3.0f - %3.0f\n",this->sidc,this->glidc,this->sodc,this->glodc);
  printf("Vstupni %% '1': %3.0f - %3.0f Vystupni %% '1': %3.0f - %3.0f\n",this->sidt,this->glidt,this->sodt,this->glodt);
}
void GenerateInfo::PrintOdchylka(GenerateInfo *gi)
{
  printf("Odchylky pocitane se zadanym:\n" );
  printf("Vstupni %% dont-care: %3.0f ",gi->glidc==-1?this->idc-gi->idc:this->idc-((gi->sidc+gi->glidc)/2));
  printf("Vystupni %% dont-care: %3.0f\n",gi->glodc==-1?this->odc-gi->odc:this->odc-((gi->sodc+gi->glodc)/2));
  printf("Vstupni %% '1'      : %3.0f ",gi->glidt==-1?this->idt-gi->idt:this->idt-((gi->sidt+gi->glidt)/2));
  printf("Vystupni %% '1'      : %3.0f\n",gi->glodt==-1?this->odt-gi->odt:this->odt-((gi->sodt+gi->glodt)/2));
  printf("Vstupni %% '0'      : %3.0f ",gi->glidt==-1?gi->idt-this->idt:((gi->sidt+gi->glidt)/2)-this->idt);
  printf("Vystupni %% '0'      : %3.0f\n",gi->glodt==-1?gi->odt-this->odt:((gi->sodt+gi->glodt)/2)-this->odt);
  if ( (gi->glidc!=-1) || (gi->glidt!=-1) || (gi->glodc!=-1) || (gi->glodt!=-1) )
  printf("Zadane linearni rozlozeni puvodniho:\n");
  if (gi->glidc!=-1) printf("Vstupni %% dc   : %3.0f - %3.0f\n",gi->sidc,gi->glidc);
  if (gi->glodc!=-1) printf("Vystupni %% dc  : %3.0f - %3.0f\n",gi->sodc,gi->glodc);
  if (gi->glidt!=-1) printf("Vstupni %% '1'  : %3.0f - %3.0f\n",gi->sidt,gi->glidt);
  if (gi->glodt!=-1) printf("Vystupni %% '1' : %3.0f - %3.0f\n",gi->sodt,gi->glodt);

}

THash_Polozka* THash_Tabulka::VratPolozkuZTabulky(long index)
{
  return this->tabulka[index];
}

void THash_Tabulka::UlozPolozkuDoTabulky(THash_Polozka *pol,long index)
{
  this->tabulka[index] = pol;
}

THash_Seznam_Polozek::THash_Seznam_Polozek()
{
 this->next = NULL;
 this->index = 0;
}

THash_Seznam_Polozek::~THash_Seznam_Polozek()
{
  if ( this == NULL ) return;
  if ( this->next != NULL )
  {
    delete this->next;
  }
}

THash_Polozka::THash_Polozka()
{
  this->next = NULL;
  this->fnct = NULL;
}

THash_Tabulka::THash_Tabulka(int bits,TBoolFnct *parent)
{
  long i;
  this->bitu=bits;
  this->parent=parent;
  this->polozek=1 << bits;
  this->pocet=0;
  this->tabulka = (THash_Polozka * *) malloc(sizeof(THash_Polozka *) * polozek);  // alokuju pole
  for (i=0;i<polozek;++i)
  {
    this->tabulka[i]=NULL;
  }
}

THash_Tabulka::~THash_Tabulka()         // Znici jen strukturu THash_Tabulka, fnct zustanou v TBoolfnct
{
  THash_Polozka * pol, * pol2;
  long i;
  if ( this == NULL ) return;
  for (i=0;i<this->polozek;++i)
  {
    pol = this->tabulka[i];
    while ( pol != 0 )
    {
      pol2 = pol->next;
      delete pol;
      pol = pol2;
    }
  }
}

void THash_Tabulka::Push(TPfnct * ff,long kam)
{
	THash_Polozka *novy;
	novy = new THash_Polozka;
	novy->fnct = ff;
	novy->next = this->tabulka[kam];
  this->tabulka[kam]=novy;
  this->pocet++;
}

void THash_Tabulka::AddItem(TPfnct * ff )
{
  this->AddItemPrivate(ff,0,0);
}

void THash_Tabulka::AddItemPrivate(TPfnct * ff, int pozice, long kam)
{
  if ((pozice == this->parent->inpvars ) || (pozice==this->bitu))
  {
    this->Push(ff,kam);
  }
  else
  {
    kam = kam << 1;
    if (ff->iv[pozice]=='-')
    {
      this->AddItemPrivate(ff,pozice+1,kam);
      this->AddItemPrivate(ff,pozice+1,kam+1);
    }
    else if (ff->iv[pozice]=='0') { this->AddItemPrivate(ff,pozice+1,kam); }
    else if (ff->iv[pozice]=='1') { this->AddItemPrivate(ff,pozice+1,kam+1); }
  }
}

THash_Seznam_Polozek* THash_Tabulka::Vrat_Seznam(TPfnct * ff)
{
  THash_Seznam_Polozek* pol;
  pol=NULL;
  pol = this->Vrat_SeznamPrivate(ff,pol,0,0);
  return pol;
}


THash_Seznam_Polozek* THash_Tabulka::Vrat_SeznamPrivate(TPfnct * ff,THash_Seznam_Polozek* pol, int pozice, long kde)
{
  THash_Seznam_Polozek* pol2;
  if ((pozice == this->parent->inpvars) || (pozice==this->bitu))
  {
    pol2 = new THash_Seznam_Polozek;
    pol2->next = pol;
    pol2->index=kde;
    return pol2;
  }
  else
  {
    kde = kde << 1;
    if (ff->iv[pozice]=='-')
    {
      pol = this->Vrat_SeznamPrivate(ff,pol,pozice+1,kde);
      pol = this->Vrat_SeznamPrivate(ff,pol,pozice+1,kde+1);
    }
    else if (ff->iv[pozice]=='0') { pol = this->Vrat_SeznamPrivate(ff,pol,pozice+1,kde); }
    else if (ff->iv[pozice]=='1') { pol = this->Vrat_SeznamPrivate(ff,pol,pozice+1,kde+1); }
  }
  return pol;
}




void THash_Tabulka::DeleteTerm(TPfnct *ff)

{

    THash_Seznam_Polozek *ff1,*ff1n;

    THash_Polozka *ff2,*ff2n,*ff3,*ff4;
    int brk;

    ff1=NULL;
    ff1n=ff1=this->Vrat_Seznam(ff);
    while (ff1!=NULL)
    {
        ff2n=ff2=this->VratPolozkuZTabulky(ff1->index);
        brk=0;
        while ((ff2!=NULL) && (brk==0))
        {
          if (ff2->fnct == ff)
          {
            brk=1;
            if ( ff2n == ff2 )
            {
              this->tabulka[ff1->index] = ff2->next;
              ff2->next = NULL;
              delete ff2;
              ff2 = this->tabulka[ff1->index];
              ff3 = ff2;
              this->pocet--;
            }
            else
            {
              ff4 = ff2->next;
              ff2->next = NULL;
              delete ff2;
              ff3->next = ff4;
              ff2 = ff4;
              this->pocet--;
            }
          }
          else
          {
            ff3=ff2;
            ff2=ff2->next;
          }
        }
        ff1=ff1->next;
    }
    delete ff1n;
}


void THash_Tabulka::Print()

{
  THash_Polozka * pol;
  int i;
  for (i=0;i<this->polozek;++i)
  {
    pol = this->tabulka[i];
    printf ("%d - ",i);
    while ( pol != 0 )
    {
      printf("%s*%s",pol->fnct->iv,pol->fnct->ov);
      pol = pol->next;
      if (pol) printf(",");
    }
    printf("\n");
  }
  printf("\n");
}



int NewGauge( char * name, int max, int context )
{
  return 0;
}

void CloseGauge()
{
}

int GaugeStep( int val, int context )
{
  return 0;
}

void help()
{
  fprintf( stderr, "syntax: genpla -i n -o n -t n [-idc n] [-odc n] [-idt n] [-odt n] [-glidc n] [-glodc n] [-glidt n] [-glodt n] [-NC] [-IN] [-L] [-timeout n] [file_name]\n" );
  fprintf( stderr, "   -i n        Specify the number of inputs\n" );
  fprintf( stderr, "   -o n        Specify the number of outputs\n" );
  fprintf( stderr, "   -t n        Specify the number of defined terms\n" );
  fprintf( stderr, "   -h n        Specify the number of hash bits. 0 is default\n" );
  fprintf( stderr, "   -idc n      Specify the percentage of input don't cares. 0 is default\n" );
  fprintf( stderr, "   -odc n      Specify the percentage of output don't cares. 0 is default\n" );
  fprintf( stderr, "   -idt n      Specify the percentage of input ones. 50 is default\n" );
  fprintf( stderr, "   -odt n      Specify the percentage of output ones. 50 is default\n" );
  fprintf( stderr, "   -gl[x] n    Linear granularity, if defined specify gl[x] at the end term and\n");
  fprintf( stderr, "               [x] at the first term. [x] is default (no granularity).\n" );
  fprintf( stderr, "               as [x] use 'idc','odc','idt' or 'odt'\n" );
  fprintf( stderr, "   -timeout n  The timeout limit, in seconds. 1000s is the default\n" );
  fprintf( stderr, "   -NC         The consistency check is not performed. PLA type fd is generated\n" );
  fprintf( stderr, "   -ND         The duplicity check is not performed.\n" );
  fprintf( stderr, "   -IN         Print info about generated terms\n" );
  fprintf( stderr, "   -L          Load PLA from file and print info about it\n" );
}

void RandomFillOneFnct(THash_Tabulka *htab, TBoolFnct *srcf, TPfnct *ff, double r, double r2, int mask)
{
    int i,v;

    ff->dim=0;
    if ((mask & 1) == 1)
    {
      for (i = 0; i < srcf->inpvars; i++)
      {
        v = random(100);
        if (v < r) {
            ff->iv[i] = '-';
            ff->dim++;
        } else {
            v = random(100);
            if (v<r2) { ff->iv[i] = '1'; }
            else ff->iv[i] = '0';
        }
      }

    }
    if ((mask &2) == 2) for (i=0; i<srcf->outvars; i++) {
        v=random(100);
        if (v<r) {
                ff->ov[i]='-';
        } else {
            v = random(100);
            if (v<r2) { ff->ov[i] = '1'; }
            else ff->ov[i] = '0';
        }
    }
}

int DoPostChecks(THash_Tabulka *htab, TBoolFnct *fn, TPfnct *ffl,int filt,int dupl)   // dela kontrolu validity 0-OK, 1-dupl,2-inkonzistent
{
  THash_Seznam_Polozek *ff1,*ffn;
  THash_Polozka* ff2;
  int i,brk;

  if ((filt==0) && (dupl==0)) {
	return 0;
  }
  ff1=ffn=NULL;
  if (ffl!=NULL)
  {
    ffn=ff1=htab->Vrat_Seznam(ffl);
      while (ff1!=NULL)
      {
        ff2=htab->VratPolozkuZTabulky(ff1->index);
        while (ff2!=NULL)
        {
          if (ff2->fnct->valid==1) {
            // duplicity
			if ((dupl) && (strcmp(ffl->iv,ff2->fnct->iv)==0) && (strcmp(ffl->ov,ff2->fnct->ov)==0) ) {
				return 1;
			}
			// konzistence
			if (filt) {
				brk=0;
	            for (i=0; i<fn->inpvars; i++) {
	                if (ffl->iv[i]!=ff2->fnct->iv[i] && ffl->iv[i]!='-' && ff2->fnct->iv[i]!='-') {
						brk=1;
						break;
					}
				}
				if (brk==0)
				{
					for (i=0; i<fn->outvars; i++)
					{
						if (ffl->ov[i]!=ff2->fnct->ov[i] && ffl->ov[i]!='-' && ff2->fnct->ov[i]!='-')
						{
							return 2;
						}
					}
				}
			}
		  }
          ff2=ff2->next;
        }
        ff1=ff1->next;
      }
    delete ffn;
  }
  return 0;
}

int RndConFillFnct( GenerateInfo *gi )
//THash_Tabulka * htab,TBoolFnct *fn, int mask, int irnd, int ornd,int idt,int odt, int filt, int to)
/*
    Randomly fills a function fn. Terms must be defined.
    mask: bit 0 == 1 -> fill input
    mask: bit 1 == 1 -> fill output
    irnd: % of input DCs
    ornd: % of input DCs
    filt == 0 -> checks only duplicity
    filt == 1 -> consistent fill (no inconsistencies)
    to: # of seconds until timeout
    returns true if succeeded
*/
{
    int zbyvajicich=0,brk,k,j;
    float skokidc,skokidt,skokodc,skokodt;
    float rnidc,rnidt,rnodc,rnodt;
    TPfnct *ff, *ffl;
    struct timeb t2, t1;

    ftime(&t2);

    RandomFillOneFnct(gi->hashtab, gi->fn, gi->fn->fnct, gi->idc, gi->idt, gi->mask & 1);
       #ifdef LADICI_HLASENI
        gi->hashtab->Print();
        gi->fn->Print();
       #endif
    RandomFillOneFnct(gi->hashtab, gi->fn, gi->fn->fnct, gi->odc, gi->odt, gi->mask & 2);
       #ifdef LADICI_HLASENI
        gi->hashtab->Print();
        gi->fn->Print();
       #endif
        ffl = ff = gi->fn->fnct;
        gi->hashtab->AddItem(ff);
        ff=ff->next;
        j=1;
        ftime(&t1);
        skokidc = 0;
        skokidt = 0;
        skokodc = 0;
        skokodt = 0;
        if (gi->t > 1)
        {
          if (gi->glidc != -1) skokidc = ((float)gi->glidc-(float)gi->sidc) / (float)(gi->t-1);
          if (gi->glidt != -1) skokidt = ((float)gi->glidt-(float)gi->sidt) / (float)(gi->t-1);
          if (gi->glodc != -1) skokodc = ((float)gi->glodc-(float)gi->sodc) / (float)(gi->t-1);
          if (gi->glodt != -1) skokodt = ((float)gi->glodt-(float)gi->sodt) / (float)(gi->t-1);
        }
        rnidc=(float)gi->sidc+skokidc;
        rnidt=(float)gi->sidt+skokidt;
        rnodc=(float)gi->sodc+skokodc;
        rnodt=(float)gi->sodt+skokodt;

        while (j < gi->t && t1.time-t2.time < gi->timeout)
        {
          if (zbyvajicich != gi->t-j)
          {
            zbyvajicich = gi->t-j;
           #ifdef VYPIS_CHYBEJICICH_TERMU
            printf("Zbyva %d termu\n",zbyvajicich);
           #endif
           #ifdef VYPIS_NAHOD
            printf("Nahody: idc-%6.2f, idt-%6.2f, odc-%6.2f, odt-%6.2f\n",rnidc,rnidt,rnodc,rnodt);
           #endif
          }
         #ifdef LADICI_HLASENI
          gi->hashtab->Print();
          gi->fn->Print();
         #endif
          RandomFillOneFnct(gi->hashtab, gi->fn, ff, rnidc, rnidt, gi->mask & 1);
          gi->hashtab->AddItem(ff);
         #ifdef LADICI_HLASENI
          gi->hashtab->Print();
          gi->fn->Print();
         #endif
          RandomFillOneFnct(gi->hashtab, gi->fn, ff, rnodc, rnodt, gi->mask & 2);
         #ifdef LADICI_HLASENI
          gi->hashtab->Print();
          gi->fn->Print();
         #endif
          ff->valid=0;
		  brk=DoPostChecks(gi->hashtab, gi->fn, ff,gi->filt,gi->dupl); // 0=consistent 1=incosnistent = must be deleted
          k=gi->pocet_output;
          while ((brk) && (k>0) && ((gi->mask & 2)==2) ) // pokud mame jeste pokusy a zajima nas output  tak zkousime menit output
          {
            --k;
            RandomFillOneFnct(gi->hashtab, gi->fn, ff, rnodc, rnodt, gi->mask & 2);
           #ifdef LADICI_HLASENI
            gi->hashtab->Print();
            gi->fn->Print();
           #endif
			brk=DoPostChecks(gi->hashtab, gi->fn, ff,gi->filt,gi->dupl); // 0=consistent 1=incosnistent = must be deleted
          }
          if (brk)       // brk1 inconsistent => mazeme z hash a budem zkouset znovu
          {
            gi->hashtab->DeleteTerm(ff);
          }
          else 
          {
            ff->valid=1;
            ffl=ff;
            ff=ff->next;
            j++;
            rnidc+=skokidc;
            rnidt+=skokidt;
            rnodc+=skokodc;
            rnodt+=skokodt;

          }
          ftime(&t1);
        }

    return (j == gi->t);
}

void GetInfo(GenerateInfo *z,TBoolFnct *fn)
{
  long indc,intr,infa,oudc,outr,oufa,inp,out,pom;
  TPfnct *ff;
  int i,j;
  float a,b,c11,c12,c21,c22,c31,c32,c41,c42,p1,p2;
  indc=intr=infa=oudc=outr=oufa=inp=out=pom=0;
  z->fn = fn;
  z->iv = fn->inpvars;
  z->ov = fn->outvars;
  z->t = fn->terms;
  ff=fn->fnct;
  j=0;
  a=b=c11=c12=c21=c22=c31=c32=c41=c42=0;
  while (ff!=NULL)
  {
    for (i=0; i<fn->inpvars; i++)
      if (ff->iv[i]=='0') { infa++; z->tab[j*6]++; }
      else if (ff->iv[i]=='1') { intr++; z->tab[j*6+1]++; }
      else if (ff->iv[i]=='-') { indc++; z->tab[j*6+2]++; }
      else if (ff->iv[i]=='~') { indc++; z->tab[j*6+2]++; }
    for (i=0; i<fn->outvars; i++)
      if (ff->ov[i]=='0') { oufa++; z->tab[j*6+3]++; }
      else if (ff->ov[i]=='1') { outr++; z->tab[j*6+4]++; }
      else if (ff->ov[i]=='~') { oudc++; z->tab[j*6+5]++; }
      else if (ff->ov[i]=='-') { oudc++; z->tab[j*6+5]++; }
    ff=ff->next;
    // konstanty pro lin regresi
    a+=(j*j);                                  // suma xi^2
    b+=j;                                      // suma xi
    c11+=j*(100*z->tab[j*6+2]/fn->inpvars);    // suma xi*yi  indc
    c12+=100*z->tab[j*6+2]/fn->inpvars;        // suma yi     indc

    p1=(float)(fn->inpvars-z->tab[j*6+2]);
    if (p1) p1=(100*z->tab[j*6+1]/p1);
    else p1 = 50;
    c21+=j*p1;                                 // suma xi*yi  intr
    c22+=p1;                                   // suma yi     intr
    c31+=j*(100*z->tab[j*6+5]/fn->outvars);    // suma xi*yi  oudc
    c32+=100*z->tab[j*6+5]/fn->outvars;        // suma yi     oudc

    p1=(float)(fn->outvars-z->tab[j*6+5]);
    if (p1) p1=(100*z->tab[j*6+4]/p1);
    else p1 = 50;

    c41+=j*p1;                                 // suma xi*yi  outr
    c42+=p1;                                   // suma yi     outr

    j++;
  }
  inp = z->iv*z->t;
  out = z->ov*z->t;
  z->idc = 100*indc / inp;
  z->odc = 100*oudc / out;
  pom=inp-indc;
  if (pom)
  {
    z->idt = 100*intr / pom;
  }
  else
  {
    z->idt = -1;
  }
  pom=out-oudc;
  if (pom)
  {
    z->odt = 100*outr / pom;
  }
  else
  {
    z->odt = -1;
  }
  // Zjistovani lin granularity pomoci linearni regrese, metodou nejmensich ctvercu.
  // idc
  p2= (b*c11-a*c12)/(b*b-z->t*a);
  p1= (c11-p2*b)/a;
  z->sidc=p2;
  z->glidc=p1*(z->t-1)+p2;
  // idt
  p2= (b*c21-a*c22)/(b*b-z->t*a);
  p1= (c21-p2*b)/a;
  z->sidt=p2;
  z->glidt=p1*(z->t-1)+p2;
  //odc
  p2= (b*c31-a*c32)/(b*b-z->t*a);
  p1= (c31-p2*b)/a;
  z->sodc=p2;
  z->glodc=p1*(z->t-1)+p2;
  //odt
  p2= (b*c41-a*c42)/(b*b-z->t*a);
  p1= (c41-p2*b)/a;
  z->sodt=p2;
  z->glodt=p1*(z->t-1)+p2;

}

int main( int argc, char * argv[] )
{
  int i;
  int cas,load,info,ready;
  struct timeb t2, t1;

  ftime(&t2);

  Boom * boominst;
  GenerateInfo *gi,*gg;

  boominst = new Boom();
  boominst->gauge.NewGauge = NewGauge;
  boominst->gauge.CloseGauge = CloseGauge;
  boominst->gauge.GaugeStep = GaugeStep;

  srand((unsigned int)time((time_t *)NULL));
  gi = new GenerateInfo(0);
  gi->pocet_output = POCET_POKUSU_OUTPUT;
  gi->bits = 0;
  gi->onmpla = 0;
  gi->onminf = 0;
  gi->iv = -1;
  gi->ov = -1;
  gi->t = -1;
  gi->idc = 0;
  gi->odc = 0;
  gi->idt = 50;
  gi->odt = 50;
  gi->glidc = -1;
  gi->glodc = -1;
  gi->glidt = -1;
  gi->glodt = -1;
  gi->filt = 1;
  gi->dupl = 1;
  gi->timeout = 1000;
  gi->mask = 3;

  i = 1;
  load = 0;
  info = 0;
  ready = 0;

  fprintf( stderr, "PLA Generator 2.11, (c) May 2008\n\n" );
  while ( i != argc )
  {
    if ( argv[i] [0] == '-' )
    {
        if ( strcmp(argv[i], "-i") == 0)
            gi->iv = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-o") == 0)
            gi->ov = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-t") == 0)
            gi->t = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-h") == 0)
        {
            gi->bits = atoi( argv[++i] );
            gi->bits=gi->bits>16?16:gi->bits;
        }
        else if ( strcmp(argv[i], "-p") == 0)
			gi->pocet_output = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-idc") == 0)
            gi->idc = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-odc") == 0)
            gi->odc = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-idt") == 0)
            gi->idt = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-odt") == 0)
            gi->odt = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-glidc") == 0)
            gi->glidc = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-glodc") == 0)
            gi->glodc = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-glidt") == 0)
            gi->glidt = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-glodt") == 0)
            gi->glodt = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-timeout") == 0)
            gi->timeout = atoi( argv[++i] );
        else if ( strcmp(argv[i], "-NC") == 0)
            gi->filt = 0;
        else if ( strcmp(argv[i], "-ND") == 0)
            gi->dupl = 0;
        else if ( strcmp(argv[i], "-IN") == 0)
            info = 1;
        else if ( strcmp(argv[i], "-L") == 0) {
            load = 1;
            info = 1; }
        else {
            fprintf( stderr, "Unknown parameter %s\n", argv[i] );
            exit( 1 );
        }
    } else
      gi->onmpla = argv[i];
    i++;
  }

  gi->sidc = gi->idc;
  gi->sodc = gi->odc;
  gi->sidt = gi->idt;
  gi->sodt = gi->odt;

  if (( gi->iv == -1 || gi->ov == -1 || gi->t == -1 ) && (load==0)) help();
  else
  {

    if (load)
    {
      if (gi->fn=gi->fn->LoadFnct(gi->onmpla,boominst->gauge))
      { ready=1; }
      else fprintf(stderr, "Cannot open file \"%s\"",gi->onmpla);
    }
    else
    {
      gi->fn = new TBoolFnct( gi->iv, gi->ov, gi->t, gi->filt );
      gi->fn->FillEmptyFnct();
      gi->fn->NameVars();
      gi->hashtab = new THash_Tabulka(gi->bits,gi->fn);
      if ( RndConFillFnct( gi ) )
         {
           gi->fn->SaveFnct( gi->onmpla, boominst->gauge, boominst->go);
           ready=1;
         }
      else fprintf( stderr, "Timeout\n" );
    }
    if (info && ready)
    {
      gg = new GenerateInfo(gi->fn->terms);
     #ifdef VYPIS_TERMU
      gi->fn->Print();
     #endif
      GetInfo(gg,gi->fn);
      gg->Print();
      if (!load) gg->PrintOdchylka(gi);
      delete gg;
	}
    ftime(&t1);
    cas=t1.time*1000+t1.millitm-t2.time*1000-t2.millitm;
#ifdef VYPIS_CASU
	  printf("Program was runnig: %.3f sekund.",(float)cas/1000);
#endif

    delete gi->fn;
    if (!load) delete gi->hashtab;
    delete gi;

  }
  return 0;
}
