/********************************************************************/
/* Copyright (c) 2019 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
/********************************************************************/
#include "stdafx.h"
#include "mg/Group.h"
#include "mg/MGStl.h"
#include "resource.h"
#include "fugen.h"
#include "IO/GLUnvImporter.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CGLUnvImporter::CGLUnvImporter()
	 : CGLFileImporter(IDS_FILTER_UNV)
{
}

namespace
{
	bool IsNodeSectBegin(const std::string& str)
	{
		return str == "781" || str == "2411";
	}

	bool IsCellSectBegin(const std::string& str)
	{
		return str == "71" || str == "780" || str == "2412";
	}

	// TODO: skipws を明示的に指定しなければ動かぬようだったら、
	// そのように修正すること。
	std::vector<std::string> split_ws(const std::string strLine)
	{
		std::vector<std::string> fields;
		std::string strWk;
		std::istringstream iss(strLine, std::istringstream::in);
		while(iss >> strWk){
			fields.push_back(strWk);
		}
		return fields;
	}

	enum Section
	{
		SOMETHING = 0,
		OTHER = 55,
		CELL = 780,
		NODE = 781,
	};
	
	bool LoadOnlyTriangles(const CString& strFilePath, MGStl& stl)
	{
		std::ifstream fin(strFilePath);
		if(!fin){
			return false;
		}

		std::vector<MGPosition> vertices; // 出現順 -> XYZ
		std::map<int, int> ids; // Node ID -> 出現順
		int nCount = 0; // Node の出現順をカウントアップ
		std::vector<std::vector<int> > cells; // Cell レコード

		Section mode = SOMETHING;
		std::string strLine;
		while(std::getline(fin, strLine)){

			// 空白文字で split する。
			std::vector<std::string> fields(split_ws(strLine));
			if(fields.empty()){
				continue;
			}

			const std::string field0 = fields.front(); 
			if(field0.find("displacement") == 0){
				// ここから先は読み込まなくてよい
				break;
			}

			// セクションのタイプを知る

			if(mode != SOMETHING && field0 == "-1"){
				// ダミー行
				mode = SOMETHING;
			}
			else if(mode == SOMETHING && IsNodeSectBegin(field0)){
				// NODE レコード開始
				mode = NODE;
			}
			else if(mode == SOMETHING && IsCellSectBegin(field0)){
				// CELL レコード開始
				mode = CELL;
			}
			else if(mode == SOMETHING && field0 == "55"){
				// 解析データ
				mode = OTHER;
			}
			else{

				// セクション内のレコードを処理する

				switch(mode){
				case NODE:
					//       4653         0         0        11
					//    1.4000000000000000D+02   2.0000000000000000D+01   1.6000000000000001D+00
					{
						const int nID = atoi(field0.c_str());
						ids.insert(std::make_pair(nID, nCount));
						++nCount;

						// 追加で一行読み取る
						if(std::getline(fin, strLine)){
							///strLine.replace('D', 'E');
							std::replace(strLine.begin(), strLine.end(), 'D', 'E');
							std::vector<std::string> rec(split_ws(strLine));
							if(rec.size() >= 3){
								vertices.push_back(
									MGPosition(atof(rec[0].c_str()),
											   atof(rec[1].c_str()),
											   atof(rec[2].c_str())));
							}
						}
					}
					break;
				case CELL:
					{
						//const int nID = atoi(field0.c_str());
						//ids.insert(std::make_pair(nID, nCount));
						//++nCount;

						// 一行目を捨てて
						// Node ID の配列を読み込む
						if(std::getline(fin, strLine)){
							std::vector<std::string> rec(split_ws(strLine));
							std::vector<int> cell;

							// 整数に変換して cell をひとつ追加
							for(size_t i = 0; i < rec.size(); ++i){
								cell.push_back(atoi(rec[i].c_str()));
							}
							cells.push_back(cell);
						}
					}
					break;
				case OTHER:
					break;
				default:
					// ここには来ない
					mode = SOMETHING;
					break;
				}
			}
		} // getline

		if(vertices.empty() || cells.empty()){
			return false;
		}

		CString str, strMsg;
		strMsg.Format(IDS_MESH_CELLS_AND_POINTS, cells.size(), vertices.size());
		str.Format(IDS_INFORMATION, strMsg);
		putInOutputWindow(str);

		// 後半戦
		// cells から三角形列を得る
		std::vector<int> indices;
		const size_t nCell = cells.size();
		for(size_t i = 0; i < nCell; ++i){
			const std::vector<int>& cell = cells[i];
			if(cell.size() != 3){
				continue;
			}

			// cell は三角形
			for(int j = 0; j < 3; ++j){
				// ID 変換を行う
				indices.push_back(ids[cell[j]]);
			}
		}

		if(indices.empty()){
			return false;
		}

		// フィニッシュ
		stl.set_all_data(vertices, indices);
		return true;
	}
} // namespace

bool CGLUnvImporter::Load(MGGroup& group)
{
	const CString& strFileName = GetFileName();

	std::unique_ptr<MGStl> spStl(new MGStl);
	if(!LoadOnlyTriangles(strFileName, *spStl)){
		CString str, strMsg;
		strMsg.Format(IDS_TRIANGLE_NOT_EXIST, strFileName);
		str.Format(IDS_ERROR, strMsg);
		putInOutputWindow(str);
		return false;
	}

	group.append(spStl.release());
	return true;
}
