package com.blueland.bpm.manage.web;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import cn.hutool.core.util.StrUtil;
import com.blueland.bpm.application.service.ApplicationManager;
import com.blueland.bpm.engine.core.service.impl.ProcessModelNewService;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.ReadOnlyProcessDefinition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.task.TaskDefinition;
import org.activiti.validation.ProcessValidator;
import org.activiti.validation.ProcessValidatorFactory;
import org.activiti.validation.ValidationError;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.blueland.bpm.application.model.ApplicationEntity;
import com.blueland.bpm.common.page.Page;
import com.blueland.bpm.common.util.DateUtil;
import com.blueland.bpm.common.util.ServiceResponse;
import com.blueland.bpm.engine.config.model.ProcessInfoConfig;
import com.blueland.bpm.engine.config.model.SysGlType;
import com.blueland.bpm.engine.config.service.ProcessInfoConfigManager;
import com.blueland.bpm.engine.config.service.SysGlTypeManager;
import com.blueland.bpm.engine.core.model.ActivityDefinitionModel;
import com.blueland.bpm.engine.core.model.ActivityResourceModel;
import com.blueland.bpm.engine.core.model.ProcessDefinitionModel;
import com.blueland.bpm.engine.core.model.ProcessMgrDataShare;
import com.blueland.bpm.engine.core.model.SearchProcessListDTO;
import com.blueland.bpm.engine.core.service.ProcessConfigService;
import com.blueland.bpm.engine.core.service.ProcessDefinitionService;
import com.blueland.bpm.engine.core.service.ProcessModelService;
import com.blueland.bpm.engine.core.service.ProcessTraceService;
import com.blueland.bpm.engine.util.CustomProcessValidator;
import com.blueland.bpm.engine.util.JsonUtil;
import com.blueland.bpm.engine.util.ProcessDefinitionUtils;
import com.blueland.bpm.engine.util.ProcessModelUtils;
import com.blueland.bpm.engine.util.WorkFlowContants;
import com.blueland.bpm.identity.OrgService;
import com.blueland.bpm.identity.RoleService;
import com.blueland.bpm.identity.UserService;
import com.blueland.bpm.identity.model.Org;
import com.blueland.bpm.identity.model.Role;
import com.blueland.bpm.identity.model.User;
import com.blueland.bpm.manage.config.web.ProcDefTreeManager;
import com.blueland.bpm.manage.util.BaseUser;
import com.blueland.bpm.manage.util.MyContants;
import com.blueland.bpm.manage.util.ProcessZipUtil;
import com.blueland.bpm.manage.util.TreeNode;
import com.blueland.bpm.manage.util.XLSExportUtil;
@Controller
@RequestMapping(value = "/procDefMgr")
public class ProcessDefinitionController extends BaseProcessController{
	@Autowired
	private ProcessInfoConfigManager processInfoConfigManager;
	@Autowired
	private ProcessDefinitionService processDefinitionService;
	@Autowired
	private ProcessConfigService processConfigService;
	@Autowired
	private ProcessModelService processModelService;
	@Autowired  
	private RepositoryService repositoryService;  
	@Autowired
	CustomProcessValidator customProcessValidator;
	@Autowired
	ProcDefTreeManager procDefTreeManager;
	@Autowired
	private SysGlTypeManager sysGlTypeManager;
	@Autowired
	private UserService	userService;
	@Autowired
	private OrgService	orgService;
	@Autowired
	private RoleService	roleService;
	@Autowired
	private ProcessModelNewService processModelNewService;
	@Autowired
	private ProcessTraceService processTraceService;
	@Autowired
	private ApplicationManager applicationManager;
	protected Logger logger = LoggerFactory.getLogger(getClass());
	/**
	 * 默认的流程定义列表
	 * @param userId
	 * @param query
	 * @param request
	 * @return
	 */
	@RequestMapping(value="/list")
	public ModelAndView list(String userId, ProcessInfoConfig query, String flag, String customSso,
							 HttpServletRequest request, HttpServletResponse response) {
		SysGlType sysGlType  = new SysGlType();
		sysGlType.setTypeParentId("TOP_FLOW_TYPE");
		sysGlType.setAppKey((String)request.getSession().getAttribute(MyContants.APP_ID_KEY));
		List<SysGlType> sysGlTypes = sysGlTypeManager.findByExample(sysGlType);
		query.setSortColumns("CREATE_TIME desc");
		if("1".equals(customSso)){
			HttpSession session = request.getSession(true);
			session.setAttribute("customSso", customSso);

			User user = userService.getUserById("admin");
			BaseUser bUser = BaseUser.getInstance();
			if(user!=null && StrUtil.isNotEmpty(user.getUserId())){
				bUser.cleanCookieUser(request, response);
				bUser.setCookieUser(response, BaseUser.toUpperCase(user.getUserId()));
				List<ApplicationEntity> list = applicationManager.selectByUserId("admin");
				bUser.saveUserToSession(request, user, list);
			}
		}
		if("true".equalsIgnoreCase(MyContants.IS_OPEN_TENANT) && StringUtils.isEmpty(flag)){
			query.setTenantId(BaseUser.getInstance().getLoginUserAppId(request));
		}
		Page<List<ProcessInfoConfig>> page=processConfigService.findProcessInfoConfigsPage(query);
		ModelAndView modelAndView = new ModelAndView("/procDefMgr/list");
		modelAndView.addAllObjects(toModelMap(page, query));
		modelAndView.addObject("sysGlTypes", sysGlTypes);
		modelAndView.addObject("flag", flag);
		return modelAndView;
	}
	
	
	/**
	 * 查看流程图
	 * @param procDefId
	 * @param resourceType
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	@RequestMapping(value="/resource")
	public void resource(String procDefKey, String procDefId,String resourceType,HttpServletRequest request,HttpServletResponse response) throws IOException {
		if(StringUtils.isEmpty(procDefId)) {
			ProcessDefinitionModel model = processDefinitionService.getProcessDefBykey(procDefKey);
			if(model !=null )
				procDefId = model.getProcDefId();
		}
		
		InputStream in=processDefinitionService.loadProcessResource(procDefId, resourceType);
		OutputStream out=response.getOutputStream();
		try{
			
			org.apache.commons.io.IOUtils.copy(in, out); 
			response.flushBuffer();
		}catch(Exception e){
			logger.error("",e);
		}finally{
			try {
				in.close();
			} catch (IOException e) {
				logger.error("",e);
			}
		}
		
	}
	
	
	/**
	 * 导出 流程清单 excel
	 * 
	 * 
	 */
	@RequestMapping(value = "/export")
	public void export(HttpServletRequest request,HttpServletResponse response){
		SearchProcessListDTO params=new SearchProcessListDTO();
		params.setTenantId(BaseUser.getInstance().getLoginUserAppId(request));
		System.out.println("租户ID:"+BaseUser.getInstance().getLoginUserAppId(request));
		List<ProcessDefinitionModel> defs=processDefinitionService.findProcessDefs(params);
		List<ReadOnlyProcessDefinition> rpdf=new ArrayList<ReadOnlyProcessDefinition>();
		
		for(int i=0;i<defs.size();i++){
			RepositoryServiceImpl repositoryServiceImpl = (org.activiti.engine.impl.RepositoryServiceImpl) repositoryService;
			ReadOnlyProcessDefinition rpd= repositoryServiceImpl.getDeployedProcessDefinition(defs.get(i).getProcDefId());
			if(rpd==null){
				System.out.println("流程模型出现异常，pdf:"+defs.get(i));
				continue;
			}
			rpdf.add(rpd);
		}
		
		String url=request.getServletContext().getRealPath("/");
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		String exls=url+"/file/" ;
		String name="流程清单"+"_"+df.format(new Date())+".xls";
	    String path=exls.replace("/", File.separator);
		File file=new File(exls);
		if(!file.exists()){
			file.mkdirs();
		}
		  XLSExportUtil exportUtil=new XLSExportUtil(name, path);
		  exportUtil.removeSheetAt(0);
		  String[] sheet1={"流程定义ID","流程KEY","流程名称","应用"};
		  //第一个sheet
		  ProcessDefSheet(exportUtil,"流程定义",sheet1,defs);
		  
		  String[] sheet2={"流程定义ID","流程KEY","流程名称","环节ID","环节名称","应用"};
		  //第二个sheet
		  ReadOnlyProcessSheet(exportUtil,"流程环节",sheet2,defs,rpdf);
		  
		  //第三个sheet
		  String[] sheet3={"流程定义ID","流程KEY","流程名称","环节ID","环节名称","资源类型","资源ID","应用"};
		  ActivityResourceSheet(exportUtil,"流程资源",sheet3,defs,rpdf);
		  
		  response.setContentType("application/vnd.ms-excel");   
		   
	        BufferedInputStream bis = null;
	        BufferedOutputStream bos = null;
	        try {
	        exportUtil.exportXLS();
			response.setHeader("Content-disposition", "attachment;filename="+new String(name.getBytes(),"iso-8859-1"));
			
	        FileInputStream is=new FileInputStream(exls+name);
	        ServletOutputStream out = response.getOutputStream();
	        bis = new BufferedInputStream(is);
	        bos = new BufferedOutputStream(out);
	        byte[] buff = new byte[2048];
	        int bytesRead;
	        // Simple read/write loop.
	        while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
	          bos.write(buff, 0, bytesRead);
	        }
	        bis.close();
	        bos.close();
	        } catch (Exception e) {
				
				e.printStackTrace();
			}
		  
	}
	
	
	
	/**
	 * 导出 流程清单 excel
	 * 
	 * 
	 */
	@RequestMapping(value = "/allExport")
	public void allExport(HttpServletRequest request,HttpServletResponse response){
		SearchProcessListDTO params=new SearchProcessListDTO();
		System.out.println("租户ID:"+BaseUser.getInstance().getLoginUserAppId(request));
		List<ProcessDefinitionModel> defs=processDefinitionService.findProcessDefs(params);
		List<ReadOnlyProcessDefinition> rpdf=new ArrayList<ReadOnlyProcessDefinition>();
		
		for(int i=0;i<defs.size();i++){
			RepositoryServiceImpl repositoryServiceImpl = (org.activiti.engine.impl.RepositoryServiceImpl) repositoryService;
			ReadOnlyProcessDefinition rpd= repositoryServiceImpl.getDeployedProcessDefinition(defs.get(i).getProcDefId());
			if(rpd==null){
				System.out.println("流程模型出现异常，pdf:"+defs.get(i));
				continue;
			}
			rpdf.add(rpd);
		}
		
		String url=request.getServletContext().getRealPath("/");
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		String exls=url+"/file/" ;
		String name="流程清单"+"_"+df.format(new Date())+".xls";
	    String path=exls.replace("/", File.separator);
		File file=new File(exls);
		if(!file.exists()){
			file.mkdirs();
		}
		  XLSExportUtil exportUtil=new XLSExportUtil(name, path);
		  exportUtil.removeSheetAt(0);
		  String[] sheet1={"流程定义ID","流程KEY","流程名称","应用"};
		  //第一个sheet
		  ProcessDefSheet(exportUtil,"流程定义",sheet1,defs);
		  
		  String[] sheet2={"流程定义ID","流程KEY","流程名称","环节ID","环节名称","应用"};
		  //第二个sheet
		  ReadOnlyProcessSheet(exportUtil,"流程环节",sheet2,defs,rpdf);
		  
		  //第三个sheet
		  String[] sheet3={"流程定义ID","流程KEY","流程名称","环节ID","环节名称","资源类型","资源ID","应用"};
		  ActivityResourceSheet(exportUtil,"流程资源",sheet3,defs,rpdf);
		  
		  response.setContentType("application/vnd.ms-excel");   
		   
	        BufferedInputStream bis = null;
	        BufferedOutputStream bos = null;
	        try {
	        exportUtil.exportXLS();
			response.setHeader("Content-disposition", "attachment;filename="+new String(name.getBytes(),"iso-8859-1"));
			
	        FileInputStream is=new FileInputStream(exls+name);
	        ServletOutputStream out = response.getOutputStream();
	        bis = new BufferedInputStream(is);
	        bos = new BufferedOutputStream(out);
	        byte[] buff = new byte[2048];
	        int bytesRead;
	        // Simple read/write loop.
	        while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
	          bos.write(buff, 0, bytesRead);
	        }
	        bis.close();
	        bos.close();
	        } catch (Exception e) {
				
				e.printStackTrace();
			}
		  
	}
	
	public void ProcessDefSheet(XLSExportUtil exportUtil,String sheetName,String[] titles,List<ProcessDefinitionModel> defs){
		int rowNum = 0;								//行数
		int cellNum = 0;							//列数
		exportUtil.createSheet(sheetName);			//新增sheet设置名称
		exportUtil.createRow(rowNum++);				//在sheet中新增一行、展示查询数据——标题
		for (String title : titles) {
			exportUtil.setCell(cellNum++, title);
		}
		for (ProcessDefinitionModel pdf : defs) {
			exportUtil.createRow(rowNum++);	
			exportUtil.setCell(0,pdf.getProcDefId());
			exportUtil.setCell(1,pdf.getProcDefKey());
			exportUtil.setCell(2,pdf.getProcDefName());
			exportUtil.setCell(3,pdf.getTenantId());
		}
	}
	
	public void ReadOnlyProcessSheet(XLSExportUtil exportUtil,String sheetName,String[] titles,List<ProcessDefinitionModel> defs,List<ReadOnlyProcessDefinition> rpdf){
		int rowNum = 0;								//行数
		int cellNum = 0;							//列数
		exportUtil.createSheet(sheetName);			//新增sheet设置名称
		exportUtil.createRow(rowNum++);				//在sheet中新增一行、展示查询数据——标题
		for (String title : titles) {
			exportUtil.setCell(cellNum++, title);
		}
		for(int i=0;i<defs.size();i++){
			
			List<PvmActivity> actis = (List<PvmActivity>) rpdf.get(i).getActivities();
			for(PvmActivity activity :actis){
				if (!ProcessDefinitionUtils.isUserTask((ActivityImpl) activity)) {
					continue;
				}
				exportUtil.createRow(rowNum++);	
				exportUtil.setCell(0,defs.get(i).getProcDefId());
				exportUtil.setCell(1,defs.get(i).getProcDefKey());
				exportUtil.setCell(2,defs.get(i).getProcDefName());
				exportUtil.setCell(3,activity.getId());
				exportUtil.setCell(4,activity.getProperty("name").toString());
				exportUtil.setCell(5,defs.get(i).getTenantId());
			}
			
		}
	}
	
	public void ActivityResourceSheet(XLSExportUtil exportUtil,String sheetName,String[] titles,List<ProcessDefinitionModel> defs,List<ReadOnlyProcessDefinition> rpdf){
		int rowNum = 0;								//行数
		int cellNum = 0;							//列数
		exportUtil.createSheet(sheetName);			//新增sheet设置名称
		exportUtil.createRow(rowNum++);				//在sheet中新增一行、展示查询数据——标题
		for (String title : titles) {
			exportUtil.setCell(cellNum++, title);
		}
		for(int i=0;i<defs.size();i++){
			List<PvmActivity> actis = (List<PvmActivity>) rpdf.get(i).getActivities();
			for(PvmActivity activity :actis){
				if (!ProcessDefinitionUtils.isUserTask((ActivityImpl) activity)) {
					continue;
				}
				TaskDefinition taskDefinition = (TaskDefinition) activity
						.getProperty("taskDefinition");
				Set<Expression> roles = taskDefinition
						.getCandidateGroupIdExpressions();
				for (Expression roleId : roles) {
					exportUtil.createRow(rowNum++);	
					exportUtil.setCell(0,defs.get(i).getProcDefId());
					exportUtil.setCell(1,defs.get(i).getProcDefKey());
					exportUtil.setCell(2,defs.get(i).getProcDefName());
					exportUtil.setCell(3,activity.getId());
					exportUtil.setCell(4,activity.getProperty("name").toString());
					exportUtil.setCell(5,"角色");
					exportUtil.setCell(6,roleId.getExpressionText());
					exportUtil.setCell(7,defs.get(i).getTenantId());
				}
				Set<Expression> orgs = taskDefinition
						.getCandidateOrgIdExpressions();
				for (Expression orgId : orgs) {
					exportUtil.createRow(rowNum++);	
					exportUtil.setCell(0,defs.get(i).getProcDefId());
					exportUtil.setCell(1,defs.get(i).getProcDefKey());
					exportUtil.setCell(2,defs.get(i).getProcDefName());
					exportUtil.setCell(3,activity.getId());
					exportUtil.setCell(4,activity.getProperty("name").toString());
					exportUtil.setCell(5,"组织");
					exportUtil.setCell(6,orgId.getExpressionText());
					exportUtil.setCell(7,defs.get(i).getTenantId());
				}
				Set<Expression> users = taskDefinition
						.getCandidateUserIdExpressions();
				for (Expression userId : users) {
					exportUtil.createRow(rowNum++);	
					exportUtil.setCell(0,defs.get(i).getProcDefId());
					exportUtil.setCell(1,defs.get(i).getProcDefKey());
					exportUtil.setCell(2,defs.get(i).getProcDefName());
					exportUtil.setCell(3,activity.getId());
					exportUtil.setCell(4,activity.getProperty("name").toString());
					exportUtil.setCell(5,"人员");
					exportUtil.setCell(6,userId.getExpressionText());
					exportUtil.setCell(7,defs.get(i).getTenantId());
				}
			}
		}
	}
	
	/**
	 * 导出流程模型XML
	 * @param procDefId
	 * @param resourceType
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	@RequestMapping(value="/exportProcessResource")
	public void exportProcessResource(String procDefId,String resourceType,HttpServletRequest request,HttpServletResponse response) throws IOException {
		ProcessDefinitionModel processDefinition=processDefinitionService.getProcessDef(procDefId);
		InputStream in=processDefinitionService.loadProcessResource(procDefId, resourceType);
		OutputStream out=response.getOutputStream();
		try{
			String filename = processDefinition.getProcDefName()
					+ ".bpmn20.xml";
			response.reset();  
			response.setCharacterEncoding("UTF-8");
			response.setHeader("Content-Disposition", "attachment; filename="+URLEncoder.encode(filename,"UTF-8"));  
			response.setContentType("application/octet-stream; charset=utf-8");  
			org.apache.commons.io.IOUtils.copy(in, out); 
			response.flushBuffer();
		}catch(Exception e){
			logger.error("",e);
		}finally{
			try {
				in.close();
			} catch (IOException e) {
				logger.error("",e);
			}
		}
		
	}
	
	/**
	 * 导出所有流程数据包含模型和配置数据
	 * @param resourceType
	 * @param request
	 * @param response
	 * @throws IOException
	 */
	@RequestMapping(value="/exportProcessAllFile")
	public void exportProcessAllFile(String[] procDefIds,String exportall,String resourceType,HttpServletRequest request,HttpServletResponse response) throws IOException {
		OutputStream out=response.getOutputStream();
		InputStream in=null;
		ByteArrayOutputStream processModelDataOut=null;
		ByteArrayOutputStream processDataDataOut=null;
		
		String exportFileName = "";
		
		ApplicationEntity app = BaseUser.getInstance().getLoginUserApplication(request);
		exportFileName = app.getAppName();
		
		if("0".equals(exportall)|| ("1".equals(exportall) && procDefIds.length>1) ){//导出多个流程文件或者导出全部流程文件生成文件名
			//导出全部时文件名
			exportFileName = exportFileName +"-"+ DateUtil.convertDateToString("yyyyMMddHHmm", new Date()) + "--流程文件";
		}
		
		try{
			Map<String,byte[]> fileData=new HashMap<String,byte[]>();
			if("0".equals(exportall)){//导出所有
				ProcessInfoConfig params = new ProcessInfoConfig();
				params.setTenantId(BaseUser.getInstance().getLoginUserAppId(request));
				List<String> procDefIdsList =processConfigService.getAllProcessIdForExport(params);
				if(!procDefIdsList.isEmpty()){
					procDefIds = procDefIdsList.toArray(new String[procDefIdsList.size()]);
				}
				
			}
			if(null!=procDefIds && !"".equals(procDefIds)){
				for (String procDefId : procDefIds) {
					ProcessDefinitionModel processDefinition=processDefinitionService.getProcessDef(procDefId);
					if(processDefinition==null){
						return;
					}
					//生成导出文件文件名
					if("1".equals(exportall)){//导出单个流程文件
						if(procDefIds.length<=1){
							exportFileName = exportFileName+ processDefinition.getProcDefName() +"-"+DateUtil.convertDateToString("yyyyMMddHHmm", new Date())+"-流程文件"+processDefinition.getVersion();
						}
					}
					
					//导出流程图
					in=processDefinitionService.loadProcessResource(procDefId, resourceType);
					processModelDataOut=new ByteArrayOutputStream();
					org.apache.commons.io.IOUtils.copy(in, processModelDataOut);
					String processModelfilename = processDefinition.getProcDefKey()
							+ ".bpmn20.xml";
					
					//导出流程配置
					processDataDataOut=processConfigService.exportOneProcessData(procDefId);
					String processDataFilename = processDefinition.getProcDefKey()+".data"
							+ ".xml";
					
					
					fileData.put(processModelfilename, processModelDataOut.toByteArray());
					fileData.put(processDataFilename, processDataDataOut.toByteArray());
				}
				
			}
			
			response.reset();  
			response.setCharacterEncoding("UTF-8");
//			response.setHeader("Content-Disposition", "attachment; filename="+URLEncoder.encode(processDefinition.getProcDefName(),"UTF-8")+".zip");  
			response.setHeader("Content-Disposition", "attachment; filename="+URLEncoder.encode(exportFileName,"UTF-8")+".zip");  
			response.setContentType("application/octet-stream; charset=utf-8"); 
			
			ProcessZipUtil.zipFiles(fileData,out);
			response.flushBuffer();
		}catch(Exception e){
			logger.error("导出流程所有资源出现异常,procDefIds:"+procDefIds,e);
		}finally{
			IOUtils.closeQuietly(in);
			IOUtils.closeQuietly(processDataDataOut);
			IOUtils.closeQuietly(processModelDataOut);
			
		}
		
	}
	
	

	/**
	 * 导入所有流程数据包含模型和配置数据
	 * 
	 * @param request
	 * @throws IOException
	 */
	@RequestMapping(value = "/importProcessAllFile")
	public ModelAndView importProcessAllFile(
			@RequestParam(value = "file", required = false) MultipartFile file,
			HttpServletRequest request) throws IOException {
		ModelAndView modelAndView = new ModelAndView(
				"/procDefMgr/importProcessConfigData");
		String savetype = request.getParameter("savetype");
		String result = "导入成功";
		try {
			// 每一个流程包含流程图和流程配置文件数据
			Map<String, byte[][]> processAllFile = ProcessZipUtil
					.unZipFiles(file.getBytes());
			for (Entry<String, byte[][]> processAllFileEntry : processAllFile
					.entrySet()) {
				byte[][] processByteList = processAllFileEntry.getValue();
				// 每一个流程包含流程图和流程配置文件数据,下标0为流程图、下标1为流程配置数据
				// 导入流程图
				BpmnModel bpmnModel;
				try{
					bpmnModel=processModelService.importBpmnFile(processByteList[0],
						BaseUser.getInstance().getLoginUserAppId(request));
				}catch(Exception e){
					result=processAllFileEntry.getKey()+"-导入失败:"+e.getMessage();
					logger.error(result, e);
					continue;
				}
				ProcessDefinitionModel processDefinition = deployProcess(
						processByteList[0], bpmnModel.getMainProcess().getId(),
						BaseUser.getInstance().getLoginUserAppId(request),savetype);
				if (processDefinition != null) {
					processConfigService.importOneProcessData(processDefinition
							.getProcDefId(), BaseUser.getInstance().getLoginUserAppId(request),processDefinition
							.getDeploymentId(), new String(processByteList[1],"UTF-8"), "0");
				}
			}
			modelAndView.addObject("flashSuccess", result);
		} catch (Exception e) {
			e.printStackTrace();
			modelAndView.addObject("flashSuccess", "导入流程图及配置文件失败!");
		}
		
		//操作日志
		MyContants.saveUserOperate(request, "", true, result,
				MyContants.LOGIN_SESSION_USER,MyContants.APPLICATION);
		return modelAndView;

	}
	
	/**
	 * 彻底删除流程定义（可能包含该定义下所有运行流程实例数据）
	 * @param procDefId
	 * @param deploymentId
	 * @param cascode
	 * @param request
	 * @param redirectAttributes
	 * @return
	 */
	@RequestMapping(value = "/delete")
	public ModelAndView delete(String procDefId, String deploymentId,
			boolean cascode, HttpServletRequest request,
			RedirectAttributes redirectAttributes) {
		boolean result = false;
		try {
			ProcessDefinitionModel processDefinition = processDefinitionService
					.getProcessDef(procDefId);
			if (processDefinition != null) {
				result = processDefinitionService.delete(procDefId,
						deploymentId, cascode);
				ProcessDefinitionModel processDefinitionModel = processDefinitionService
						.getProcessDefBykey(processDefinition.getProcDefKey());
				if (processDefinitionModel == null) {
					processModelService.updateModelState(processDefinition
							.getProcDefKey(), BaseUser.getInstance()
							.getLoginUserAppId(request), "UNRELEASE");
				}
			}
		} catch (Exception e) {
			logger.error("", e);
		}
		redirectAttributes.addFlashAttribute(ACTION_MESSAGE,
				result ? DELETE_SUCCESS : this.ACTION_ERROR);
		ModelAndView modelAndView = new ModelAndView(
				"redirect:/procDefMgr/list.do");
		return modelAndView;
	}
	
	/**
	 * 删除历史版本界面
	 * @param procDefId
	 * @param deploymentId
	 * @param cascode
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/history/delete")
	@ResponseBody
	public Map deleteforhistorypage(String procDefId, String deploymentId,
			boolean cascode, HttpServletRequest request) {
		Map result = new HashMap();
		result.put("success", true);
		try {
			ProcessDefinitionModel processDefinition = processDefinitionService
					.getProcessDef(procDefId);
			if (processDefinition != null) {
				ProcessMgrDataShare.setProcessMgrData(WorkFlowContants.PROCESS_DEF_DEL_MANAGE_OPT);
				boolean temp = processDefinitionService.delete(procDefId,
						deploymentId, cascode);
				ProcessMgrDataShare.clear();
				result.put("success", temp);
				
				ProcessDefinitionModel processDefinitionModel = processDefinitionService
						.getProcessDefBykey(processDefinition.getProcDefKey());
				if (processDefinitionModel == null) {
					processModelService.updateModelState(processDefinition
							.getProcDefKey(), BaseUser.getInstance()
							.getLoginUserAppId(request), "UNRELEASE");
				}
			}
			
			//根据key获取到所有版本
			List<ProcessDefinitionModel> allVersionList = processDefinitionService.findAllVersionProcessDefs(processDefinition.getProcDefKey());
			String returnProcDefId = "";
			if(null!=allVersionList && 0!=allVersionList.size()){
				returnProcDefId = allVersionList.get(0).getProcDefId();
			}
			result.put("returnProcDefId", returnProcDefId);
		} catch (Exception e) {
			logger.error("", e);
			result.put("success", false);
			result.put("reason", e.getMessage());
		}
		MyContants.saveUserOperate(request, "deploymentId;procDefId", 
				(Boolean) result.get("success"), 
				result.containsKey("reason")?result.get("reason").toString():"",
						MyContants.LOGIN_SESSION_USER,MyContants.APPLICATION);
		return result;
	}
	
	/**
	 * 导入、部署流程
	 * @param file
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/deploy")
	public ModelAndView deploy(@RequestParam(value = "file", required = false) MultipartFile file,HttpServletRequest request) {
		ModelAndView modelAndView = new ModelAndView("/procDefMgr/deployProcessFile");
		String fileName = file.getOriginalFilename();
		BpmnModel bpmnModel=null;
		try{
			bpmnModel=processModelService.convertFileToBpmnModel(new ByteArrayInputStream(file.getBytes()));
		}catch(Exception e){
			logger.error("",e);
		}
		if(bpmnModel==null){
			modelAndView.addObject("flashSuccess","验证bpmn.xml出现异常，非法的bpmn.xml");
			return modelAndView;
		}
		InputStream in=new ByteArrayInputStream(processModelService.convertBpmnModelToByte(bpmnModel));
		try {
			ProcessDefinitionModel processDefinition=processDefinitionService.deploySingleProcess(BaseUser.getInstance().getLoginUserAppId(request),in, fileName);
			if(processDefinition!=null){
				processModelService.syncBpmnModelToDb(processDefinition);
				modelAndView.addObject("flashSuccess","导入成功!");
			}
		} catch (Exception e) {
			logger.error("",e);
			modelAndView.addObject("flashSuccess","导入失败!");
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				logger.error("",e);
			}
		}
		return modelAndView;
	}
	
	/**
	 * 流程配置界面
	 * @param userId
	 * @param procDefId
	 * @param request
	 * @param query
	 * @return
	 */
	@RequestMapping(value="/config")
	public ModelAndView config(String userId,String procDefId,HttpServletRequest request,ProcessInfoConfig query) {
		ProcessDefinitionModel processDefinition=processDefinitionService.getProcessDef(procDefId);
		ModelAndView modelAndView = new ModelAndView("/procDefMgr/config");
		modelAndView.addObject("processDefinition",processDefinition);
		this.saveQueryParams(request, query);
		return modelAndView;
	}
	
	/**
	 * 贯穿流程设置
	 */
	@RequestMapping(value="/callactivityconfig")
	public ModelAndView callactivityconfig(String userId,String callActivityProcKey,String isSubProcess,String sys,String mAppId,HttpServletRequest request,ProcessInfoConfig query) {
		ProcessDefinitionModel processDefinition=processDefinitionService.getProcessDefBykey(callActivityProcKey);
		ModelAndView modelAndView = new ModelAndView("/procDefMgr/config");
		modelAndView.addObject("processDefinition",processDefinition);
		modelAndView.addObject("isSubProcess",isSubProcess);
		modelAndView.addObject("sys", sys);
		modelAndView.addObject("mAppId", mAppId);
		this.saveQueryParams(request, query);
		return modelAndView;
	}
	
	/**
	 * 直接修改、更新流程模型XML
	 * @param request
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	@RequestMapping(value = "/updateBpmnFile",method=RequestMethod.POST)
	@ResponseBody
	public String updateBpmnFile(@RequestBody Map<String, String> values,
			HttpServletRequest request) throws UnsupportedEncodingException {
		String procDefId = values.get("procDefId");
		String bpmnXml=values.get("bpmnXml");
		ProcessDefinitionModel processDefinition = processDefinitionService
				.getProcessDef(procDefId);
		byte[] updateBpmnByte = bpmnXml.getBytes("UTF-8");
		/*List<ValidationError> validationErrors = null;
		try {
			BpmnModel bpmnModel = processModelNewService.convertByteToBpmnModel(updateBpmnByte, "");
			ProcessValidator processValidator = new ProcessValidatorFactory().createDefaultProcessValidator();
			validationErrors = processValidator.validate(bpmnModel);
		} catch (Exception e) {
			logger.error("",e);
			//return "验证bpmn.xml出现异常，非法的bpmn.xml";
		}
		if (!validationErrors.isEmpty()) {
			//return validationErrors.toString();
		}*/
		// 更新bpmn.xml
		processDefinitionService.updateDeploymentResource(
				processDefinition.getDeploymentId(),
				processDefinition.getProcDefId(), updateBpmnByte,
				false);
		// 更新流程定义缓存
		processDefinitionService.refreshProcessDefineCache(processDefinition
				.getProcDefId());
		processModelService.syncBpmnModelToDb(processDefinition);

		return this.ACTION_SUCCESS;
	}
	
	/**
	 * 编辑流程模型XML
	 * @param procDefId
	 * @param request
	 * @return
	 */
	@RequestMapping(value="/editProcessFile")
	public ModelAndView editProcessFile(String procDefId,HttpServletRequest request) {
		InputStream in=processDefinitionService.loadProcessResource(procDefId, "xml");
		String bpmnXml="";
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		try{
			org.apache.commons.io.IOUtils.copy(in, out); 
			bpmnXml=out.toString("UTF-8");
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				in.close();
				out.close();
			} catch (IOException e) {
				logger.error("",e);
			}
		}
		ModelAndView modelAndView = new ModelAndView("/procDefMgr/editProcessFile");
		modelAndView.addObject("bpmnXml",bpmnXml);
		modelAndView.addObject("procDefId",procDefId);
		return modelAndView;
	}
	
	/**
	 * 将流程定义XML转换成流程模型JSON
	 * @param procDefId
	 * @return
	 */
	@RequestMapping(value = "/convert-to-model")
	@ResponseBody
	public String convertToModel(String procDefId) {
		boolean result=processModelService.syncProcessModelToJsonModel(procDefId);
		return result?this.ACTION_SUCCESS:this.ACTION_ERROR;
	}


	/**
	 * 发布流程
	 **/
	@RequestMapping(value = "releaseProcess")
	@ResponseBody
	public String releaseProcess(HttpServletRequest request, String procDefId) {
		ProcessInfoConfig processInfoConfig = processInfoConfigManager
				.getById(procDefId);
		if (processInfoConfig == null) {
			return "procDefId[" + procDefId + "]无效!";
		}
		/*if (StringUtils.isEmpty(processInfoConfig.getProcessTypeName())) {
			return "流程分类不能为空,请选择流程分类后再发布流程!";
		}*/
		String result = this.ACTION_SUCCESS;
		try {
			String validateMsg=customProcessValidator.validate(procDefId);
			if(!StringUtils.isEmpty(validateMsg)){
				return ACTION_ERROR +"!"+validateMsg;
			}
			processInfoConfigManager.releaseProcessInfo(processInfoConfig);
			processModelService.syncProcessModelToJsonModel(procDefId);
		} catch (Exception e) {
			logger.error("", e);
			result = ACTION_ERROR + e.getMessage();
		}
		return result;
	}

	/**
	 * 保存更新对象
	 **/
	@RequestMapping(value = "unReleaseProcess")
	@ResponseBody
	public String unReleaseProcess(HttpServletRequest request,String procDefId)  {
		ProcessInfoConfig processInfoConfig=processInfoConfigManager.getById(procDefId);
		if(processInfoConfig==null){
			return "procDefId["+procDefId+"]无效!";
		}
		processInfoConfigManager.unReleaseProcessInfo(processInfoConfig);
		return UPDATE_SUCCESS;
	}
	
	
