//---------------------------------------------------------------------------
#ifndef SkemaKontrolH
#define SkemaKontrolH
//#include <iostream.h>
#include "SkemaListe.h"
//#include "lektion.h"
//#include "hold_skema.h"
//#include "lokale_skema.h"
//#include "laerer_skema.h"
#include "comm.h"
//------------------------------Hjælpe structs--------------------------------//
///Structen indeholder 3 pointer til henholdsvis et hold, lærer og lokale skema.
struct SkemaPtr
{
	SkemaPtr(hold_skema* Hskema_ = NULL,
             laerer_skema* Lskema_ = NULL,
             lokale_skema* LOskema_ = NULL);
    void udskriv();

    hold_skema* Hskema;
    laerer_skema* Lskema;
    lokale_skema* LOskema;
};
void SkemaPtr::udskriv()
{
    cout << "\nhold " << Hskema->ID<< " ";
	Hskema->Udskriv();
    cout << "\nlaerer "  << Lskema->ID<< " ";
    Lskema->Udskriv();
    cout << "\nlokale "<< LOskema->ID<< " ";
    LOskema->Udskriv();
}
SkemaPtr::SkemaPtr(hold_skema* Hskema_,laerer_skema* Lskema_, lokale_skema* LOskema_)
{
	Hskema = Hskema_;
    Lskema = Lskema_;
    LOskema = LOskema_;
}
///structen indeholder et koordinat sæt.
struct koord
{
    koord(int col_, int row_) { col = col_; row = row_; }
    koord() {}
    indsaet(int col_, int row_) { col = col_; row = row_; }
	int col;
    int row;
};
//--------------------------skema kontrol klassen-----------------------------//
class SkemaKontrol
{
public:
  //konstruktør
    SkemaKontrol(int user_max_col_, int user_max_row_);

  //Byt funktioner
    //PreC: ID = angiver ID for det skema man ønsker at bytningen skal tage
    //udgangspunkt i, blok = blokstoerrelsen, type = angiver om det er et hold,
    //lærer eller lokale skema ID'et står for, col+row = div koordinater.
    //PostC: Funktionen vurder om det kan lade sig gøre at bytte en lektion med en anden.
	//Hvis det er muligt byttes de 2 lektioner. Alt efter udfaldet returneres en
    //sandhedsværdi.
    bool VurderOgBytLektion(string ID, int blok, char type, int fra_col,
                            int fra_row, int til_col, int til_row);

    //PreC: ID = angiver ID for det skema man ønsker at bytningen skal tage
    //udgangspunkt i, blok = blokstoerrelsen, type = angiver om det er et hold,
    //lærer eller lokale skema ID'et står for, col+row = div koordinater.
    //PostC: Funktionen vurder om det kan lade sig gøre at bytte en lektion med en anden.
	//Alt efter udfaldet returneres en sandhedsværdi.
    bool VurderBytningAfLektion(string ID, int blok, char type, int fra_col,
                                int fra_row, int til_col, int til_row);

    //PreC: ID: angiver ID'et for dte skema man ønsker at bytningen skal tage
    //udgangspunkt i, type = angiver om det er et hold,
    //lærer eller lokale skema ID'et står for, col+row = div koordinater.
    //PostC: Funktionen bytter direkte 2 lektioner med hinanden, dog stopper
    //processen hvis der ikke er nogen lektioner at flytte eller der er noget
    //forkert med dem..
    void BytLektion(string ID, char type, int fra_col, int fra_row,
                    int til_col, int til_row);

  //Opret funktioner
    ///Funktionen opretter et nyt skema dersom det ikke allerede er oprettet
    //PreC: Det bør gælde at alle skemaer til de implicerede ID'er er allerede
    //oprettet.
    //PostC: Funktionen opretter og lægger en lektion på de forskellige skemaer.
    //Alt efter udfaldet returneres en sandhedsværdi. Det bør dog bemærkes at
    //funktionen ignorere blok stoerrelsen.! og lægger alle lektioner som
    //enkelt lektioner også dem som skal være dobbelt!
    bool OpretOgLaegLektion(string HoldID, string FagID, string LaererID,
                              string LokaleID, int blok, int col, int row);

    ///Funktionen vurdere om en prioritets lektion kan placeres på lærer skemaet.
    bool VurderOgLaegPLektion(string LaererID, int prioritet, int col, int row);

    //PreC: ID = ID'et for det skema som ønskes oprettet, Type = angiver
    //hvilket skema det skal være (h, l, k). NB: ID'et må ikke være identisk
    //med et allerede oprettet skema på den pågældende liste.
    //PostC: Funktionen opretter et nyt skema dersom det ikke allerede er oprettet
    bool OpretSkema(const string& ID, char type);

  //Hent funktion
    //PreC: ID = ID'et for det skema som ønskes hentet, stack = den stack hvorpå
    //lektionerne transporteres på, Type = skema typen.
    //PostC: Funktionen henter det skema som hører til ID'et.
	//Alt efter om skemaet eksistere returneres en sandhedsværdi.
    bool HentSkema(const string& ID, stack<LektionsData*>* Stack, char type);

    //PostC: Funktionen henter det næste skema i rækken.
	//Alt efter om der er flere skemaer på listen returneres en sandhedsværdi.
    bool HentNaesteSkema(stack<LektionsData*>& Stack, char type);

