#pragma once
#include "ergebnis.h"
#include "art.h"
#include <vector>
#include "massnahme.h"
#include "gruenland.h"
#include "modell.h"
#include <algorithm>

class simulation
{
public:
    simulation( void);
    ~simulation( void);
    //struct artenqualitaet{art* art; double qualitaet;};
    //modell::masspixelergeb { int pixelID; int matrix_i; int matrix_j; vector<artenqualitaet> artenq; double kosten; double gewinn; massnahme m; };
    vector< modell::masspixelergeb> massnahmenergebnis;
    struct mapixelliste_mit_pos
    {
        vector< modell::masspixelergeb> massnahmenergebnis;
        int position;
    }; //wir für die Simulation gebraucht!
    struct mgruenland
    {
        massnahme massnahm;
        list< gruenland*> gliste;
        vector< double> faktorliste;
        vector< double> kosten;
        vector< double> gewinn;
        double hoehe_niedrig1;
        double hoehe_niedrig2;
        double hoehe_niedrig3;
        double hoehe_mittel1;
        double hoehe_mittel2;
        double hoehe_mittel3;
        double hoehe_hoch1;
        double hoehe_hoch2;
        double hoehe_hoch3;
    };
    vector< mgruenland> massnamegruenlandliste;
    struct masnahmen_position
    {
        int mas;
        int pos;
    }; //massnahme und posistion in Massnahmenliste
    struct ergebnis
    {
        vector< modell::masspixelergeb> massnahmenergebnis;
        vector< double> artenflaechen;
        vector< int> masspixel;
        vector< double> zahlung;
        vector< int> mengen;
    };
    masnahmen_position calculate_best_massnahme(
            vector< struct mapixelliste_mit_pos>& mmp,
            vector< int>& menge,
            vector< int>& pixelproma);
    double gesammtkosten(
            vector< struct mapixelliste_mit_pos>& mpos,
            vector< modell::masspixelergeb>& ergebnis,
            vector< double>& artflaechen,
            vector< int>& menge,
            vector< int>& pixelproma,
            int zeilen,
            int spalten,
            int anzahl_arten);
    //vector<vector< struct masspixelergeb> > calculate_oekologiemodell(vector<art*> artlist, vector<massnahme> mliste, vector<double> minqualitaet);

    ergebnis simulate(
            int tzahlung,
            vector< art*>& artlist,
            vector< massnahme>& mliste,
            vector< double>& minqualitaet,
            vector< double>& ziehlartqual,
            bool zahlung,
            int zeilen,
            int spalten,
            int bundeslandID,
            bool hoch,
            bool egal);
    ergebnis simulate(
            int tzahlung,
            vector< art*>& artlist,
            vector< massnahme>& mliste,
            vector< double>& gewichte,
            vector< double>& minqualitaet,
            int budget,
            bool zahlung,
            int zeilen,
            int spalten,
            int bundeslandID,
            bool hoch,
            bool egal);


ergebnis optimiere(
            int tzahlung,
            vector< art*>& artlist,
            vector< massnahme>& mliste,
            vector< double>& gewichte,
            vector< double>& minqualitaet,
            int budget,
            bool zahlung,
            int zeilen,
            int spalten,
            int bundeslandID,
            bool hoch,
            bool egal);

	ergebnis maximiereEffFlaeche( 
			int tzahlung,
            vector< art*>& artlist,
            vector< massnahme>& mliste,
            vector< double>& gewichte,
            vector< double>& minqualitaet,
            int budget,
            bool zahlung,
            int zeilen,
            int spalten,
            int bundeslandID,
            bool hoch,
            bool egal);

	void verbessere(
			int anzIt,
			double AnfTemp,
			vector<double> &zahlungenAkt,
			vector<int> &flaechenAkt,
			double &erreichteFlaeche,
			double &erreichteAusgabe,
			int tzahlung,
			vector< massnahme> &mliste,
            vector< double> &gewichte,
			int budget,
			int anzahl_arten,
			int zeilen,
            int spalten,
			vector<double> &artflaecheAkt,
			vector<vector<modell::masspixelergeb>> &massnahmenergebvectorAkt,
			vector<simulation::mapixelliste_mit_pos> &pixellisten_mit_positionAkt,
			vector< modell::masspixelergeb> &ergebnislisteAkt,
			vector<int> &pixelpromassnahmeAkt);

