//
// Program: STEPToMesh
//
// Description:
//
// The program STEPToMesh converts solids contained in STEP files into triangle meshes.
//
// Copyright(C) 2020 Alexander Leutgeb
//
// This library is free software; 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.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110 - 1301  USA
//

#include <TopoDS_Solid.hxx>
#include <TopoDS_Compound.hxx>
#include <TopoDS_Builder.hxx>
#include <TopoDS.hxx>
#include <STEPControl_Reader.hxx>
#include <TopoDS_Shape.hxx>
#include <IFSelect_ReturnStatus.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Edge.hxx> 
#include <TopExp_Explorer.hxx>
#include <Bnd_Box.hxx>
#include <BRepBndLib.hxx>
#include <BRepMesh_IncrementalMesh.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <TopLoc_Location.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <TColgp_Array1OfDir.hxx>
#include <Geom_Surface.hxx>
#include <Geom_Curve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <Poly_Connect.hxx>
#include <Poly_Triangulation.hxx>
#include <Poly_Array1OfTriangle.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <GCPnts_TangentialDeflection.hxx>
#include <StdPrs_ToolTriangulatedShape.hxx>

#include "PotPack.h"
#include "MeshUnit.h"

#include <cmath>
#include <iostream>
#include <map>
#include <fstream>
#include "cxxopts.hpp"

using namespace std;

struct Vector {
	double x;
	double y;
	double z;
};

// 获取线性偏差值
double getLinearDeflection(const TopoDS_Shape& shape)
{
	Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
	Bnd_Box box;

	BRepBndLib::Add(shape, box);
	box.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);

	double xSize = Xmax - Xmin;
	double ySize = Ymax - Ymin;
	double zSize = Zmax - Zmin;

	// 计算包围盒大小
	double boxSize = sqrt(xSize * xSize + ySize * ySize + zSize * zSize);
	// cout << "box size -> " << boxSize << endl;
	double linearDeflection = boxSize / 100;
	if (linearDeflection < 0.1) {
		linearDeflection = 0.1;
	}
	
	return linearDeflection;
}

// 对结点做处理
void handleNodes(TColgp_Array1OfPnt& nodes, TopLoc_Location& aLocation, struct FaceUnit& this_face)
{
	for (int i=0; i < nodes.Length(); i++) {
		gp_Trsf edgeTransf = aLocation.Transformation();
		gp_Pnt aPoint = nodes.Value(i + 1);
		// cout << "Point info -> " << aPoint.X() << "," << aPoint.Y() << "," << aPoint.Z() << endl;
		gp_Pnt p = aPoint.Transformed(edgeTransf);
		// cout << "Point info -> " << aPoint.X() << "," << aPoint.Y() << "," << aPoint.Z() << endl;
		// cout << "Point info -> " << p.X() << "," << p.Y() << "," << p.Z() << endl;

		this_face.vertex_coord.push_back(p.X());
		this_face.vertex_coord.push_back(p.Y());
		this_face.vertex_coord.push_back(p.Z());
	}
}
// 对UV结点做处理
void handleUVNodes(TColgp_Array1OfPnt2d uvNodes, double& uMin, double& uMax, double& vMin, double& vMax, struct FaceUnit& this_face)
{
	for (int i=0; i < uvNodes.Length(); i++) {
		gp_Pnt2d p = uvNodes.Value(i + 1);

		double x = p.X();
		double y = p.Y();
		this_face.uv_coord.push_back(x);
		this_face.uv_coord.push_back(y);

		if (i == 0) {
			uMin = x;
			uMax = x;
			vMin = y;
			vMax = y;
		}

		if (x < uMin) {
			uMin = x;
		} else if (x > uMax) {
			uMax = x;
		}

		if (y < vMin) {
			vMin = y;
		} else if (y > vMax) {
			vMax = y;
		}
		// cout << "Point info -> " << aPoint.X() << "," << aPoint.Y() << endl;
	}
}

