package cn.myapps.runtime.dynaform.document.controller;

import cn.myapps.common.auth.IUser;
import cn.myapps.common.controller.ErrorMessage;
import cn.myapps.common.controller.Resource;
import cn.myapps.common.controller.ResourceNotFoundException;
import cn.myapps.common.data.DataPackage;
import cn.myapps.common.data.ParamsTable;
import cn.myapps.common.exception.OBPMValidateException;
import cn.myapps.common.model.view.AbstractView;
import cn.myapps.common.util.StringUtil;
import cn.myapps.designtime.common.service.DesignTimeServiceManager;
import cn.myapps.designtime.view.service.ViewDesignTimeService;
import cn.myapps.runtime.common.controller.AbstractRuntimeController;
import cn.myapps.runtime.common.service.RunTimeServiceManager;
import cn.myapps.runtime.dynaform.document.ejb.Document;
import cn.myapps.runtime.dynaform.document.ejb.DocumentProcess;
import cn.myapps.runtime.dynaform.document.ejb.Item;
import cn.myapps.runtime.dynaform.form.ejb.ValidateMessage;
import cn.myapps.runtime.macro.runner.IRunner;
import cn.myapps.runtime.macro.runner.JavaScriptFactory;
import cn.myapps.runtime.workflow.storage.runtime.ejb.FlowRuntimeService;
import cn.myapps.runtime.workflow.storage.runtime.ejb.FlowRuntimeServiceImpl;
import cn.myapps.runtime.workflow.storage.runtime.ejb.FlowStateRT;
import cn.myapps.common.util.cache.MemoryCacheUtil;
import cn.myapps.util.ParamsTableUtil;
import cn.myapps.util.ProcessFactory;
import com.bcxin.runtime.domain.imports.components.DataImportComponentProvider;
import com.bcxin.runtime.domain.imports.dtos.WebUserDto;
import com.bcxin.saas.core.exceptions.SaasBadException;
import com.bcxin.saas.core.exceptions.SaasNofoundException;
import com.bcxin.saas.core.utils.SqlUtil;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.Option;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import java.util.*;

import static com.jayway.jsonpath.JsonPath.parse;

/**
 * Document Restful 接口
 *
 * @author ahan
 */
