/*******************************************************
 * Copyright (C) 2017-2020 CENOS Ltd vg@cenos-platform.com
 *
 * This file is part of CENOS.
 *
 * CENOS can not be copied and/or distributed without the express
 * permission of CENOS Ltd
 *******************************************************/

#include "Topology_Worker.h"
#include "topology/geometryData.h"
#include "misc/miscFunctions.hpp"

Topology_Worker::Topology_Worker(std::shared_ptr<Job>& j) : Worker(j)
{
}


messagedata Topology_Worker::run(MessageQueue_ messageQueue)
{
	try
	{
		if (assignedJob_->command() == "getGeometryData")
		{
			messagedata msg(messagedata(messagedata::info_lvl, messagedata::wait, ""));
			msg.guid = assignedJob_->guid();
			messageQueue->push(msg);
		}

		std::optional<json> wdir = assignedJob_->getArg("caseDir"); // wdir
		std::optional<json> rawGeometryData = assignedJob_->getArg("geometryDataFile"); // raw geometry data
		std::optional<json> geometry_data_json = assignedJob_->getArg("geometryData"); // raw geometry data
		std::optional<json> meshFile = assignedJob_->getArg("meshFile"); // mesh file

		
		//Check if mesh file exists
		//try to fix by prepending working directory if mesh file does not exist
		if (meshFile.has_value() && !meshFile.value().is_null())
		{
			if (!misc::fileExist(meshFile.value()))
			{
				std::string fn_abs = wdir.value().get<std::string>() + "/" + meshFile.value().get<std::string>();
				if (misc::fileExist(fn_abs))
					meshFile = fn_abs;
			}
		}


		if (!wdir.has_value() or !(rawGeometryData.has_value() or geometry_data_json.has_value()))
		{
			messagedata retData(messagedata::error, messagedata::response, "Incorrect input for GeometryData.");
			retData.guid = assignedJob_->guid();
			return retData;
		}

		GeometryData gd;
		if (geometry_data_json.has_value())
		{
			gd = GeometryData(geometry_data_json.value(), wdir.value().get<std::string>());
		}
		else
		{

			std::ifstream in_fstream(rawGeometryData.value().get<std::string>());
			if (!in_fstream.is_open())
			{
				messagedata retData(messagedata::error, messagedata::response, "RawGeometryData.json file missing.");
				retData.guid = assignedJob_->guid();
				return retData;
			}
			json inp_json = json::parse(in_fstream);
			gd = GeometryData(inp_json, wdir.value().get<std::string>());

		}

		if (meshFile.has_value() && !meshFile.value().is_null())
				gd.setMeshFile(meshFile.value());

		//analyze commands
		if (assignedJob_->command() == "getGeometryData" or assignedJob_->command() == "reMergeGroups")
		{
			try
			{
				json geomData;
				if (meshFile.has_value() && !meshFile.value().is_null())
				{
					std::shared_ptr<Mesh> mesh = std::make_shared<Mesh>();
					mesh->readMesh(meshFile.value().get<std::string>(), std::string("GMSH"));
					if (mesh != nullptr)
						gd.setMeshStats( mesh->getMeshStats() );
					geomData["meshFile"] = meshFile.value();
				}

				geomData["geometryData"] = gd.getJson();

				messagedata retData(messagedata::success, messagedata::response, geomData.dump());
				retData.guid = assignedJob_->guid();
				return retData;
			}
			catch (json::exception& e)
			{
				// output exception information
				std::string errMsg = "message: " + std::string(e.what()) + ", exception id: " + std::to_string(e.id);
				LOG(ERROR) << errMsg;
				messagedata retData(messagedata::error, messagedata::response, "Error running getGeometryData " + errMsg);
				retData.guid = assignedJob_->guid();
				return retData;
			}
		}
		if (assignedJob_->command() == "mergeGroups")
		{
			try
			{
				gd.merge(assignedJob_->getArg("names").value().get<std::vector<std::string>>(), assignedJob_->getArg("label").value().get<std::string>());
				json geomData;
				geomData["geometryData"] = gd.getJson();
				messagedata retData(messagedata::success, messagedata::response, geomData.dump());
				retData.guid = assignedJob_->guid();
				return retData;
			}
			catch (json::exception& e)
			{
				// output exception information
				std::string errMsg = "message: " + std::string(e.what()) + ", exception id: " + std::to_string(e.id);
				LOG(ERROR) << errMsg;
				messagedata retData(messagedata::error, messagedata::response, "Error running getGeometryData " + errMsg);
				retData.guid = assignedJob_->guid();
				return retData;
			}
		}
		if (assignedJob_->command() == "unmergeGroups")
		{
			try
			{
				gd.unmerge(assignedJob_->getArg("names").value().get<std::vector<std::string>>());
				json geomData;
				geomData["geometryData"] = gd.getJson();
				messagedata retData(messagedata::success, messagedata::response, geomData.dump());
				retData.guid = assignedJob_->guid();
				return retData;
			}
			catch (json::exception& e)
			{
				// output exception information
				std::string errMsg = "message: " + std::string(e.what()) + ", exception id: " + std::to_string(e.id);
				LOG(ERROR) << errMsg;
				messagedata retData(messagedata::error, messagedata::response, "Error running getGeometryData " + errMsg);
				retData.guid = assignedJob_->guid();
				return retData;
			}
		}
		else
		{
			messagedata retData(messagedata::error, messagedata::response, "No command " + assignedJob_->command() + " defined");
			retData.guid = assignedJob_->guid();
			return retData;
		}

	}
	catch (json::exception& e)
	{
		std::string message = e.what();
		messagedata retData(messagedata::error, messagedata::response, "Topology_Worker exception " + message);
		retData.guid = assignedJob_->guid();
		return retData;
	}
	catch (std::exception e)
	{
		std::string message = e.what();
		messagedata retData(messagedata::error, messagedata::response, "Topology_Worker exception " + message);
		retData.guid = assignedJob_->guid();
		return retData;
	}
	catch (std::string e)
	{
		messagedata retData(messagedata::error, messagedata::response, "Topology_Worker exception " + e);
		retData.guid = assignedJob_->guid();
		return retData;
	}
}