#pragma warning (disable: 4996) 
#pragma warning (disable: 4819) 
#pragma warning (disable: 4995) 

#include <tc/tc.h>
#include "epm_handler_common.h"

#include <ict/ict_userservice.h>
#include <tccore/custom.h>
#include <epm/epm_toolkit_tc_utils.h>
#include <tccore/aom.h>
#include <tccore/aom_prop.h>
#include <tccore/item.h>
#include <bom/bom.h>
#include "ps/ps.h";
#include "ps/vrule.h"
#include "sstream"
#include <tccore/grm.h>
#include "epm/epm.h"
#include "sa/sa.h"
#include "libxl.h"
#include <map>
#include "epm/signoff.h"
#include <ctime>
#include <vector>
#include <locale>
#include <codecvt>
#include "ae/dataset.h"
#include <iostream>
#include <stdlib.h>
#include <tccore/aom.h>
#include <tc/emh.h>
#include <ict/ict_userservice.h>
#include <tc/tc.h>
#include <tccore/tctype.h>
#include <sa/tcfile.h>
#include <ss/ss_errors.h>
#include <ae/datasettype.h>
#include "hx_custom.h"
#include "tc_log.h"
#include "jk_custom.h"

typedef struct{
	string ITEMID;//ID
	string ITEM_NAME;//名称
	string ITEM_REV;//版本
	string DATE_RELEASED;//发布时间
}BOM_STRUCT;