// 对UVNodes做归一化处理
void normalUVNodes(TColgp_Array1OfPnt2d uvNodes, double& uMin, double& uMax, double& vMin, double& vMax, struct FaceUnit& this_face, int orient)
{
	for (int i=0; i < uvNodes.Length(); i++) {
		double x = this_face.uv_coord[(i * 2) + 0];
		double y = this_face.uv_coord[(i * 2) + 1];

		x = (x - uMin) / (uMax - uMin);
		y = (y - vMin) / (vMax - vMin);
		if (orient != 0) {
			x = 1.0 - x;
		}

		this_face.uv_coord[(i * 2) + 0] = x;
		this_face.uv_coord[(i * 2) + 1] = y;
	}
}

void setVector(struct Vector& point, double x, double y, double z) {
	point.x = x;
	point.y = y;
	point.z = z;
}

// 复制vSrc的值到vDest
void copyVector(struct Vector& vSrc, struct Vector& vDest) {
	vDest.x = vSrc.x;
	vDest.y = vSrc.y;
	vDest.z = vSrc.z;
}

// 计算空间2个点的距离
double distanceTo(struct Vector& p1, struct Vector& p2)
{
	double x, y, z;
	double d;

	x = fabs(p1.x - p2.x);
	y = fabs(p1.y - p2.y);
	z = fabs(p1.z - p2.z);
	d = sqrt(x*x + y*y + z*z);

	return d;
}

// 计算Curve长度
double lengthOfCurve(GeomAdaptor_Curve& geomAdaptor, double uMin, double uMax)
{
	int segments = 5;

	struct Vector point1;
	struct Vector point2;
	double arcLength = 0;
	gp_Pnt gpPnt;

	bool firstCycle = true;
	for (double s = uMin; s <= uMax; s+= (uMax - uMin) / segments) {
		geomAdaptor.D0(s, gpPnt);
		setVector(point1, gpPnt.X(), gpPnt.Y(), gpPnt.Z());
		if (firstCycle) {
			copyVector(point1, point2);
			firstCycle = false;
		} else {
			arcLength += distanceTo(point1, point2);
		}
		copyVector(point1, point2);
	}

	return arcLength;
}

// 处理Curve
void handleCurve(const TopoDS_Face& myFace, double uMin, double uMax, double vMin, double vMax, int curFace, vector<struct UvUnit>& uv_boxes)
{
	// 计算UV Bounds
	double uParam = uMin + (uMax - uMin) * 0.5;
	double vParam = vMin + (vMax - vMin) * 0.5; 

	Handle(Geom_Surface) surface = BRep_Tool::Surface(myFace);
	Handle(Geom_Curve) uIsoHandle = surface->UIso(uParam);
	Handle(Geom_Curve) vIsoHandle = surface->VIso(vParam);
	GeomAdaptor_Curve uAdaptor = GeomAdaptor_Curve(vIsoHandle);
	GeomAdaptor_Curve vAdaptor = GeomAdaptor_Curve(uIsoHandle);

	struct UvUnit boxUnit;
	boxUnit.w = lengthOfCurve(uAdaptor, uMin, uMax);
	boxUnit.h = lengthOfCurve(vAdaptor, vMin, vMax);
	boxUnit.index = curFace;
	uv_boxes.push_back(boxUnit);
	// cout << "width and height -> " << w << "," << h << endl;
}

// 三角面片处理
void handleTriangles(Handle(Poly_Triangulation) myT, struct FaceUnit& this_face, int orient)
{
	int validFaceTriCount = 0;
	const Poly_Array1OfTriangle& triangles = myT->Triangles();
	for (int nt=1; nt <= myT->NbTriangles(); nt++) {
		const Poly_Triangle& t = triangles.Value(nt);
		int n1 = t.Value(1);
		int n2 = t.Value(2);
		int n3 = t.Value(3);
		// cout << "handleTriangles -> " << n1 << "," << n2 << "," << n3 << endl;

		if (orient != 0) {
			int tmp = n1;
			n1 = n2;
			n2 = tmp;
		}

		this_face.tri_indexes.push_back(n1 - 1);
		this_face.tri_indexes.push_back(n2 - 1);
		this_face.tri_indexes.push_back(n3 - 1);
		validFaceTriCount++;	
	}

	this_face.number_of_triangles = validFaceTriCount;	
}

