//---------------------------------------------------------------------------
#pragma hdrstop
#include "Generator.h"
#pragma package(smart_init)
//----------------------Genererings funktioner--------------------------------//
///Funktionen står for hele konstrollen med genererings processe.
///Frekvens: antallet af gange der skal gå forend et nyt sæt indekser skal
///beregnes.
///Styrken: ANtallet af gange som en relation må blive forsøgt lagt.
///Type: Angiver om projektet allerede tidligere har været genereret.
bool Generator::Generer(int frekvens, int Styrke, int col_, int row_, int type, bool Skrivebeskyttet)
{
    Tid Total, Del;
    double Tid(0);
    Beskyttet = Skrivebeskyttet;
    ++Total;
    if(type == 1)
      TidligereGenereret = true;
    else
      TidligereGenereret = false;

    k->AendreStyrke(Styrke);
    p->AendreGraenser(col_, row_);
    int col_gem = col;
    int row_gem = row;
    col = col_;
    row = row_;

    ++Del;
    if(KontrollerLister())
    {
      --Del;
      Del >> Tid;
      comm.IndsaetISpecifikation(Tid, "Kontrol af lister", 1);
      ++Del;
      if(KlargoerTilGenerering1Del())
      {
        --Del;
        Del >> Tid;
        comm.IndsaetISpecifikation(Tid, "Klargoering til 1 del", 2);
        IndexTidligereBeregnet = false;
        ++Del;
        while(Session1Del(frekvens));
        --Del;
        Del >> Tid;

        comm.IndsaetISpecifikation(Tid, "Lægning af HLPL relationer:", 3);

        ++Del;
        KlargoerTilGenerering2Del();
        --Del;
        Del >> Tid;
        comm.IndsaetISpecifikation(Tid, "Klargør til anden del:", 4);
        IndexTidligereBeregnet = false;
        ++Del;
        while(Session2Del(frekvens));
        --Del;
        Del >> Tid;
        comm.IndsaetISpecifikation(Tid, "Lægning af HLP relationer:", 5);

        col = col_gem;
        row = row_gem;
        p->AendreGraenser(col_gem, row_gem);
        ++Del;
        if(!p->KontrollerSkemaer())
          comm.FejlBox("Der er uoverensstemmelser i skemaerne");
        --Del;
        Del >> Tid;
        comm.IndsaetISpecifikation(Tid, "Kontrol af skemaer: ", 6);
        --Total;
        Total >> Tid;
        comm.IndsaetISpecifikation(Tid, "Total tid:", 7);
        return true;
      }
    }
    col = col_gem;
    row = row_gem;
    p->AendreGraenser(col_gem, row_gem);
    --Del;
    --Total;
    if(p->KontrollerSkemaer())
      comm.FejlBox("Skemaer stemmer ikke overens!");
    return false;
}//
//----------------------------------------------------------------------------//
///Funktionen varetager lægningsprocessen af anden del. DVS HLP relationer.
bool Generator::Session2Del(int frekvens)
{
    bool ok = true;
    if(!IndexTidligereBeregnet)
    {
      k->BeregnIndex(1, 's');  cout << "1 ";
      k->BeregnIndex(3, 's');  cout << "3 ";
      k->BeregnIndex(5, 's');  cout << "5 ";
      k->BeregnIndex(2, 's');  cout << "2 ";
      k->BeregnIndex(6, 's');  cout << "6 ";
      k->SorterVvaerdi('s');   cout << "S ";
    }
    for(int i = 0; i < frekvens && ok; i++)
    {
      //næste relation hentes.
      if(k->HentNaestePaLaeggeListen(HoldID, FagID, LaererID, LokaleTypeID, LokaleID,
                                     blok, 's', PL))
      {
        //hvis den ikke er den samme som den forrige.
        if(!(ForrigeHoldID == HoldID && ForrigeLaererID == LaererID && ForrigeFagID == FagID))
        {
          RelationsType = "HLP";
          LL = 0;
            LaegRelation();
          if(LL > 0)
            k->OpdaterLagteLektioner(LL, 's');
          ForrigeHoldID = HoldID;
          ForrigeLaererID = LaererID;
          ForrigeFagID = FagID;
          IndexTidligereBeregnet = !(LL > 0);
          ok = true;
        }
        else
        {
          ok = true;
          IndexTidligereBeregnet = true;
        }
      }
      else ok = false;
    }
    return ok;
}//
///Funktionen klargøre til generingens dasen 2 del.
void Generator::KlargoerTilGenerering2Del()
{
    k->BeregnLagteLektioner(1, 's'); cout << "1 ";//hold
    k->BeregnLagteLektioner(3, 's'); cout << "3 ";//lærer
    k->BeregnLagteLektioner(5, 's'); cout << "5 ";//lokaletype
    k->BeregnLagteLektioner(2 ,'s'); cout << "2 ";//fag
}//
///Funktionen varetager lægnings processen i første del.
bool Generator::Session1Del(int frekvens)
{
    bool ok = true;

    if(!IndexTidligereBeregnet)
    {
      k->BeregnIndex(1, 'b'); cout << "1 ";
      k->BeregnIndex(3, 'b'); cout << "3 ";
      k->BeregnIndex(4, 'b'); cout << "4 ";
      k->BeregnIndex(2, 'b'); cout << "2 ";
      k->BeregnIndex(6, 'b'); cout << "6 ";
      k->SorterVvaerdi('b');  cout << "S ";
    }
    for(int i = 0; i < frekvens && ok; i++)
    {
      //hvis der er flere HLP relationer at lægge.
      if(k->HentNaestePaLaeggeListen(HoldID, FagID, LaererID, LokaleTypeID, LokaleID,
                                     blok, 'b', PL))
      {
        //hvis det ikke er det samme som sidste.
        if(!(ForrigeHoldID == HoldID && ForrigeLaererID == LaererID && ForrigeFagID == FagID))
        {
          RelationsType = "HLPL";
          //Hvis relationen ikke har et lokale.. FIndes et til den.
          if(LokaleID == "tom" && !k->FindLokaleTilLokaleType(LokaleTypeID, LokaleID))
            return false;
          LL = 0;
          LaegRelation();
          k->OpdaterLagteLektioner(LL, 'b');
          ForrigeHoldID = HoldID;
          ForrigeLaererID = LaererID;
          ForrigeFagID = FagID;
          IndexTidligereBeregnet = !(LL > 0);
          ok = true;
        }
        else
        {
          ok = true;
          IndexTidligereBeregnet = true;
        }
      }
      else ok = false;
    }
    return ok;
}//
///Funktionen klargører til første delen.
bool Generator::KlargoerTilGenerering1Del()
{
    if(!TidligereGenereret && k->Indlaes(6));
    else if(!TidligereGenereret)
    {
      comm.FejlBox("Fejl: Det er ikke muligt at lave lægge listen", "Genereringen er stoppet!");
      return false;
    }
    if(k->OpdelEfterSpecialLokaler())
    {
      k->BeregnLagteLektioner(1, 'b');//hold
      k->BeregnLagteLektioner(3, 'b');//lærer
      k->BeregnLagteLektioner(4, 'b');//lokaletype
      k->BeregnLagteLektioner(2 ,'b'); //fag
    }
    return true;
}//
///Funktionen kontrollere indledende om liste 7 og 8 er i orden.
bool Generator::KontrollerLister()
{
    if(!TidligereGenereret && k->Indlaes(8) && k->Indlaes(9))
    {
      if(k->FindLokalerTilHold())
      {
        if(k->FindLaererTilHold())
        {
          if(!Beskyttet && k->Gem(7) && k->Gem(8))
            return true;
          else if(Beskyttet) return true;
        }
      }
    }
    else if(TidligereGenereret)
      return true;
    else
      comm.FejlBox("Genereringen er stoppet\n da det ikke var muligt at indlæse LokaleHold og HoldLaererRelationen");
    return false;
}//
//-----------------------Funktioner til at lægge en relation------------------//
///Funktionen varetager kontrollen med lægings processen af en relation.
bool Generator::LaegRelation()
{
    NytASkema(blok);

    if(blok == 1 && PL < col)
    {
      if(!LaegEnkelt())
      {
        a->AendreBlokTil(2);
        blok = 2;
        return LaegDobbelt(1);
      }
      return true;
    }
    else if(blok == 1 && PL >= col)
    {
      //Forsøger at lægge dem som i dobbelt lektioner først
      a->AendreBlokTil(2);
      blok = 2;
      if(!LaegDobbelt())
      {
        a->AendreBlokTil(1);
        blok = 1;
        return LaegEnkelt(1);
      }
      return true;
    }
    else if(blok == 2)
    {
      if(!LaegDobbelt())
      {
        a->AendreBlokTil(1);
        blok = 1;
        return LaegEnkelt(1);
      }
      return true;
    }
}//
///Funktionen forsøger at lægge relationen som en enkel lektioner.
bool Generator::LaegEnkelt(int type)
{
    LavASkema(type);

    int ML = a->AntalAfVaerdi(4) + a->AntalAfVaerdi(5);
    if(PL > ML)
    {
      if(PL < (ML + 2))
      {
        a->LaegFagLektioner(LL);
        if(a->SkabFrieLektioner())
          return a->LaegFagLektioner(LL);
      }
      a->PresSkemaOp();
      a->FindFrieFagLektioner();
      a->FjernIkkeEgnedeEnkeltFagLektioner();
      ML = a->AntalAfVaerdi(4) + a->AntalAfVaerdi(5);
      if(PL > ML)
      {
        a->LaegFagLektioner(LL);
        a->SkabFrieLektioner();
      }
      return a->LaegFagLektioner(LL);
    }
    else
      return a->LaegFagLektioner(LL);
}//
///Funktionen lægger en relation som dobbelt lektioner.
bool Generator::LaegDobbelt(int type)
{
    LavASkema(type);

    int ML = a->AntalAfVaerdi(4) + a->AntalAfVaerdi(5);
    if(PL > ML)
    {
      if(PL < (ML + 2))
      {
        a->LaegFagLektioner(LL);
        if(!a->SkabFrieDobbeltLektioner())
        {
          NytDobbeltASkema();
          if(b->SkabFrieLektioner())
            return b->LaegFagLektioner(LL);

          //Springer den ned og presser skemaet op.!
        }
        else
          return a->LaegFagLektioner(LL);
      }
      a->PresSkemaOp();
      a->FindFrieFagLektioner();
      a->FjernIkkeEgnedeDobbeltFagLektioner();
      ML = a->AntalAfVaerdi(4) + a->AntalAfVaerdi(5);
      if(PL > ML)
      {
        a->LaegFagLektioner(LL);
        if(!a->SkabFrieDobbeltLektioner())
        {
          NytDobbeltASkema();
          b->SkabFrieLektioner();
        }
      }
    }
    return a->LaegFagLektioner(LL);
}//
///Funktionen laver et analyse skema. Typen angiver om den skal lave skemaet
///helt fra bunden (0) eller kun delvist.
bool Generator::LavASkema(int type)
{
    if(type != 1)
    {
      if(RelationsType == "HLP")
        a->LavHLPSkema();
      else if(RelationsType == "HLPL")
        a->LavHLPLSkema();

      a->FindFagLektioner();
    }
    a->FindFrieFagLektioner();

    if(blok == 1)
      a->FjernIkkeEgnedeEnkeltFagLektioner();
    else if(blok == 2)
      a->FjernIkkeEgnedeDobbeltFagLektioner();
}//
///Funktionen laver et dobbelt analyse skema.
void Generator::NytDobbeltASkema()
{
    if(b != NULL)
      delete b;
    b = new AnalyseSkema(*a);
    b->LavDobbeltLektionsSkema(a);
}//
inline Generator::NytASkema(int blok)
{
    if(a != NULL)
      delete a;
    a = new AnalyseSkema(p, HoldID, FagID, LaererID, LokaleID, blok, PL, col, row);
}
//----------------------------------------------------------------------------//
///Konstruktør
Generator::Generator(KontrolListe* k_, Portal* p_, int col_, int row_, char Kilde_)
{
    a = NULL;
    b = NULL;
    k = k_;
    p = p_;
    col = col_;
    row = row_;
    Kilde = Kilde_;
    LL = 0;
    PL = 0;
    ForrigeHoldID = "tom";
    ForrigeLaererID = "tom";
    ForrigeFagID = "tom";
    TidligereGenereret = false;
    Beskyttet = false;
}//
///destructor
Generator::~Generator()
{
    delete a;
    delete b;
}//

