/********************************************************
 *  ██████╗  ██████╗████████╗██╗
 * ██╔════╝ ██╔════╝╚══██╔══╝██║
 * ██║  ███╗██║        ██║   ██║
 * ██║   ██║██║        ██║   ██║
 * ╚██████╔╝╚██████╗   ██║   ███████╗
 *  ╚═════╝  ╚═════╝   ╚═╝   ╚══════╝
 * Geophysical Computational Tools & Library (GCTL)
 *
 * Copyright (c) 2023  Yi Zhang (yizhang-geo@zju.edu.cn)
 *
 * GCTL is distributed under a dual licensing scheme. You can redistribute 
 * it and/or modify it under the terms of the GNU Lesser General Public 
 * License as published by the Free Software Foundation, either version 2 
 * of the License, or (at your option) any later version. You should have 
 * received a copy of the GNU Lesser General Public License along with this 
 * program. If not, see <http://www.gnu.org/licenses/>.
 * 
 * If the terms and conditions of the LGPL v.2. would prevent you from using 
 * the GCTL, please consider the option to obtain a commercial license for a 
 * fee. These licenses are offered by the GCTL's original author. As a rule, 
 * licenses are provided "as-is", unlimited in time for a one time fee. Please 
 * send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget 
 * to include some description of your company and the realm of its activities. 
 * Also add information on how to contact you by electronic and paper mail.
 ******************************************************/

#include "mesh.h"

gctl::base_mesh::base_mesh()
{
	initialized = false;
	//std::clog << "A new mesh object is created." << std::endl;
}

gctl::base_mesh::~base_mesh()
{
	clear();
	//std::clog << "A mesh object is destroyed." << std::endl;
}

void gctl::base_mesh::clear()
{
	meshdata *data_ptr;
	if (!saved_data.empty())
	{
		for (iter = saved_data.begin(); iter != saved_data.end(); ++iter)
		{
			data_ptr = *iter;
			meshdata::destroy(data_ptr);
		}
		saved_data.clear();
	}

	initialized = false;
	return;
}

bool gctl::base_mesh::initiated() const
{
	return initialized;
}

bool gctl::base_mesh::saved(std::string datname) const
{
	if (saved_data.empty())
	{
		return false;
	}
	else
	{
		meshdata *data_ptr = nullptr;
		// 这里我们需要使用常量迭代器
		std::list<meshdata*>::const_iterator c_iter;
		for (c_iter = saved_data.begin(); c_iter != saved_data.end(); ++c_iter)
		{
			data_ptr = *c_iter;
			if (data_ptr->get_datname() == datname)
			{
				return true;
			}
		}
		return false;
	}
}

gctl::meshdata *gctl::base_mesh::get_data(std::string datname) const
{
	if (saved_data.empty())
	{
		throw std::runtime_error("[gctl::base_mesh] No data saved.");
	}

	meshdata *curr_data = nullptr;
	std::list<meshdata*>::const_iterator c_iter;
	for (c_iter = saved_data.begin(); c_iter != saved_data.end(); ++c_iter)
	{
		curr_data = *c_iter;
		if (curr_data->get_datname() == datname)
		{
			return curr_data;
		}
	}

	throw gctl::runtime_error("[gctl::base_mesh] No data found by the name: " + datname);
}

void gctl::base_mesh::get_all_data(array<meshdata*>& out_list) const
{
	if (saved_data.empty())
	{
		throw runtime_error("[gctl::base_mesh] No data saved.");
	}

	int c_count = 0;
	out_list.resize(saved_data.size());

	meshdata *curr_data = nullptr;
	std::list<meshdata*>::const_iterator c_iter;
	for (c_iter = saved_data.begin(); c_iter != saved_data.end(); ++c_iter)
	{
		curr_data = *c_iter;
		out_list[c_count] = curr_data;
		c_count++;
	}
	return;
}

void *gctl::base_mesh::get_datval(std::string datname) const
{
	meshdata *curr_data = get_data(datname);
	return curr_data->get_datval_ptr();
}