// 处理面中的边集合
void handleEdgesWithinFace(const TopoDS_Face& myFace, Handle(Poly_Triangulation) myT, TopLoc_Location& aLocation,
	struct FaceUnit& this_face, map<int, int>& fullShapeEdgeHashes, map<int, int>& fullShapeEdgeHashes2, vector<struct EdgeUnit>& edgeList)
{
	TopExp_Explorer anEdgeExp(myFace, TopAbs_EDGE);
	for (anEdgeExp.Init(myFace, TopAbs_EDGE, TopAbs_SHAPE); anEdgeExp.More(); anEdgeExp.Next()) {
		const TopoDS_Edge& myEdge = TopoDS::Edge(anEdgeExp.Current());
		int edgeHash = myEdge.HashCode(100000000);

		if (fullShapeEdgeHashes2.count(edgeHash) > 0) {
			struct EdgeUnit this_edge;
			this_edge.edge_index = -1;

			Handle(Poly_PolygonOnTriangulation) myP = BRep_Tool::PolygonOnTriangulation(myEdge, myT, aLocation);
			TColStd_Array1OfInteger edgeNodes = myP->Nodes();
			for (int j=0; j < edgeNodes.Length(); j++) {
				int vertexIndex = edgeNodes.Value(j + 1);
				this_edge.vertex_coord.push_back( this_face.vertex_coord[((vertexIndex - 1) * 3) + 0] );
				this_edge.vertex_coord.push_back( this_face.vertex_coord[((vertexIndex - 1) * 3) + 1] );
				this_edge.vertex_coord.push_back( this_face.vertex_coord[((vertexIndex - 1) * 3) + 2] );
		
				// cout << "vertex index -> " << vertexIndex << endl;
			}
			this_edge.edge_index = fullShapeEdgeHashes[edgeHash];
			edgeList.push_back(this_edge);
		} else {
			fullShapeEdgeHashes2[edgeHash] = edgeHash;
		}
	}
}

// 处理独立的边集合
void handleEdges(TopoDS_Shape& shape, double linearDeflection, map<int, int>& fullShapeEdgeHashes, 
	map<int, int>& fullShapeEdgeHashes2, vector<struct EdgeUnit>& edgeList)
{
	TopExp_Explorer anEdgeExp(shape, TopAbs_EDGE);
	for (anEdgeExp.Init(shape, TopAbs_EDGE, TopAbs_SHAPE); anEdgeExp.More(); anEdgeExp.Next()) {
		const TopoDS_Edge& myEdge = TopoDS::Edge(anEdgeExp.Current());
		int edgeHash = myEdge.HashCode(100000000);
		if (fullShapeEdgeHashes2.count(edgeHash) <= 0) {
			struct EdgeUnit this_edge;
			this_edge.edge_index = -1;

			TopLoc_Location aLocation;
			BRepAdaptor_Curve adaptorCurve(myEdge);
			GCPnts_TangentialDeflection tangDef(adaptorCurve, linearDeflection, 0.1, 2, 1.0e-9, 1.0e-7);

			// 写入顶点数据集
			for (int j = 0; j < tangDef.NbPoints(); j++) {
				gp_Pnt vertex = tangDef.Value(j + 1).Transformed(aLocation.Transformation());
				this_edge.vertex_coord.push_back(vertex.X());
				this_edge.vertex_coord.push_back(vertex.Y());
				this_edge.vertex_coord.push_back(vertex.Z());
				// cout << "tangDef NbPoint -> " << vertex.X() << "," << vertex.Y() << "," << vertex.Z() << endl;
			}

			this_edge.edge_index = fullShapeEdgeHashes[edgeHash];
			fullShapeEdgeHashes2[edgeHash] = edgeHash;

			edgeList.push_back(this_edge);
		}

    }
}

// 获取Shell数量
int statShellCount(TopoDS_Shape& shape)
{
	int shellCount = 0;
	TopExp_Explorer aShellExp(shape, TopAbs_SHELL);
	for (aShellExp.Init(shape, TopAbs_SHELL, TopAbs_SHAPE); aShellExp.More(); aShellExp.Next()) {
		shellCount++;
	}

	return shellCount;
}