	void verbessereTest(
			int anzIt,
			double AnfTemp,
			CString varianteVar,
			vector<double> &zahlungenAkt,
			vector<int> &flaechenAkt,
			double &erreichteFlaeche,
			double &erreichteAusgabe,
			int tzahlung,
			vector< massnahme> &mliste,
            vector< double> &gewichte,
			int budget,
			int anzahl_arten,
			int zeilen,
            int spalten,
			vector<double> &artflaecheAkt,
			vector<vector<modell::masspixelergeb>> &massnahmenergebvectorAkt,
			vector<simulation::mapixelliste_mit_pos> &pixellisten_mit_positionAkt,
			vector< modell::masspixelergeb> &ergebnislisteAkt,
			vector<int> &pixelpromassnahmeAkt);


	//Funktionen zum Testen von Anfangsheuristiken:

	ergebnis testeAnfHeurMaxFlaeche(
			int tzahlung,
            vector< art*>& artlist,
            vector< massnahme>& mliste,
            vector< double>& gewichte,
            vector< double>& minqualitaet,
            int budget,
            bool zahlung,
            int zeilen,
            int spalten,
            int bundeslandID,
            bool hoch,
            bool egal);

	ergebnis testeSensitivitaetVerschiedenerAnfTemp(
		int tzahlung,
		vector< art*>& artlist,
		vector< massnahme>& mliste,
		vector< double>& gewichte,
		vector< double>& minqualitaet,
		int budget,
		bool zahlung,
		int zeilen,
		int spalten,
		int bundeslandID,
		bool hoch,
		bool egal);

	ergebnis testeIterationszahlAnhandBsp(
		int tzahlung,
		vector< art*>& artlist,
		vector< massnahme>& mliste,
		vector< double>& gewichte,
		vector< double>& minqualitaet,
		int budget,
		bool zahlung,
		int zeilen,
		int spalten,
		int bundeslandID,
		bool hoch,
		bool egal);

	void testeAnfHeurMaxFlaecheStatistisch(int anzWiederholungen);

	void testeVariationStatistisch(int anzWiederholungen);

	void testeIterationszahlStatistisch(int anzWiederholungen);

	//Anfangsheuristiken und Hilfsfunktionen

	static void HeurMFAstrid(vector<double> &zahlungen, 
						 	 vector<int> &flaechen, 
						     vector<double> &kostendifferenz,
							 vector<double> &kostenmax,
							 vector<int> &max_flaeche,
							 int budget,
							 int tzahlung,
							 vector < vector < modell::masspixelergeb >> &massnahmenergebvector,
							 vector< simulation::mapixelliste_mit_pos> &pixellisten_mit_position,
							 vector< modell::masspixelergeb> &ergebnisliste,
							 vector< int> &pixelpromassnahme);

	static void HeurMFBudgetwichtung(
									vector<double> &zahlungen, 
									vector<int> &flaechen, 
									CString varianteWichtung,
									CString varianteKonkAufschlag,
									vector<double> &gewichte,
									double konkFak,
									int budget,
									int tzahlung,
									vector < vector < modell::masspixelergeb >> &massnahmenergebvector,
									vector< simulation::mapixelliste_mit_pos> &pixellisten_mit_position,
									vector< modell::masspixelergeb> &ergebnisliste,
									vector< int> &pixelpromassnahme);

	static void HeurMFBudgetwichtungOhneKonku(
									vector<double> &zahlungen, 
									vector<int> &flaechen, 
									CString varianteWichtung,
									vector<double> &gewichte,
									int budget,
									int tzahlung,
									vector < vector < modell::masspixelergeb >> &massnahmenergebvector,
									vector< simulation::mapixelliste_mit_pos> &pixellisten_mit_position,
									vector< modell::masspixelergeb> &ergebnisliste,
									vector< int> &pixelpromassnahme);

	static vector<double> berechneTeilbudgets(double budget,
									   int tzahlung, 
									   CString varianteWichtung,
									   CString varianteKonku,
									   vector<double> &gewichte,
									   vector<vector<modell::masspixelergeb>> &massnahmenergebvector);