void gctl::base_mesh::remove_data(std::string datname)
{
	if (saved_data.empty())
	{
		throw runtime_error("[gctl::base_mesh] No data saved.");
	}

	meshdata *curr_data;
	for (iter = saved_data.begin(); iter != saved_data.end(); ++iter)
	{
		curr_data = *iter;
		if (curr_data->get_datname() == datname)
		{
			meshdata::destroy(curr_data);
			iter = saved_data.erase(iter);
			//std::clog << "Meshdata: " << datname << " is destroyed." << std::endl;
			break;
		}
	}
	return;
}

void gctl::base_mesh::show_info(std::ostream &os) const
{
	if (meshtype == REGULAR_MESH) os << "Mesh: Regular | ";
	if (meshtype == LINEAR_MESH)  os << "Mesh: Linear | ";
	if (meshtype == TRI_TET_MESH) os << "Mesh: Unstructured | ";
	if (meshtype == REGULAR_MESH_SPH) os << "Mesh: Regular (spherical) | ";
	if (meshtype == LINEAR_MESH_SPH)  os << "Mesh: Linear (spherical) | ";
	if (meshtype == TRI_TET_MESH_SPH) os << "Mesh: Unstructured (spherical) | ";
	if (meshtype == REGULAR_GRID) os << "Mesh: Grid | ";

	if (meshdim == MESH_2D) os << "2D" << std::endl;
	else if (meshdim == MESH_3D) os << "3D" << std::endl;

	os << "Name: " << meshname << std::endl;
	os << "Info: " << meshinfo << std::endl;

	show_mesh_dimension(os);

	meshdata *curr_data;
	std::list<meshdata*>::const_iterator c_iter;
	for (c_iter = saved_data.begin(); c_iter != saved_data.end(); ++c_iter)
	{
		curr_data = *c_iter;
		curr_data->show_info();
	}
	return;
}

void gctl::base_mesh::rename_data(std::string oldname, std::string newname)
{
	meshdata *curr_data = get_data(oldname);
	curr_data->set_datname(newname);
	return;
}

gctl::mesh_type_e gctl::base_mesh::get_meshtype() const
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	return meshtype;
}

gctl::mesh_dim_e gctl::base_mesh::get_meshdim() const
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	return meshdim;
}

int gctl::base_mesh::get_nodenum() const
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	return node_num;
}

int gctl::base_mesh::get_elenum() const
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	return ele_num;
}

int gctl::base_mesh::get_datanum() const
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	return saved_data.size();
}

std::string gctl::base_mesh::get_meshname() const
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	return meshname;
}

void gctl::base_mesh::set_meshname(std::string in_name)
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	if (in_name.empty())
	{
		throw std::runtime_error("[gctl::base_mesh] The input name is empty.");
	}

	meshname = in_name;
	return;
}

std::string gctl::base_mesh::get_meshinfo() const
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	return meshinfo;
}

void gctl::base_mesh::set_meshinfo(std::string in_info)
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	if (in_info == "")
	{
		throw runtime_error("[gctl::base_mesh] The input info. is empty.");
	}

	meshinfo = in_info;
	return;
}

gctl::meshdata *gctl::base_mesh::add_data(std::string in_name, mesh_data_type_e in_type, bool if_output, double init_val)
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	meshdata *data_ptr;
	if(saved(in_name))
	{
		data_ptr = get_data(in_name);
		if (data_ptr->get_valtype() != Scalar || data_ptr->get_dattype() != in_type)
		{
			throw gctl::runtime_error("[gctl::base_mesh] A data object is already created with a different data or value type by the name:" + in_name);
		}

		// 存在一个同名 同数据类型 同赋值类型的数据 则将其数据设置为初始值
		array<double>* val_ptr = (array<double>*) data_ptr->get_datval_ptr();
		val_ptr->assign_all(init_val);
		return data_ptr;
	}

	if (in_type == NodeData)
	{
		data_ptr = meshdata_scalar::create(in_name, in_type, node_num, if_output, init_val);
	}
	else if (in_type == ElemData || in_type == ElemData2D || in_type == ElemData3D)
	{
		data_ptr = meshdata_scalar::create(in_name, in_type, ele_num, if_output, init_val);
	}

	saved_data.push_back(data_ptr);
	return data_ptr;
}

