package cn.myapps.runtime.activity.service;

import cn.myapps.authtime.common.dao.PersistenceUtils;
import cn.myapps.authtime.common.service.AuthTimeServiceManager;
import cn.myapps.authtime.user.model.UserVO;
import cn.myapps.authtime.user.service.UserProcess;
import cn.myapps.common.Environment;
import cn.myapps.common.auth.IUser;
import cn.myapps.common.data.ParamsTable;
import cn.myapps.common.model.activity.Activity;
import cn.myapps.common.model.activity.ActivityParent;
import cn.myapps.common.model.excelimport.IMPMappingConfigVO;
import cn.myapps.common.model.summary.SummaryCfgVO;
import cn.myapps.common.model.view.AbstractView;
import cn.myapps.common.model.workflow.BillDefiVO;
import cn.myapps.common.util.DefaultProperty;
import cn.myapps.common.util.StringUtil;
import cn.myapps.common.util.cache.MemoryCacheUtil;
import cn.myapps.designtime.activity.service.ActivityDesignTimeService;
import cn.myapps.designtime.common.service.DesignTimeServiceManager;
import cn.myapps.designtime.dts.excelimport.config.service.IMPMappingConfigDesignTimeService;
import cn.myapps.designtime.form.service.FormDesignTimeService;
import cn.myapps.designtime.summary.service.SummaryCfgDesignTimeService;
import cn.myapps.designtime.view.service.ViewDesignTimeService;
import cn.myapps.runtime.common.service.RunTimeServiceManager;
import cn.myapps.runtime.dynaform.document.ejb.Document;
import cn.myapps.runtime.dynaform.document.ejb.DocumentHelper;
import cn.myapps.runtime.dynaform.document.ejb.DocumentProcess;
import cn.myapps.runtime.dynaform.dts.excelimport.ExcelMappingDiagram;
import cn.myapps.runtime.dynaform.dts.excelimport.Factory;
import cn.myapps.runtime.dynaform.dts.excelimport.config.ImpExcelException;
import cn.myapps.runtime.dynaform.dts.excelimport.config.ImpExcelToDoc;
import cn.myapps.runtime.dynaform.form.FormDataPacket;
import cn.myapps.runtime.dynaform.form.ejb.Form;
import cn.myapps.runtime.dynaform.form.ejb.FormField;
import cn.myapps.runtime.dynaform.form.ejb.ValidateMessage;
import cn.myapps.runtime.dynaform.form.ejb.ValueStoreField;
import cn.myapps.runtime.macro.runner.IRunner;
import cn.myapps.runtime.macro.runner.JavaScriptFactory;
import cn.myapps.runtime.macro.runner.JsMessage;
import cn.myapps.runtime.workflow.FlowState;
import cn.myapps.runtime.workflow.FlowType;
import cn.myapps.runtime.workflow.element.*;
import cn.myapps.runtime.workflow.engine.StateMachine;
import cn.myapps.runtime.workflow.storage.runtime.ejb.*;
import cn.myapps.support.sms.SMSMode.SMSParcels;
import cn.myapps.support.sms.SMSQueueOperator;
import cn.myapps.util.DocumentRequestUtil;
import cn.myapps.util.mail.EmailUtil;
import cn.myapps.util.sequence.Sequence;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.saas.core.exceptions.SaasNofoundException;
import net.sf.json.JSONArray;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.print.Doc;
import java.io.*;
import java.util.*;

public class ActivityRunTimeServiceImpl implements ActivityRunTimeService {

	private static final Logger LOG = LoggerFactory.getLogger(ActivityRunTimeServiceImpl.class);