// 获取顶点数量
int statVertexCount(TopoDS_Shape& shape)
{
	int vertexCount = 0;
	TopExp_Explorer aVertexExp(shape, TopAbs_VERTEX);
	for (aVertexExp.Init(shape, TopAbs_VERTEX, TopAbs_SHAPE); aVertexExp.More(); aVertexExp.Next()) {
		vertexCount++;
	}

	return vertexCount;
}

// 统计Solid
void statSolid(TopoDS_Shape& shape, vector<struct SolidUnit>& solidList)
{
	int eachFaceIndex = 0;
	int index = 0;

	TopExp_Explorer aSolidExp(shape, TopAbs_SOLID);
	for (aSolidExp.Init(shape, TopAbs_SOLID, TopAbs_SHAPE); aSolidExp.More(); aSolidExp.Next()) {
		const TopoDS_Solid& mySolid = TopoDS::Solid(aSolidExp.Current());
		index++;

		// 增加Solid单元
		struct SolidUnit solidUnit;
		solidUnit.solid_index = index;
		solidUnit.face_start_index = eachFaceIndex;
		
		TopExp_Explorer aFaceExp(mySolid, TopAbs_FACE);
		for (aFaceExp.Init(mySolid, TopAbs_FACE, TopAbs_SHAPE); aFaceExp.More(); aFaceExp.Next()) {
			eachFaceIndex++;
		}

		solidUnit.face_end_index = eachFaceIndex;
		solidList.push_back(solidUnit);
	}

	// cout << "stat solid -> " << index << "," << eachFaceIndex << endl;
}

// 输出系统时间
void outTime()
{
	time_t now = time(0);
	tm* ltm = localtime(&now);

	char realTime[100];
	sprintf(realTime,"%d/%d/%d %d:%d:%d", 1900 + ltm->tm_year, 1 + ltm->tm_mon, ltm->tm_mday, (ltm->tm_hour) % 24, ltm->tm_min, ltm->tm_sec);
	// cout << "now time -> " << realTime << endl;
}

// 输出测试HASH
void outHashes(map<int, int>& objHashes)
{
	map<int, int>::iterator iter;
	for(iter = objHashes.begin(); iter != objHashes.end(); iter++) {
		cout << iter->first << " : " << iter->second << endl;
	}
}

// 初始化边Hash
void initEdgeHashes(TopoDS_Shape& shape, map<int, int>& edgeHashes)
{
	int edgeIndex = 0;

	TopExp_Explorer anEdgeExp(shape, TopAbs_EDGE);
	for (anEdgeExp.Init(shape, TopAbs_EDGE, TopAbs_SHAPE); anEdgeExp.More(); anEdgeExp.Next()) {
		const TopoDS_Edge& myEdge = TopoDS::Edge(anEdgeExp.Current());

		int edgeHash = myEdge.HashCode(100000000);
		// cout << edgeHash << endl;
		if (edgeHashes.count(edgeHash) <= 0) {
			edgeHashes[edgeHash] = edgeIndex;
			edgeIndex++;
		}
	}
}

// 初始化面Hash
void initFaceHashes(TopoDS_Shape& shape, map<int, int>& faceHashes)
{
	int faceIndex = 0;

	TopExp_Explorer aFaceExp(shape, TopAbs_FACE);
	for (aFaceExp.Init(shape, TopAbs_FACE, TopAbs_SHAPE); aFaceExp.More(); aFaceExp.Next()) {
		const TopoDS_Face& myFace = TopoDS::Face(aFaceExp.Current());

		int faceHash = myFace.HashCode(100000000);
		if (faceHashes.count(faceHash) <= 0) {
			faceHashes[faceHash] = faceIndex;
			faceIndex++;
		}
	}
}

// 读取STEP文件
void initReader(STEPControl_Reader& reader, const Standard_CString filename)
{
	IFSelect_ReturnStatus stat = reader.ReadFile(filename);
	// cout << "read file complete!" << endl;
	  
	reader.TransferRoots();
	// cout << "transfer roots complete!" << endl;
}