gctl::meshdata *gctl::base_mesh::add_data(std::string in_name, mesh_data_type_e in_type, bool if_output, gctl::point3dc init_val)
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	meshdata *data_ptr;
	if(saved(in_name))
	{
		data_ptr = get_data(in_name);
		if (data_ptr->get_valtype() != Scalar || data_ptr->get_dattype() != in_type)
		{
			throw gctl::runtime_error("[gctl::base_mesh] A data object is already created with a different data or value type by the name:" + in_name);
		}

		// 存在一个同名 同数据类型 同赋值类型的数据 则将其数据设置为初始值
		array<point3dc>* val_ptr = (array<point3dc>*) data_ptr->get_datval_ptr();
		val_ptr->assign_all(init_val);
		return data_ptr;
	}

	if (in_type == NodeData)
	{
		data_ptr = meshdata_vector::create(in_name, in_type, node_num, if_output, init_val);
	}
	else if (in_type == ElemData || in_type == ElemData2D || in_type == ElemData3D)
	{
		data_ptr = meshdata_vector::create(in_name, in_type, ele_num, if_output, init_val);
	}

	saved_data.push_back(data_ptr);
	return data_ptr;
}

gctl::meshdata *gctl::base_mesh::add_data(std::string in_name, mesh_data_type_e in_type, bool if_output, gctl::tensor init_val)
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	meshdata *data_ptr;
	if(saved(in_name))
	{
		data_ptr = get_data(in_name);
		if (data_ptr->get_valtype() != Scalar || data_ptr->get_dattype() != in_type)
		{
			throw gctl::runtime_error("[gctl::base_mesh] A data object is already created with a different data or value type by the name:" + in_name);
		}

		// 存在一个同名 同数据类型 同赋值类型的数据 则将其数据设置为初始值
		array<tensor>* val_ptr = (array<tensor>*) data_ptr->get_datval_ptr();
		val_ptr->assign_all(init_val);
		return data_ptr;
	}

	if (in_type == NodeData)
	{
		data_ptr = meshdata_tensor::create(in_name, in_type, node_num, if_output, init_val);
	}
	else if (in_type == ElemData || in_type == ElemData2D || in_type == ElemData3D)
	{
		data_ptr = meshdata_tensor::create(in_name, in_type, ele_num, if_output, init_val);
	}

	saved_data.push_back(data_ptr);
	return data_ptr;
}

gctl::meshdata *gctl::base_mesh::add_data(std::string in_name, mesh_data_type_e in_type, bool if_output, mesh_data_value_e val_type)
{
	if (!initialized)
	{
		throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
	}

	meshdata *data_ptr;
	if(saved(in_name))
	{
		data_ptr = get_data(in_name);
		if (data_ptr->get_valtype() != Scalar || data_ptr->get_dattype() != in_type)
		{
			throw gctl::runtime_error("[gctl::base_mesh] A data object is already created with a different data or value type by the name:" + in_name);
		}

		return data_ptr;
	}

	if (val_type == Scalar && in_type == NodeData)
	{
		data_ptr = meshdata_scalar::create(in_name, in_type, node_num, if_output, 0.0);
	}
	else if (val_type == Scalar && in_type == ElemData)
	{
		data_ptr = meshdata_scalar::create(in_name, in_type, ele_num, if_output, 0.0);
	}
	else if (val_type == Vector && in_type == NodeData)
	{
		point3dc init_val = {0.0, 0.0, 0.0};
		data_ptr = meshdata_vector::create(in_name, in_type, node_num, if_output, init_val);
	}
	else if (val_type == Vector && in_type == ElemData)
	{
		point3dc init_val = {0.0, 0.0, 0.0};
		data_ptr = meshdata_vector::create(in_name, in_type, ele_num, if_output, init_val);
	}
	else if (val_type == Tensor && in_type == NodeData)
	{
		tensor init_val = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
		data_ptr = meshdata_tensor::create(in_name, in_type, node_num, if_output, init_val);
	}
	else if (val_type == Tensor && in_type == ElemData)
	{
		tensor init_val = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
		data_ptr = meshdata_tensor::create(in_name, in_type, ele_num, if_output, init_val);
	}


	saved_data.push_back(data_ptr);
	return data_ptr;
}