	static double berZahlung(modell::masspixelergeb &mpe, int tzahlung, double aufschlag);


	static int bestimmeIndexAusschoepfendesPixel(double budget, 
												 int tzahlung,
												 double aufschlag,
												 vector<modell::masspixelergeb> &ergebliste);

	static vector<int> berechneWunschpixelEffPixel(	vector<int> maxPosi, 
													vector<double> &gewichte,
													vector < vector < modell::masspixelergeb >> &massnahmenergebvector);

	static vector<int> berechneWunschpixelEffPixelBudget(vector<int> maxPosi, 
													int budget,
													int M_greifend,
													vector<double> &gewichte,
													vector < vector < modell::masspixelergeb >> &massnahmenergebvector);

	static vector<double> setzeWunschpixelDurch(vector<int> flaechen,
												int tzahlung,
												vector < vector < modell::masspixelergeb >> &massnahmenergebvector,
												vector< simulation::mapixelliste_mit_pos> &pixellisten_mit_position,
												vector< modell::masspixelergeb> &ergebnisliste,
												vector< int> &pixelpromassnahme);

	static vector<double> setzeWunschpixelDurchLOA(vector<int> flaechen,
												   int tzahlung,
												   int M_greifend,
												   vector < vector < modell::masspixelergeb >> &massnahmenergebvector,
													vector< simulation::mapixelliste_mit_pos> &pixellisten_mit_position,
													vector< modell::masspixelergeb> &ergebnisliste,
													vector< int> &pixelpromassnahme);

	static void HeurSukWP(vector<double> &zahlungen, 
							vector<int> &flaechen, 
							int budget,
							int tzahlung,
							int maxIt,
							CString varianteEff,
							vector<double> &gewichte,
							vector < vector < modell::masspixelergeb >> &massnahmenergebvector,
							vector< simulation::mapixelliste_mit_pos> &pixellisten_mit_position,
							vector< modell::masspixelergeb> &ergebnisliste,
							vector< int> &pixelpromassnahme);

	static void bestimmeSuchgrenzen(vector<int> &untereSG,
									vector<int> &obereSG,
									int AnzMass, 
									int AnzMassGreifAkt,
									double budget,
									int tzahlung,
									vector<int> vergebeneMass,
									vector<double> &gewichte,
									vector<vector<modell::masspixelergeb>> &massnahmenergebvector);

	//Variation von AUP

	void variiereZahlungenFlaechenAstrid(vector<double> &zahlung1,
										 vector<int> &mengeneu,
										 bool besser, bool zwischen,
										 int tzahlung,
										 vector<double> kostenmax,
										 vector<double> kostendifferenz,
										 vector<int> max_flaeche,
										 vector<vector<modell::masspixelergeb>> &massnahmenergebvector2, 
										 vector< simulation::mapixelliste_mit_pos> &pixellisten_mit_position2,
										 vector< int> &pixelpromassnahme2);

	void variiereZahlungenFlaechen(vector<double> &zahlungen,
								   vector<int> &flaechen,
								   vector<int> &AnzPixel,
								   vector<int> &erreichteFlaechen,
								   int maxAnzVeraenderterMass,
								   vector<double> minAbweichungZahlung,
								   vector<double> maxAbweichungZahlung,
								   vector<int> minAnzahlAbweichungFlaeche,
								   vector<int> maxAnzahlAbweichungFlaeche,
								   int tzahlung, 
								   vector<vector<modell::masspixelergeb>> &massnahmenergebvector, 
								   vector< simulation::mapixelliste_mit_pos> &pixellisten_mit_position,
								   vector< int> &pixelpromassnahme);

	void bestimmeSprungstufenZahlungen( vector<vector<double>> &Sprungstufen, 
										double eps,
										int tzahlung,
										vector<vector<modell::masspixelergeb>> &mev);

