/********************************************************
 *  ██████╗  ██████╗████████╗██╗
 * ██╔════╝ ██╔════╝╚══██╔══╝██║
 * ██║  ███╗██║        ██║   ██║
 * ██║   ██║██║        ██║   ██║
 * ╚██████╔╝╚██████╗   ██║   ███████╗
 *  ╚═════╝  ╚═════╝   ╚═╝   ╚══════╝
 * 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 "gmsh_io.h"

gctl::gmshio::gmshio()
{
    in_packed = out_packed = Packed;
}

gctl::gmshio::gmshio(std::string filename, file_direction_e f_direct)
{
    init_file(filename, f_direct);
}

gctl::gmshio::~gmshio()
{
    if (gmsh_in.is_open()) gmsh_in.close();
    if (gmsh_out.is_open()) gmsh_out.close();
    if (!rgst_elem.empty()) destroy_vector(rgst_elem);
}

void gctl::gmshio::init_file(std::string filename, file_direction_e f_direct)
{
    if (filename == "")
        throw runtime_error("Empty filename. From gmshio::init_file(...)");

    if (f_direct == Input)
    {
        open_infile(gmsh_in, filename, ".msh");
    }
    else if (f_direct == Output)
    {
        open_outfile(gmsh_out, filename, ".msh");
    }

    return;
}

void gctl::gmshio::reset_file(std::string filename, file_direction_e f_direct)
{
    if (filename == "")
        throw runtime_error("Empty filename. From gmshio::reset_file(...)");

    if (f_direct == Input)
    {
        if (gmsh_in.is_open()) gmsh_in.close();
        open_infile(gmsh_in, filename, ".msh");
    }
    else if (f_direct == Output)
    {
        if (gmsh_out.is_open()) gmsh_out.close();
        open_outfile(gmsh_out, filename, ".msh");
    }

    return;
}

void gctl::gmshio::set_packed(index_packed_e is_packed, file_direction_e f_direct)
{
    if (f_direct == Input)
    {
        in_packed = is_packed;
    }
    else if (f_direct == Output)
    {
        out_packed = is_packed;
    }

    return;
}

bool gctl::gmshio::initialized(file_direction_e f_direct)
{
    if (f_direct == Input && gmsh_in.is_open()) return true;
    if (f_direct == Output && gmsh_out.is_open()) return true;

    throw domain_error("File stream not initialized. From gmshio::initialized(...)");
    return false;
}

void gctl::gmshio::read_physical_groups(array<gmsh_physical_group> &phy_groups)
{
    initialized(Input);

    // 将文件指针重置到文件头
    gmsh_in.clear(std::ios::goodbit);
    gmsh_in.seekg(0, std::ios::beg);

    size_t phys_num;
    std::string tmp_str, tmp_str2;
	std::stringstream tmp_ss;
    while (getline(gmsh_in, tmp_str))
    {
        if (tmp_str == "$PhysicalNames")
        {
            getline(gmsh_in, tmp_str);
            gctl::str2ss(tmp_str, tmp_ss);
            tmp_ss >> phys_num;

            phy_groups.resize(phys_num);
            for (size_t i = 0; i < phys_num; i++)
            {
                getline(gmsh_in, tmp_str);
                str2ss(tmp_str, tmp_ss);
                tmp_ss >> phy_groups[i].dim_tag >> phy_groups[i].phys_tag >> tmp_str2;
                // 去掉两端的双引号
                replace_all(phy_groups[i].name, tmp_str2, "\"", "");
            }
        }
        else continue;
    }
    return;
}

void gctl::gmshio::save_physical_groups(const array<gmsh_physical_group> &phy_groups)
{
    initialized(Output);

    // 将文件指针重置到文件尾
    gmsh_out.clear(std::ios::goodbit);
    gmsh_out.seekp(0, std::ios::end);

    gmsh_out << "$PhysicalNames\n";
    for (size_t i = 0; i < phy_groups.size(); i++)
    {
        gmsh_out << phy_groups[i].dim_tag << " " << phy_groups[i].phys_tag << " \"" << phy_groups[i].name << "\"\n";
    }
    gmsh_out << "$EndPhysicalNames\n";
    return;
}

int gctl::gmshio::physical_name2tag(const array<gmsh_physical_group> &phy_groups, std::string name)
{
    for (size_t i = 0; i < phy_groups.size(); i++)
    {
        if (phy_groups[i].name == name) return phy_groups[i].phys_tag;
    }

    throw std::runtime_error("[gctl::gmshio::physical_name2tag] Physical group name not found.");
    return -1;
}