void gctl::base_mesh::init(std::string in_name, std::string in_info, int xnum, int ynum, 
	double xmin, double ymin, double dx, double dy)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::init(std::string in_name, std::string in_info, int xbnum, int ybnum, int zbnum, 
	double xmin, double ymin, double zmin, double xsize, double ysize, double zsize)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::init(std::string in_name, std::string in_info, double lon_min, double lat_min, 
	double rad_min, double lon_size, double lat_size, double rad_size, int lon_bnum, int lat_bnum, int rad_bnum)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::init(std::string in_name, std::string in_info, double xmin, double ymin, 
	const gctl::array<double> &xsizes, const gctl::array<double> &ysizes)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::init(std::string in_name, std::string in_info, double xmin, double ymin, 
	double zmin, const gctl::array<double> &xsizes, const gctl::array<double> &ysizes, 
	const gctl::array<double> &zsizes)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::init(std::string in_name, std::string in_info, const gctl::array<gctl::vertex2dc> &in_nodes, 
	const gctl::array<gctl::triangle2d> &in_triangles)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::init(std::string in_name, std::string in_info, const gctl::array<gctl::vertex3dc> &in_nodes, 
	const gctl::array<gctl::tetrahedron> &in_tets)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::show_mesh_dimension(std::ostream &os) const
{
	return;
}

void gctl::base_mesh::save_gmsh(std::string filename, index_packed_e packed)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::save_gmsh(std::string filename, mesh_data_type_e d_type, output_type_e out_mode, index_packed_e packed)
{
	if (out_mode == OverWrite) save_gmsh(filename, packed);

	std::ofstream outfile;
	gctl::open_outfile(outfile, filename, ".msh", std::ios::out|std::ios::app);

	meshdata *curr_data;
	for (iter = saved_data.begin(); iter != saved_data.end(); ++iter)
	{
		curr_data = *iter;
		if (curr_data->get_dattype() == d_type && d_type == NodeData && 
			curr_data->get_valtype() == Scalar && curr_data->get_output())
		{
			gctl::array<double> *data_ptr = (gctl::array<double>*) curr_data->get_datval_ptr();
			gctl::save_gmsh_data(outfile, curr_data->get_datname(), *data_ptr, gctl::NodeData, packed);
		}
		else if (curr_data->get_dattype() == d_type && d_type == ElemData && 
			curr_data->get_valtype() == Scalar && curr_data->get_output())
		{
			gctl::array<double> *data_ptr = (gctl::array<double>*) curr_data->get_datval_ptr();
			gctl::save_gmsh_data(outfile, curr_data->get_datname(), *data_ptr, gctl::ElemData, packed);
		}
		else if (curr_data->get_dattype() == d_type && d_type == NodeData && 
			curr_data->get_valtype() == Vector && curr_data->get_output())
		{
			gctl::array<gctl::point3dc> *data_ptr = (gctl::array<gctl::point3dc>*) curr_data->get_datval_ptr();
			gctl::save_gmsh_data(outfile, curr_data->get_datname(), *data_ptr, gctl::NodeData, packed);
		}
		else if (curr_data->get_dattype() == d_type && d_type == ElemData && 
			curr_data->get_valtype() == Vector && curr_data->get_output())
		{
			gctl::array<gctl::point3dc> *data_ptr = (gctl::array<gctl::point3dc>*) curr_data->get_datval_ptr();
			gctl::save_gmsh_data(outfile, curr_data->get_datname(), *data_ptr, gctl::ElemData, packed);
		}
	}

	outfile.close();
	return;
}