/**
 * 导出单独的流程配置数据
 * @param procDefId
 * @param request
 * @param response
 * @throws IOException
 */
	@RequestMapping(value="/exportProcessConfigData")
	public void exportProcessConfigData(String procDefId,HttpServletRequest request,HttpServletResponse response) throws IOException {
		ProcessDefinitionModel processDefinition=processDefinitionService.getProcessDef(procDefId);
		if(processDefinition==null){
			return;
		}
		ByteArrayOutputStream dataOut=processConfigService.exportOneProcessData(procDefId);
		OutputStream out=response.getOutputStream();
		String filename = processDefinition.getProcDefName()+"-data"
				+ ".xml";
		try{
			response.reset();  
			response.setCharacterEncoding("UTF-8");
			response.setHeader("Content-Disposition", "attachment; filename="+URLEncoder.encode(filename,"UTF-8"));  
			response.setContentType("application/octet-stream; charset=utf-8");  
			ByteArrayInputStream in=new ByteArrayInputStream(dataOut.toByteArray());
			IOUtils.copy(in, out);
			response.flushBuffer();
		}catch(Exception e){
			logger.error("",e);
		}finally{
			try {
				dataOut.close();
			} catch (IOException e) {
				logger.error("",e);
			}
		}
		
	}
	
/**
 * 导入流程配置数据
 * @param file
 * @param request
 * @return
 */
	@RequestMapping(value = "/importProcessConfigData")
	public ModelAndView importProcessConfigData(
			@RequestParam(value = "file", required = false) MultipartFile file,HttpServletRequest request) {
		ModelAndView modelAndView = new ModelAndView(
				"/procDefMgr/importProcessConfigData");
		try {
			ServiceResponse serviceResponse=processConfigService.importOneProcessData("",BaseUser.getInstance().getLoginUserAppId(request),"",new String(file.getBytes(),"UTF-8"), "0");
			if(serviceResponse.getStatus().equals(serviceResponse.STATUS_OP_SUCCESS)){
				modelAndView.addObject("flashSuccess", "导入成功!");
			}else{
				modelAndView.addObject("flashSuccess", "导入失败!");
			}
		} catch (Exception e) {
			logger.error("", e);
			modelAndView.addObject("flashSuccess", "导入失败!");
		}
		return modelAndView;
	}
	
	/**
	 * 进入更新页面
	 **/
	@RequestMapping(value = "getActivityDefModel")
	@ResponseBody
	public ActivityDefinitionModel getActivityDefModel(HttpServletRequest request, String procDefId, String actDefId) {
		ActivityDefinitionModel activityDefinitionModel = processDefinitionService.getActivity(procDefId, actDefId);

		BpmnModel bpmnModel = processModelService.getBpmnModelByProcDefId(procDefId);
		UserTask userTask = ProcessModelUtils.findUserTask(bpmnModel, actDefId);
		List<ActivityResourceModel> activityResources = new ArrayList<ActivityResourceModel>();
		if (!userTask.getCandidateGroups().isEmpty()) {
			for (String groupId : userTask.getCandidateGroups()) {
				Role role = roleService.getRoleById(groupId);
				ActivityResourceModel actitityResource = new ActivityResourceModel(groupId, "角色",
						role != null ? role.getRoleName() : "<font color='red'>该角色已失效</font>", 0, "ROLE",
						role.getRoleSort());
				actitityResource.setRemark(groupId);
				activityResources.add(actitityResource);
			}
		}
		if (!userTask.getCandidateOrgs().isEmpty()) {
			for (String orgId : userTask.getCandidateOrgs()) {
				Org org = orgService.getOrgById(orgId);
				ActivityResourceModel actitityResource = new ActivityResourceModel(orgId, "组织",
						org != null ? org.getOrgName() : "<font color='red'>该组组已失效</font>", 0, "ORG", org.getOrgSort());
				actitityResource.setRemark(orgId);
				activityResources.add(actitityResource);
			}
		}
		if (!userTask.getCandidateUsers().isEmpty()) {
			for (String userId : userTask.getCandidateUsers()) {
				User user = userService.getUserById(userId);
				Org org = orgService.getOrgById(user.getOrgId());
				ActivityResourceModel actitityResource = new ActivityResourceModel(userId, "人员",
						(user != null && StrUtil.isNotEmpty(user.getUserId())) ? user.getUserName() + "（" + org.getOrgName() + "）"
								: "<font color='red'>该人员已失效</font>",
						0, "USER", user.getUserSort());
				actitityResource.setRemark(user.getUserId());
				activityResources.add(actitityResource);
			}
		}
		activityDefinitionModel.setActivityResources(activityResources);
		return activityDefinitionModel;
	}
	
	/**
	 *获取流程类型树
	 * @throws Exception 
	 **/
	@RequestMapping(value="getProcDefTree")
	@ResponseBody 
	public List<TreeNode> getProcDefTree(HttpServletRequest request,String filterNodeIdsStr,String selectType) throws Exception {
		String typeId=request.getParameter("id");
		
		String userId = BaseUser.getInstance().getSessionUser(request).getUserId();
		List<TreeNode> treeNodes=procDefTreeManager.getProcDefTree(typeId,userId,selectType);
		String[] filterNodeIds=null;
		if(StringUtils.isNotEmpty(filterNodeIdsStr)){
			if(filterNodeIdsStr.indexOf(",")!=-1){
				filterNodeIds=filterNodeIdsStr.split(",");
			}else{
				filterNodeIds=new String[]{filterNodeIdsStr};
			}
			for (String filterNodeId : filterNodeIds) {
				TreeNode treeNode=new TreeNode();
				treeNode.setId(filterNodeId);
				treeNodes.remove(treeNode);
			}
		}
		return treeNodes;
	}
	@RequestMapping(value="getProcDefTree_bak")
	@ResponseBody 
	public List<TreeNode> getProcDefTree_bak(HttpServletRequest request,String filterNodeIdsStr) throws Exception {
		String typeId=request.getParameter("id");
		SearchProcessListDTO searchProcessList =new SearchProcessListDTO();
		searchProcessList.setTenantId(BaseUser.getInstance().getLoginUserAppId(request));
		List<TreeNode> treeNodes=procDefTreeManager.getProcDefTree_bak(searchProcessList);;
		String[] filterNodeIds=null;
		if(StringUtils.isNotEmpty(filterNodeIdsStr)){
			if(filterNodeIdsStr.indexOf(",")!=-1){
				filterNodeIds=filterNodeIdsStr.split(",");
			}else{
				filterNodeIds=new String[]{filterNodeIdsStr};
			}
			for (String filterNodeId : filterNodeIds) {
				TreeNode treeNode=new TreeNode();
				treeNode.setId(filterNodeId);
				treeNodes.remove(treeNode);
			}
		}
		return treeNodes;
	}

	/**
	 * 获取历史定义
	 * 
	 * @param procDefId
	 * @param request
	 * @return
	 */
	@RequestMapping(value="getHistoryProcessDefModel")
	public ModelAndView getHistoryProcessDefModel(String procDefId,HttpServletRequest request){
		ModelAndView modelAndView = new ModelAndView(
				"/procDefMgr/historyVersionProcess");
        try {
        	String[] size =  processTraceService.getProcessDiagramSize(procDefId);
        	 modelAndView.addObject("imageWidth",size[0]);
        	 modelAndView.addObject("imageHeight",size[1]);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		ProcessDefinitionModel proc =  processDefinitionService.getProcessDef(procDefId);
		//根据key获取到所有版本
		List<ProcessDefinitionModel> result = processDefinitionService.findAllVersionProcessDefs(proc.getProcDefKey());
		modelAndView.addObject("result", result);
		return modelAndView;
	}
	/**
	 * 对比流程历史版本
	 * @param procDefIdOld
	 * @param procDefIdNew
	 * @param nameOld
	 * @param nameNew
	 * @param request
	 * @return
	 */
	@RequestMapping(value="compareHistoryModel")
	public ModelAndView compareHistoryModel(String procDefIdOld,String procDefIdNew,String nameOld,String nameNew,HttpServletRequest request){
		ModelAndView modelAndView = new ModelAndView(
				"/procDefMgr/compareHistory");
		String xmlOld = "";
		String xmlNew = "";
		xmlOld=getProcessXml(procDefIdOld);
		xmlNew=getProcessXml(procDefIdNew);
		modelAndView.addObject("xmlOld", xmlOld);
		modelAndView.addObject("xmlNew", xmlNew);
		modelAndView.addObject("nameOld", nameOld);
		modelAndView.addObject("nameNew", nameNew);
		return modelAndView;
	}
	
	/**
	 * 获取流程图的宽高
	 **/
	@RequestMapping(value = "getProcessImageWidthAndHeight")
	@ResponseBody
	public String getProcessImageWidthAndHeight(HttpServletRequest request, String procDefId) {
		Map result = new HashMap();
		result.put("success",true);
		
		//为了获取版本号
		ProcessDefinitionModel proc =  processDefinitionService.getProcessDef(procDefId);
		
		try {
			String[] size =  processTraceService.getProcessDiagramSize(procDefId);
        	result.put("imageWidth",size[0]); 
        	result.put("imageHeight",size[1]); 
		} catch (Exception e) {
			e.printStackTrace();
			result.put("success", false);
			result.put("reason", e.getMessage());
		}
		result.put("version", proc.getVersion());
		String returnValue = JsonUtil.convertToJson(result);
		return returnValue;
	}
	
	/**
	 * @param bpmnBytes
	 * @param procDefKey
	 * @param appId
	 * @param savetype 标示是新建还是覆盖 savetype为'create'为新建  值为'update'为覆盖
	 * @return
	 */
	private ProcessDefinitionModel deployProcess(byte[] bpmnBytes, String procDefKey,String appId,String savetype) {
		ProcessDefinitionModel proceDefModel = null;
		if("create".equals(savetype)){//如果选择新建
			//直接新增版本
			proceDefModel = processDefinitionService
					.deploySingleProcess(appId,new ByteArrayInputStream(bpmnBytes),procDefKey+".bpmn20.xml");
		}else{//如果选择覆盖
			// 获取最新版本的流程定义
			proceDefModel = processDefinitionService
					.getProcessDefBykey(procDefKey);
			if(proceDefModel==null){//查询不到已有版本，新增版本
				proceDefModel = processDefinitionService
						.deploySingleProcess(appId,new ByteArrayInputStream(bpmnBytes),procDefKey+".bpmn20.xml");
			} else {// 覆盖已有版本
				// 更新bpmn.xml
				processDefinitionService.updateDeploymentResource(
						proceDefModel.getDeploymentId(), proceDefModel.getProcDefId(),
						bpmnBytes, true);
				// 更新流程定义缓存
				processDefinitionService.refreshProcessDefineCache(proceDefModel
						.getProcDefId());
			}
		}
		return proceDefModel;
	}
	//获取流程模型xml
	private String getProcessXml(String procDefId) {
		InputStream in=processDefinitionService.loadProcessResource(procDefId, "xml");
		String bpmnXml="";
		ByteArrayOutputStream out=new ByteArrayOutputStream();
		try{
			org.apache.commons.io.IOUtils.copy(in, out); 
			bpmnXml=out.toString("UTF-8");
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			try {
				in.close();
				out.close();
			} catch (IOException e) {
				logger.error("",e);
			}
		}
		return bpmnXml;
	}
	/**
	 * 查看流程图
	 * @param procDefId
	 * @return
	 * @throws Exception
	 */
    @RequestMapping(value="/viewImage")
	public ModelAndView traceImage(String procDefId) throws Exception {
		ModelAndView modelAndView = new ModelAndView("/procDefMgr/viewImage");
		String bpmXml = getProcessXml(procDefId);
		modelAndView.addObject("bpmXml", bpmXml);
		return modelAndView;
	}

	public String validate(byte[] bpmnBytes) {
		String errorMsg = "";
		List<ValidationError> validationErrors = null;
		try {
			BpmnModel bpmnModel = this.processModelNewService.convertByteToBpmnModel(bpmnBytes, "");
			ProcessValidator processValidator = new ProcessValidatorFactory().createDefaultProcessValidator();
			validationErrors = processValidator.validate(bpmnModel);
		} catch (Exception e) {
			errorMsg = "非法的流程模型!";
			e.printStackTrace();
		}
		if (!validationErrors.isEmpty()) {
			errorMsg = validationErrors.toString();
		}
		return errorMsg;

	}
}