// 处理Normal Buffer
void handleNormalBuffer(Handle(Poly_Triangulation)& myT, TColgp_Array1OfPnt& nodes, const TopoDS_Face& myFace, 
	TopLoc_Location& aLocation, struct FaceUnit& this_face)
{
	Poly_Connect pc(myT);
	TColgp_Array1OfDir myNormal(nodes.Lower(), nodes.Upper());
	StdPrs_ToolTriangulatedShape::Normal(myFace, pc, myNormal);
	for (int i=0; i < myNormal.Length(); i++) {
		gp_Dir d = myNormal.Value(i + 1).Transformed(aLocation.Transformation());
		this_face.normal_coord.push_back(d.X());
		this_face.normal_coord.push_back(d.Y());
		this_face.normal_coord.push_back(d.Z());
		// cout << "myNormal point -> " << d.X() << "," << d.Y() << "," << d.Z() << endl;
	}
}

// 每个面UV调整为世界坐标，并通过potpack调整为0-1间的值
void uvPadding(vector<struct UvUnit>& uv_boxes, vector<struct FaceUnit>& faceList)
{
	// padding填充与potpack处理
	int padding = 2;
	for (int i = 0; i < uv_boxes.size(); i++) {
		uv_boxes[i].w += padding;
		uv_boxes[i].h += padding;
	}

	struct UvUnit packing_stats;
	potpack(packing_stats, uv_boxes);
	// cout << "potpack complete!" << endl;

	// 遍历每个uv_boxes元素
	for (int f = 0; f < uv_boxes.size(); f++) {
		struct UvUnit& box = uv_boxes[f];
      	struct FaceUnit& this_face = faceList[box.index];
		// cout << "iterate uv box " << f << "," << box.index << "," << this_face.uv_coord.size() << endl;

		for (int q = 0; q < this_face.uv_coord.size() / 2; q++) {
			double x = this_face.uv_coord[(q * 2) + 0];
			double y = this_face.uv_coord[(q * 2) + 1];
			
			x = ((x * (box.w - padding)) + (box.x + (padding * 0.5))) / std::max(packing_stats.w, packing_stats.h);
			y = ((y * (box.h - padding)) + (box.y + (padding * 0.5))) / std::max(packing_stats.w, packing_stats.h);

			this_face.uv_coord[(q * 2) + 0] = x;
			this_face.uv_coord[(q * 2) + 1] = y;
		}

	}
}

// 每个面的处理
void handleEachFace(const TopoDS_Face& myFace, vector<struct FaceUnit>& faceList, vector<struct EdgeUnit>& edgeList,
	map<int, int>& fullShapeEdgeHashes, map<int, int>& fullShapeFaceHashes, 
	int curFace, vector<struct UvUnit>& uv_boxes, map<int, int>& fullShapeEdgeHashes2)
{
	// 对面做三角网格处理
	TopLoc_Location aLocation;
	Handle(Poly_Triangulation) myT = BRep_Tool::Triangulation(myFace, aLocation);
	if (myT.IsNull()) {
		// cout << "myT is null ..." << endl;

		struct FaceUnit errorData;
		errorData.face_index = fullShapeFaceHashes[myFace.HashCode(100000000)];
		errorData.number_of_triangles = 0;
		faceList.push_back(errorData);
		return;
	}

	struct FaceUnit this_face;
	this_face.face_index = fullShapeFaceHashes[myFace.HashCode(100000000)];
	this_face.number_of_triangles = 0;

	// 处理Nodes和UVNodes
	TColgp_Array1OfPnt nodes = myT->Nodes();
	handleNodes(nodes, aLocation, this_face);

	TopAbs_Orientation orient = myFace.Orientation();
	this_face.orient = orient;
	// cout << "orient -> " << orient << endl;

	if (myT->HasUVNodes()) {
		double uMin, uMax, vMin, vMax;
		TColgp_Array1OfPnt2d uvNodes = myT->UVNodes();
		handleUVNodes(uvNodes, uMin, uMax, vMin, vMax, this_face);
		normalUVNodes(uvNodes, uMin, uMax, vMin, vMax, this_face, orient);
		// cout << "uv nodes bounds -> " << uMin << "," << uMax << "," << vMin << "," << vMax << endl;

		// 处理Curve
		handleCurve(myFace, uMin, uMax, vMin, vMax, curFace, uv_boxes);

	}

	// 写入Normal缓冲区
	handleNormalBuffer(myT, nodes, myFace, aLocation, this_face);

	// 三角面片处理
	handleTriangles(myT, this_face, orient);
	faceList.push_back(this_face);

	// 处理面中的边集合
	handleEdgesWithinFace(myFace, myT, aLocation, this_face, fullShapeEdgeHashes, fullShapeEdgeHashes2, edgeList);

}

