#include "jd_clear_field.h"
#include <string>
#include <vector>
#include <map>
#include <fstream>

#include <epm/epm.h>
#include <epm/epm_toolkit_tc_utils.h>
#include <ict/ict_userservice.h>
#include <tccore/item.h>
#include <ae/ae.h>
#include <tc/folder.h>
#include <tccore/aom.h>
#include <sa/sa.h>
#include <tccore/aom_prop.h>
#include <property/prop_errors.h>
#include <tccore/workspaceobject.h>
#include <tc/preferences.h>
#include <tccore/imantype.h>
#include <tccore//grm.h>
#include <tccore/grmtype.h>
#include <sa/am.h>
#include <cfm/cfm.h>
#include <bom/bom.h>
#include <iostream>
#include <tccore/uom.h>
#include <ps/ps.h>
#include <epm/signoff.h>
#include <fclasses/tc_date.h>
#include <sa/tcfile_cache.h>
#include <ics\ics2.h>
#include "sstream"
#include "atlstr.h"

#include <tc\tc_macros.h>
#include <tc\emh.h>
#include <tc\preferences.h>
#include <property\propdesc.h>
#include <epm\epm.h>
#include <epm\epm_toolkit_tc_utils.h>
#include <tccore\item.h>
#include <tccore\grmtype.h>
#include <tccore\grm.h>
#include <tccore\imantype.h>
#include <sa\am.h>
#include <sa\sa.h>
#include <tccore\aom.h>
#include <tccore\aom_prop.h>
#include <property\prop_errors.h>
#include <tccore\workspaceobject.h>
#include <qry\qry.h>
#include <bom\bom_attr.h>
#include <bom\bom.h>
#include <epm\signoff.h>
#include <pom\pom\pom.h>
#include <pom\pom\pom_errors.h>
#include <fclasses\tc_date.h>
#include <epm\cr.h>
#include <cfm\cfm.h>
#include <sa\am.h>
#include "tc/envelope.h"
#include <stdio.h>
#include "ae/dataset.h"
#include <ctype.h>
#include <string.h>
#include <string>
#include <iostream>
#include <iterator>
#include <map>
#include <vector>
#include "ce/ce.h"
#include <time.h>
#include <windows.h>  
#include <iostream>  
#include <sql.h>  
#include <sqlext.h>  
#include "string"
#include "sstream"
#include <sa/tcfile.h>
#include <tccore/aom.h>
#include <sa/tcfile_cache.h>
#include <form/form.h>
#include "ctime"
#include "tchar.h"
#include "jni.h"

#ifdef WIN32
#include <io.h>
#include <direct.h> 
#else
#include <unistd.h>
#include <sys/stat.h>
#endif
#include <stdint.h>
#include <string>
#define MAX_PATH_LEN 256

#define GUID_LEN 64

#ifdef WIN32
#define ACCESS(fileName,accessMode) _access(fileName,accessMode)
#define MKDIR(path) _mkdir(path)
#else
#define ACCESS(fileName,accessMode) access(fileName,accessMode)
#define MKDIR(path) mkdir(path,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
#endif

#define LOCALJARPATH "D:\\Siemens\\Teamcenter12\\bin\\tc_extra_jar\\"
#define REMOTEJARPATH "D:\\app\\Siemens\\Teamcenter12\\bin\\tc_extra_jar\\"

