#include "PortModeData.h"
#include "../nlohmann/json.hpp"

#include <fstream>
#include <iostream>

using json = nlohmann::json;

static Eigen::VectorXcd readComplexArrays(const json& reArr, const json& imArr)
{
	const size_t n = reArr.size();
	Eigen::VectorXcd v(static_cast<int>(n));
	for (size_t i = 0; i < n; i++)
		v(static_cast<int>(i)) = std::complex<double>(reArr[i].get<double>(), imArr[i].get<double>());
	return v;
}

static PortNumericMode parseMode(const json& j)
{
	PortNumericMode m;
	m.type = j.at("type").get<int>();
	const auto& g = j.at("gamma");
	m.gamma = std::complex<double>(g[0].get<double>(), g[1].get<double>());
	m.powerCoef = j.at("powerCoef").get<double>();
	const auto& n = j.at("normal");
	m.normal << n[0].get<double>(), n[1].get<double>(), n[2].get<double>();

	const auto& fc = j.at("facesConn");
	m.facesConn = Eigen::MatrixXi::Zero(static_cast<int>(fc.size()), 2);
	for (size_t i = 0; i < fc.size(); i++)
	{
		m.facesConn(static_cast<int>(i), 0) = fc[i][0].get<int>();
		m.facesConn(static_cast<int>(i), 1) = fc[i][1].get<int>();
	}

	const auto& pf = j.at("portNewFaces");
	m.portNewFaces = Eigen::MatrixXi::Zero(static_cast<int>(pf.size()), 3);
	for (size_t i = 0; i < pf.size(); i++)
		for (int k = 0; k < 3; k++)
			m.portNewFaces(static_cast<int>(i), k) = pf[i][k].get<int>();

	const auto& pe = j.at("portEdgeOfFace");
	m.portEdgeOfFace = Eigen::MatrixXi::Zero(static_cast<int>(pe.size()), 3);
	for (size_t i = 0; i < pe.size(); i++)
		for (int k = 0; k < 3; k++)
			m.portEdgeOfFace(static_cast<int>(i), k) = pe[i][k].get<int>();

	const auto& nodes = j.at("portNodes");
	m.portNodes = Eigen::MatrixXd::Zero(static_cast<int>(nodes.size()), 3);
	for (size_t i = 0; i < nodes.size(); i++)
		for (int k = 0; k < 3; k++)
			m.portNodes(static_cast<int>(i), k) = nodes[i][k].get<double>();

	m.Ez = readComplexArrays(j.at("Ez_re"), j.at("Ez_im"));
	m.Et = readComplexArrays(j.at("Et_re"), j.at("Et_im"));
	return m;
}

void PortModeLibrary::Clear()
{
	_mModes.clear();
}

void PortModeLibrary::AddMode(const PortNumericMode& m)
{
	_mModes.push_back(m);
}

bool PortModeLibrary::LoadFromFile(const std::string& path)
{
	_mModes.clear();
	std::ifstream ifs(path);
	if (!ifs.is_open())
	{
		std::cerr << "[PortModeLibrary] cannot open " << path << std::endl;
		return false;
	}
	json js;
	try
	{
		ifs >> js;
	}
	catch (const std::exception& e)
	{
		std::cerr << "[PortModeLibrary] JSON parse error: " << e.what() << std::endl;
		return false;
	}
	if (js.contains("input"))
		_mModes.push_back(parseMode(js.at("input")));
	if (js.contains("output"))
		_mModes.push_back(parseMode(js.at("output")));
	return !_mModes.empty();
}
