package com.blueland.bpm.manage.web;

import java.io.ByteArrayInputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.blueland.bpm.common.page.Page;
import com.blueland.bpm.common.page.PageRequest;
import com.blueland.bpm.engine.core.service.ProcessModelService;
import com.blueland.bpm.engine.util.WorkFlowException;
import com.blueland.bpm.manage.util.BaseUser;
import com.blueland.bpm.manage.util.MyContants;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

@Controller
@RequestMapping(value = "/procModelMgr")
public class ProcessModelController extends BaseProcessController {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	@Autowired
	RepositoryService repositoryService;
	@Autowired
	ProcessModelService processModelService;

	/**
	 * 流程模型列表
	 */
	@RequestMapping(value = "list")
	public ModelAndView modelList(HttpServletRequest request) {
		ModelAndView mav = new ModelAndView("/procModelMgr/list");
		PageRequest pageRequest = this.bindPageRequest(request,
				new PageRequest(), "");
		ModelQuery modelQuery = repositoryService.createModelQuery();
		String appId = BaseUser.getInstance().getLoginUserAppId(request);
		if ("true".equalsIgnoreCase(MyContants.IS_OPEN_TENANT)
				&& !StringUtils.isEmpty(appId)) {
			modelQuery.modelTenantId(appId);
		}
		if (!StringUtils.isEmpty(request.getParameter("modelKey")))
			modelQuery.modelKeyLike("%" + request.getParameter("modelKey")+"%");
		if (!StringUtils.isEmpty(request.getParameter("modelName")))
			modelQuery.modelNameLike("%" + request.getParameter("modelName")
					+ "%");
		Page<Model> page = new Page<Model>(pageRequest,
				(int) modelQuery.count());
		List<Model> list = modelQuery.orderByCreateTime().desc()
				.listPage(page.getFirstResult(), pageRequest.getPageSize());
		page.setResult(list);
		mav.addAllObjects(toModelMap(page, null));
		mav.addObject("modelKey", request.getParameter("modelKey"));
		mav.addObject("modelName", request.getParameter("modelName"));
		return mav;
	}

	/**
	 * 复制模型
	 */
	@RequestMapping(value = "copy")
	@ResponseBody
	public String copy(String modelId, String name, String key,
			String description) {
		String errorMsg = "";
		try {
			 processModelService.copy(modelId,name, key, description);
		} catch (Exception e) {
			if (e instanceof WorkFlowException) {
				errorMsg = ((WorkFlowException) e).getWebShowErrorMessage();
			}
		}
		return StringUtils.isEmpty(errorMsg)?this.ACTION_SUCCESS:errorMsg;
	}

	/**
	 * 复制模型
	 */
	@RequestMapping(value = "copyView")
	public ModelAndView copyView(String modelId) {
		ModelAndView modelAndView = new ModelAndView("/procModelMgr/copy");
		Model modelData = repositoryService.getModel(modelId);
		modelAndView.addObject("modelData", modelData);
		return modelAndView;
	}

	/**
	 * 创建模型
	 */
	@RequestMapping(value = "create")
	@ResponseBody
	public Map<String, String> create(String name, String key,
			String description, HttpServletRequest request,
			HttpServletResponse response) {
		String path = "";
		String errorMsg = "";
		try {
			String modelId = processModelService.create(name, key, description,
					BaseUser.getInstance().getLoginUserAppId(request));
			path = MyContants.BPM_PROCESS_MODELER_PATH + "?id=" + modelId;
		} catch (Exception e) {
			if (e instanceof WorkFlowException) {
				errorMsg = ((WorkFlowException) e).getWebShowErrorMessage();
			}
		}
		Map result = new HashMap();
		result.put("path", path);
		result.put("errorMsg", errorMsg);
		return result;

	}