//#include <iostream>
using namespace std;
#ifdef __cplusplus
extern "C" int POM_AM__set_application_bypass(logical bypass);
extern "C" {
#endif

	int32_t createDirectory(const std::string &directoryPath) {
		uint32_t dirPathLen = directoryPath.length();
		if (dirPathLen > MAX_PATH_LEN) {
			return -1;
		}
		char tmpDirPath[MAX_PATH_LEN] = { 0 };
		for (uint32_t i = 0; i < dirPathLen; ++i) {
			tmpDirPath[i] = directoryPath[i];
			if (tmpDirPath[i] == '\\' || tmpDirPath[i] == '/') {
				if (ACCESS(tmpDirPath, 0) != 0) {
					int32_t ret = MKDIR(tmpDirPath);
					if (ret != 0) {
						return ret;
					}
				}
			}
		}
		return 0;
	}

	static void replace_dataset_named_reference(tag_t dataset_tag, tag_t old_file,
		const char *new_file_path, char *ref_name) {
		IMF_file_data_p_t file_data;
		int index = 0;
		char *name;

		IMF_get_file_access(old_file, 0, &file_data);

		tag_t new_file_tag = NULLTAG;
		AOM_lock(old_file);

		IMF_ask_original_file_name2(old_file, &name);

		IMF_replace_file_and_get_new_tag(old_file, new_file_path,
			FALSE, &new_file_tag);

		AOM_lock(dataset_tag);

		AE_replace_dataset_named_ref2(dataset_tag, old_file, ref_name,
			AE_PART_OF, new_file_tag);
		AE_save_myself(dataset_tag);

		IMF_set_original_file_name2(new_file_tag, name);
		AOM_unlock(dataset_tag);
		IMF_release_file_access(&file_data);
	}

	bool isTypeOf(tag_t objtag, const char * type_name) {
		tag_t type = NULLTAG;
		TCTYPE_ask_object_type(objtag, &type);
		tag_t item_type = NULLTAG;
		TCTYPE_find_type(type_name, "", &item_type);
		bool is_type = false;
		if (item_type != NULLTAG) {
			logical isok = FALSE;
			TCTYPE_is_type_of(type, item_type, &isok);
			if (isok) {
				is_type = true;
			}
		}
		return is_type;
	}

	string GBKToUTF8(const char* strGBK) {
		int len = MultiByteToWideChar(CP_ACP, 0, strGBK, -1, NULL, 0);
		wchar_t* wstr = new wchar_t[len + 1];
		memset(wstr, 0, len + 1);
		MultiByteToWideChar(CP_ACP, 0, strGBK, -1, wstr, len);
		len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
		char* str = new char[len + 1];
		memset(str, 0, len + 1);
		WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
		string strTemp = str;
		if (wstr) delete[] wstr;
		if (str) delete[] str;
		return strTemp;
	}


	/*
	映射
	-path 路径
	-name 用户名
	*/
	static int sign(JNIEnv* env, jclass class_Test, const char* path, char* name, char* sign_location, char* sign_str) {
		printf("signin\n");
		jmethodID methodId_main = env->GetStaticMethodID(class_Test, "sign", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I");
		if (methodId_main == NULL) {
			printf("error, check jar location\n");
			return 0;
		}
		string path1 = GBKToUTF8(path);
		string name1 = GBKToUTF8(name);
		string sign_location1 = GBKToUTF8(sign_location);
		string sign_str1 = GBKToUTF8(sign_str);
		jstring jpath = env->NewStringUTF(path1.c_str());
		jstring jname = env->NewStringUTF(name1.c_str());
		jstring jsign_location = env->NewStringUTF(sign_location1.c_str());
		jstring jsign_str = env->NewStringUTF(sign_str1.c_str());
		printf("path:%s\nname:%s\nsign_location:%s\nsign_str:%s\n", path1.c_str(), name1.c_str(), sign_location1.c_str(), sign_str1.c_str());
		jint result = 0;
		result = env->CallStaticIntMethod(class_Test, methodId_main, jpath, jname, jsign_location, jsign_str);
		int res = result;
		printf("result:%d\n", res);
		printf("signout\n");
		return res;
	}

	void add_path(JNIEnv* env, const std::string& path) {
		const std::string urlPath = "file:/" + path;
		jclass classLoaderCls = env->FindClass("java/lang/ClassLoader");
		printf("111\n");
		jmethodID getSystemClassLoaderMethod = env->GetStaticMethodID(classLoaderCls, "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
		jobject classLoaderInstance = env->CallStaticObjectMethod(classLoaderCls, getSystemClassLoaderMethod);
		jclass urlClassLoaderCls = env->FindClass("java/net/URLClassLoader");
		jmethodID addUrlMethod = env->GetMethodID(urlClassLoaderCls, "addURL", "(Ljava/net/URL;)V");
		jclass urlCls = env->FindClass("java/net/URL");
		jmethodID urlConstructor = env->GetMethodID(urlCls, "<init>", "(Ljava/lang/String;)V");
		jobject urlInstance = env->NewObject(urlCls, urlConstructor, env->NewStringUTF(urlPath.c_str()));
		env->CallVoidMethod(classLoaderInstance, addUrlMethod, urlInstance);
		std::cout << "Added " << urlPath << " to the classpath." << std::endl;
	}

	int JD_clear(METHOD_message_t* msg, va_list args, tag_t new_rev) {
		printf("升版执行\n");
		//获取数据集
		const char *sign_location1, *sign_str;
		char *temp_path, *attach_type,*prop,**pref_values1;
		int n_attachs, pref_count1;
		tag_t ref_obj, excelx_tag, excel_tag, wordx_tag, word_tag, type_tag, word_ref, excel_ref, *dataset;
		stringstream sign_date;
		ITEM_attached_object_t *rev_attachments;
		AE_reference_type_t ae_ref;
		TCTYPE_find_type("MSExcelX", "Dataset", &excelx_tag);
		TCTYPE_find_type("MSExcel", "Dataset", &excel_tag);
		TCTYPE_find_type("MSWord", "Dataset", &word_tag);
		TCTYPE_find_type("MSWordX", "Dataset", &wordx_tag);
		temp_path = getenv("temp");

		printf("temp_path:%s\n", temp_path);

		//创建tc_export目录
		stringstream dir;
		dir << temp_path;
		dir << "\\tc_export\\";
		createDirectory(dir.str());

		printf("dir:%s\n", dir.str().c_str());

		//获取guid
		char buffer[GUID_LEN] = { 0 };
		GUID guid;

		if (CoCreateGuid(&guid)) {
			fprintf(stderr, "create guid error\n");
			return -1;
		}
		_snprintf(buffer, sizeof(buffer),
			"%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X",
			guid.Data1, guid.Data2, guid.Data3,
			guid.Data4[0], guid.Data4[1], guid.Data4[2],
			guid.Data4[3], guid.Data4[4], guid.Data4[5],
			guid.Data4[6], guid.Data4[7]);
		printf("guid: %s\n", buffer);

		POM_AM__set_application_bypass(true);

		//申请虚拟机
		wstringstream wss;
		wss << getenv("JRE_HOME") << "\\bin\\server\\jvm.dll";

		printf("wxs:%s\n", wss.str().c_str());

		JavaVMInitArgs vmArgs;
		const int OPTION_COUNT = 1;
		vmArgs.nOptions = OPTION_COUNT;
		JavaVMOption options[OPTION_COUNT] = { 0 };
		options[0].optionString = "-Xmx1024m";
		vmArgs.options = options;
		vmArgs.version = JNI_VERSION_1_8;
		vmArgs.ignoreUnrecognized = JNI_TRUE;
		printf("before load dll\n");
		HMODULE hModule = LoadLibrary(wss.str().c_str());
		if (hModule == NULL) {
			printf("error load dll");
			return -1;
		}
		printf("after load dll\n");
		typedef jint(JNICALL *CreateJavaVMFuncPtr)(JavaVM **pvm, void **penv, void *args);
		CreateJavaVMFuncPtr CreateJavaVM = (CreateJavaVMFuncPtr)GetProcAddress(hModule, "JNI_CreateJavaVM");
		typedef jint(JNICALL * GetCreatedJavaVMs)(JavaVM**, jsize, jsize*);

		GetCreatedJavaVMs jni_GetCreatedJavaVMs;
		jni_GetCreatedJavaVMs = (GetCreatedJavaVMs)GetProcAddress(GetModuleHandle(
			TEXT("jvm.dll")), "JNI_GetCreatedJavaVMs");
		JavaVM *jvm = nullptr, *jvms;
		JNIEnv *env = nullptr;
		jsize size = 0;
		jni_GetCreatedJavaVMs(&jvms, 0, &size);
		printf("before load jvm\n");
		if (size) {
			JavaVM** buffer = new JavaVM*[size];
			jni_GetCreatedJavaVMs(buffer, size, &size);
			buffer[0]->GetEnv((void**)&env, JNI_VERSION_1_8);
			jint result = buffer[0]->AttachCurrentThread((void**)&env, NULL);
		} else {
			jint res = (*CreateJavaVM)(&jvm, (void**)&env, &vmArgs);
			if (res < 0) {
				printf("error load jvm");
				return -1;
			}
		}

		printf("after load jvm\n");


		stringstream s;
		if (ACCESS(LOCALJARPATH, 0) != 0) {
			s << REMOTEJARPATH;
			s << "sign2fileRunnable.jar";
			add_path(env, s.str().c_str());
		} else {
			s << LOCALJARPATH;
			s << "sign2fileRunnable.jar";
			add_path(env, s.str().c_str());
		}
		
		printf("add path\n");
		jclass class_Test;
		int file_type = -1;

		int ifail = ITK_ok, objects_count;

		tag_t *objects;


		ITKCALL(AOM_ask_value_tags(new_rev, "IMAN_master_form_rev", &objects_count, &objects));

		PREF_ask_char_values("jd2_signoff_list", &pref_count1, &pref_values1);
		stringstream temps;
		for (int i = 0;i < pref_count1;i++) {
			temps << pref_values1[i];
			temps << ",";
		}
		//表单签名
		for (auto iii = 0; iii < objects_count; iii++) {
			AOM_lock(objects[iii]);
			for (int i = 0;i < pref_count1;i++) {
				sign_date.str("");
				sign_date << pref_values1[i];
				sign_date << "rq";
				AOM_ask_value_string(objects[iii], pref_values1[i], &prop);
				if (tc_strlen(prop) != 0) {
					AOM_set_value_string(objects[iii], pref_values1[i], "");
					AOM_set_value_string(objects[iii], sign_date.str().c_str(), "");
				}
			}
			printf("sign clear\n");
			ITKCALL(AOM_save(objects[iii]));
			AOM_unlock(objects[iii]);
		}
		MEM_free(objects);

		printf("startSign\n");
		ITKCALL(AOM_ask_value_tags(new_rev, "IMAN_specification", &n_attachs, &dataset));
		for (int i = 0;i < n_attachs;i++) {
			stringstream ss;
			ss << dir.str().c_str();
			printf(ss.str().c_str());
			ITKCALL(TCTYPE_ask_object_type(dataset[i], &type_tag));
			if (type_tag == wordx_tag || type_tag == word_tag) {
				ITKCALL(AE_ask_dataset_named_ref2(dataset[i], "word", &ae_ref, &word_ref));
				char *file_name;
				ITKCALL(AOM_UIF_ask_value(word_ref, "file_name", &file_name));
				ss << buffer;
				ss << "_";
				ss << file_name;
				printf("path:%s\n", ss.str().c_str());
				ITKCALL(AE_export_named_ref(dataset[i], "word", ss.str().c_str()));
				file_type = 0;
			} else if (type_tag == excel_tag || type_tag == excelx_tag) {
				ITKCALL(AE_ask_dataset_named_ref2(dataset[i], "excel", &ae_ref, &excel_ref));
				char *file_name;
				ITKCALL(AOM_UIF_ask_value(excel_ref, "file_name", &file_name));
				ss << buffer;
				ss << "_";
				ss << file_name;
				printf("path:%s\n", ss.str().c_str());
				ITKCALL(AE_export_named_ref(dataset[i], "excel", ss.str().c_str()));
				file_type = 1;
			}

			printf("file_type:%d\n", file_type);
			if (file_type == 0) {
				class_Test = env->FindClass("sign2file/SignToWord");
				int res = sign(env, class_Test, ss.str().c_str(), "", "clear", (char*)temps.str().c_str());
				if (res) {
					replace_dataset_named_reference(dataset[i], word_ref, ss.str().c_str(), "word");
				}
			} else if (file_type == 1) {
				class_Test = env->FindClass("sign2file/SignToExcel");
				int res = sign(env, class_Test, ss.str().c_str(), "", "clear", (char*)temps.str().c_str());
				if (res) {
					replace_dataset_named_reference(dataset[i], excel_ref, ss.str().c_str(), "excel");
				}
			}
			file_type = -1;
		}
		MEM_free(dataset);
		AOM_ask_value_tags(new_rev, "TC_Attaches", &n_attachs, &dataset);
		for (int i = 0;i < n_attachs;i++) {
			stringstream ss;
			ss << dir.str().c_str();
			ITKCALL(TCTYPE_ask_object_type(dataset[i], &type_tag));
			if (type_tag == wordx_tag || type_tag == word_tag) {
				ITKCALL(AE_ask_dataset_named_ref2(dataset[i], "word", &ae_ref, &word_ref));
				char *file_name;
				ITKCALL(AOM_UIF_ask_value(word_ref, "file_name", &file_name));
				ss << buffer;
				ss << "_";
				ss << file_name;
				printf("path:%s\n", ss.str().c_str());
				ITKCALL(AE_export_named_ref(dataset[i], "word", ss.str().c_str()));
				file_type = 0;
			} else if (type_tag == excel_tag || type_tag == excelx_tag) {
				ITKCALL(AE_ask_dataset_named_ref2(dataset[i], "excel", &ae_ref, &excel_ref));
				char *file_name;
				ITKCALL(AOM_UIF_ask_value(excel_ref, "file_name", &file_name));
				ss << buffer;
				ss << "_";
				ss << file_name;
				printf("path:%s\n", ss.str().c_str());
				ITKCALL(AE_export_named_ref(dataset[i], "excel", ss.str().c_str()));
				file_type = 1;
			}

			printf("file_type:%d\n", file_type);
			if (file_type == 0) {
				class_Test = env->FindClass("sign2file/SignToWord");
				int res = sign(env, class_Test, ss.str().c_str(), "", "clear", (char*)temps.str().c_str());
				if (res) {
					replace_dataset_named_reference(dataset[i], word_ref, ss.str().c_str(), "word");
				}
			} else if (file_type == 1) {
				class_Test = env->FindClass("sign2file/SignToExcel");
				int res = sign(env, class_Test, ss.str().c_str(), "", "clear", (char*)temps.str().c_str());
				if (res) {
					replace_dataset_named_reference(dataset[i], excel_ref, ss.str().c_str(), "excel");
				}
			}
			file_type = -1;
		}
		MEM_free(dataset);
		printf("endSign\n");

		FreeLibrary(hModule);
		POM_AM__set_application_bypass(false);
		return ITK_ok;
	}

	int JD_Revise_clear(METHOD_message_t* msg, va_list args) {

		tag_t new_rev = va_arg(args, tag_t);
		char *operation = va_arg(args, char*), **pref_values, *type;
		int ifail = ITK_ok, pref_count;
		AOM_ask_value_string(new_rev, "object_type", &type);
		printf("operation======>%s\n", operation);
		if (strcmp(operation, "Revise") == 0 || strcmp(operation, "SaveAs") == 0) {
			if (isTypeOf(new_rev, "ItemRevision")) {
				//获取首选项
				PREF_ask_char_values("jd_revise_clear_revisions",&pref_count,&pref_values);
				for (int i = 0;i < pref_count;i++) {
					if (strcmp(pref_values[i],type)==0) {
						JD_clear(msg, args, new_rev);
						break;
					}
				}
			}
			
		}
		
		return ifail;
	}

	extern int Register_revise_msg(void) {
		int status = ITK_ok;
		char *err_string, *err_function;
		int err_line = -1;
		printf("JD_Revise_clear函数开始注册\n");

		METHOD_id_t mth_tag;
		ITKCALL(status = METHOD_find_method("ItemRevision", ITEM_deep_copy_msg, &mth_tag));
		if (mth_tag.id != 0) {
			ITKCALL(METHOD_add_action(mth_tag, METHOD_post_action_type, JD_Revise_clear, NULL));
			printf("JD_Revise_clear注册成功\n");
		}
		return status;
	}

#ifdef __cplusplus
}
#endif




#include <stdarg.h>
#include <base_utils\Mem.h>
#include <tccore\grm.h>
#include <tccore\grmtype.h>
#include <tc\iman.h>
#include <user_exits\user_exits.h>
#include <tccore\method.h>
#include <property\prop.h>
#include <tccore\aom_prop.h>
#include <property\prop_msg.h>
#include <tccore\imantype.h>
#include <property\prop_errors.h>
#include <tccore\item.h>
#include <lov\lov.h>
#include <sa\sa.h>
#include <tc\emh.h>
#include <res\reservation.h>
#include <tccore\workspaceobject.h>
#include <tc\wsouif_errors.h>
#include <tccore\aom.h>
#include <form\form.h>
#include <bom\bom.h>
#include <epm\cr.h>
#include <epm\releasestatus.h>


/**
* @headerfile			standard c & cpp header files
*/
#include  <stdio.h>
#include  <stdlib.h>
#include <time.h>
#include <string>
#include <vector>
#include <map>
#include <fstream>
#include <iostream>
using namespace std;

/**
* @headerfile			user's header files
*/



