/*
 * setup.hpp
 *
 *  Created on: Nov 23, 2017
 *      Author: vadims
 */

#ifndef SETUP_HPP_
#define SETUP_HPP_
#include <iostream>
#include <queue>

#include "Physics.hpp"
#include "Numerics.hpp"
#include "Parameter.h"
#include "mesh/Mesh.h"
#include "Motion.h"

#include "misc/messagedata.hpp"
#include "nlohmann/json.hpp"
#include "easylogging++/easylogging++.h"
#include "topology/geometryData.h"
#include "misc/messageQueue.hpp"
#include "outputAnalyzer/OutputAnalyzer.hpp"
#include "misc/Stopper.hpp"

using json = nlohmann::json;

class Setup
{
public:
	Setup();
	~Setup();

	//reads physics from json file

	virtual std::string Setup::isA() = 0;

	//sets working directory
	void setWDir(std::string workingdir);
	
	//sets guid
	void setGuid(std::string guid);

	void setMessageQueue(MessageQueue_ m);

	void setOutputAnalyzer(OutputAnalyzer_ o);

	void setStopper(Stopper s);

	//sets mesh
	void setMesh(std::shared_ptr<Mesh>);

	void setGeometryData(std::shared_ptr<GeometryData>);

	// temporary solution for transorming new mesh to old type
	void transformMesh(std::shared_ptr<Mesh>);

	// read full input from json
	// including physics, numerics, bcs, postvalues, etc..
	void readInput(json input);

	void readPost(json input);

	virtual void readConfigurations() = 0;

	virtual void writeSetup() = 0;

	virtual void writePostSetup() = 0;

	virtual messagedata calculate() = 0;

	virtual messagedata postProcess() = 0;

	virtual void outputGlobals() = 0;

	virtual bool remesh() = 0;

	virtual void initialize() = 0;

	virtual bool update() = 0;

	virtual void finalize() = 0;

	virtual void stop() = 0;

	virtual void validateInput() = 0;

	virtual messagedata convertCaseNewResultJson() = 0;


	// get boundaries list of physics. In case of multiphysics,
	// merged list will be returned
	// Merged means - duplicates will be omitted
	std::map<std::string, int> getBoundariesIdMap();
	std::map<std::string, int>  getDomainsIdMap();

	//get physics with passed solverkey
	Physics getPhysics(std::string slvKey);
	std::vector<Physics> getCasePhysics();

	// in multiphysics case check if case has transient physics
	bool hasTransientPhysics();

	std::string getWdir();

	// get transient physics
	// assumed that only one transient physics is present. If multiple are present, only the first will be returned
	Physics& Setup::getTransientPhysics();

	//get solver configuration
	// returns json from physics.json config file that corresponds to passed keys
	static json getPhysicsConfig();
	static json getSolverConfig(std::string solverKey, std::string physicsKey, std::string subPhysicsKey, std::string basisKey);
	static json getSubPhysicsConfig(json, std::string physicsKey, std::string subPhysicsKey, std::string basisKey, std::string multiSubPhysicsKey);
	static std::optional<json> getLastParams(std::string);
	bool hasMultipleCalculations();
	bool stoppedDuringCalculation();
	bool hasNoResults();

protected:
	struct config
	{
		std::map<std::string, std::string> boundaryGroups;
		std::map<std::string, std::string> domainGroups;
	};

	json postProcConfig; // stored json with post processing config
	std::vector<Physics> casePhysics;
	std::vector<Motion> caseMotions;
	Numerics caseNumerics;
	std::string wDir;
	std::shared_ptr<Mesh> mesh;
	std::shared_ptr<GeometryData> geom_data;
	std::vector<config> configurations;
	std::vector<Parameter> parameterList;
	bool noRemeshing;
	std::string guid;
	bool hasMultipleCalculations_;
	std::string solver_script;
	bool stopped_during_calculation;
	bool no_results;

	MessageQueue_ messageQueue;
	OutputAnalyzer_ outputAnalyzer;
	Stopper stopper;
};


#endif /* SETUP_HPP_ */