void gctl::base_mesh::save_gmsh(std::string filename, std::string datname, output_type_e out_mode, index_packed_e packed)
{
	meshdata *curr_data = get_data(datname);

	if (!curr_data->get_output())
	{
		throw gctl::runtime_error("[gctl::base_mesh] Output is disabled for the data:" + datname);
	}

	if (out_mode == OverWrite) save_gmsh(filename, packed);

	std::ofstream outfile;
	gctl::open_outfile(outfile, filename, ".msh", std::ios::out|std::ios::app);

	if (curr_data->get_valtype() == Scalar)
	{
		gctl::array<double> *data_ptr = (gctl::array<double>*) curr_data->get_datval_ptr();
		if (curr_data->get_dattype() == NodeData)
		{
			gctl::save_gmsh_data(outfile, curr_data->get_datname(), *data_ptr, gctl::NodeData, packed);
		}
		else if (curr_data->get_dattype() == ElemData)
		{
			gctl::save_gmsh_data(outfile, curr_data->get_datname(), *data_ptr, gctl::ElemData, packed);
		}
	}
	else if (curr_data->get_valtype() == Vector)
	{
		gctl::array<gctl::point3dc> *data_ptr = (gctl::array<gctl::point3dc>*) curr_data->get_datval_ptr();
		if (curr_data->get_dattype() == NodeData)
		{
			gctl::save_gmsh_data(outfile, curr_data->get_datname(), *data_ptr, gctl::NodeData, packed);
		}
		else if (curr_data->get_dattype() == ElemData)
		{
			gctl::save_gmsh_data(outfile, curr_data->get_datname(), *data_ptr, gctl::ElemData, packed);
		}
	}
	else if (curr_data->get_valtype() == Tensor)
	{
		gctl::array<gctl::tensor> *data_ptr = (gctl::array<gctl::tensor>*) curr_data->get_datval_ptr();
		if (curr_data->get_dattype() == NodeData)
		{
			array<double> v(data_ptr->size());
			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[0][0];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Txx", v, gctl::NodeData, packed);

			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[0][1];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Txy", v, gctl::NodeData, packed);

			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[0][2];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Txz", v, gctl::NodeData, packed);

			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[1][1];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Tyy", v, gctl::NodeData, packed);

			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[1][2];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Tyz", v, gctl::NodeData, packed);

			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[2][2];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Tzz", v, gctl::NodeData, packed);
		}
		else if (curr_data->get_dattype() == ElemData)
		{
			array<double> v(data_ptr->size());
			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[0][0];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Txx", v, gctl::ElemData, packed);

			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[0][1];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Txy", v, gctl::ElemData, packed);

			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[0][2];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Txz", v, gctl::ElemData, packed);

			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[1][1];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Tyy", v, gctl::ElemData, packed);

			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[1][2];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Tyz", v, gctl::ElemData, packed);

			for (size_t i = 0; i < v.size(); i++)
			{
				v[i] = data_ptr->at(i).val[2][2];
			}
			gctl::save_gmsh_data(outfile, curr_data->get_datname() + "_Tzz", v, gctl::ElemData, packed);
		}
	}

	outfile.close();
	return;
}

void gctl::base_mesh::load_data_cloud(const array<point2dc> &in_posi, const array<double> &in_val, 
	double search_xlen, double search_ylen, double search_deg, std::string datname, mesh_data_type_e d_type)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::load_data_cloud(const array<point3dc> &in_posi, const array<double> &in_val, 
	double search_xlen, double search_ylen, double search_deg, std::string datname, mesh_data_type_e d_type)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::extract_points(std::string datname, const array<point2dc> &in_posi, array<double> &out_val)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::extract_points(std::string datname, const array<point3dc> &in_posi, array<double> &out_val)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::extract_profile(std::string datname, const point2dc &start_p, const point2dc &end_p, int size_p, 
	array<point2dc> &out_posi, array<double> &out_val)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::extract_profile(std::string datname, const point3dc &start_p, const point3dc &end_p, int size_p, 
	double dh, array<point3dc> &out_posi, array<double> &out_val)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::edit_data(std::string datname, physical_type_e p_type, value_operator_e v_type, std::string para_str, double in_val)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::edit_data(std::string datname, physical_type_e p_type, value_operator_e v_type, std::string para_str, point3dc in_val)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::edit_data(std::string datname, physical_type_e p_type, value_operator_e v_type, std::string para_str, tensor in_val)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::purge_data(std::string datname, double in_val)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::purge_data(std::string datname, point3dc in_val)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