	void variiereZahlungenFlaechenStufen(
									   vector<vector<double>> &Sprungstufen,
									   vector<double> &zahlungen,
									   vector<int> &flaechen,
									   vector<int> &AnzPixel,
									   vector<int> &erreichteFlaechen,
									   int maxAnzVeraenderterMass,
									   vector<int> minAnzahlAbweichungFlaeche,
									   vector<int> maxAnzahlAbweichungFlaeche,
									   int tzahlung, 
									   vector<vector<modell::masspixelergeb>> &massnahmenergebvector, 
									   vector< simulation::mapixelliste_mit_pos> &pixellisten_mit_position,
									   vector< int> &pixelpromassnahme);

	//Hilfsfunktionen

	static CString AUPtoString(	vector<massnahme> mlist, 
								vector<double> zahlungen, 
								vector<int> flaechen);

	static void zeigeAUP(	vector<massnahme> mlist, 
							vector<double> zahlungen, 
							vector<int> flaechen);

	static double calcAlpha(int wunschItZahl, 
							double T0, 
							double TAbb);

	static double berechneAnfangstemperatur(double maxVerschlechterung, double Akzeptanzwkt);

	static bool isIn(	int val, 
						vector<int> vec);

	static int suchePixelID(int pID, 
							int maxIndex, 
							vector < modell::masspixelergeb > vec);

	static void zeigeVektor(vector<double> vec);
	static void zeigeVektor(vector<int> vec);
	static void zeigeMatrix(vector<vector<double>> mat);

	static void calcRandomKonfiMaxFlaeche(
				int &tzahlung,
				vector< art*> &artlist,
				vector< massnahme> &mliste,
				vector< double> &gewichte,
				vector< double> &minqual,
				int &budget,
				bool &zahlung,
				int &zeilen,
				int &spalten,
				int &bundeslandID,
				bool &hoch,
				bool &egal);

	static void sortiereMassnahmenlisten(vector < vector < modell::masspixelergeb >> &massnahmenergebvector);

	static void loescheMassnahmenlisten(vector < vector < modell::masspixelergeb >> &massnahmenergebvector);

	static void klaereFormalitaeten(vector<double> zahlungen,
									 int tzahlung,
									 vector < vector < modell::masspixelergeb >> &massnahmenergebvector,
									 vector< simulation::mapixelliste_mit_pos> &pixellisten_mit_position,
									 vector< int> &pixelpromassnahme);



	static void schreibeInDatei(CString filename, CString text);

	static vector<int> NullvektorInt(int length);

	static vector<double> NullvektorDouble(int length);

	static int RandomInt(int a, int b);

	static double RandomDouble(double a, double b);

	static void speichereErgebnisvektoren(vector<vector<modell::masspixelergeb>> mev, CString filename, vector<double> &gewichte);

	static vector<double> berechneKostenmaxAst(vector<vector<modell::masspixelergeb>> &massnahmenergebvector);

	static vector<double> berechneKostendifferenzAst(vector<vector<modell::masspixelergeb>> &massnahmenergebvector);

	static vector<int> berechneMaxFlaecheAst(vector<vector<modell::masspixelergeb>> &massnahmenergebvector, double budget);

	static vector<double> berechneMaximaleZahlungen(vector<vector<modell::masspixelergeb>> &massnahmenergebvector, 
												  int tzahlung, double fak)	;

	static vector<int> berechneAnzPixel(vector<vector<modell::masspixelergeb>> &massnahmenergebvector);

	static int bestimmeAnzahlGreifMass(vector<int> AnzPixel);

	static vector<int> berechneGreifendeKonkurrenz(vector<vector<modell::masspixelergeb>> &massnahmenergebvector);

	static vector<int> berechneTypen(vector<vector<modell::masspixelergeb>> &massnahmenergebvector);

	static vector<int> bestimmeRanking(vector<double> vals);

	static vector<int> bestimmeRankingBesteAUP(vector<double> gesamtflaeche,
											   vector<bool> bOk,
											   vector<double> ausgabe);


	static double logZwischenNullUndXMax(double x, double xMax, double A);

	static double berechneObereKostenschranke(vector<double> zahlungen, vector<int> flaechen);

	static double lineareFkt(double x, double x0, double x1, double y0, double y1);

	static vector<double> berechneDurchschnitte(vector<vector<double>> Stichproben);

	static vector<double> berechneVarianzen(vector<double> Durchschnitte, vector<vector<double>> Stichproben);

	static CString toString(vector<massnahme> mliste);

};