@Api(tags = "文档执行模块")
@Component
@RequestMapping(path = "/api/runtime/{applicationId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class DocumentController extends AbstractRuntimeController implements DataImportComponentProvider {

    /**
     * 获取文档
     *
     * @param applicationId 软件id
     * @param id            文档id
     * @return
     * @throws Exception
     */
    @GetMapping(path = "/documents/{id}")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "获取文档", notes = "获取文档")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "id", value = "文档id", required = true, paramType = "path", dataType = "string")})
    public Resource doGetDocument(@PathVariable String applicationId, @PathVariable String id) throws Exception {
        DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
                applicationId);
        Document doc = (Document) dProcess.doView(id);
        if (doc != null) {
            return success("ok", doc);
        } else {
            throw new ResourceNotFoundException("Not Found");
        }
    }

    /**
     * 创建文档(带校验)
     *
     * @param applicationId 软件id
     * @param content       请求包体
     * @return
     * @throws Exception
     */
    @PostMapping(path = "/documents")
    @ResponseStatus(HttpStatus.CREATED)
    @ApiOperation(value = "创建文档(带校验)", notes = "创建文档(带校验)")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")})
    public Resource doCreateDocument(@PathVariable String applicationId, @RequestBody String content) throws Exception {
        try{
            ParamsTable params = getParams();
            //执行中的时候直接去执行前的Document对象
            Document doc = getDocumentFromBeforeAction(params.getDocId(), getUser());
            //Document doc = this.prepareDocument(content, applicationId, "$", params);

            Collection<Document> subDocuments = doc.getFrontSubDocuments();
            Collection<ErrorMessage> errors = validateDocument(params, doc, applicationId, getUser());

            if (errors.isEmpty()) {
                doc.setStateid("");
                DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
                        applicationId);
                if(subDocuments != null){
                    List<Document> copySubDocuments = new ArrayList<Document>();
                    copySubDocuments.addAll(doc.getSubDocuments());
                    for (Document document : copySubDocuments) {
                        //保存子表
                        if(document.isDelete()){
                            dProcess.doRemove(document.getId());
                            doc.removeSubDocument(document.getId());
                        } else if(document.isEdit()) {
                            Collection<ErrorMessage> subErrors = validateDocument(params, document, applicationId, getUser());
                            if(!subErrors.isEmpty()){
                                return error(4001, "子表单校验不通过", subErrors);
                            }
                            dProcess.doCreateOrUpdate(document, getUser());
                        }
                    }
                    //在保存完子表之后重计算一下主表
                    doc = doc.getForm().recalculateDocument(doc, params, getUser());
                }
                dProcess.doCreate(doc);
                MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, getUser());
                return success("保存成功", doc);
            } else {
                return error(4001, "表单校验不通过", errors);
            }
        } catch(Exception e){
            e.printStackTrace();
            return error(500, e.getMessage(), null);
        }
    }

    /**
     * 创建文档
     *
     * @param applicationId 软件id
     * @param content       请求包体
     * @return
     * @throws Exception
     */
    @PostMapping(path = "/documents/withoutValid")
    @ResponseStatus(HttpStatus.CREATED)
    @ApiOperation(value = "创建文档", notes = "创建文档")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")})
    public Resource doCreateDocumentWithoutValid(@PathVariable String applicationId, @RequestBody String content)
            throws Exception {
        try{
            ParamsTable params = getParams();
            //执行中的时候直接去执行前的Document对象
            Document doc = getDocumentFromBeforeAction(params.getDocId(), getUser());

            //Document doc = this.prepareDocument(content, applicationId, "$", params);
            doc.setStateid("");
            DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
                    applicationId);
            //保存子表
            Collection<Document> subDocuments = doc.getFrontSubDocuments();
            if(subDocuments != null){
                List<Document> copySubDocuments = new ArrayList<Document>();
                copySubDocuments.addAll(doc.getSubDocuments());
                for (Document document : copySubDocuments) {
                    //保存子表
                    if(document.isDelete()){
                        dProcess.doRemove(document.getId());
                        doc.removeSubDocument(document.getId());
                    } else if(document.isEdit()) {
                        dProcess.doCreateOrUpdate(document, getUser());
                    }
                }
                //在保存完子表之后重计算一下主表
                doc = doc.getForm().recalculateDocument(doc, params, getUser());
            }
            dProcess.doCreate(doc);
            MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, getUser());
            return success("保存成功", doc);
        } catch(Exception e){
            e.printStackTrace();
            return error(500, e.getMessage(), null);
        }
    }

    /**
     * 更新文档
     *
     * @param applicationId 软件id
     * @param id            文档id
     * @param content       请求包体
     * @return
     * @throws Exception
     */
    @PutMapping(path = "/documents/{id}/withoutValid")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "更新文档", notes = "更新文档")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "id", value = "文档id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")})
    public Resource doUpdateDocumentWithoutValid(@PathVariable String applicationId, @PathVariable String id,
                                                 @RequestBody String content) throws Exception {
        try{
            ParamsTable params = getParams();
            //执行中的时候直接去执行前的Document对象
            Document doc = getDocumentFromBeforeAction(params.getDocId(), getUser());

            DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
                    applicationId);
            Collection<Document> subDocuments = doc.getFrontSubDocuments();
            if(subDocuments != null){
                List<Document> copySubDocuments = new ArrayList<Document>();
                copySubDocuments.addAll(doc.getSubDocuments());
                for (Document document : copySubDocuments) {
                    //保存子表
                    if(document.isDelete()){
                        dProcess.doRemove(document.getId());
                        doc.removeSubDocument(document.getId());
                    } else if(document.isEdit()) {
                        dProcess.doCreateOrUpdate(document, getUser());
                    }
                }
                //在保存完子表之后重计算一下主表
                doc = doc.getForm().recalculateDocument(doc, params, getUser());
            }
            FlowRuntimeService stateProcess = new FlowRuntimeServiceImpl( applicationId);
            FlowStateRT instance = (FlowStateRT) stateProcess.findFlowStateRT(doc.getStateid());
            if(instance == null){
                doc.setStateid("");
            }
            dProcess.doCreateOrUpdate(doc, getUser());
            MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, getUser());

            return success("保存成功", doc);
        } catch(Exception e){
            e.printStackTrace();
            String message ="";
            if(e instanceof OBPMValidateException) {
                message = ((OBPMValidateException) e).getValidateMessage();
            }else if (e.getMessage().contains("Data too long for column")){
                message = e.getMessage().replace("Data truncation: Data too long for column","").replace("at row 1","文本内容超出限制");
            }else {
                message =e.getMessage();
            }
            Collection<ErrorMessage> errmsgs = new ArrayList<ErrorMessage>();
            ErrorMessage msg = new ErrorMessage();
            msg.setErrcode(40001);
            msg.setErrmsg(message);
            msg.setField("");
            errmsgs.add(msg);
            e.printStackTrace();
            return error(4001, "文档校验不通过", errmsgs);
        }
    }

    /**
     * 更新文档(带校验)
     *
     * @param applicationId 软件id
     * @param id            文档id
     * @param content       请求包体
     * @return
     * @throws Exception
     */
    @PutMapping(path = "/documents/{id}")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "更新文档(带校验)", notes = "更新文档(带校验)")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "id", value = "文档id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")})
    public Resource doUpdateDocument(@PathVariable String applicationId, @PathVariable String id,
                                     @RequestBody String content) throws Exception {
        try {
            ParamsTable params = getParams();
            Configuration configuration = Configuration.defaultConfiguration();
            configuration = configuration.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);
            DocumentContext parse = parse(content, configuration);

            Map<String, Object> items = parse.read("$.items");
            if (items != null) {
                for (Map.Entry<String, Object> entry : items.entrySet()) {
                    String key = entry.getKey();
                    Object value = entry.getValue();
                    params.setParameter(key, value);
                }
            }

            //执行中的时候直接去执行前的Document对象
            Document doc = getDocumentFromBeforeAction(params.getDocId(), getUser());

            DocumentProcess dProcess = RunTimeServiceManager.documentProcess(applicationId);
            Collection<Document> subDocuments = doc.getFrontSubDocuments();
            Collection<ErrorMessage> errors = validateDocument(params, doc, applicationId, getUser());

            if (errors.isEmpty()) {
                if (subDocuments != null) {
                    List<Document> copySubDocuments = new ArrayList<Document>();
                    copySubDocuments.addAll(doc.getSubDocuments());
                    for (Document document : copySubDocuments) {
                        //保存子表
                        if (document.isDelete()) {
                            dProcess.doRemove(document.getId());
                            doc.removeSubDocument(document.getId());
                        } else if (document.isEdit()) {
                            Collection<ErrorMessage> subErrors = validateDocument(params, document, applicationId, getUser());
                            if (!subErrors.isEmpty()) {
                                return error(4001, "子表单校验不通过", subErrors);
                            }
                            dProcess.doCreateOrUpdate(document, getUser());
                        }
                    }
                    //在保存完子表之后重计算一下主表
                    doc = doc.getForm().recalculateDocument(doc, params, getUser());
                }
                FlowRuntimeService stateProcess = new FlowRuntimeServiceImpl(applicationId);
                if (!StringUtil.isBlank(doc.getStateid())) {
                    FlowStateRT instance = (FlowStateRT) stateProcess.findFlowStateRT(doc.getStateid());
                    if (instance == null) {
                        doc.setStateid("");
                    }
                }
                dProcess.doCreateOrUpdate(doc, getUser());
                MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, getUser());
                return success("保存成功", doc);
            } else {
                return error(4001, "表单校验不通过", errors);
            }
        } catch (Exception e) {
            e.printStackTrace();
            String message = "";
            if (e instanceof OBPMValidateException) {
                message = ((OBPMValidateException) e).getValidateMessage();
            } else if (e.getMessage().contains("Data too long for column")) {
                message = e.getMessage().replace("Data truncation: Data too long for column", "").replace("at row 1", "文本内容超出限制");
            } else {
                message = e.getMessage();
            }
            Collection<ErrorMessage> errmsgs = new ArrayList<ErrorMessage>();
            ErrorMessage msg = new ErrorMessage();
            msg.setErrcode(40001);
            msg.setErrmsg(message);
            msg.setField("");
            errmsgs.add(msg);
            e.printStackTrace();

            return error(4001, "文档校验不通过", errmsgs);
        }
    }

    /**
     * 更新文档(带校验)
     *
     * @param applicationId 软件id
     * @param id            文档id
     * @param content       请求包体
     * @return
     * @throws Exception
     */
    @PostMapping(path = "/documents/batch")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "批量更新文档(带校验)", notes = "批量更新文档(带校验)")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")})
    public Resource doBatchUpdateDocument(@PathVariable String applicationId, @RequestBody String content) throws Exception {
        ParamsTable params = getParams();
        IUser user = getUser();

        List<Document> resultDocs = new ArrayList<Document>();
        DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
                applicationId);
        List<Document> docs = this.prepareDocuments(content, applicationId, "$.data[?(@.edit)]");
        List<String> deleteIds = parse(content).read("$.data[?(@.delete)].id");
        try {
            dProcess.beginTransaction();

            //删除文档
            for (String deleteId : deleteIds) {
                Document doc = (Document)dProcess.doView(deleteId);
                if(doc != null){
                    dProcess.doRemove(deleteId);
                    MemoryCacheUtil.removeFromPrivateSpace(deleteId, user);
                }
            }

            //更新文档
            for (Document doc : docs) {
                Collection<ErrorMessage> errors = validateDocument(params, doc, applicationId, user);

                if (errors.isEmpty()) {
                    dProcess.doCreateOrUpdate(doc, user);
                    MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, user);
                    resultDocs.add(doc);
                } else {
                    return error(4001, "表单校验不通过", errors);
                }
            }
            dProcess.commitTransaction();
            return success("保存成功", resultDocs);
        } catch (Exception e) {
            e.printStackTrace();
            dProcess.rollbackTransaction();
            return error(500, e.getMessage(), null);
        }
    }

    /**
     * 校验方法
     *
     * @param params
     * @param doc
     * @param applicationId
     * @param webUser
     * @return
     * @throws Exception
     */
    private Collection<ErrorMessage> validateDocument(ParamsTable params, Document doc, String applicationId,
                                                      IUser webUser) throws Exception {
        Collection<ErrorMessage> errmsgs = new ArrayList<ErrorMessage>();
        doc.setDomainid(getDomain());
        //doc = doc.getForm().recalculateDocument(doc, params, webUser);
        DocumentProcess proxy = RunTimeServiceManager.documentProcess(
                applicationId);
        Collection<ValidateMessage> errors = proxy.doValidate(doc, params, webUser);
        if (errors != null && errors.size() > 0) {
            for (Iterator<ValidateMessage> iter = errors.iterator(); iter.hasNext();) {
                ValidateMessage err = (ValidateMessage) iter.next();
                ErrorMessage msg = new ErrorMessage();
                msg.setErrcode(40001);
                msg.setErrmsg(err.getErrmessage());
                msg.setField(err.getFieldname());
                errmsgs.add(msg);
            }
        }
        return errmsgs;
    }

    /**
     * 局部更新文档
     *
     * @param applicationId 软件id
     * @param id            文档id
     * @param content       请求包体
     * @return
     * @throws Exception
     */
    @PatchMapping(path = "/documents/{id}")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "局部更新文档", notes = "局部更新文档")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "id", value = "文档id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")})
    public Resource doUpdatePartDocument(@PathVariable String applicationId, @PathVariable String id,
                                         @RequestBody String content) throws Exception {
        try{
            Map<String, Object> items = parse(content).read("$.items");

            DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
                    applicationId);
            Document doc = (Document) dProcess.doView(id);

            for (Map.Entry<String, Object> entry : items.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                Item item = doc.findItem(key);
                if (item == null)
                    continue;
                item.setValue(value);
            }
            dProcess.doUpdate(doc);

            return success("保存成功", null);
        } catch(Exception e){
            e.printStackTrace();
            return error(500, e.getMessage(), null);
        }
    }

    /**
     * 删除文档
     *
     * @param applicationId 软件id
     * @param id            文档id
     * @return
     * @throws Exception
     */
    @DeleteMapping(path = "/documents/{id}")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "删除文档", notes = "删除文档")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "id", value = "文档id", required = true, paramType = "path", dataType = "string")})
    public Resource doDeleteDocument(@PathVariable String applicationId, @PathVariable String id) throws Exception {
        DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
                applicationId);
        dProcess.doRemove(id);
        MemoryCacheUtil.removeFromPrivateSpace(id, getUser());

        return success("ok", null);
    }

    /**
     * 获取文档集合
     *
     * @param applicationId 软件id
     * @param content       请求包体
     * @param sortby        根据排序的字段
     * @param order         升序/降序
     * @return
     * @throws Exception
     */
    @GetMapping(path = "/documents")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "获取文档集合", notes = "获取文档集合")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string"),
            @ApiImplicitParam(name = "sortby", value = "根据排序的字段", required = true, paramType = "query", dataType = "string"),
            @ApiImplicitParam(name = "order", value = "升序/降序", required = true, paramType = "query", dataType = "string")})
    public Resource doGetDocuments(@PathVariable String applicationId, @RequestBody(required = false) String content,
                                   String sortby, String order) throws Exception {
        content = SqlUtil.encode(content);

        Map<String, String> filter = null;
        if (StringUtils.isNotBlank(content)) {
            filter = parse(content).read("$");
        }

        DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
                applicationId);
        DataPackage<Document> dataPackage = dProcess.queryDocuments(getParams(), filter, getUser());
        Collection<Document> data = dataPackage.getDatas();
        int page = dataPackage.getPageNo();
        int page_lines = dataPackage.getLinesPerPage();
        int row_count = dataPackage.getRowCount();
        return successWithPagination("ok", data, page, page_lines, row_count);
    }

    /**
     * 批量删除文档
     *
     * @param applicationId 软件id
     * @param content       请求包体
     * @return
     * @throws Exception
     */
    @DeleteMapping(path = "/documents")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "批量删除文档", notes = "批量删除文档")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")})
    public Resource doBatchDeleteDocument(@PathVariable String applicationId, @RequestBody String content)
            throws Exception {
        List<String> ids = parse(content).json();
        String[] idArray = {};
        idArray = ids.toArray(idArray);
        DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
                applicationId);
        dProcess.doRemove(idArray);

        for (String id:ids) {
            MemoryCacheUtil.removeFromPrivateSpace(id, getUser());
        }
        return success("ok", null);
    }

    /**
     * 更新缓存中子表数据
     * @param applicationId
     * 		软件id
     * @param id     * 		主表id
     * @param content
     * @return
     * @throws Exception
     */
    @PostMapping(path = "/views/{viewId}/documents/{parentId}/childs")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "更新缓存中子表数据", notes = "更新缓存中子表数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "viewId", value = "视图id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "parentId", value = "主表文档id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")})
    public Resource saveSubDocumentsToCache(@PathVariable String applicationId, @PathVariable String viewId, @PathVariable String parentId, @RequestBody String content) throws Exception{
        ParamsTable params = getParams();
        IUser user = getUser();

        Document subDocument = this.prepareDocument(content, applicationId, "$", params);
        Collection<ErrorMessage> subErrors = validateDocument(params, subDocument, applicationId, getUser());
        if (!subErrors.isEmpty()) {
            return error(4001, "校验不通过", subErrors);
        }

        ViewDesignTimeService vProcess = DesignTimeServiceManager.viewDesignTimeService();
        AbstractView view = vProcess.doView(viewId);
        IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), applicationId);
        runner.initBSFManager(subDocument, params, user, new ArrayList<ValidateMessage>());

        String confirmActivityScript = view.getConfirmActivityScript();;
        if(!StringUtil.isBlank(confirmActivityScript)){
            runner.run( view,"VIEW(" + view.getName() + "." + view.getId() + ").confirmActivityScript", confirmActivityScript);
        }
        DocumentProcess dProcess = RunTimeServiceManager.documentProcess(applicationId);
        // 从私有的临时空间取出文档
        Document doc = (Document) MemoryCacheUtil.getFromPrivateSpace(parentId, getUser());
        if(doc == null){
            doc = (Document) dProcess.doView(parentId);
        }
        if(doc != null) {
            doc.addSubDocument(subDocument);
            MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, getUser());
        }
        MemoryCacheUtil.putToPrivateSpace(subDocument.getId(), subDocument, getUser());
        return success("ok", null);
    }

    /**
     * 删除缓存中子表数据
     * @param applicationId
     * 		软件id
     * @param viewId
     *      视图id
     * @param parentId
     * 		主表文档id
     * @param childId
     * 		子表文档id
     * @return
     * @throws Exception
     */
    @DeleteMapping(path = "/views/{viewId}/documents/{parentId}/childs/{childId}")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "删除缓存中子表数据", notes = "删除缓存中子表数据")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "viewId", value = "视图id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "parentId", value = "主表文档id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "childId", value = "子表文档id", required = true, paramType = "path", dataType = "string")})
    public Resource removeSubDocumentsToCache(@PathVariable String applicationId, @PathVariable String viewId, @PathVariable String parentId, @PathVariable String childId) throws Exception{
        DocumentProcess dProcess = RunTimeServiceManager.documentProcess(
                applicationId);
        ParamsTable params = getParams();
        IUser user = getUser();

        // 从私有的临时空间取出文档
        Document subDocument = (Document) MemoryCacheUtil.getFromPrivateSpace(childId, user);
        if(subDocument == null){
            subDocument = (Document) dProcess.doView(childId);
        }

        ViewDesignTimeService vProcess = DesignTimeServiceManager.viewDesignTimeService();
        AbstractView view = vProcess.doView(viewId);
        IRunner runner = JavaScriptFactory.getInstance(user.getSessionid(), applicationId);
        runner.initBSFManager(subDocument, params, user, new ArrayList<ValidateMessage>());

        String removeActivityScript = view.getRemoveActivityScript();
        if(!StringUtil.isBlank(removeActivityScript)){
            runner.run(view,"VIEW(" + view.getName() + "." + view.getId() + ").removeActivityScript", removeActivityScript);
        }

        // 从私有的临时空间取出文档
        Document doc = (Document) MemoryCacheUtil.getFromPrivateSpace(parentId, user);
        if(doc == null){
            doc = (Document) dProcess.doView(parentId);
        }
        if(doc != null) {
            doc.removeSubDocument(childId);
            MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, user);
        }
        MemoryCacheUtil.removeFromPrivateSpace(childId, user);
        return success("ok", null);
    }

    /**
     * 校验控件方法
     * @param applicationId
     *      软件id
     * @param content
     *      请求包体
     * @return
     * @throws Exception
     */
    @PostMapping("/documents/validate")
    @ResponseStatus(HttpStatus.OK)
    @ApiOperation(value = "校验方法", notes = "校验方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "applicationId", value = "软件id", required = true, paramType = "path", dataType = "string"),
            @ApiImplicitParam(name = "content", value = "请求包体", required = true, paramType = "body", dataType = "string")})
    public Resource validate(@PathVariable String applicationId, @RequestBody String content) throws Exception{
        ParamsTable params = getParams();
        Document doc = this.prepareDocument(content, applicationId, "$", params);

        Collection<ErrorMessage> result = new ArrayList<ErrorMessage>();
        DocumentProcess proxy = RunTimeServiceManager.documentProcess(
                applicationId);
        Collection<ValidateMessage> errors = proxy.doValidate(doc, params, getUser());
        if (errors != null && errors.size() > 0) {
            for (Iterator<ValidateMessage> iter = errors.iterator(); iter.hasNext();) {
                ValidateMessage err = iter.next();
                ErrorMessage msg = new ErrorMessage();
                msg.setErrcode(40001);
                msg.setErrmsg(err.getErrmessage().replace("'", ""));
                msg.setField(err.getFieldname());
                result.add(msg);
            }
        }
        if(result.isEmpty()){
            return success("ok", null);
        }
        return error(4001, "表单校验不通过", result);
    }

    @Override
    public void saveWithoutValid(String domainId, String userId,String appId, String content) throws Exception {
        /*
        ParamsTable params = new ParamsTable();
        params.setParameter("domainid",domainId);
        params.setParameter("userid",userId);

        Document doc = this.prepareDocument(content, appId, "$", params);

        DocumentProcess dProcess = (DocumentProcess) ProcessFactory.createRuntimeProcess(DocumentProcess.class,
                appId);
        Collection<Document> subDocuments = doc.getFrontSubDocuments();
        if (subDocuments != null) {
            List<Document> copySubDocuments = new ArrayList<Document>();
            copySubDocuments.addAll(doc.getSubDocuments());
            for (Document document : copySubDocuments) {
                //保存子表
                if (document.isDelete()) {
                    dProcess.doRemove(document.getId());
                    doc.removeSubDocument(document.getId());
                } else if (document.isEdit()) {
                    document.setVersions(-1);
                    dProcess.doCreateOrUpdate(document, getUser());
                }
            }
            //在保存完子表之后重计算一下主表
            doc = doc.getForm().recalculateDocument(doc, params, getUser());
        }
        FlowRuntimeService stateProcess = new FlowRuntimeServiceImpl(appId);
        FlowStateRT instance = (FlowStateRT) stateProcess.findFlowStateRT(doc.getStateid());
        if (instance == null) {
            doc.setStateid("");
        }
        doc.setVersions(-1);
        dProcess.doCreateOrUpdate(doc, getUser());
        MemoryCacheUtil.putToPrivateSpace(doc.getId(), doc, getUser());

         */
    }

    @Override
    public WebUserDto getCurrentUser() {
        try {
            return WebUserDto.create(this.getUser().getId(), this.getUser().getDomainid());
        } catch (Exception ex) {
            ex.printStackTrace();

            throw new SaasBadException("当前用户无效");
        }
    }

    private Document getDocumentFromBeforeAction(String docId, IUser user) {
        //执行中的时候直接去执行前的Document对象
        Document doc = (Document) MemoryCacheUtil.getFromPrivateSpace(docId, user);

        if (doc == null) {
            throw new SaasNofoundException("非预期请求, 无法从执行前中获取文档信息");
        }

        return doc;
    }
}
