#include <shlwapi.h>
#include <shlobj.h>
#include "common\skyscript.h"
#include "common\plugin.h"
#include "common\enums.h"
#include "grutils.h"

#pragma comment(lib, "shlwapi.lib")

static LoadOrder PlugInList;

//
// GRLoadOrder
//

// 初期化
//      メインループを実行する前に、一土だけ実行すること
bool GRLoadOrder::Initialize(void)
{
	memset(&PlugInList, 0, sizeof(PlugInList));

	// plugins.txt のパス取得＆存在チェック
	static char path[MAX_PATH];
	bool ret = (SHGetSpecialFolderPath(NULL, path, CSIDL_LOCAL_APPDATA, 0) == TRUE);
	if (ret) {
        // plugins.txt のフルパス作成
		strcat_s(path, sizeof(path), "\\Skyrim\\plugins.txt");
		ret = (PathFileExistsA(path) == TRUE);
		if (ret) {
            // リストの０番目、１番目はそれぞれ Skyrim.esm、Update.esm 固定とする
			PlugInList.count = 2;
			strcpy_s(PlugInList.plugins[0].filename, PLUGINFILE_SIZE, "Skyrim.esm");
			strcpy_s(PlugInList.plugins[1].filename, PLUGINFILE_SIZE, "Update.esm");
			// plugins.txt 読み込み（２番めのエントリー以降を取得する）
			FILE *fp;
			fopen_s(&fp, path, "r");
            // plugin.txt を一行ずつ読み込んで処理する
			while((PlugInList.count <= 0xff) &&
				(fgets(PlugInList.plugins[PlugInList.count].filename, PLUGINFILE_SIZE, fp) != NULL)) {
				char *p;
                // 行末の改行を除去
				if ((p = strchr(PlugInList.plugins[PlugInList.count].filename, 0x0a)) != NULL)	*p = '\0';
				if ((p = strchr(PlugInList.plugins[PlugInList.count].filename, 0x0d)) != NULL)	*p = '\0';
				// SkyrimLauncher, NMM, Wrye Bash, BOSSのフォーマット違いを吸収
                // 空行、コメント行、Skyrim.esm、Update.esmのエントリーをスキップする
				if ((PlugInList.plugins[PlugInList.count].filename[0] == '\0') || 
					(PlugInList.plugins[PlugInList.count].filename[0] == '#') ||
					(_stricmp(PlugInList.plugins[PlugInList.count].filename, "Skyrim.esm") == 0) ||
					(_stricmp(PlugInList.plugins[PlugInList.count].filename, "Update.esm") == 0)
					)
					continue;
                // ロードしたMODの個数を加算
				PlugInList.count++;
			}
			fclose(fp);
		}
	}
	return (ret && (PlugInList.count > 0));
}

//  ロードしたMODの総数取得
int GRLoadOrder::GetPluginCount(void)
{
	return PlugInList.count;
}

// ロードしたMODのリストを取得
LoadOrder *GRLoadOrder::GetPlugInList(void)
{
	return &PlugInList;
}

// MOD名からオーダーNoを取得
int GRLoadOrder::GetOrderNoFromName(char *pluginname)
{
	// 空文字列は Skyrim.esmとして扱う
	if (strlen(pluginname) == 0) return 0;
	for(int i=0; i < PlugInList.count; i++) {
		if (_stricmp(pluginname, PlugInList.plugins[i].filename) == 0)
			return i;
	}

	return -1;
}

//
// FormIDのオーダーNo部分を取得
//
int	GRLoadOrder::GetOrderNoFromID(uint aiFormID)
{
	uint maskid = (aiFormID & 0xff000000);
	return (int)(maskid >> 24);
}

//
// Form に関連づいたMODファイル名取得
//
char *GRLoadOrder::GetPluginName(TESForm *form, bool fIgnoreLoadOrder)
{
	TESForm *unarmed = Game::GetFormById(ID_TESObjectWEAP::Unarmed);
	if (!form || (form == unarmed) || fIgnoreLoadOrder)	return NULL;
	LoadOrder *order = GRLoadOrder::GetPlugInList();
	int orderNo = GRLoadOrder::GetOrderNoFromID(Form::GetFormID(form));
	if (orderNo < 0) return NULL;
	return order->plugins[orderNo].filename;
}

//
// Game::GerFormID() 拡張版
// ロードオーダーが変わった場合でも追跡する
// MODが削除されたような場合はNULLが返る
//
TESForm *GRLoadOrder::GetExtraFormByID(uint aiFormID, char *pluginName, bool fIgnoreLoadOrder)
{
	if (aiFormID == 0) return NULL;
	if (fIgnoreLoadOrder) return Game::GetFormById(aiFormID);

	TESForm *form = NULL;

	// フォームIDとMDOファイル名のそれぞれからロードオーダーを取得
	int orderNo_id	 = GRLoadOrder::GetOrderNoFromID(aiFormID);
	int orderNo_name = GRLoadOrder::GetOrderNoFromName(pluginName);
	if (orderNo_name < 0) return NULL;

	if (orderNo_id == orderNo_name) {
        // フォームIDとMOD名から抽出したオーダーNoが一致すれば、
        // ロードオーダーに変更がないということになるので、通常のGetFormByID()をコール
		form = Game::GetFormById(aiFormID);
	} else {
		// ロードオーダーが変わっている場合、MODファイル名からロードオーダーを探る
        // 上位１バイトの所に、オーダーNoを代入する
		uint baseID = (aiFormID & 0x00ffffff);
		orderNo_name <<= 24;
		form = Game::GetFormById(baseID | orderNo_name);
	}

	return form;
}

