#ifndef PARSE_H
#define PARSE_H

#include"toml11\toml.hpp"
#include<iostream>

struct param_struct {
	string run;
	double dx_au;
	Cvec x_list;
	// Ground state
	string potential_type;			// "box" - Kastenpotential, "fermi" - Fermipotential, "personal" - benutzerdefiniert, "coulomb" - Coulomb-Potential Wasserstoff
	double V0;
	double W;
	double E_F;
	double width;
	double x0;
	double smooth;
	int maximal_states;					// maximal number of states
	int use_parallel;					// use parallel algorithm? -- recommended for broad boxes
	vector<vector<double>> state_numbers{};	// Welche Zustände sollen als Startwellenfunktion gemixt werden? (leer - gleichmäßige Aufteilung)

	// Laser
	int laser;							// Laser nutzen?
	vector<int> SC_laser;						// Single Cycle Puls nutzen?
	vector<double> wavelength;
	vector<double> intensity;
	vector<double> t0;
	vector<double> phase;
	vector<double> FWHM;

	// Enhancement profile
	int enhancenment;					// Nahfeldverstärkung anschalten? 
	double gamma0;
	double lambda_NF;
	double x_right;

	// Import von Feldern? (nein - "0") 
	int import_field;
	string input;

	// Propagation 
	int propagation;					// Propagation berechnen?
	double prop_step;
	Cvec t_prop;
	int track;							// Tracken von Variablen über der Zeit? (ja - 1)

	// Save rho(x,t)
	int write_spec;						// Speicher der Wellenfunktion in jedem Zeitschritt? (ja - 1)
	double write_step_x;				// every #th entry will be saved
	int write_step_t;					// every #th timestep the wf will be saved

	// Spektrum
	int outprojection;					// outprojection of groundstate after propagation
	int calc_spec;
	int half_spec;						// use only x > 0? (yes - 1)
	Cvec Elist_spec;
	int order;
	double gamma;
	int write_spec_evol;

	// loop
	int make_loop;
	double loop_start;
	double loop_end;
	double loop_step;
	int loop_number;
	string loop_var;
} ;

ostream& operator<<(ostream& out, const param_struct& p) {
	return out << p.run << '\n'
		<< p.dx_au << '\n'
		//<< p.x_list << '\n'
		<< p.potential_type << '\n'
		<< p.V0 << '\n'
		<< p.width << '\n'
		<< p.x0 << '\n'
		<< p.smooth << '\n'
		<< p.maximal_states << '\n'
		<< p.use_parallel << '\n'
		//<< p.state_numbers << '\n'
		<< p.laser << '\n'
		//<< p.wavelength << '\n'
		//<< p.intensity << '\n'
		//<< p.t0 << '\n'
		//<< p.phase << '\n'
		//<< p.FWHM << '\n'
		<< p.enhancenment << '\n'
		<< p.gamma0 << '\n'
		<< p.lambda_NF << '\n'
		<< p.x_right << '\n'
		<< p.input << '\n'
		<< p.propagation << '\n'
		//<< p.t_prop << '\n'
		<< p.track << '\n'
		<< p.write_spec << '\n'
		<< p.outprojection << '\n'
		<< p.calc_spec << '\n'
		<< p.half_spec << '\n'
		//<< p.Elist_spec << '\n'
		<< p.order << '\n'
		<< p.gamma << '\n'
		<< p.write_spec_evol << '\n'
		<< p.make_loop << '\n'
		<< p.loop_start << '\n'
		<< p.loop_end << '\n'
		<< p.loop_step << '\n'
		<< p.loop_var << '\n';
}