	@Override
	public JSONObject runbeforeactionscript(String applicationId, String id, Document doc, ParamsTable params,
											IUser user) throws Exception {
		ActivityParent actParent = null;
		Activity act = null;
		String docid = params.getParameterAsString("docId");
		String viewid = params.getParameterAsString("viewId");
		String formid = params.getParameterAsString("formId");
		String templateForm = params.getParameterAsString("_templateForm");
		String parentId = params.getParameterAsString("parentId");
		params.setParameter("application", applicationId);
		params.setParameter("docid", docid);
		params.setParameter("viewid", viewid);
		params.setParameter("formid", formid);
		params.setParameter("parentid", parentId);

		if (docid != null && docid.equals(parentId)) {
			parentId = null;
			params.removeParameter("parentid");
		}
		if (id != null && id.trim().length() > 0) {
			if (!StringUtil.isBlank(formid) || !StringUtil.isBlank(templateForm)) {
				FormDesignTimeService formService = DesignTimeServiceManager.formDesignTimeService();
				if (!StringUtil.isBlank(templateForm)) {
					actParent = (ActivityParent) formService.doView(templateForm);
					act = actParent.findActivity(id);
				}
				if (act == null) {
					actParent = (ActivityParent) formService.doView(formid);
					if (actParent != null) {
						act = actParent.findActivity(id);
					}
				}
			} else {
				if (act == null && !StringUtil.isBlank(viewid)) {
					ViewDesignTimeService viewService = DesignTimeServiceManager.viewDesignTimeService();
					actParent = (ActivityParent) viewService.doView(viewid);
					act = actParent.findActivity(id);
				} else {
					ActivityDesignTimeService activityService = DesignTimeServiceManager.activityDesignTimeService();
					act = activityService.findById(id);
				}
			}
		}

		if (act == null) {
			ActivityDesignTimeService activityService = DesignTimeServiceManager.activityDesignTimeService();
			act = activityService.findById(id);
		}

		// 运行前脚本
		if (!StringUtil.isBlank(act.getBeforeActionScript()) || !StringUtil.isBlank(act.getRetractBeforeActionScript())) {
			// 保存先前doc,以便与执行完脚本的后的doc做比较
			Object result = act.runBeforeActionScript(doc, params, user);
			if (result != null) {
				if (result instanceof String && ((String) result).trim().length() > 0) {
					result = new JsMessage(JsMessage.TYPE_SUCCESS, (String) result);
				}
			}

			JSONObject jsonObj = new JSONObject();
			if (result != null && result instanceof JsMessage
					&& !StringUtil.isBlank(((JsMessage) result).getContent())) {
				jsonObj.put("type", ((JsMessage) result).getType());
				jsonObj.put("content", ((JsMessage) result).getContent());
			} else {
				//当执行成功之后, 将Document推入缓存中
				MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, user);
			}

			return jsonObj;
		}else {
			//当无执行前脚本的时候, 将数据加入缓存中
			MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, user);
		}

		return null;
	}

	@Override
	public JSONObject runafteractionscript(String id, String applicationId, String content, ParamsTable params, IUser user)
			throws Exception {
		ActivityParent actParent = null;
		Activity act = null;
		String docid = params.getParameterAsString("docId");
		String viewid = params.getParameterAsString("viewId");
		String formid = params.getParameterAsString("formId");
		String templateForm = params.getParameterAsString("_templateForm");
		String parentId = params.getParameterAsString("parentId");
		params.setParameter("application", applicationId);
		params.setParameter("docid", docid);
		params.setParameter("viewid", viewid);
		params.setParameter("formid", formid);
		params.setParameter("parentid", parentId);

		if (docid != null && docid.equals(parentId)) {
			parentId = null;
			params.removeParameter("parentid");
		}
		if (id != null && id.trim().length() > 0) {
			if (!StringUtil.isBlank(formid) || !StringUtil.isBlank(templateForm)) {
				FormDesignTimeService formService = DesignTimeServiceManager.formDesignTimeService();
				if (!StringUtil.isBlank(templateForm)) {
					actParent = (ActivityParent) formService.doView(templateForm);
				} else {
					actParent = (ActivityParent) formService.doView(formid);
				}
				act = actParent.findActivity(id);
			} else {
				if (act == null && !StringUtil.isBlank(viewid)) {
					ViewDesignTimeService viewService = DesignTimeServiceManager.viewDesignTimeService();
					actParent = (ActivityParent) viewService.doView(viewid);
					act = actParent.findActivity(id);
				} else {
					ActivityDesignTimeService activityService = DesignTimeServiceManager.activityDesignTimeService();
					act = activityService.findById(id);
				}
			}
		}

		if (act == null) {
			ActivityDesignTimeService activityService = DesignTimeServiceManager.activityDesignTimeService();
			act = activityService.findById(id);
		}

		JSONObject JsonObj = new JSONObject();

		if (!StringUtil.isBlank(act.getAfterActionScript()) || !StringUtil.isBlank(act.getRetractAfterActionScript())) {
			Document doc = DocumentRequestUtil.prepareDocument(
					AuthTimeServiceManager.getUser(params.getHttpRequest()),
					content, applicationId, "$.document", params);

			params.setParameter("_flowType", doc.getLastFlowOperation());
			Object message = act.runAfterActionScript(doc, params, user);
			if (message != null) {
				if (message instanceof String && ((String) message).trim().length() > 0) {
					message = new JsMessage(JsMessage.TYPE_SUCCESS, (String) message);
				}
				if (message instanceof JsMessage) {
					JsonObj.put("type", "message");
					JsonObj.put("content", message);
				}
			}
		}

		return JsonObj;
	}

	@Override
	public JSONObject execute(String applicationId, String id, String content, ParamsTable params, IUser user) throws Exception {
		ActivityParent actParent = null;
		Activity act = null;

		String docid = params.getParameterAsString("docId");
		String viewid = params.getParameterAsString("viewId");
		String formid = params.getParameterAsString("formId");
		String templateForm = params.getParameterAsString("_templateForm");
		String parentId = params.getParameterAsString("parentId");
		params.setParameter("application", applicationId);
		params.setParameter("docid", docid);
		params.setParameter("viewid", viewid);
		params.setParameter("formid", formid);
		params.setParameter("parentid", parentId);
		if (docid != null && docid.equals(parentId)) {
			parentId = null;
			params.removeParameter("parentid");
		}
		if (id != null && id.trim().length() > 0) {
			if ((!StringUtil.isBlank(formid) || !StringUtil.isBlank(templateForm)) && StringUtil.isBlank(viewid)) {
				FormDesignTimeService formService = DesignTimeServiceManager.formDesignTimeService();
				if (!StringUtil.isBlank(templateForm)) {
					actParent = (ActivityParent) formService.doView(templateForm);
				} else {
					actParent = (ActivityParent) formService.doView(formid);
				}
				act = actParent.findActivity(id);
			} else {
				if (act == null && !StringUtil.isBlank(viewid)) {
					ViewDesignTimeService viewService = DesignTimeServiceManager.viewDesignTimeService();
					actParent = (ActivityParent) viewService.doView(viewid);
					act = actParent.findActivity(id);
				} else {
					ActivityDesignTimeService activityService = DesignTimeServiceManager.activityDesignTimeService();
					act = activityService.findById(id);
				}
			}
		}
		if (act == null) {
			ActivityDesignTimeService activityService = DesignTimeServiceManager.activityDesignTimeService();
			act = activityService.findById(id);
		}

		JSONObject JsonObj = new JSONObject();
		if (!StringUtil.isBlank(act.getActionScript()) || !StringUtil.isBlank(act.getDispatcherUrl())) {
			/*
			Document doc = DocumentRequestUtil.prepareDocument(AuthTimeServiceManager.getUser(params.getHttpRequest()), content, applicationId,
					"$.document", params);
			 */
			Document doc = (Document) MemoryCacheUtil.getFromPrivateSpace(docid, user);
			if (doc == null) {
				throw new SaasNofoundException(String.format("系统异常,找不到(%s) 程序为按照预期执行-执行前请求", docid));
			}

			IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), applicationId);
			StringBuffer labelAction = new StringBuffer();
			labelAction.append("Activity(").append(act.getId()).append(")." + act.getName()).append(".actionScript");
			runner.initBSFManager(doc, params, user, new ArrayList<ValidateMessage>());
			runner.run(act,labelAction.toString(), act.getActionScript());

			StringBuffer labelDispatcherUrl = new StringBuffer();
			labelDispatcherUrl.append("Activity(").append(act.getId()).append(")." + act.getName())
					.append(".dispatcherUrlScript");
			String dispatcherUrl = (String) runner.run(act,labelDispatcherUrl.toString(), act.getDispatcherUrl());

			if (!StringUtil.isBlank(dispatcherUrl)) {
				JsonObj.put("dispatcherUrl", dispatcherUrl);
			}
		}

		return JsonObj;
	}

	@Override
	public String archive(String applicationId, String docId, IUser user, ParamsTable params) throws Exception {
		DocumentProcess proxy = RunTimeServiceManager.documentProcess(applicationId);
		Document doc = (Document) proxy.doView(docId);
		if (doc != null && doc.getState() != null) {
			proxy.doArchive(doc, user, params);
		}
		return "归档成功";
	}

	@Override
	public Document saveStartWorkFlow(String applicationId, Document doc, IUser user, ParamsTable params)
			throws Exception {
		// 设置提交动作类型
		params.setParameter("_flowType", FlowType.START2RUNNING);
		params.setParameter("_flowid", doc.getForm().getOnActionFlow());
		DocumentProcess proxy = RunTimeServiceManager.documentProcess(applicationId);
		doc = DocumentHelper.rebuildDocument(doc, params, user);
		doc = (Document) proxy.doStartFlowOrUpdate(doc, params, user);
		MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, user);
		return doc;
	}

	@Override
	public Document copy(String applicationId, Document doc, IUser user, ParamsTable params) throws Exception {
		Document newDoc = null;
		DocumentProcess proxy = RunTimeServiceManager.documentProcess(applicationId);
		if (doc != null && doc.getId() != null) {
			FormDesignTimeService formPross = DesignTimeServiceManager.formDesignTimeService();

			Form form = (Form) formPross.doView(((Document) doc).getFormid());
			newDoc = proxy.doNewWithChildren(form, user, params, doc.getChilds());
			MemoryCacheUtil.putToPrivateSpace(newDoc.getId(), newDoc, user);
		}
		return newDoc;
	}

	@Override
	public void clear(String applicationId, IUser user, String formId) throws Exception {
		DocumentProcess proxy = RunTimeServiceManager.documentProcess(applicationId);
		FormDesignTimeService fb = DesignTimeServiceManager.formDesignTimeService();

		Form form = (Form) fb.doView(formId);
		String dql = "$formname = '" + form.getFullName() + "'";

		Collection<Document> docs = proxy.queryByDQL(dql, user.getDomainid()).datas;

		for (Iterator<Document> iter = docs.iterator(); iter.hasNext();) {
			Document _doc = (Document) iter.next();
			proxy.doRemoveOnlyDocuments(_doc);
		}

		final Collection<Document> documents = docs;
		new Thread(new Runnable() {
			public void run() {
				try {
					proxy.doRemoveDocRelateData(documents);
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					try {
						PersistenceUtils.closeSessionAndConnection();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}

	@Override
	public net.sf.json.JSONObject batchApprove(String applicationId, String limistStrList, String[] docIds,
											   String actId, String attitude, String remark, ParamsTable params, IUser user) throws Exception {
		params.setParameter("_attitude", attitude);
		params.setParameter("_remark", remark);
		params.setParameter("_activityid", actId);
		List<String> limistList = new ArrayList<String>();
		if (!StringUtil.isBlank(limistStrList)) {
			limistList = Arrays.asList(limistStrList.split(","));
		}
		DocumentProcess proxy = RunTimeServiceManager.documentProcess(applicationId);

		net.sf.json.JSONObject result = proxy.doBatchApprove(docIds, user, Environment.getInstance(), params,
				limistList);

		return result;
	}

	@Override
	public JSONObject executeAddress(String applicationId, String actId, ParamsTable params, IUser user, String docId)
			throws Exception {
		Document doc = null;
		Document oldDoc = null;
		params.setParameter("application", applicationId);
		ActivityDesignTimeService actService = DesignTimeServiceManager.activityDesignTimeService();
		Activity act = actService.findById(actId);

		// 地址脚本
		if (act != null && (!StringUtil.isBlank(act.getActionDispatcherUrlScript()) || !StringUtil.isBlank(act.getDispatcherUrl()))) {
			if (StringUtils.isNotBlank(docId)) {
				doc = (Document) MemoryCacheUtil.getFromPrivateSpace(docId, user);
				if (doc == null) {
					DocumentProcess proxy = RunTimeServiceManager.documentProcess(applicationId);
					doc = (Document) proxy.doView(docId);
				}
				if (doc != null) {
					doc.setId(docId);
					oldDoc = (Document) doc.deepClone();
				} else {
					doc = new Document();
					oldDoc = new Document();
				}
			} else {
				doc = new Document();
				oldDoc = new Document();
			}

			Object result = null;
			try {
				result = act.runDispatcherUrlScript(oldDoc, params, user);
			} catch (Throwable e) {
				LOG.error("failed to runDispatcherUrlScript", e);
			}

			if (result != null) {
				if (result instanceof String && ((String) result).trim().length() > 0) {
					result = new JsMessage(JsMessage.TYPE_SUCCESS, (String) result);
				}
			}

			// 与之前的doc做比较,记录下有变化的字段,更新最新的值给页面
			Collection<String> rtn = doc.compareTo(oldDoc);
			JSONObject JsonObj = new JSONObject();
			JSONObject changedField = new JSONObject();
			for (Iterator<String> it = rtn.iterator(); it.hasNext();) {
				String fieldName = (String) it.next();
				String fieldValue = doc.getItemValueAsString(fieldName);
				changedField.put(fieldName, fieldValue);
			}
			if (changedField.size() > 0) {
				JsonObj.put("changedField", changedField);
			}
			if (result != null && result instanceof JsMessage
					&& !StringUtil.isBlank(((JsMessage) result).getContent())) {
				JsonObj.put("type", ((JsMessage) result).getType());
				JsonObj.put("content", ((JsMessage) result).getContent());
			}
			return JsonObj;
		}

		return null;
	}

	@Override
	public FormDataPacket print(String applicationId, String formid, String docid, ParamsTable params, IUser user)
			throws Exception {
		FormDesignTimeService fProcess = DesignTimeServiceManager.formDesignTimeService();
		Form form = fProcess.doView(formid);

		DocumentProcess dProcess = RunTimeServiceManager.documentProcess(applicationId);

		// 从数据库取出文档
		Document doc = (Document) dProcess.doView(docid);

		if (doc == null) {// 数据库没有文档时，从私有的临时空间取出文档
			doc = (Document) MemoryCacheUtil.getFromPrivateSpace(docid, user);
		}

		if (doc == null) {
			if (form != null) {
				if (!StringUtil.isBlank(form.getOnActionFlow())) {
					doc = dProcess.doNewWithFlowPermission(form, user, params);
				} else {
					doc = dProcess.doNew(form, user, params);
				}
				doc.set_new(true);
				// 放入缓存中
				MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, user);
			}
		}

		FormDataPacket formDef = new FormDataPacket(doc);
		Collection<ValidateMessage> errors = new ArrayList<ValidateMessage>();
		IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), doc.getApplicationid());
		runner.initBSFManager(doc, params, user, errors);

		formDef.setStyle(form.getStyle());
		if (!StringUtil.isBlank(doc.getStateLabelInfo())) {
			formDef.setApprovers(cn.myapps.util.json.JsonTmpUtil.fromObject(doc.getStateLabelInfo()));
		}

		StringBuilder buffer = new StringBuilder();

		doc.setAudituserid(user.getId());

		// getErrorMessages
		StringBuilder template = new StringBuilder();
		if (errors != null && errors.size() > 0) {
			template.append("<table class=dybody width='100%'><tr>");
			template.append(
					"<td align='right' width='1%' valign='top' nowrap><font color='red'><b>提示信息：</b></font></td>");
			template.append("<td align='left' width='99%'><font color='red'><b>");
			Iterator<ValidateMessage> iter = errors.iterator();
			while (iter.hasNext()) {
				ValidateMessage error = (ValidateMessage) iter.next();
				template.append(error.getErrmessage());
			}
			template.append("</font><b></td></tr></table>");
		}
		buffer.append(template.toString());

		// addScript
		buffer.append("<input type=\"hidden\" id=\"dy_refreshObj\" formid=\"" + form.getId() + "\"");
		buffer.append(" docid=\"" + doc.getId() + "\" userid=\"" + user.getId() + "\"");
		buffer.append(" mapVal=\"");

		for (Iterator<FormField> iter = form.getAllFields().iterator(); iter.hasNext();) {
			Object obj = iter.next();

			if (obj instanceof ValueStoreField) {
				FormField field = (FormField) obj;
				buffer.append(field.getName() + ";");
			}
		}
		if (buffer.lastIndexOf(";") != -1) {
			buffer.deleteCharAt(buffer.lastIndexOf(";"));
		}
		buffer.append("\" />");

		buffer.append(form.getHtmlTemplate(doc, runner, user));

		Map<String, Object> map = new HashMap<String, Object>();
		map.put("template", buffer.toString());
		formDef.setFormTemplate(map);
		Collection<FormField> fields = form.getFields();
		List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
		for (FormField formField : fields) {
			Map<String, Object> value = formField.toPrintAttributes(doc, runner, user);
			//由于md皮肤和新的h5皮肤需要带上表单编辑器自定义的属性
			if(formField.getOtherPropsAsMap() != null && value != null && !value.isEmpty()) {
				for(String propertyKey:formField.getOtherPropsAsMap().keySet()) {
					if(value.get(propertyKey) == null) {
						value.put(propertyKey,formField.getOtherPropsAsMap().get(propertyKey));
					}
				}
			}
			data.add(value);
		}
		if (form.getShowWaterMark()) {
			String waterMark = (String) runner.run(form,"form:" + form.getName() + "-" + form.getId() + ".waterMarkScript",
					form.getWaterMarkScript());
			formDef.setShowWaterMark(true);
			formDef.setWaterMarkText(waterMark);
		}

		if (!StringUtil.isBlank(form.getDescription())) {
			map.put("formName", form.getDescription());
		} else {
			map.put("formName", form.getName());
		}

		formDef.setFormTemplate(map);
		formDef.setFields(data);
		return formDef;
	}

	/**
	 * 获取处理流程时显示的按钮
	 *
	 * @return
	 * @throws Exception
	 */
	public List<Activity> getShowAct(Document doc, IUser webUser, ParamsTable params) throws Exception {
		List<Activity> activityList = new ArrayList<Activity>();
		FlowStateRT instance = doc.getState();
		if (instance != null) {
			BillDefiVO flowVO = instance.getFlowVO();
			NodeRT nodert = null;
			String currNodeId = null;
			FlowDiagram fd = null;
			if (flowVO != null) {
				fd = flowVO.toFlowDiagram();
				if (currNodeId == null && nodert == null) {
					nodert = StateMachine.getCurrUserNodeRT(doc, webUser, currNodeId);
					if (nodert != null)
						currNodeId = nodert.getNodeid();
				}
			}
			// 流程催办操作按钮
			List<NodeRT> allowUrge2ApprovalNodeRTs = getAllowUrge2ApprovalNodeRTs(instance, params, webUser, fd);
			if (nodert == null) {
				// 流程回撤
				if (allowRetracement(doc, webUser, params)) {
					Activity act = new Activity();
					act.setType(51);
					act.setName("{*[cn.myapps.runtime.workflow.retracement]*}");
					activityList.add(act);
				}
				if (!doc.getIstmp() && !allowUrge2ApprovalNodeRTs.isEmpty()) {
					Activity act = new Activity();
					act.setType(48);
					act.setName("{*[Urgent]*}");
					activityList.add(act);
				}
				return activityList;
			}
			// 获取当前结点
			Node currnode = null;
			if (currNodeId != null) {
				currnode = (Node) fd.getElementByID(currNodeId);
			}

			// 挂起;恢复 操作
			if (currnode != null) {
				if ((currnode instanceof ManualNode) && !doc.getIstmp() // 新建文档，不显示挂起按钮
						&& !instance.isTemp() // 流程为临时流程，不显示挂起按钮
				) {

					boolean flag = false;
					if (((ManualNode) currnode).handupEditMode == 0) {
						flag = ((ManualNode) currnode).isHandup;
					} else if (((ManualNode) currnode).handupEditMode == 1) {
						IRunner runner = JavaScriptFactory.getInstance(webUser.getSessionid(), doc.getApplicationid());
						runner.initBSFManager(doc, params, webUser, new ArrayList<ValidateMessage>());
						StringBuffer label = new StringBuffer();
						label.append("FlowName:" + fd.getName() + " handupScript(").append(fd.getId())
								.append(")." + fd.getName()).append(".handupScript");
						Object result = runner.run(currnode, label.toString(), ((ManualNode) currnode).handupScript);
						if (result != null && result instanceof Boolean) {
							flag = ((Boolean) result).booleanValue();
						}
					}
					if (flag) {
						if (nodert.getState() == 0) {
							Activity act = new Activity();
							act.setType(49);
							act.setName("{*[cn.myapps.runtime.workflow.suspend]*}");
							activityList.add(act);
						} else if (nodert.getState() == 1) {
							Activity act = new Activity();
							act.setType(50);
							act.setName("{*[cn.myapps.runtime.workflow.recover]*}");
							activityList.add(act);
						}
					}
				}
			}

			// 流程回撤操作按钮
			if (!doc.getIstmp() && nodert.getState() == 0 && allowRetracement(doc, webUser, params)) {
				Activity act = new Activity();
				act.setType(51);
				act.setName("{*[cn.myapps.runtime.workflow.retracement]*}");
				activityList.add(act);
			}
			// 流程加签操作按钮
			if (!doc.getIstmp() && nodert.getState() == 0 && currnode instanceof ManualNode
					&& Integer.parseInt(((ManualNode) currnode).passcondition) == ManualNode.PASS_CONDITION_ORDERLY_AND
					&& ((ManualNode) currnode).isApproverEdit) {
				Activity act = new Activity();
				act.setType(55);
				act.setName("{*[cn.myapps.runtime.workflow.add_auditor]*}");
				activityList.add(act);
			}
			// 编辑流程审批人操作按钮
			if (!doc.getIstmp() && nodert.getState() == 0 && currnode instanceof ManualNode
					&& ((ManualNode) currnode).isAllowEditAuditor) {
				Activity act = new Activity();
				act.setType(53);
				act.setName("{*[Edit_Auditor]*}");
				activityList.add(act);
			}
			// 调整流程操作按钮
			if (!doc.getIstmp() && nodert.getState() == 0 && currnode instanceof ManualNode
					&& ((ManualNode) currnode).isFrontEdit) {
				Activity act = new Activity();
				act.setType(54);
				act.setName("{*[cn.myapps.runtime.workflow.adjustment_flow]*}");
				activityList.add(act);
			}
			// 流程终止操作按钮
			if (!doc.getIstmp() && nodert.getState() == 0 && currnode instanceof ManualNode
					&& ((ManualNode) currnode).isAllowTermination) {
				Activity act = new Activity();
				act.setType(52);
				act.setName("{*[Terminate]*}");
				activityList.add(act);
			}
			// 流程回退操作按钮
			if (!doc.getIstmp() && nodert.getState() == 0 && currnode instanceof ManualNode
					&& ((ManualNode) currnode).cBack) {
				Collection<Node> backNodeList = getBackToNodeList(doc, nodert, webUser, 0);
				if (backNodeList != null && !backNodeList.isEmpty()) {
					Activity act = new Activity();
					act.setType(47);
					act.setName("{*[cn.myapps.runtime.workflow.reject]*}");
					activityList.add(act);
				}
			}
			if (!doc.getIstmp() && nodert.getState() == 0 && currnode instanceof ManualNode
					&& ((ManualNode) currnode).jumpTo.equals("1") && ((ManualNode) currnode).jump) {
				Collection<Node> backNodeList = getBackToNodeList(doc, nodert, webUser, 0);
				if (backNodeList != null && !backNodeList.isEmpty()) {
					Activity act = new Activity();
					act.setId(Sequence.getUUID());
					act.setType(77);
					IRunner runner = JavaScriptFactory.getInstance("", doc.getApplicationid());
					runner.initBSFManager(doc, params, webUser, new ArrayList<ValidateMessage>());
					String actName = (String) runner.run(currnode,"流程跳转按钮", ((ManualNode) currnode).jumpNameScript);
					act.setName(actName);
					activityList.add(act);
				}
			}

		}

		return activityList;
	}

	/**
	 * 获取当前流程状态下允许催办的状态节点
	 *
	 * @return
	 * @throws Exception
	 */
	public List<NodeRT> getAllowUrge2ApprovalNodeRTs(FlowStateRT instance, ParamsTable params, IUser user,
													 FlowDiagram fd) throws Exception {
		List<NodeRT> list = new ArrayList<NodeRT>();
		if (instance.isTemp() || instance.isTerminated())
			return list;
		// 获取当前流程实例的节点(nodeRT)
		Collection<NodeRT> noderts = instance.getNoderts();
		// 获取当前NodeRT对应的ManualNode对象
		for (Iterator<NodeRT> iterator = noderts.iterator(); iterator.hasNext();) {
			NodeRT nodeRT = iterator.next();
			if (nodeRT.getActorIdList().contains(user.getId())) {
				continue;
			}
			Node node = fd.getNodeByID(nodeRT.getNodeid());
			if (node instanceof ManualNode) {
				if (((ManualNode) node).isAllowUrge2Approval(instance.getDocument(), params, user)) {
					list.add(nodeRT);
				}
			}
		}

		return list;
	}

	/**
	 * 获取回退节点（按历史痕迹回退|定制回退）
	 *
	 * @param doc
	 * @param user
	 * @param flowState
	 * @return
	 * @throws Exception
	 */
	public Collection<Node> getBackToNodeList(Document doc, NodeRT currNodeRT, IUser user, int flowState)
			throws Exception {
		BillDefiVO flowVO = null;
		Collection<Node> backToNodeList = new ArrayList<Node>();
		flowVO = doc.getState().getFlowVO();
		FlowDiagram fd = flowVO.toFlowDiagram();
		Node node = (Node) fd.getElementByID(currNodeRT.getNodeid());
		// 手工节点回退
		if (node instanceof ManualNode) {
			if (((ManualNode) node).backType == 1 && ((ManualNode) node).cBack) {
				backToNodeList = StateMachine.getBackToNodeList(flowVO, currNodeRT, user, 0);
			} else if (((ManualNode) node).backType == 0 && ((ManualNode) node).cBack) {
				backToNodeList = StateMachine.getBackToNodeList(doc, flowVO, currNodeRT, user, flowState);
			} else if (((ManualNode) node).retracementScript == null) {// 兼容旧版本
				backToNodeList = StateMachine.getBackToNodeList(doc, flowVO, currNodeRT, user, flowState);
			}
		} else {// 非手工节点回退(如：挂起)
			backToNodeList = StateMachine.getBackToNodeList(doc, flowVO, currNodeRT, user, flowState);
		}

		return backToNodeList;

	}

	/**
	 * 是否允许流程回撤
	 *
	 * @return
	 * @throws Exception
	 */
	private boolean allowRetracement(Document doc, IUser user, ParamsTable params) throws Exception {
		boolean isAllow = false;
		if (!StringUtil.isBlank(doc.getParentid())) {// 子表单没有回撤操作权限单
			return false;
		}
		BillDefiVO flowVO = doc.getState().getFlowVO();
		FlowDiagram fd = flowVO.toFlowDiagram();
		Node currNode = null;
		if (doc.getState().isComplete()) {
			FlowHistoryService procss = new FlowHistoryServiceImpl(doc.getApplicationid());
			RelationHIS his = procss.getCompleteRelationHIS(doc.getId(), doc.getState().getId());
			if (his != null) {
				currNode = (Node) fd.getElementByID(his != null ? his.getEndnodeid() : null);
			}

		} else if (doc.getState().getNoderts() != null && doc.getState().getNoderts().size() > 0) {
			NodeRT nodert = doc.getState().getNoderts().iterator().next();
			currNode = (Node) fd.getElementByID(nodert.getNodeid());
		}

		if (currNode != null) {
			if (currNode instanceof SubFlow) {
				return false;
			}
			if (currNode instanceof CompleteNode) {
				return false;
			}
			if (currNode instanceof AutoNode) {
				return false;
			}

			Node nextNode = StateMachine.getBackNodeByHis(doc, flowVO, currNode.id, user, FlowState.RUNNING);
			if (nextNode != null) {
				if (nextNode instanceof SubFlow) {
					return false;
				}
				if (((ManualNode) nextNode).retracementEditMode == 0 && ((ManualNode) nextNode).cRetracement) {
					isAllow = true;
				} else if (((ManualNode) nextNode).retracementEditMode == 1
						&& ((ManualNode) nextNode).retracementScript != null
						&& (((ManualNode) nextNode).retracementScript).trim().length() > 0) {
					IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), doc.getApplicationid());
					runner.initBSFManager(doc, params, user, new ArrayList<ValidateMessage>());
					StringBuffer label = new StringBuffer();
					label.append(currNode.name).append("[" + currNode.id + "]").append(".retracementScript");
					Object result = runner.run(nextNode,label.toString(),
							StringUtil.dencodeHTML(((ManualNode) nextNode).retracementScript));
					if (result != null && result instanceof Boolean) {
						if (((Boolean) result).booleanValue())
							isAllow = true;
					}
				}
			}
		}
		return isAllow;

	}

	@Override
	public String improtExcel(String applicationId, String impmappingconfigid, String path, IUser user,
							  ParamsTable params, String actId, String viewId) throws Exception {
		Environment evt = Environment.getInstance();
		String excelPath = evt.getRealPath(path);

		if (!excelPath.toLowerCase().endsWith(".xls") && !excelPath.toLowerCase().endsWith(".xlsx")) {
			throw new Exception("not a excel file");
		}
		IMPMappingConfigDesignTimeService process = DesignTimeServiceManager.impMappingConfigDesignTimeService();
		IMPMappingConfigVO vo = (IMPMappingConfigVO) process.doView(impmappingconfigid);

		ExcelMappingDiagram em = Factory.trnsXML2Dgrm(vo.getXml());
		ImpExcelToDoc imp = new ImpExcelToDoc(excelPath, em);
		String result = "";
		try {
			params.setParameter("application", applicationId);
			result = imp.creatDocument(em,excelPath,user, params, applicationId);

			// Excel导入动作执行后脚本
			// runAfterActionScript(params, user, viewId, actId);

		} catch (ImpExcelException iee) {
			// Excel导入动作执行后脚本
			// runAfterActionScript(params, user, viewId, actId);
		} catch (Exception e) {
			result = e.getMessage();
			e.printStackTrace();
		} finally {
			// Excel导入成功后删除文档 2015-1-21
			File file = new File(excelPath);
			if (file.exists() && file.isFile()) {
				file.delete();
			}
			JavaScriptFactory.clear();
		}
		return result;
	}

	@Override
	public String validationExcel(String applicationId, String impmappingconfigid, String path, IUser user,
								  ParamsTable params, String actId, String viewId) throws Exception {
		Environment evt = Environment.getInstance();
		String excelPath = evt.getRealPath(path);

		if (!excelPath.toLowerCase().endsWith(".xls") && !excelPath.toLowerCase().endsWith(".xlsx")) {
			throw new Exception("not a excel file");
		}
		IMPMappingConfigDesignTimeService process = DesignTimeServiceManager.impMappingConfigDesignTimeService();
		IMPMappingConfigVO vo = (IMPMappingConfigVO) process.doView(impmappingconfigid);

		ExcelMappingDiagram em = Factory.trnsXML2Dgrm(vo.getXml());
		ImpExcelToDoc imp = new ImpExcelToDoc(excelPath, em);
		String result = "";
		try {
			params.setParameter("application", applicationId);
			result = imp.validationDocument(em,excelPath,user, params, applicationId);

			// Excel导入动作执行后脚本
			// runAfterActionScript(params, user, viewId, actId);

		} catch (ImpExcelException iee) {
			// Excel导入动作执行后脚本
			// runAfterActionScript(params, user, viewId, actId);
		} catch (Exception e) {
			result = e.getMessage();
			e.printStackTrace();
		} finally {
			JavaScriptFactory.clear();
		}
		return result;
	}

	private void runAfterActionScript(ParamsTable params, IUser user, String viewId, String actId) throws Exception {
		if (!StringUtil.isBlank(actId)) {
			ViewDesignTimeService viewService = DesignTimeServiceManager.viewDesignTimeService();
			ActivityParent actParent = (ActivityParent) viewService.doView(viewId);

			if (actParent != null && actId != null && actId.trim().length() > 0) {
				Activity act = actParent.findActivity(actId);

				// 运行后脚本
				if (!StringUtil.isBlank(act.getAfterActionScript())) {
					IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), actParent.getApplicationid());
					runner.initBSFManager(new Document(), params, user, new java.util.ArrayList<ValidateMessage>());
					StringBuffer label = new StringBuffer();
					label.append("Activity Action(").append(act.getId()).append(")." + act.getName())
							.append("afterActionScript");
					runner.run(act,label.toString(), act.getAfterActionScript());
				}
			}
		}
	}

	@Override
	public String exportExcel(String viewId, String actId, IUser user, ParamsTable params, OutputStream outputStream,String[] ids)
			throws Exception {
		String fileWebPath = "";
		ViewDesignTimeService process = DesignTimeServiceManager.viewDesignTimeService();
		AbstractView view = (AbstractView) process.doView(viewId);
		changeOrderBy(params, view);

		String fileName = process.expDocToExcel(viewId, user, params, ids);
		Environment env = Environment.getInstance();

		String webPath = "/uploads" + DefaultProperty.getProperty("REPORT_PATH");
		fileWebPath = webPath + "/" + fileName;

		String realFileName = env.getRealPath(fileWebPath);
		File file = new File(realFileName);

		doFileDownload(file, outputStream);

		return fileWebPath;
	}

	private void changeOrderBy(ParamsTable params, AbstractView view) {
		if (params.getParameter("_sortCol") == null || params.getParameter("_sortCol").equals("")) {
			setOrder(params, view.getDefaultOrderFieldArr());
		} else {
			String[] colFields = new String[1];
			String fieldName = view.getFormFieldNameByColsName(params.getParameterAsString("_sortCol"));
			String sortStatus = params.getParameterAsString("_sortStatus");
			colFields[0] = fieldName + " " + sortStatus;
			setOrder(params, colFields);
		}
	}

	private void setOrder(ParamsTable params, String[] orderFields) {
		params.setParameter("_sortCol", orderFields);
	}

	/**
	 * 文件下载response设置
	 *
	 * @return
	 * @throws IOException
	 */
	public void doFileDownload(File srcFile, OutputStream outputStream) throws IOException {

		if (srcFile.exists()) {
			try {
				OutputStream os = null;
				BufferedInputStream reader = null;
				try {
					os = outputStream;

					reader = new BufferedInputStream(new FileInputStream(srcFile));
					byte[] buffer = new byte[4096];
					int i = -1;
					while ((i = reader.read(buffer)) != -1) {
						os.write(buffer, 0, i);
					}
					os.flush();
				} catch (IOException e) {
					throw e;
				} finally {
					if (os != null) {
						reader.close();
					}
					if (reader != null) {
						reader.close();
					}
				}
			} catch (IOException e) {
				throw e;
			}
		}
	}

	@Override
	public String share(String applicationId, String docId, IUser user, ParamsTable params, String transpond,
						String handleUrl, String receiverid, Boolean email, Boolean msm) throws Exception {
		DocumentProcess proxy = RunTimeServiceManager.documentProcess(applicationId);
		Document doc = (Document) proxy.doView(docId);
		SummaryCfgDesignTimeService mp = DesignTimeServiceManager.summaryCfgDesignTimeService();
		if (transpond == null || transpond.equals("null") || transpond.equals("")) {
			throw new Exception();
		}
		SummaryCfgVO vo = (SummaryCfgVO) mp.doView(transpond);
		StringBuffer emailContent = new StringBuffer();
		StringBuffer msmContent = new StringBuffer();
		emailContent.append("[" + vo.getTitle() + "]" + "待办:</br>");
		emailContent.append("详情: " + vo.toSummay(doc, user) + "</br>");
		if (handleUrl.contains("#")) {
			handleUrl = handleUrl.replaceAll("#", "");
		}
		emailContent.append("<a href='").append(handleUrl).append("'>").append("点击查看").append("</a>").append("</br>");
		emailContent.append("日期: " + new Date().toString());
		List<String> emails = getUserEmailAddress(receiverid);

		List<String> telephones = getUserTelephoneNO(receiverid);
		if (email) {
			EmailUtil eu = new EmailUtil(applicationId, user);
			Iterator<String> emailIt = emails.iterator();
			while (emailIt.hasNext()) {
				String _email = emailIt.next();
				eu.sendEmailBySystemUserForTranspond(_email, vo.getTitle(), emailContent.toString());
			}
		}

		msmContent.append("[" + vo.getTitle() + "]" + "待办: ");
		msmContent.append(vo.toSummay(doc, user) + "  ");
		msmContent.append("日期: " + new Date().toString());
		if (msm) {
//			boolean falg = false;
			SMSQueueOperator operator = SMSQueueOperator.getInstance();

//				replyCode = code;

//				this.content = body;
//				this.receiver = receiver.trim().split(",");
			try {
				Iterator<String> telephoneIt = telephones.iterator();
				while (telephoneIt.hasNext()) {
					String telephone = telephoneIt.next();
					SMSParcels parcels = new SMSParcels(msmContent.toString(), new String[] { telephone}, "70104",applicationId, user.getDomainid());
					operator.add(parcels);
				}
				operator.send();

			} catch (Exception e) {
				throw e;
			} finally {
				try {
					PersistenceUtils.closeSessionAndConnection();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}

//					if(flag){
//						msmSuccessCount++;
//					}else{
//						msmFailCount++;
//					}
		}
		if (email || msm)

		{
			return "已发送";
		}
		return null;
	}

	private List<String> getUserEmailAddress(String receiverid) throws Exception {
		UserProcess up = AuthTimeServiceManager.userRuntimeService();
		List<String> emails = new ArrayList<String>();
		String[] _receiverid = receiverid.split(";");
		for (int i = 0; i < _receiverid.length; i++) {
			UserVO user = (UserVO) up.doView(_receiverid[i]);
			emails.add(user.getEmail());
		}
		return emails;
	}

	private List<String> getUserTelephoneNO(String receiverid) throws Exception {
		UserProcess up = AuthTimeServiceManager.userRuntimeService();
		List<String> telephones = new ArrayList<String>();
		String[] _receiverid = receiverid.split(";");
		for (int i = 0; i < _receiverid.length; i++) {
			UserVO user = (UserVO) up.doView(_receiverid[i]);
			telephones.add(user.getTelephone());
		}
		return telephones;
	}

}