// 获取json文件
string getJsonFile(const char* stpFile)
{
	string fromFile = stpFile;
	int pos = fromFile.find(".");
	
	string jsonFile = fromFile.substr(0, pos);
	jsonFile.append(".self");
	return jsonFile;
}

// json文本输出到文件
void writeFile(string jsonText, string& jsonFile)
{
	ofstream fout;
	fout.open(jsonFile, ios::out);
	fout << jsonText;
	fout.close();
}

int main(int argc, char* argv[]) {
	if (argc <= 1) {
		cout << "Usage: ./STEPToMesh StpFile" << endl;
		return 0;
	}
	const Standard_CString filename = argv[1];


	// ---------------------------- 文件读取 -------------------------------
	// 读取STEP文件
	STEPControl_Reader reader;
	initReader(reader, filename);

	TopoDS_Shape shape = reader.OneShape();
	// cout << "one shape complete!" << endl;

	// ---------------------------- 全局变量初始化 -------------------------------
	// 初始化边和面HASH
	map<int, int> fullShapeEdgeHashes;
	map<int, int> fullShapeEdgeHashes2;
	map<int, int> fullShapeFaceHashes;
	initEdgeHashes(shape, fullShapeEdgeHashes);
	initFaceHashes(shape, fullShapeFaceHashes);
	// outHashes(fullShapeEdgeHashes);

	// 全局变量定义
	vector<struct UvUnit> uv_boxes;

	// 待返回的数据变量
	vector<struct FaceUnit> faceList;
	vector<struct EdgeUnit> edgeList;
	vector<struct SolidUnit> solidList;


	// ---------------------------- 模型网格化与解析 -------------------------------
	// 网格化处理
	double linearDeflection = getLinearDeflection(shape);
	BRepMesh_IncrementalMesh mesh(shape, linearDeflection, false, 0.5, false);
	// cout << "mesh complete!" << endl;

	// 遍历面
	int curFace = 0;
	TopExp_Explorer aFaceExp;
	for (aFaceExp.Init(shape, TopAbs_FACE, TopAbs_SHAPE); aFaceExp.More(); aFaceExp.Next()) {
		const TopoDS_Face& myFace = TopoDS::Face(aFaceExp.Current());
		handleEachFace(myFace, faceList, edgeList, fullShapeEdgeHashes, fullShapeFaceHashes, curFace, uv_boxes, fullShapeEdgeHashes2);
		curFace++;
	}
	// cout << "iterate faces complete!" << endl;

	// 每个面UV调整为世界坐标，并通过potpack调整为0-1间的值
	uvPadding(uv_boxes, faceList);

	// 处理独立的边集合
	handleEdges(shape, linearDeflection, fullShapeEdgeHashes, fullShapeEdgeHashes2, edgeList);

    // 统计数量
    int shellCount = statShellCount(shape);
	int vertexCount = statVertexCount(shape);
	// cout << "stat count -> " << shellCount << "," << vertexCount << endl;
	statSolid(shape, solidList);
	outTime();


	// --------------------------- 模型数据写入输出 --------------------------
	string jsonText = toJson(faceList, edgeList, solidList, shellCount, vertexCount);
	string jsonFile = getJsonFile(filename);
	if (argc >= 3) {
		jsonFile = argv[2];
	}
	writeFile(jsonText, jsonFile);
	
}
