package cn.myapps.util;

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.ActivityType;
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.form.service.FormDesignTimeService;
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.Form;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.Option;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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

public class DocumentRequestUtil {
    public static ParamsTable parseRequestParams(HttpServletRequest request, String domainId, String id,
                                                 String content,boolean isBeforeAction) {
        ParamsTable params = getParams(request, domainId);

        params = parseAndMergeActionB_A(params, id, content, isBeforeAction);

        return params;
    }

    /**
     * Retrieve the ParamsTable
     *
     * @return ParamsTable
     */
    private static ParamsTable getParams(HttpServletRequest request, String domainId) {
        final int defaultLinePerPage = 10;
        ParamsTable pm = ParamsTable.convertHTTP(request);
        // put the domain id to parameters table.
        if (domainId != null) {
            pm.setParameter("domainid", domainId);
        }

        // put the page line count id to parameters table.
        if (pm.getParameter("_pagelines") == null) {
            pm.setParameter("_pagelines", defaultLinePerPage);
        }


        String parentId = pm.getParameterAsString("parentId");
        if(!cn.myapps.common.util.StringUtil.isBlank(parentId)){
            pm.setParameter("relateid", parentId);
            pm.setParameter("parentid", parentId);
        }
        String parentid = pm.getParameterAsString("parentid");
        if(!cn.myapps.common.util.StringUtil.isBlank(parentid)){
            pm.setParameter("relateid", parentid);
            pm.setParameter("parentId", parentid);
        }

        String isRelate = pm.getParameterAsString("isRelate");
        if(cn.myapps.common.util.StringUtil.isBlank(isRelate) || !"true".equals(isRelate)){
            pm.removeParameter("parentId");
            pm.removeParameter("parentid");
        }

        return pm;
    }

    private static ParamsTable parseAndMergeActionB_A(ParamsTable params, String id, String content, boolean isBeforeAction) {
        Configuration configuration = Configuration.defaultConfiguration();
        configuration = configuration.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);
        DocumentContext parse = parse(content, configuration);

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

        Map<String, Object> document = parse.read("$.document");
        if (document != null) {
            for (Map.Entry<String, Object> entry : document.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                Object oldVal = params.getParameter(key);
                if (value instanceof String) {
                    if (!cn.myapps.common.util.StringUtil.isBlank(String.valueOf(value))) {
                        params.setParameter(key, value);
                    }
                } else {
                    params.setParameter(key, value);
                }
            }
        }

        List<String> selects = parse.read("$._selects");
        if (selects != null)
            params.setParameter("_selects", cn.myapps.common.util.StringUtil.unite(selects.toArray()));

        List<String> subSelects = parse.read("$.subSelects");
        if (subSelects != null) {
            params.setParameter("subSelects", cn.myapps.common.util.StringUtil.unite(subSelects.toArray()));
        }

        List<String> nextNodeIds = parse.read("$.nextNodeIds");
        if (nextNodeIds != null)
            params.setParameter("_nextids", cn.myapps.common.util.StringUtil.unite(nextNodeIds.toArray()));

        String attitude = parse.read("$.attitude");
        if (!cn.myapps.common.util.StringUtil.isBlank(attitude))
            params.setParameter("attitude", attitude);
        String signature = parse.read("$.signatureJson");
        if (!StringUtil.isBlank(signature)) {
            params.setParameter("_signature", signature);
        }

        List<Map<String, String>> submitTo = parse.read("$.submitTo");
        if (submitTo != null) {
            params.setParameter("submitTo", submitTo.toString());
        }