	/**
	 * 根据Model部署流程
	 */
	@RequestMapping(value = "deploy")
	@ResponseBody
	public String deploy(String modelId, HttpServletRequest request,
			RedirectAttributes redirectAttributes) {
		String result = "";
		try {
			if (StringUtils.isEmpty(modelId)) {
				result = "传入modelId为空值,无法找到模型！";
				return result;
			}
			result = processModelService.deploy(modelId, BaseUser.getInstance()
					.getLoginUserAppId(request));
		} catch (Exception e) {
			String errorMsg = String.format("根据流程模型[%s]来部署流程失败,错误信息:[%s]",
					modelId, e.getLocalizedMessage());
			logger.error(errorMsg, e);
			result = errorMsg;
		}
		return result;
	}

	/**
	 * 直接覆盖已有流程定义版本，并更新流程定义的缓存
	 */
	@RequestMapping(value = "deployCascodeUpdate")
	@ResponseBody
	public String deployCascodeUpdate(String modelId,
			HttpServletRequest request, RedirectAttributes redirectAttributes) {
		String result = "";
		boolean isSuccess = false;
		try {
			if (StringUtils.isEmpty(modelId)) {
				result = "传入modelId为空值,无法找到模型！";
				return result;
			}
			/*String flowElementUptMsg=processModelService.getFlowElementUptMsg(modelId);
			if(StringUtils.isNotEmpty(flowElementUptMsg)){
				result=flowElementUptMsg;
				return result;
			}*/
			if (processModelService.isPprocessDeployment(modelId, BaseUser
					.getInstance().getLoginUserAppId(request))) {
				result = processModelService.deployCascodeUpdate(modelId);
			} else {
				result = processModelService.deploy(modelId, BaseUser
						.getInstance().getLoginUserAppId(request));
			}
			isSuccess = true;
		} catch (Exception e) {
			logger.error("根据模型部署流程失败：modelId={}", modelId, e);
			result = "根据模型部署流程失败";
		}
		MyContants.saveUserOperate(request, "modelId", isSuccess, result,
				MyContants.LOGIN_SESSION_USER,MyContants.APPLICATION);
		return result;
	}

	/**
	 * 导出model的xml文件
	 */
	@RequestMapping(value = "export")
	public void export(String modelId, HttpServletResponse response) {
		try {
			BpmnModel bpmnModel = this.processModelService
					.getBpmnModelByModelId(modelId);
			BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
			byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);
			ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
			IOUtils.copy(in, response.getOutputStream());
			String filename = bpmnModel.getMainProcess().getName()
					+ ".bpmn20.xml";
			response.setHeader("Content-Disposition", "attachment; filename="
					+ URLEncoder.encode(filename, "UTF-8"));
			response.flushBuffer();
		} catch (Exception e) {
			logger.error("导出model的xml文件失败：modelId={}", modelId, e);
		}
	}

	/**
	 * 导入流程模型文件
	 * 
	 * @param file
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/importBpmnFile")
	public ModelAndView importBpmnFile(
			@RequestParam(value = "file", required = false) MultipartFile file,
			HttpServletRequest request) {
		ModelAndView modelAndView = new ModelAndView(
				"/procModelMgr/importBpmnFile");
		try {
			processModelService.importBpmnFile(file.getBytes(),
					BaseUser.getInstance().getLoginUserAppId(request));
			modelAndView.addObject("flashSuccess", "导入成功!");
		} catch (Exception e) {
			modelAndView.addObject("flashSuccess", "非法的BPMN文件!");
		}
		return modelAndView;
	}

	/**
	 * 删除流程模型
	 * 
	 * @param modelId
	 * @param redirectAttributes
	 * @return
	 */
	@RequestMapping(value = "delete")
	public ModelAndView delete(String modelId,HttpServletRequest request,
			RedirectAttributes redirectAttributes) {
		ModelAndView modelAndView = new ModelAndView(
				"redirect:/procModelMgr/list.do");
		redirectAttributes.addFlashAttribute(ACTION_MESSAGE, DELETE_SUCCESS);
		repositoryService.deleteModel(modelId);
		
		MyContants.saveUserOperate(request, "modelId", true, DELETE_SUCCESS,
				MyContants.LOGIN_SESSION_USER,MyContants.APPLICATION);
		return modelAndView;
	}

}
