// ECodeParserTest.cpp: 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <strstream>
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#include "../ECodeParser/ECodeParser.h"
using namespace std;

BOOL GetRegValue(LPCSTR path, LPCSTR name, char* buffer, DWORD& len)
{
	HKEY hKey;
	BOOL bRet = FALSE;
	if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CURRENT_USER, path, 0, KEY_READ, &hKey))
	{
		if (ERROR_SUCCESS == RegQueryValueExA(hKey, name, 0, NULL, (LPBYTE)buffer, &len))
		{
			bRet = TRUE;
		}

		RegCloseKey(hKey);
	}
	return bRet;
}

// 命令行调用方式, 0 = 程序路径, 1=被解析源码路径, [2=解析模式], [3=易语言安装目录]
int main(int argc, char* argv[])
{
	// 1. 读入源码数据
	string file;
	string path;
	string fileName;
	int mode = 0;
	if (argc > 1)	// 有命令行, 1 = 源码路径, 2 = 解析模式, 3 = 易语言安装目录,e.exe所在的目录, "\" 可有可无
	{
		file = argv[1];
	}
	if (!file.empty() && (file.substr(file.size() - 2, 2) == ".e" || file.substr(file.size() - 3, 3) == ".ec"))
	{
		string ePath;
		if (argc > 3)
			mode = atoi(argv[2]);
		if (argc >= 4)
		{
			ePath = argv[3];
		}
		else
		{
			char tmpPath[MAX_PATH] = { 0 };
			DWORD dwLen = MAX_PATH;
			GetRegValue("Software\\FlySky\\E\\Install", "Path", tmpPath, dwLen);
			ePath = tmpPath;
			ePath = ePath.substr(0, ePath.size() - 4);
			if (ePath.size() < 4)
				return -5;	// 易语言安装目录获取失败
		}
		if (ePath.substr(ePath.size() - 1, 1) != "\\")
		{
			ePath.append("\\");
		}
		ECode* parser = ECodeParser_Create(ePath.c_str());

		ifstream fs(file, ios::binary);
		ostrstream stream(NULL, 0, ios::binary);
		stream << fs.rdbuf();
		fs.close();

		EInfo* info = ECodeParser_Parse(parser, (LPBYTE)stream.str(), stream.pcount(), FALSE);
		printf("共有命令:%d\n", info->Program.Methods.size());
		//int exitCode = parser->saveECode(file.c_str(), mode);
		//ECodeParser_Destroy(parser);

		return 0;
	}


	cout << "请输入易语言源码文件路径(输入 0 退出程序):\n";
	while (true)
	{
		cin >> file;
		if (file == "0") return 0;
		if (file.size() < 6)
		{
			cout << "路径不正确, 请重新输入(输入 0 退出程序):\n";
			continue;
		}
		path = file;
		if (path.substr(path.size() - 3, 3) == ".ec")
		{
			path = path.substr(0, path.size() - 2);
			path += "_解析\\";
			int flag = GetFileAttributesA(path.c_str());
			if (!(flag & FILE_ATTRIBUTE_DIRECTORY) || (flag == INVALID_FILE_ATTRIBUTES && GetLastError() == 2))	// 目录不存在则创建
			{
				if (!CreateDirectoryA(path.c_str(), NULL))
				{
					cout << "文件夹:" << path << "  创建失败\n程序将退出\n";

					return 0;
				}
			}
			fileName = PathFindFileNameA(file.c_str());
			int nPos = fileName.rfind('.');
			if (nPos != string::npos)
				fileName = fileName.substr(0, nPos);
		}
		else
		{
			cout << "路径不正确, 请重新输入(输入 0 退出程序):\n";
			continue;
		}

		ifstream fs(file, ios::binary);
		ostrstream stream(NULL, 0, ios::binary);
		stream << fs.rdbuf();
		fs.close();
		try
		{
			if (stream.str() == NULL)
				throw 1;
		}
		catch (int i)
		{
			if (i == 1)
			{
				cout << "文件数据 \"" << file << "\" 未获取成功....请重新加载......\n";
				continue;
			}
		}

		// 2. 创建解析的对象
		ECode* parser = ECodeParser_Create("E:\\易语言正式版\\");
		EInfo* info = ECodeParser_Parse(parser, (LPBYTE)stream.str(), stream.pcount(), FALSE);

		//所有重要的内容都在：ECodeParser_Parse中了。他是ECodeParser的对外接口，内部调用类方法实现。具体请参考源码

		string sysInfo = parser->getSysInfo();
		string DllInfo = parser->getDllInfo();
		string DataTypeInfo = parser->getDataType();
		string GlobalInfo = parser->getGlobal();
		vector<string> AssembliesInfo = parser->getAssemblies();
		string constInfo = parser->getConstInfo();
		string strs, consts;
		cout << "请输入保存方式: (1)单文件方式保存, (其他)分开保存   ";
		int mode = 0;
		cin >> mode;

		if (mode == 1)
		{
			string saveFile = path + fileName + ".txt";
			for (auto i = AssembliesInfo.begin(); i < AssembliesInfo.end(); i++)
			{
				i++;	// 第一个记录程序集类型,跳过
				strs += *i;
				//consts;
			}
			strs = strs + GlobalInfo + DllInfo + DataTypeInfo + constInfo + sysInfo;
			writeFile(saveFile, strs);
		}
		else
		{
			//这是写出结果的路径。
			string sys = path + "系统配置.txt";	// 包括用户配置,加载的模块,加载的支持库
			string dll = path + "DLL信息.txt";
			string dataType = path + "数据类型.txt";
			string global = path + "全局变量.txt";
			string constFile = path + "常量.txt";

			writeFile(sys, sysInfo);
			writeFile(dll, DllInfo);
			writeFile(dataType, DataTypeInfo);
			writeFile(global, GlobalInfo);
			writeFile(constFile, constInfo);
			for (auto i = AssembliesInfo.begin(); i < AssembliesInfo.end(); i++)
			{
				string saveFile = path + *i + ".txt";
				i++;	// 第一个记录程序集类型,跳过
				writeFile(saveFile, *i);
			}
		}


		cout << "解析完毕,请查看 \"" << path << "\" 目录下解码好的txt文件\n";
		cout << "请输入易语言源码文件路径(如果不需要解码其他文件, 输入 0 退出程序):\n";
		ECodeParser_Destroy(parser);
	}

	return 0;
}