    //PostC: Funktionen henter næste prioritets skemaerne på lærer listen.
	//Alt efter om der er flere tilbage returneres en sandhedsværdi.
    bool HentNaestePSkema(stack<PLektionsData*>& Stack, string& LaererID);

    //PostC: Funktionen henter en bestemt læreres prioritets skema.
    bool HentPSkema(stack<PLektionsData*>& Stack, const string& LaererID);

  //access funktioner
    //Funktionen ændre de yderste grænser for skemaerne.!
    void AendreGraenser(int col, int row) { user_max_col = col; user_max_row = row; }
    void SletAlt();
    void Reset(char type);
    bool ErLektionTom(string ID, char type, int col, int row);
    bool ErFagLektion(string HoldID, string FagID, int col, int row);
    bool ErLektionDobbelt(string ID, char type,int col, int row);

  //Optællings/beregnings funktioner
    int LagteFagLektioner(string HoldID, string FagID);
    int SkemalagteLektioner(string ID, char type);
    int LagtePLektioner(string LaererID);
    double BeregnVariansFor(const string& ID, char type);
    int AntalMellemLektioner();
	int BeregnTotaleLagteLektioner();

  //Skema Kontrol funktion
    //Funktionen kontrollere om de lektioner der ligger på hold skemaerne også
	//ligger de tilsvarende steder på lærer og lokale skemaerne.
	//Antallet af fejl optælles og en sandhedsværdi returneres herfor.
    bool KontrollerSkemaer(int& fejl, char type);

  //Udskrivs funktioner
    void UdskrivAlleSkemaer();
    void UdskrivSkema(const string& ID, char type);
    void UdskrivPSkema(const string& ID);

private:
  //Byt funktioner
    //Funktionen forsøger at finder den første lektion den møder i koordinatet på et af
	//skemaerne til relationen. Herefter returnere den en sandhedsværdi.
    bool FindEgnetBytteLektion(lektion& lPtr2, SkemaPtr& s, int til_col, int til_row);

    //Funktionen undersøger om der er en tilsvarende lektionen på det angivene skema.
	//Herefter kanalisere funktionen alt efter vurderingen videre til
	//henholdsvis en byt eller en flyt funktion.
    //Formen angiver om der kun skal vurderes, eller om der også skal byttes (v/u)
    //(v = vurder, u = udfør)
	bool BytInitialiser(string ID, int blok, char type, int fra_col,
    					int fra_row, int til_col, int til_row, char form);

    //Funktionen undersøger om det kan lade sig gøre at bytte to lektioner.
	//alt efter vTypen udføres eller vurderes kun bytningen. (v/u)
	//Alt efter udfaldet returneres en sandhedsværdi.
    bool BytningAfLektion(const lektion& lPtr1, const lektion& lPtr2,
                          const SkemaPtr& s1, const SkemaPtr& s2,
						  const koord& fra, const koord& til,
                          char vType);

    ///Funktionen bytter direkte 2 lektioner med hinanden uden overhovedet at vurdere.!
    void BytLektion(const lektion& lPtr1, const lektion& lPtr2, const SkemaPtr& s1,
                    const SkemaPtr& s2, const koord& fra, const koord& til);

  //Flyt funktioner
    //Funktionen vurdere om en lektion kan flyttes hvorefter den evt. flyttes.
    bool FlytningAfLektion(const lektion& lPtr, const SkemaPtr& s,
						   const koord& fra, const koord& til,
                           int blok, char vType);

    //Funktionen flytter direkte en lektion uden at vurdere noget.
    void FlytLektion(const lektion& lPtr, const SkemaPtr& s, const koord& fra,
                     const koord& til, int blok);

  //Basis funktioner
    void SletLektion(const SkemaPtr& s, const koord& k, int blok);
    void LaegLektion(const lektion& ptr, const SkemaPtr& s,
                           const koord& k, int blok);
    bool HentSkemaPtr(const lektion& ptr);
    bool VurderLektion(const lektion& ptr, const SkemaPtr& s, const koord& k,
                         int blok);
    bool HentLektion(lektion& Ptr, const SkemaPtr& s, const koord& k);
    bool Initialiser(string ID, lektion& Ptr, SkemaPtr& s, char type,
					 int col, int row, bool& ErTom);
    bool GodkendLektion(const lektion& Ptr, const SkemaPtr& s, int col, int row);
    
  //alm kontrol funktioner
    bool ErLektionTom(const SkemaPtr& s, const koord& k, int blok);
    bool ErDobbeltLektion(const SkemaPtr& s, const koord& k);

  //Kontrol af Koordinat funktioner
    inline bool KontrollerKoordinat(const int& col, const int& row);
    inline bool KontrollerKoordinat(const koord& k);
    bool KontrollerKoordinat(const koord& k, const int& blok);

  //variable
    SkemaPtr s, s2, s1;  //benyttes til at opbevare skema pointere.
    lektion lPtr, lPtr2; //benyttes til at tage arbejds kopier af lektioner.
    koord k, fra, til;   //koordinat sæt.
    int user_max_col, user_max_row; //brugens valgte antal dage samt lektioner.
    bool svar;

    SkemaListe<hold_skema> HS;     //Liste indeholdene alle hold skemaer
    SkemaListe<laerer_skema> LS;   //Liste indeholdene alle lærer skemaer
    SkemaListe<lokale_skema> LOS;  //liste indeholdene alle lokale skemaer.
    comm comm;  //objekt af kommunikations klassen. Adgang til brugergrænsen.!
};
#endif