int getTopLevel(tag_t target,map<tag_t,string> &rev_map)
{
	int ifail=0;
	int * levels;
	tag_t *parents=NULLTAG;
	int   n_parents=0;
	ITKCALL(ifail=	PS_where_used_all(target,1,&n_parents,&levels,&parents));
	// cout<<"共有使用对象----->"<<n_parents<<"个"<<endl;
	if(n_parents>0)
	{
		for(int i=0;i<n_parents;i++)
		{
			tag_t upTag=parents[i];
			char * object_type=NULL;
			ITKCALL(ifail=AOM_ask_value_string(upTag,"object_type",&object_type));
			if(strstr(object_type,"JK8MaterialRevision")!=NULL)
			{
				getTopLevel(upTag,rev_map);
			}
			if(object_type!=NULL)
			{
				MEM_free(object_type);
				object_type=NULL;
			}
		}
	}else
	{
		char *tar_id=NULL;
		char *tar_rev=NULL;
		AOM_ask_value_string(target,"item_id",&tar_id);
		AOM_ask_value_string(target,"item_revision_id",&tar_rev);
		//遍历map，如果重复就不插入
		
		boolean doesHave=false;
		map<tag_t,string>::iterator rev_it;
		for( rev_it = rev_map.begin(); rev_it != rev_map.end(); rev_it++ )
		{
			//对每个版本遍历BOM，存储，输出excel，挂到版本下
			tag_t target_Rev=NULL;
			target_Rev=rev_it->first;
			char * item_id=NULL;
			char *item_revision_id=NULL;
			AOM_ask_value_string(target_Rev,"item_id",&item_id);
			AOM_ask_value_string(target_Rev,"item_revision_id",&item_revision_id);
			// cout<<item_id<<endl;
			// cout<<item_revision_id<<endl;
			// char *item_revision_id=NULL;
			if(strcmp(tar_id,item_id)==0&&strcmp(tar_rev,item_revision_id)==0)
			{
				doesHave=true;
				if(item_id!=NULL)
				{
					MEM_free(item_id);
					item_id=NULL;
				}
				if(item_revision_id!=NULL)
				{
					MEM_free(item_revision_id);
					item_revision_id=NULL;
				}
				break;
			}
			if(item_id!=NULL)
			{
				MEM_free(item_id);
				item_id=NULL;
			}
			if(item_revision_id!=NULL)
			{
				MEM_free(item_revision_id);
				item_revision_id=NULL;
			}
			
		}
		if(tar_id!=NULL)
			{
				MEM_free(tar_id);
				tar_id=NULL;
			}
			if(tar_rev!=NULL)
			{
				MEM_free(tar_rev);
				tar_rev=NULL;
			}
			if(doesHave==false)
			{
				rev_map.insert(pair<tag_t,string>(target,""));
			}
		
	}
	if(levels!=NULL)
	{
		MEM_free(levels);
		levels=NULL;
	}
	if(parents!=NULL)
	{
		MEM_free(parents);
		parents=NULL;
	}
	return 0;
}
static void get_release_time(char *date_time)
{
    time_t the_time;
    struct tm *time_ptr;
    char *time_format = "%Y-%m-%d %H:%M ";

    the_time = time((time_t *)0);
    time_ptr = localtime (&the_time);
    strftime(date_time, 128, time_format, time_ptr);
}
int getBomVector(tag_t top_bom_line_tag,vector<BOM_STRUCT> &vector)
{
	int ifail=0;
		//获得顶层的属性
		char * topID=NULL;
		char * topRev=NULL;
		char * topNAME=NULL;
	char * dateReleased=NULL;
		AOM_ask_value_string(top_bom_line_tag,"bl_item_item_id",&topID);
		AOM_ask_value_string(top_bom_line_tag,"bl_rev_item_revision_id",&topRev);
		AOM_ask_value_string(top_bom_line_tag,"bl_item_object_name",&topNAME);
		AOM_ask_value_string(top_bom_line_tag,"bl_rev_date_released",&dateReleased);
		BOM_STRUCT one_elem;
		one_elem.ITEMID=topID;
		one_elem.ITEM_NAME=topNAME;
		one_elem.ITEM_REV=topRev;
	string releaseDateString=dateReleased;
	one_elem.DATE_RELEASED=releaseDateString;
	/*if(releaseDateString.size()==0)
	{
		WriteLog_jk("%s %s没有发布",topID,topRev);
		char current_date_time_str[128 + 1] = {"\0"};
	get_release_time(current_date_time_str);
		WriteLog_jk("%s启用当前日期\n",current_date_time_str);
		one_elem.DATE_RELEASED=current_date_time_str;
	}else if(releaseDateString.size()>0)
	{
		one_elem.DATE_RELEASED=dateReleased;
	}*/
		
		vector.push_back(one_elem);

		int child_count = 0;
		tag_t * child_tags = NULLTAG;
		ITKCALL(ifail =  BOM_line_ask_all_child_lines(top_bom_line_tag,&child_count,&child_tags));
		for(int i=0;i<child_count;i++)
		{
			tag_t childTag=child_tags[i];
			getBomVector(childTag,vector);
		}
		if(child_tags!=NULL)
		{
			MEM_free(child_tags);
			child_tags=NULL;
		}
		if(topID!=NULL)
		{
			MEM_free(topID);
			topID=NULL;
		}
		if(topRev!=NULL)
		{
			MEM_free(topRev);
			topRev=NULL;
		}
		if(topNAME!=NULL)
		{
			MEM_free(topNAME);
			topNAME=NULL;
		}
		if(dateReleased!=NULL)
		{
			MEM_free(dateReleased);
			dateReleased=NULL;
		}



		

	return 0;
}
static void get_current_time(char *date_time)
{
    time_t the_time;
    struct tm *time_ptr;
    char *time_format = "%Y-%m-%d %H-%M ";

    the_time = time((time_t *)0);
    time_ptr = localtime (&the_time);
    strftime(date_time, 128, time_format, time_ptr);
}
// 把char *转换为TCHAR *或WCHAR *
TCHAR convertTemp3[256] = {0};
TCHAR convertTemp4[256] = {0};
bool convertBufferSwitch2(false);
TCHAR* Char2Tchar(const char* str, int len)
{
	#ifdef _UNICODE 
	TCHAR* temp = convertBufferSwitch2 ? convertTemp3 : convertTemp4; 
	convertBufferSwitch2 = !convertBufferSwitch2; 
	memset(temp, 0, sizeof(convertTemp3)); 
	MultiByteToWideChar(CP_UTF8, 0, str, len, temp, 256); 
	return temp;
	#else 
	return str;
	#endif
}
int create_dataset(char *type_name, const char *name,  tag_t item_rev)
{
	 tag_t dataset;
	tag_t item;
	ITEM_ask_item_of_rev(item_rev, &item) ;//通过版本获得item
	AOM_load(item);
	AOM_lock(item);
	// cout<<"新建数据集路径------------"<<name<<endl;
    char      format_name[AE_io_format_size_c + 1] = "BINARY_REF";
    tag_t       datasettype,      tool;
   
    ITKCALL(AE_find_datasettype(type_name, &datasettype));
    if (datasettype == NULLTAG)
    {
        printf("Dataset Type %s not found!\n", type_name);
        exit (EXIT_FAILURE);
    }
    
    ITKCALL(AE_ask_datasettype_def_tool(datasettype, &tool));
    
    printf("Creating Dataset: %s\n", name);
	string newPdfDatasetName=name;
	
    ITKCALL(AE_create_dataset(datasettype, newPdfDatasetName.c_str(), "", &dataset));
    
    ITKCALL(AE_set_dataset_tool(dataset, tool));
    if (strcmp(type_name, "Text")) strcpy(format_name, "TEXT_REF");
    
    ITKCALL(AE_set_dataset_format(dataset, format_name));
    printf("Saving Dataset: %s\n", newPdfDatasetName.c_str());
	// cout<<"添加命名引用------------------"<<endl;
	tag_t spec_dataset_rev = NULLTAG,
		ref_object = NULLTAG;
	AE_reference_type_t reference_type;
	ITKCALL(AE_ask_dataset_latest_rev(dataset, &spec_dataset_rev));//获得数据集的最新版本
	char ref_name[WSO_name_size_c + 1] = "excel";
	ITKCALL(AE_ask_dataset_named_ref(spec_dataset_rev, ref_name, &reference_type, &ref_object));//获得数据集命名引用的文件对象


	// cout<<"开始添加----------------"<<endl;
		//pdf的系统路径
		char *temp_dir = getenv("temp");//获得缓存路径
	temp_dir="E:\\TEMP";
		char output_file[SS_MAXPATHLEN] = "";
		strcpy(output_file, temp_dir);
		strcat(output_file, "\\");
//		strcat(output_file, newDatasetName.c_str());
		strcat(output_file, name);

		// cout<<"名称-----------"<<name<<endl;
		tag_t new_file_tag1 = NULLTAG;
		IMF_file_t file_descriptor1;	
		int ifail=0;
		ITKCALL(ifail=IMF_import_file(output_file, name, SS_BINARY, &new_file_tag1, &file_descriptor1));//将缓存路径下生成的文件导入tc，获得tc中的这个文件对象
//		ITKCALL(ifail=IMF_set_original_file_name(new_file_tag1, origin_file_name));//设置文件对象的数据集的原始文件名称
		ITKCALL(ifail=IMF_set_original_file_name(new_file_tag1, name));//设置文件对象的数据集的原始文件名称
		ITKCALL(ifail=IMF_close_file(file_descriptor1));
		ITKCALL(ifail=AOM_save(new_file_tag1));
		ITKCALL(ifail=AOM_unlock(new_file_tag1));


		ITKCALL(ifail=AOM_lock(spec_dataset_rev));
		//	ITKCALL(ifail=AE_remove_dataset_named_ref_by_tag(spec_dataset_rev, ref_name, ref_object));//删除数据集的命名引用对象
		ITKCALL(ifail=AE_add_dataset_named_ref(spec_dataset_rev, ref_name, AE_PART_OF, new_file_tag1));
		ITKCALL(ifail=AOM_save(spec_dataset_rev));
		ITKCALL(ifail=AOM_unlock(spec_dataset_rev));


    ITKCALL(AOM_save(dataset));

    
    /*attach dataset to item revision */
	POM_AM__set_application_bypass(true);//必须开旁路，否则可能出现不具有写权限或者零组件因发布不可修改的报错
    ITKCALL(ITEM_attach_rev_object(item_rev, dataset, ITEM_specification_atth));//把数据集放置到规范关系下，也可以通过设置对象属性的方法添加
  	//2019.11.27快速发布
		int temp_count = 1;
	tag_t * release_objs = NULL;
	tag_t release_status=NULLTAG;
	release_objs = (tag_t *)MEM_alloc(temp_count*sizeof(tag_t));
	release_objs[0] = dataset;

	ITKCALL(ifail = CR_create_release_status("TCM Released",&release_status));
	ITKCALL(ifail = EPM_add_release_status(release_status,temp_count,release_objs,TRUE));
	
	POM_AM__set_application_bypass(false);
	if(release_objs!=NULL)
	{
		MEM_free(release_objs);
		release_objs=NULL;
	}
	ITKCALL(ITEM_save_item(item));
	ITKCALL(AOM_unlock(item));
	return 0;
}
int writeToExcel(vector<BOM_STRUCT> vector,tag_t target_Rev,tag_t excelTag)
{
	int ifail=0;
	
	// ITK__convert_uid_to_tag("E8bxyzeUYvbLjA",&excelTag);//先定义一个数据集
	libxl::Book* book = nullptr;
	book = xlCreateBook();//xls文件用xlCreateBook() 函数打开，xlsx文件是xml结构，所以得用xlCreateXMLBook() 函数来打开。
	book->setKey(L"Halil Kural", L"windows-2723210a07c4e90162b26966a8jcdboe");//如果购买了该库，则设置相应的key，若没有购买，则不用这行
	int n_refs = 0;
	tag_t* refs = NULL;

	ifail = AE_ask_all_dataset_named_refs(excelTag, "excel", &n_refs, &refs);
	if (ifail != ITK_ok) { /* your error logic here */ }

	char current_date_time_str[128 + 1] = {"\0"};
	get_current_time(current_date_time_str);
	char * itemID=NULL;
	char * itemRevId=NULL;
	AOM_ask_value_string(target_Rev,"item_id",&itemID);
	AOM_ask_value_string(target_Rev,"item_revision_id",&itemRevId);

	string time_now=current_date_time_str;
	time_now.append("-").append(itemID).append("-").append(itemRevId);
	string datasetName=time_now;
	datasetName=datasetName.append(".xls");
	time_now="E:\\TEMP\\"+time_now+".xls";
	// cout<<"文件路径----------"<<time_now<<endl;
	if(itemID!=NULL)
	{
		MEM_free(itemID);
		itemID=NULL;
	}
	if(itemRevId!=NULL)
	{
		MEM_free(itemRevId);
		itemRevId=NULL;
	}
	ifail = AE_export_named_ref(excelTag, "excel", time_now.c_str());
	if (ifail != ITK_ok) { /* your error logic here */ }
	//检查是否存在单元格名称为“xxxx”
	wstringstream excel_path;
	
//	excel_path<<"C:\\TEMP\\export_text.xls";
	excel_path<<time_now.c_str();
	libxl::Sheet* sheet;
	if (book->load(excel_path.str().c_str()))
	{
		 sheet = book->getSheet(0);//获得第1个sheet页

	}
	//写到表格中
	TCHAR *array1;
	TCHAR array2[100];
	TCHAR array3[100];
	for (int i=0;i<vector.size();i++)
	{
		 array1 = Char2Tchar(vector[i].ITEMID.c_str(),200);
		sheet->writeStr(i+1, 0, array1);
		 array1 = Char2Tchar(vector[i].ITEM_REV.c_str(),200);
		sheet->writeStr(i+1, 1, array1);
		 MultiByteToWideChar(CP_ACP, 0, vector[i].ITEM_NAME.c_str(), -1, array2, 100);
		sheet->writeStr(i+1, 2,array2 );	
		MultiByteToWideChar(CP_ACP, 0, vector[i].DATE_RELEASED.c_str(), -1, array3, 100);
		sheet->writeStr(i+1, 3,array3 );
	}
	if (book->save(excel_path.str().c_str()))//保存到example.xls
	{
		//.....
	}
	else
	{
		std::cout << book->errorMessage() << std::endl;
	}
	book->release();//释放对象！！！！
	//创建数据集，挂到版本的规范关系下
	
	create_dataset("MSExcel",datasetName.c_str(),target_Rev);//数据集类型(object_type)，数据集名称，版本
	return 0;
}
int jk_exportExcel(EPM_action_message_t msg)
{
	//20200113
	POM_AM__set_application_bypass(true);
	/*char tc_log_file_name[512];
	time_t				now;
	struct				tm *p;
	time(&now);
	p = localtime(&now);

	//sprintf(startDate,"%04d-%d-%02d 00:00", 1900+p->tm_year,p->tm_mon+1 ,p->tm_mday);
	//sprintf(endDate,"%04d-%d-%02d 23:59", 1900+p->tm_year,p->tm_mon+1 ,p->tm_mday);
	sprintf(tc_log_file_name, "D:\\LOG\\jk_bom_log_[%d-%d-%d-%d-%02d].txt",1900+p->tm_year,p->tm_mon+1 ,p->tm_mday,p->tm_hour,p->tm_min  );
	printf("tc_log_file_name=%s\n",tc_log_file_name);
	CreateLogFile_jk(tc_log_file_name);*/

	tag_t excelTag;
	//TODO 首选项
	vector<string> pref_vec;
	getPrefStrings("JK_exportbom_uid",TC_preference_site, pref_vec);
	if(pref_vec.size() > 0){
		ITK__convert_uid_to_tag(pref_vec[0].c_str(),&excelTag);//先定义一个数据集
		if(excelTag == NULLTAG){
			printf("PUID[%s]不能转换成对象\n",pref_vec[0].c_str());
			// WriteLog_jk("PUID[%s]不能转换成对象\n",pref_vec[0].c_str());
		}
		
	}

	EPM_decision_t decision = EPM_go;
	int ifail = ITK_ok, arg_cnt = 0, i = 0, att_cnt = 0;
	tag_t task_tag = NULLTAG, rootTask_tag = NULLTAG, *attachments = NULL;
	char * object_TYPE_1 = NULL;
	char * object_string1=NULL;
	string value_type = "";
	string value_property="";
	char * ref_type=NULL;
	int actualNum=0;
	tag_t *actualtags=NULL;
	string errorMessage="";
	//获取当前触发的任务
	task_tag = msg.task;
	//获取根流程节点
	ifail = EPM_ask_root_task(task_tag, &rootTask_tag);
	//获取目标引用对象
	ifail = EPM_ask_attachments(rootTask_tag, EPM_target_attachment, &att_cnt, &attachments);
	int reference_count=0;tag_t * reference_attachment=NULLTAG;
	ifail = EPM_ask_attachments(rootTask_tag, EPM_reference_attachment, &reference_count, &reference_attachment);
	map<tag_t,string>	rev_map;
	vector<BOM_STRUCT> vector;
//	vector.clear();//清空所有元素
	//循环目标对象
	for (i = 0; i < att_cnt; i++)
	{
		tag_t  targetTag=attachments[i];
		//如果是版本类型的就查找上层
		char * object_type=NULL;
		ITKCALL(ifail=AOM_ask_value_string(targetTag,"object_type",&object_type));
		if(strstr(object_type,"JK8MaterialRevision")!=NULL)
		{
			getTopLevel(targetTag,rev_map);
		}
		if(object_type!=NULL)
		{
			MEM_free(object_type);
			object_type=NULL;
		}
	}
	// cout<<"共有顶层---------"<<rev_map.size()<<endl;
	// WriteLog_jk("共有顶层---------[%d]\n",rev_map.size());
			// CloseLog_jk();
	map<tag_t,string>::iterator rev_it;
		for( rev_it = rev_map.begin(); rev_it != rev_map.end(); rev_it++ )
		{
			//对每个版本遍历BOM，存储，输出excel，挂到版本下
			tag_t target_Rev=NULL;
			target_Rev=rev_it->first;
			char * item_id=NULL;
			char *item_revision_id=NULL;
			AOM_ask_value_string(target_Rev,"item_id",&item_id);
			AOM_ask_value_string(target_Rev,"item_revision_id",&item_revision_id);
			// cout<<item_id<<endl;
			// cout<<item_revision_id<<endl;
			// WriteLog_jk("Itemid===[%s]",item_id);
			// WriteLog_jk("版本===[%s]\n",item_revision_id);
			if(item_id!=NULL)
			{
				MEM_free(item_id);
				item_id=NULL;
			}
			if(item_revision_id!=NULL)
			{
				MEM_free(item_revision_id);
				item_revision_id=NULL;
			}

		}
	

	
	
	// int index=0;
	if(rev_map.size()>0)
	{
		map<tag_t,string>::iterator rev_it2;
		for( rev_it2 = rev_map.begin(); rev_it2 != rev_map.end(); rev_it2++ )
		{
			/*index++;
			if(index>20)
			{
				break;
			}*/
			vector.clear();
			//对每个版本遍历BOM，存储，输出excel，挂到版本下
			tag_t target_Rev=NULL;
			target_Rev=rev_it2->first;
			int bom_num=0;
			int ifail=0;
			tag_t * bom_tags=NULLTAG;
			AOM_ask_value_tags(target_Rev,"structure_revisions",&bom_num,&bom_tags);
			if(bom_num>0)
			{
				tag_t only_bom=bom_tags[0];
				tag_t bom_window_tag = NULLTAG,top_bom_line_tag =NULLTAG,rev_tag = NULLTAG,item_tag =NULLTAG;

				ITKCALL(ifail = BOM_create_window(&bom_window_tag));
				ITKCALL(ifail = BOM_set_window_top_line_bvr(bom_window_tag,only_bom,&top_bom_line_tag));
				getBomVector(top_bom_line_tag,vector);//获取一个版本视图下所有的vector



				ITKCALL(ifail = BOM_save_window(bom_window_tag));//要保存，否则修改属性后bom视图不会保存
				ITKCALL(ifail = BOM_close_window(bom_window_tag));//有开必有关
			}

			if(bom_tags!=NULL)
			{
				MEM_free(bom_tags);
				bom_tags=NULL;

			}
			//写入到excel中，创建数据集，挂到关系下
			writeToExcel( vector,target_Rev,excelTag);


		}
	}
	// CloseLog_jk();
	POM_AM__set_application_bypass(false);
	return 0;
}