param_struct get_param_toml(std::string input) {
	auto data = toml::parse(input);
	param_struct p;
	p.run = toml::find<string>(data, "run");
	p.dx_au = toml::find<double>(data, "dx_au");
	double xstart = toml::find<double>(data, "x_start");
	double xend = toml::find<double>(data, "x_end");
	p.x_list = Cvec(xstart, p.dx_au, xend);

	// Ground state
	p.potential_type = toml::find<string>(data, "ground_state", "potential_type");
	p.W = toml::find<double>(data, "ground_state", "W") / au_Ee;
	p.E_F = toml::find<double>(data, "ground_state", "E_F") / au_Ee;
	p.V0 = p.W + p.E_F;
	p.width = toml::find<double>(data, "ground_state", "width") / (1e10 * au_L);
	p.x0 = toml::find<double>(data, "ground_state", "x0") * p.width;
	p.smooth = toml::find<double>(data, "ground_state", "smooth");
	p.maximal_states = toml::find<int>(data, "ground_state", "maximal_states");
	p.use_parallel = toml::find<int>(data, "ground_state", "use_parallel");
	auto state_numbers = toml::find<vector<double>>(data, "ground_state", "state_numbers");
	auto state_weights = toml::find<vector<double>>(data, "ground_state", "state_weights");
	for (int i = 0; i < state_numbers.size(); i++) {
		p.state_numbers.push_back({ state_weights[i], state_numbers[i] - 1.0 });
	}

	// Laser
	p.laser = toml::find<int>(data, "laser", "use_laser");
	p.SC_laser = toml::find<vector<int>>(data, "laser", "use_SC");
	p.wavelength = toml::find<vector<double>>(data, "laser", "wavelength");
	p.intensity = toml::find<vector<double>>(data, "laser", "intensity");
	p.t0 = toml::find<vector<double>>(data, "laser", "t0");
	auto phase = toml::find<vector<double>>(data, "laser", "phase");
	for (int i = 0; i < phase.size(); i++) {
		p.phase.push_back(phase[i] * M_PI);
	}
	p.FWHM = toml::find<vector<double>>(data, "laser", "FWHM");

	// Enhancement profile
	p.enhancenment = toml::find<int>(data, "enhancement", "use_enhancement");
	p.gamma0 = toml::find<double>(data, "enhancement", "gamma0");
	p.lambda_NF = toml::find<double>(data, "enhancement", "lambda_nf");
	p.x_right = toml::find<double>(data, "enhancement", "x_right") * p.width;

	// Import von Feldern? (nein - "0") 
	p.import_field = toml::find<int>(data, "field_import", "import_field");
	p.input = toml::find<string>(data, "field_import", "input");

	// Propagation 
	p.propagation = toml::find<int>(data, "propagation", "calc_prop");
	double prop_start = toml::find<double>(data, "propagation", "prop_start");
	double prop_end = toml::find<double>(data, "propagation", "prop_end");
	p.prop_step = toml::find<double>(data, "propagation", "prop_step");
	p.t_prop = Cvec(prop_start, p.prop_step, prop_end);
	p.track = toml::find<int>(data, "propagation", "track");

	// save rho(x,t)
	p.write_spec = toml::find<int>(data, "save_rho_time", "write_evolution");
	p.write_step_x = toml::find<double>(data, "save_rho_time", "write_step_x");
	p.write_step_t = toml::find<int>(data, "save_rho_time", "write_step_t");

	// Spektrum
	p.outprojection = toml::find<int>(data, "spectrum", "outprojection");
	p.calc_spec = toml::find<int>(data, "spectrum", "calc_spec");
	p.half_spec = toml::find<int>(data, "spectrum", "half_spec");
	double Estart = toml::find<double>(data, "spectrum", "spec_E_start");
	double Eend = toml::find<double>(data, "spectrum", "spec_E_end");
	double Estep = toml::find<double>(data, "spectrum", "spec_E_step");
	p.Elist_spec = Cvec(Estart, Estep, Eend);
	p.order = toml::find<int>(data, "spectrum", "order");
	p.gamma = toml::find<double>(data, "spectrum", "gamma");
	p.write_spec_evol = toml::find<int>(data, "spectrum", "write_spec_evolution");

	// loop
	p.make_loop = toml::find<int>(data, "loop", "make_loop");
	p.loop_start = toml::find<double>(data, "loop", "loop_start");
	p.loop_end = toml::find<double>(data, "loop", "loop_end");
	p.loop_step = toml::find<double>(data, "loop", "loop_step");
	p.loop_number = (int) ((p.loop_end - p.loop_start) / p.loop_step);
	p.loop_var = toml::find<string>(data, "loop", "loop_var");

	if (p.make_loop == 0) {
		p.loop_start = 0.0;
		p.loop_end = 0.09;
		p.loop_step = 0.1;
		p.loop_number = 0;
		p.loop_var = "0";
	}

	return p;
}

#endif