void gctl::base_mesh::purge_data(std::string datname, tensor in_val)
{
	throw runtime_error("[gctl::base_mesh] Invalid mesh type for calling this function.");
	return;
}

/**
 * 以下是类的私有函数，可以简单一些
 */

void gctl::base_mesh::init(mesh_type_e in_type, mesh_dim_e in_dim, std::string in_name, std::string in_info)
{
	if (in_name == "")
	{
		throw std::runtime_error("[gctl::base_mesh] The input name is empty.");
	}

	if (in_info == "")
	{
		throw std::runtime_error("[gctl::base_mesh] The input info. is empty.");
	}

	meshname = in_name;
	meshinfo = in_info;
	meshtype = in_type;
	meshdim  = in_dim;
	return;
}

void gctl::base_mesh::load_headinfo(std::ifstream &infile, mesh_type_e expected_type, mesh_dim_e expected_dim)
{
	// 读入网格头信息
	infile.read((char*)&meshtype, sizeof(int));
	infile.read((char*)&meshdim, sizeof(int));
	if (meshdim != expected_dim || meshtype != expected_type)
	{
		infile.close();
		throw std::runtime_error("[gctl::base_mesh] Invalid input mesh type.");
	}

	int info_size;
	infile.read((char*)&info_size, sizeof(int));
	meshname.resize(info_size);
	infile.read((char*)meshname.c_str(), info_size);

	infile.read((char*)&info_size, sizeof(int));
	meshinfo.resize(info_size);
	infile.read((char*)meshinfo.c_str(), info_size);
	return;
}

void gctl::base_mesh::load_datablock(std::ifstream &infile)
{
	meshdata *new_data;
	int in_num, info_size;
	mesh_data_type_e in_dattype;
	mesh_data_value_e in_valtype;
	std::string in_name;

	infile.read((char*)&in_num, sizeof(int));
	for (int i = 0; i < in_num; i++)
	{
		// 首先读入三个整形和数据名称
		infile.read((char*)&in_dattype, sizeof(int));
		infile.read((char*)&in_valtype, sizeof(int));
		infile.read((char*)&info_size, sizeof(int));

		in_name.resize(info_size);
		infile.read((char*)in_name.c_str(), info_size);

		new_data = add_data(in_name, in_dattype, true, in_valtype);
		new_data->load_binary(infile);
	}
	return;
}

void gctl::base_mesh::save_headinfo(std::ofstream &outfile)
{
	// 首先输出网格的类型和维度
	outfile.write((char*)&meshtype, sizeof(int));
	outfile.write((char*)&meshdim, sizeof(int));
	// 输出网格名称与信息
	int info_size = meshname.size();
	outfile.write((char*)&info_size, sizeof(int));
	outfile.write((char*)meshname.c_str(), info_size);
	info_size = meshinfo.size();
	outfile.write((char*)&info_size, sizeof(int));
	outfile.write((char*)meshinfo.c_str(), info_size);
	return;
}

void gctl::base_mesh::save_datablock(std::ofstream &outfile)
{
	// 统计输出的模型数量
	int out_num = 0;
	meshdata *curr_data = nullptr;
	for (iter = saved_data.begin(); iter != saved_data.end(); ++iter)
	{
		curr_data = *iter;
		if (curr_data->get_output())
		{
			out_num++;
		}
	}
	outfile.write((char*)&out_num, sizeof(int));

	for (iter = saved_data.begin(); iter != saved_data.end(); ++iter)
	{
		curr_data = *iter;
		if (curr_data->get_output())
		{
			curr_data->save_binary(outfile);
		}
	}
	return;
}