        if(isBeforeAction) {
            //自定义按钮不做额外的重计算
            Object obj = params.getParameter("actType");
            if (obj != null) {
                try {
                    int actType = Integer.parseInt((String) obj);
                    if (ActivityType.NOTHING == actType) {
                        ActivityDesignTimeService activityService = DesignTimeServiceManager.activityDesignTimeService();
                        Activity act = activityService.findById(id);
                        if (act == null) {
                            params.setParameter("isFromRefresh", true);
                        }
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }

        return params;
    }

    public static Document prepareDocument(IUser user, String jsonContent, String applicationId,
                                           String baseJsonPath, ParamsTable params)
            throws Exception
    {
        Configuration configuration = Configuration.defaultConfiguration();
        configuration = configuration.addOptions(Option.DEFAULT_PATH_LEAF_TO_NULL);
        DocumentContext parse = parse(jsonContent, configuration);
        String formid = parse.read(baseJsonPath + ".formId");
        String viewid = parse.read(baseJsonPath + ".viewId");
        String stateid = parse.read(baseJsonPath + ".stateId");
        String parentid = parse.read(baseJsonPath + ".parentId");
        String sign = parse.read(baseJsonPath + ".sign");
        String docId = params.getDocId();
        if(StringUtil.isBlank(docId)) {
            docId = parse.read(baseJsonPath + ".id");
        }

        String isRelate = parse.read(baseJsonPath + ".isRelate");
        List subDocuments = parse.read(baseJsonPath + ".subDocuments");
        Map<String, Object> items = parse.read(baseJsonPath + ".items");
        Object delete = parse.read(baseJsonPath + ".delete");
        Object edit = parse.read(baseJsonPath + ".edit");
        Object isFromRefresh = params.getParameter("isFromRefresh");
        Object exparams = parse.read(baseJsonPath + ".exparams");

        if (exparams != null) {
            Map<String, Object> exparamsMap = (Map<String, Object>) exparams;
            for (Map.Entry entry : exparamsMap.entrySet()) {
                String key = entry.getKey().toString();
                Object value = entry.getValue();
                params.setParameter(key, value);
            }
        }

        if (isRelate != null && isRelate.equals("true")) {
            params.setParameter("isRelate", "true");
            if (!StringUtil.isBlank(parentid)) {
                params.setParameter("relateid", parentid);
            }
        } else {
            if (!StringUtil.isBlank(parentid)) {
                params.setParameter("relateid", parentid);
            }
            parentid = "";
        }

        if (parentid != null && !parentid.isEmpty())
            params.setParameter("parentid", parentid);
        if (viewid != null && !viewid.isEmpty())
            params.setParameter("viewid", viewid);

        DocumentProcess dProcess = RunTimeServiceManager.documentProcess(applicationId);

        FormDesignTimeService formService = DesignTimeServiceManager.formDesignTimeService();
        Form form = formService.doView(formid);
        //IUser user = getUser();
        Document doc = null;
        if (items != null) {
            Document temp = (Document) dProcess.doView(docId);
            if (temp == null) {
                temp = dProcess.doNew(form, user, params);
            }

            if (temp != null) {
                for (Map.Entry<String, Object> entry : items.entrySet()) {
                    String key = entry.getKey();
                    Object value = entry.getValue();
                    Item item = temp.findItem(key);

                    if (item == null) {
                        if (!StringUtil.isBlank(key) && key.lastIndexOf("_show") > -1) {
                            item = temp.findItem(key.substring(0, key.lastIndexOf("_show")));
                        }
                    }
                    if (item != null) params.setParameter(key, value);
                }
            }

            doc = temp;
        } else {
            return new Document();
        }

        if (StringUtil.isBlank(docId)) {
            docId = doc.getId();
        }else {
            doc.setId(docId);
        }

        if (!items.isEmpty() && isFromRefresh == null) {
            doc = form.createDocument(doc, params, user);
        }

        if (!StringUtil.isBlank(parentid)) {
            doc.setParent(parentid);
        }
        if (!StringUtil.isBlank(stateid)) {
            doc.setState(stateid);
        }
        if (!StringUtil.isBlank(sign)) {
            doc.setSign(sign);
        }
        if (StringUtil.isBlank(doc.getFormid()) && !StringUtil.isBlank(formid)) {
            doc.setFormid(formid);
        }

        if (StringUtil.isBlank(doc.getApplicationid()) && !StringUtil.isBlank(applicationId)) {
            doc.setApplicationid(applicationId);
        }

        List<Document> subDocumentList = new ArrayList<Document>();
        if (subDocuments != null) {
            for (Iterator iterator = subDocuments.iterator(); iterator.hasNext(); ) {
                Map map = (Map) iterator.next();
                ParamsTable newParams = params.copyContextParams();
                Iterator<Map.Entry<String, Object>> iter = map.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry<String, Object> entry = iter.next();
                    String name = entry.getKey();
                    Object value = entry.getValue();
                    try {
                        if (value instanceof String[])
                            if (((String[]) value).length > 1)
                                newParams.setParameter(name, value);
                            else
                                newParams.setParameter(name, ((String[]) value)[0]);
                        else
                            newParams.setParameter(name, value);
                    } catch (Exception e) {
                        throw e;
                    }
                }

                Document subDoc = prepareDocument(user, net.sf.json.JSONObject.fromObject(map).toString(), applicationId, "$", newParams);
                subDocumentList.add(subDoc);
            }
        }
        doc.setSubDocuments(subDocumentList.isEmpty() ? null : subDocumentList);
        if (delete != null) {
            doc.setDelete(true);
        }
        if (edit != null) {
            doc.setEdit(true);
        }

        return doc;
    }

}
