package com.brilliance.mda.runtime.mda.util;

import com.brilliance.mda.runtime.annotation.RelPath;
import com.brilliance.mda.runtime.mda.*;
import com.brilliance.mda.runtime.mda.driver.MdaDriver;
import com.brilliance.mda.runtime.mda.driver.MdaEnv;
import com.brilliance.mda.runtime.mda.driver.compile.component.ModuleRuleContext;
import com.brilliance.mda.runtime.mda.driver.compile.processor.ModuleAnnotationProcess;
import com.brilliance.mda.runtime.mda.impl.Argument;
import com.brilliance.mda.runtime.mda.impl.DatafieldImpl;
import com.brilliance.mda.runtime.mda.impl.ModuleList;
import com.brilliance.mda.runtime.mda.impl.StreamImpl;
import com.brilliance.mda.support.td.ModuleInfoManager;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.brilliance.mda.runtime.mda.Constants.*;
import static com.brilliance.mda.runtime.mda.driver.MdaDriver.getBaseObject;

public class Systems {

    private static final Logger log = LoggerFactory.getLogger(Systems.class);

    public static void setAttribute(IDatafield field, String ATTR, Object val) {
        setAttribute(field.getParent(), field.getName(), ATTR, val);
    }

    public static int getAttribute(IDatafield field, String ATTR) {
        return getAttribute(field.getParent(), field.getName(), ATTR);
    }

    public static int getAttribute(IModule parent, String prop, String ATTR) {
        Object val = getAttributeValue(parent, prop, ATTR);
        if (val == null)
            return 0;
        if (val instanceof Integer)
            return (Integer) val;
        if (val instanceof Boolean) {
            return (Boolean) val ? 1 : 0;
        }
        if (val instanceof String) {
            if ("Visible".equals(val) || "Enabled".equals(val)) {
                return 1;
            }
        }
        return 0;
    }

    public static <T> T getAttributeValue(IModule parent, String prop, String ATTR) {
        if (parent == null) {
            MdaEnv.getContext().setErrorCode(-1);
        }
        if (ATTR == null) {
            MdaEnv.getContext().setErrorCode(-2);
        }
        if ("".equals(ATTR)) {
            MdaEnv.getContext().setErrorCode(102);
        }
        if (tdAttrName.equals(ATTR))
            return (T) prop.toUpperCase();
        if (tdAttrFullName.equals(ATTR)) {
            String fieldPath = parent.getFieldPath(prop);
            return (T) fieldPath;
        }
        if (tdAttrVisible.equals(ATTR)) {
            return (T) (Systems.isVisible(parent, prop) ? "Visible" : "Invisible");
        }
        if (tdAttrEnabled.equals(ATTR)) {
            return (T) (Systems.isEnabled(parent, prop) ? "Enabled" : "Disabled");
        }
        if (tdAttrDecpos.equals(ATTR)) {
            //TODO
        }
        if (tdAttrLines.equals(ATTR)) {
            return (T) new Integer(100);
        }
        if (tdAttrLength.equals(ATTR)) {
            return (T) new Integer(100);
        }
        if (tdAttrDatatype.equals(ATTR)) {
            IDatafield datafield = MdaDriver.getDatafield(parent, prop);
            if (datafield != null) {
                Class<T> dataType = (Class<T>) datafield.getDataType();
                if (dataType == String.class) {
                    return (T) new Integer(1);
                } else if (dataType == BigDecimal.class || dataType == Long.class || dataType == Integer.class) {
                    return (T) new Integer(2);
                } else if (dataType == Date.class) {
                    return (T) new Integer(4);
                } else if (dataType == IStream.class) {
                    return (T) new Integer(7);
                } else if (dataType == long.class) {
                    return (T) new Integer(2);
                }
            } else {// 默认返回字符串类型
                return (T) new Integer(1);
            }
        }
        if (tdAttrViewtype.equals(ATTR)) {
            //TODO
        }
        if (tdAttrFieldViewtype.equals(ATTR)) {
            //TODO
        }
        if (tdAttrModified.equals(ATTR)) {
            Object attribute = MdaEnv.getContext().getAttribute(parent, prop, ATTR);
            if (attribute == null) {
                return (T) Integer.valueOf(0);
            }
            return (T) attribute;
        }
        if (tdAttrCalendar.equals(ATTR)) {
            IDatafield datafield = MdaDriver.getDatafield(parent, prop);
            if (!(datafield.getValue() instanceof Date)) {
                MdaEnv.getContext().setErrorCode(171);
            }
            if (MdaEnv.getContext().getAttribute(parent, prop, ATTR) == null) {
                return (T) NULLSTR;
            }
        }
        if (tdAttrCodetable.equals(ATTR)) {
            Map<String, Object> itemInfo = ModuleInfoManager.getModuleFieldInfo(parent.getClass().getSimpleName().toLowerCase(), prop);
            return (T) itemInfo.get("codetable");
        }
        if (tdAttrCurrency.equals(ATTR)) {
            IDatafield datafield = MdaDriver.getDatafield(parent, prop);
            if (datafield != null) {
                Class<T> dataType = (Class<T>) datafield.getDataType();
                if (!(dataType == BigDecimal.class || dataType == Long.class || dataType == Integer.class)) {
                    MdaEnv.getContext().setErrorCode(171);
                }
            }
            if (MdaEnv.getContext().getAttribute(parent, prop, ATTR) == null) {
                return (T) NULLSTR;
            }
        }
        if (tdAttrInfo.equals(ATTR)) {
            //TODO
        }
        if (tdAttrContent.equals(ATTR)) {
            IDatafield datafield = MdaDriver.getDatafield(parent, prop);
            if (datafield != null) {
                return (T) datafield.getValue();
            }
        }
        if (tdAttrFirstValue.equals(ATTR)) {
            String list = getAttributeValue(parent, prop, tdAttrKeyList);
            if (list != null) {
                String[] split = list.split("\r\n");
                return (T) split[0];
            }
        }
        if (tdAttrKeyList.equals(ATTR)) {
            //TODO
            List<CodetableItem> codeTable = Codetables.getCodeTable(prop, Systems.getLang());
            StringBuilder sb = new StringBuilder();
            if (!codeTable.isEmpty()) {
                for (CodetableItem item : codeTable) {
                    sb.append(item.getValue() + "\r\n");
                }
                return (T) sb.toString();
            }
        }
        if (tdAttrCodeValues.equals(ATTR)) {
            //TODO
        }
        return MdaEnv.getContext().getAttribute(parent, prop, ATTR);
    }

    public static void setAttribute(IModule parent, String prop, String ATTR, Object val) {
        MdaEnv.getContext().setAttribute(parent, prop, ATTR, val);
    }

    public static void setAttributeText(IModule parent, String prop, String ATTR, Object val) {
        MdaEnv.getContext().setAttribute(parent, prop, ATTR, val);
    }

    public static void setAttributeText(Date date, String prop, String ATTR) {
        if (null != date) {
            MdaEnv.getContext().setAttribute(null, date.toString(), prop, ATTR);
        }
    }

    public static void setValues(IModule parent, String prop, IStream values) {
        setValuesToContextSet(parent, prop, values);
        MdaEnv.getContext().setAttribute(parent, prop, AttrType.VALUES.name(), values);
    }

    public static void setValuesToContextSet(IModule parent, String prop, IStream values) {
        //拦截做values专项处理
        String key = null;
        if (MdaEnv.getContext().getRoot() == parent) {
            key = prop;
        } else {
            key = parent.getPath().replaceAll("\\\\", "\\.") + "." + prop;
            key = key.substring(1).toLowerCase();
        }
        if (values != null && !(key.endsWith("sdamod.dadrcv") || key.endsWith("sdamod.dadsnd")) && hasField(MdaEnv.getContext().getVo(), key.replaceAll("\\.", "_"))) {
            MdaEnv.getContext().getValuesSet().put(key, new CodeEntity(key, values.getRows(), false));
        }
    }

    public static void setValues(IModule parent, String prop, String values) {
        IStream stream = new StreamImpl();
        Streams.streamSet(stream, values);
        setValues(parent, prop, stream);
    }

    public static void setValues(IDatafield datafield, IStream values) {
        setValues(datafield.getParent(), datafield.getName(), values);
    }

    public static void setValues(IDatafield datafield, String values) {
        setValues(datafield.getParent(), datafield.getName(), values);
    }

    public static IStream getValues(IModule parent, String prop) {
        Object attribute = MdaEnv.getContext().getAttribute(parent, prop, AttrType.VALUES.name());
        if (attribute instanceof IStream) {
            return (IStream) attribute;
        } else if (attribute instanceof Map) {
            Map map = (Map) attribute;
            List<String> rows = (List<String>) map.get("rows");
            IStream result = new StreamImpl();
            result.getRows().addAll(rows);
            return result;
        }
        return (IStream) attribute;
    }

    public static IStream getValues(IDatafield datafield) {
        //If no framefields exist for datafield, the positive (critical) error code 111 is set.
        if (MdaUtils.isEmpty(datafield.getParent())) {
            MdaEnv.getContext().setErrorCode(Constants.tdDataParentIsNull);
            return new StreamImpl();
        }
        IStream stream = getValues(datafield.getParent(), datafield.getName());
        if (stream == null)
            stream = new StreamImpl();
        return stream;
    }

    public static void setModified(IDatafield field) {
        setModified(field.getParent(), field.getName());
    }

    public static void setModified(IModule parent, String prop) {
        MdaEnv.getContext().setAttribute(parent, prop, AttrType.MODIFIED.name(), Boolean.TRUE);
    }

    public static void resetModified(IModule module) {
        resetModified(module.getParent(), module.getName());
    }

    public static void resetModified(IDatafield field) {
        resetModified(field.getParent(), field.getName());
    }

    public static void resetModified(IModule parent, String prop) {
        MdaEnv.getContext().setAttribute(parent, prop, AttrType.MODIFIED.name(), Boolean.FALSE);
    }

    public static void resetModified(IStream stream) {
        stream.setAttribute(AttrType.MODIFIED.name(), Boolean.FALSE);
    }

    public static boolean checkModuleHasModified(IModule module) {
        if (module == null) {
            return false;
        }
        Map<String, Object> attrMaps = module.getAttrMaps();
        for (String s : attrMaps.keySet()) {
            if (s.endsWith("MODIFIED") || s.endsWith("modified")) {
                return true;
            }
        }
        Field[] declaredFields = module.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            if ("_parent".equals(field.getName())) {
                continue;
            }
            if (IModule.class.isAssignableFrom(field.getType())) {
                try {
                    field.setAccessible(true);
                    IModule o = (IModule) field.get(module);
                    if (checkModuleHasModified(o)) {
                        return true;
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }

    public static boolean checkIsFieldHolder(IModule root, String prop) {
        Field[] declaredFields = root.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if (prop.equals(declaredField.getName())) {
                return declaredField.getType().isAssignableFrom(FieldHolder.class);
            }
        }
        return false;
    }

    public static boolean isModified(IModule parent, String prop) {
        if ("".equals(prop)) {
            return checkModuleHasModified(parent);
        }
        if (checkIsFieldHolder(parent, prop)) {
            IBaseObject baseObject = getBaseObject(parent, prop);
            try {
                DatafieldImpl datafield = (DatafieldImpl) baseObject;
                Field field = datafield.getClass().getDeclaredField("field");
                Field parentField = datafield.getClass().getDeclaredField("parent");
                field.setAccessible(true);
                parentField.setAccessible(true);
                FieldHolder fieldHolder = (FieldHolder) ((Field) field.get(datafield)).get(parentField.get(datafield));
                String holderPath = fieldHolder.getPath();
                if (StringUtils.isBlank(holderPath)) {
                    return false;
                }
                if (holderPath.contains("\\")) {//modle ，且有parent时
                    int indexOf = holderPath.lastIndexOf("\\");
                    IModule m = (IModule) getBaseObject(null, holderPath.substring(0, indexOf));
                    if (m != null) {
                        return isModified(m, holderPath.substring(indexOf + 1));
                    }
                } else {
                    return isModified(MdaEnv.getContext().getRoot(), holderPath);
                }
                //原代码：return isModified((IDatafield) getBaseObject(null, baseObject.getPath()));
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
            //( ((DatafieldImpl) baseObject).field.get(((DatafieldImpl) baseObject).parent)).getPath()
        }
        Object obj = MdaEnv.getContext().getAttribute(parent, prop, AttrType.MODIFIED.name());
        if (obj == null) {
            return false;
        }
        if (obj instanceof Integer) {
            return (Integer) obj != 0;
        }
        return obj == null ? false : (Boolean) obj;
    }

    public static boolean isModified(IDatafield field) {
        return isModified(field.getParent(), field.getName());
    }

    public static void resetEnabled(IDatafield field) {
        resetEnabled(field.getParent(), field.getName());
    }

    public static void resetEnabled(IModule parent, String prop) {
        MdaEnv.getContext().setAttribute(parent, prop, AttrType.ENABLED.name(), Boolean.FALSE);
    }

    public static void setEnabled(IDatafield field) {
        setEnabled(field.getParent(), field.getName());
    }

    public static void setEnabled(IModule parent, String prop) {
        MdaEnv.getContext().setAttribute(parent, prop, AttrType.ENABLED.name(), Boolean.TRUE);
    }

    public static void setEnabled(IModule parent, String... props) {
        for (String prop : props) {
            MdaEnv.getContext().setAttribute(parent, prop, AttrType.ENABLED.name(), Boolean.TRUE);
        }
    }

    public static void resetEnabled(IModule parent, String... props) {
        for (String prop : props) {
            MdaEnv.getContext().setAttribute(parent, prop, AttrType.ENABLED.name(), Boolean.FALSE);
        }
    }

    public static boolean isEnabled(IModule parent, String prop) {

        if (!isPanel(parent, prop) && !hasField(MdaEnv.getContext().getVo(), getVoFieldName(parent, prop))) {
            return false;
        }

        Object obj = MdaEnv.getContext().getAttribute(parent, prop, AttrType.ENABLED.name());
        if (obj == null) {
            Map<String, Object> infoMap = ModuleInfoManager.getModuleFieldInfo(parent.getClass().getSimpleName().toLowerCase(), prop);
            if (infoMap != null && Boolean.FALSE.equals(infoMap.getOrDefault("enabled", true))) {
                MdaEnv.getContext().setErrorCode(Constants.tdDataTypeNil);
                return false;
            }
            //不用随便添加错误码
            //MdaEnv.getContext().setErrorCode(111);
        }
        return obj == null ? true : (Boolean) obj;
    }

    public static boolean isEnabled(IDatafield field) {
        //If no framefield exist for the field, the function returns FALSE and error code 111 is set.
        if (MdaUtils.isEmpty(field.getParent())) {
            MdaEnv.getContext().setErrorCode(Constants.tdDataParentIsNull);
            return false;
        }
        return isEnabled(field.getParent(), field.getName());
    }

    public static boolean isPanel(IModule parent, String prop) {
        IBaseObject baseObject = getBaseObject(parent, prop);
        return baseObject instanceof IPanel || baseObject instanceof IControl;
    }

    public static void resetVisible(IModule parent, String prop) {
        MdaEnv.getContext().setAttribute(parent, prop, AttrType.VISIABLE.name(), Boolean.FALSE);
    }

    public static void resetVisible(IModuleList parent, String prop) {
        //MdaEnv.getContext().setAttribute(parent, prop,AttrType.VISIABLE.name(),Boolean.FALSE);
    }

    public static void resetVisible(IPanel panel) {
    }

    public static void resetVisible(IDatafield panel) {
    }

    public static void setVisible(IPanel panel) {
        if (panel == null) {
            return;
        }
        setVisible(panel.getParent(), panel.getName());
    }

    public static void setVisible(IModule parent, String prop) {
        if (parent == null) {
            return;
        }
        MdaEnv.getContext().setAttribute(parent, prop, AttrType.VISIABLE.name(), Boolean.TRUE);
    }

    public static void setVisible(IModuleList parent, String prop) {
        //MdaEnv.getContext().setAttribute(parent, prop,AttrType.VISIABLE.name(),Boolean.TRUE);
    }

    public static <T> void setVisible(IDatafield<T> value) {
        setVisible(value.getParent(), value.getName());
    }

    public static boolean isVisible(IModule parent, String prop) {
        if (!isPanel(parent, prop) && !hasField(MdaEnv.getContext().getVo(), getVoFieldName(parent, prop))) {
            return false;
        }
        Object obj = MdaEnv.getContext().getAttribute(parent, prop, AttrType.VISIABLE.name());
        if (obj == null) {
            Map<String, Object> infoMap = ModuleInfoManager.getModuleFieldInfo(parent.getClass().getSimpleName().toLowerCase(), prop);
            if (infoMap != null) {
                if (Boolean.FALSE.equals(infoMap.get("visible"))) {
                    return false;
                }
            }
            //MdaEnv.getContext().setErrorCode(111);
        }
        return obj == null ? true : (Boolean) obj;
    }

    private static Map<String, String> voFieldsMap = new ConcurrentHashMap<>();

    public static boolean hasField(Object vo, String field) {
        String prefix = vo.getClass().getName() + "_";
        int idx = field.indexOf('(');
        if (idx > -1) {
            field = field.substring(0, idx);
        }
        if (!voFieldsMap.containsKey(prefix)) {
            Arrays.stream(vo.getClass().getDeclaredFields()).forEach(
                    e -> {
                        String fieldName = e.getName();
                        if (e.isAnnotationPresent(RelPath.class)) {
                            RelPath relPath = e.getAnnotation(RelPath.class);
                            if (!MdaUtils.isEmpty((relPath.value()))) {
                                fieldName = relPath.value().replaceAll("\\.", "_");
                            }
                        }
                        voFieldsMap.put(prefix + fieldName, "1");
                    }
            );
            voFieldsMap.put(prefix, "1");
        }
        return voFieldsMap.containsKey(prefix + field);
    }


    //默认返回1(yes)
    public static int promptYesNo(String message) {
        return 1;
    }

    public static int promptYesNo(String s, String rtnTxt) {
        return 1;
    }

    public static int promptYesNo(String s, int a, int b, String rtnTxt) {
        return 1;
    }

    public static void setEnabled(IPanel panel) {
    }

    public static void resetEnabled(IPanel panel) {
    }

    public static String signature(String str, int i) {
        return macGen(str, i);
    }

    public static String macGen(String text, int startval) {
        String data = startval + text;
        String s = DigestUtils.sha1Hex(DigestUtils.md5(data)).substring(0, 8);
        return s;
    }

    public static String macGen(IStream str, int startval) {

        String data = str.getRows().stream().reduce("", (acc, item) -> acc + item);
        return macGen(data, startval);
    }

    public static <T> T cast(Class<T> clazz, Object value) {
        if (value == null) {
            MdaEnv.getContext().setErrorCode(789);
            return null;
        } else if (clazz != value.getClass()) {
            MdaEnv.getContext().setErrorCode(789);
            return null;
        }
        MdaEnv.getContext().setErrorCode(NO_ERROR);
        return (T) value;
    }

    public static void logText(String filename, String text) {
        if (filename == null || text == null) return;
        File f = new File(filename);
        if (f.isDirectory())
            throw new IllegalArgumentException("filename必须是一个文件！");
        if (!f.getParentFile().exists())
            f.getParentFile().mkdirs();

        BufferedWriter out = null;
        try {
            if (!f.exists()) {
                f.createNewFile();
            }
            out = new BufferedWriter(new FileWriter(f));
            out.append(text);
        } catch (IOException e) {
            throw new IllegalArgumentException(e.getMessage());
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void setContext(String key, Object... obj) {
        if (key == null) return;
        MdaEnv.setSessionContext(key, obj);
    }

    public static String getContext(String key) {
        if (key == null) return NULLSTR;
        if (tdContextCALLSTACK.equalsIgnoreCase(key)) {
            return MdaEnv.getContext().getConcurrentCallStack();
        }
        if (tdContextDBDRIVERNAME.equals(key))
            return "ORACLE";
        if (tdContextPOSTQUEUE.equals(key)) {
            LinkedList<Map> linkedList = (LinkedList<Map>) MdaEnv.getContext().restoreData(tdContextPOSTQUEUE);
            if (linkedList == null)
                return NULLSTR;
            Optional<String> result = linkedList.stream().map(m -> m.get("rule").toString().toUpperCase()).reduce((a, b) -> a + "\n" + b);
            if (result.isPresent())
                return result.get();
            return NULLSTR;
        }
        if (tdContextDBSERVICENAME.equals(key)) {
            return "DSN=sstfcebnew;UID=sstfcebnew;PWD=<protected>;DBQ=SSTF;DBA=W;APA=T;EXC=F;FEN=T;QTO=T;FRC=10;FDL=10;LOB=T;RST=T;BTD=F;BNF=F;BAM=IfAllSuccessful;NUM=NLS;DPM=F;MTS=T;MDI=F;CSR=F;FWC=F;FBS=64000;TLO=O;MLD=0;ODA=F;";
        }
        if (tdContextLANGUAGE.equals(key))
            return getLang();

        if (tdContextLASTUSERACTIONTIME.equals(key)) { //返回上一次操作的毫秒级时间日期
            //每次请求时会添加一个时间进入。
        }
        if (tdContextFORM.equals(key))//返回上一次操作的毫秒级时间日期
            return new Date().toString();
        Object obj = MdaEnv.getSessionContextValue(key);
        return obj == null ? NULLSTR : obj.toString();
    }

    public static String getContext(String key, String str) {
        if (key == null) key = NULLSTR;
        if (str == null) str = NULLSTR;
        return MdaEnv.getSessionContextValue(key + ":" + str);
    }

    public static void getContextStream(IStream stm, String str) {
    }

    public static void status(String format, Object... obj) {
        String message = Strings.getText(format, obj);
        log.info(message);
    }

    public static boolean checkStatement(IModule _this, String rule) {
        try {
            //Rule分三段，belong,function,expressionList
            rule = rule.trim();
            int eqAssign = rule.indexOf("=");
            if (eqAssign > 0)
                rule = rule.substring(eqAssign + 1).trim();
            String segItem = "\\w[\\w\\d]*";
            // 最复杂路径  \SETMOD\SETGLG\SETGLL(1).SETSUMS1     与invokeExpress保持一致
            String pathReg = String.format("(\\\\)|([\\\\]?%s((\\\\%s)|(\\(\\d+\\)))*)", segItem, segItem);
            String belongReg = String.format("(?<belong>%s)", pathReg);
            String functionReg = "(?<func>\\w+)";
            String argsReg = "(?<args>.*)";
            String entireReg = String.format("(%s\\s*\\.\\s*)?%s\\s*(\\(%s\\))?", belongReg, functionReg, argsReg);
            //System.out.println(entireReg);
            Matcher m = Pattern.compile(entireReg).matcher(rule);
            if (!m.find() || m.start() != 0) {
                return false;
            }
            String belong = m.group("belong");
            String function = m.group("func");
            String argsStr = m.group("args");

            String[] args = Strings.splitArgumentsString(argsStr);

            if (belong != null) {
                belong = belong.toLowerCase();
                IModule subModule = null;
                if (belong.startsWith("\\"))
                    subModule = MdaDriver.getModule(belong);
                else
                    subModule = MdaDriver.getModule(_this, belong);
                //MdaDriver.getModule(belong);
                if (subModule == null) {
                    return false;
                }
                Method method = Modules.findMethod(_this, subModule.getClass(), function, args);
                if (method != null) {
                    //invokeExpressMethod(_this, subModule, method, args);
                    return true;
                }
            } else {

                //全局函数搜索
                Method method = Modules.findMethod(_this, Platform_class, function, args);
                if (method != null && isMethodInContext(true, method)) {
                    //invokeExpressMethod(_this, null, method, args);
                    return true;
                }
//                method = Modules.findMethod(_this, Dynamic_class, function, args);
//                if (method != null && isMethodInContext(false, method)) {
//                    //invokeExpressMethod(_this, null, method, args);
//                    return true;
//                }
                //先从当前模型找
                if (_this != null) {
                    method = Modules.findMethod(_this, _this.getClass(), function, args);
                    if (method != null) {
                        //invokeExpressMethod(_this, _this, method, args);
                        return true;
                    }
                }
                //全局查找
                Argument moduleArg = new Argument();
                method = Modules.findCasecadeMethod(MdaEnv.getContext().getRoot(), _this, moduleArg, function, args);
                if (method != null) {

                    return true;
                }
            }
        } catch (Exception e) {
            //e.printStackTrace();
            //表达式执行失败
            //设置错误码
            e.printStackTrace();
        }
        return false;
    }

    public static boolean isMethodInContext(boolean globalOrStatic, Method m) {
        String methodKey = ModuleRuleContext.getMethodKey(m);
        ModuleRuleContext moduleRuleContext = ModuleAnnotationProcess.cache.get(MdaEnv.getContext().getEmitter().getModuleName());
        if (globalOrStatic) {
            return moduleRuleContext.getGlobalMethod().containsKey(methodKey);
        } else {
            return moduleRuleContext.getStaticMethod().containsKey(methodKey);
        }
    }

    public static String getAttributeText(IDatafield field, String ATTR) {
        return getAttributeValue(field.getParent(), field.getName(), ATTR);
    }

    public static String getAttributeText(IModule parent, String prop, String ATTR) {
        return getAttributeValue(parent, prop, ATTR);
    }

    public static String expandEnv(String str) {
        if (str == null || str.length() == 0 || str.indexOf("%") < 0) {
            return str;
        }
        StringBuilder sb = new StringBuilder();
        StringBuilder temp = new StringBuilder();
        char[] s = str.toCharArray();
        int j = 0;
        for (int i = 0; i < s.length; ) {
            if (s[i] != '%') {
                sb.append(s[i]);
                i++;
            } else {
                j = i + 1;
                while (j < s.length && s[j] != '%') {
                    temp.append(s[j]);
                    j++;
                }
                sb.append(System.getenv().get(temp.toString()));
                temp.setLength(0);
                i = j + 1;
            }
        }
        return sb.toString();
    }


    public static void ReInit() {
    }

    public static String getAdditional(IDatafield argFld) {
        return "";
    }

    //前台方法空实现
    public static void postDelete(String queLin) {
    }

    //前台方法空实现
    public static void setTitle(String str) {
    }

    public static int sockOpen(String socketseve, String socketport) {
        return 0;
    }

    public static void sockCall(int fd, IStream inStream, IStream outStream) {
    }

    public static void sockClose(int fd) {
    }

    public static IPanel getPanel(String str) {

        IBaseObject baseObject = getBaseObject(null, str);
        if (!(baseObject instanceof IPanel)) {
            MdaEnv.getContext().setErrorCode(Constants.NO_SUCH_FIELD);
            return null;
        }
        return (IPanel) baseObject;
    }

    public static void winExec(String dest) {
    }

    public static void winExec(String dest, boolean bool) {
    }

    public static void winExec(String dest, boolean bool, int no) {
    }

    //前台方法空实现
    public static void pause(int code) {
        //空实现
    }

    public static void pause(BigDecimal code) {
        //空实现
    }


    //前台方法空实现
    public static void popupTitledFrame(Object o, String title) {
        if (o instanceof IPanel) {
            String path = ((IPanel) o).getPath();
            log.debug("执行{}-Panel:{} rule", title, path);
            MdaEnv.getContext().postRule(((IPanel) o));
        }
    }

    public static void popupTitledFrame(Object o, String title, boolean b) {
        popupTitledFrame(o, title);
    }

    public static void setActivePanel(IPanel panel) {
    }

    public static void setActivePanel(IPanel panel, boolean b) {
    }

    //前台方法空实现
    //SaveDisplay
    public static void saveDisplayToStream(IStream stream) {
        Object requestVo = MdaEnv.getContext().restoreData(IContext.DISPLAY_KEY);
        ObjectMapper objectMapper = Modules.getObjectMapper();
        try {
            //写入到流中
            String jsonVo = objectMapper.writeValueAsString(requestVo);
            stream.addLine(jsonVo);
        } catch (Exception e) {
            log.error("快照写入错误:{}", e);
        }
    }

    //前台方法空实现
    //SetStyle
    public static void setTDStyle(Object... objects) {
    }

    //前台方法空实现
    public static void shellExec(String destfile, String download) {
    }

    //前台方法空实现
    public static <T> void setFocusField(IDatafield<T> field) {
    }

    //前台方法空实现
    public static <T> void setFocusField(String extKey) {
    }

    public static void recalc() {
    }

    public static void recalc(IModuleList list) {
    }

    public static void recalc(IModule grp) {
    }

    public static void recalc(String selusr) {
    }

    public static void recalc(IStream selusr) {
    }

    public static void recalc(IDatafield datafield) {
    }

    public static void recalc(String flt, String selusg, String selusr, String selusgset) {
    }

    public static void recalc(BigDecimal src) {
    }

    //前台方法空实现
    public static void showNotifyMessage(int num, String s) {
    }

    public static void showNotifyMessage(double num, String s) {
    }

    public static void showDisplay(String str) {
    }

    public static void showDisplay(IStream image) {
    }

    public static void showDisplay(IStream ascin, String title) {
    }

    public static void redisplay() {
    }

    public static void redisplay(String msg) {
    }

    public static void redisplay(IModule module) {
    }

    //前台方法空实现
    public static void setDescription(IPanel p, String s) {
    }

    public static void setDescription(String target, String s) {
    }

    public static void setDescription(IDatafield p, String s) {
    }

    public static String getDescription(IDatafield d) {
        return NULLSTR;
    }

    public static String getDescription(IPanel errPan, int i) {
        return NULLSTR;
    }

    //前台方法空实现
    public static void stopVideo() {
    }

    public static void startVideo() {
    }

    //前台方法空实现
    public static void showHelpText(String getFocusFieldPos, String hlp) {
    }

    //前台方法空实现
    public static final String lineFeed = "\r\n";
    public static final String langList = "EN" + lineFeed + "IT" + lineFeed + "FR" + "CN" + lineFeed + "DE" + lineFeed + "SP" + lineFeed + "VN" + lineFeed + "TH";

    public static String getPanelInfo(IPanel pan, String attr) {
        if (pan == null) {
            return NULLSTR;
        }
        if (tdPanelName.equals(attr)) {
            return getPanelInfo(pan, 1);
        }
        if (tdPanelFullName.equals(attr)) {
            return getPanelInfo(pan, 2);
        }
        return NULLSTR;
    }

    public static String getPanelInfo(IPanel pan, int attr) {
        if (pan == null) {
            return NULLSTR;
        }
        switch (attr) {
            case 1:
                return pan.getName();
            case 2:
                return pan.getPath();
            case 3:
                //TODO
                break;
            case 4:
                //TODO
                break;
            case 5:
                return getLang();
            case 6:
                //返回该面板支持的语种，暂时返回所有可支持的语种
                return langList;
            case 7:
                //TODO
                break;
            case 8:
                //TODO
                break;
            case 9:
                //TODO
                break;
            case 10:
                //TODO
                break;
            case 11:
                //TODO
                break;
        }
        return NULLSTR;
    }

    //前台方法空实现
    public static void showAboutPicture(String s) {
    }

    public static void setIcon(String icoName) {
        // Association association = new Association();
        // association.setIconFileName(icoName);
    }

    public static String getVoFieldName(IModule parent, String prop) {
        StringBuffer buf = new StringBuffer(prop);
        IModule m = parent;
        while (m != MdaEnv.getContext().getRoot() && m != null) {
            if (m instanceof ModuleList) {
                buf.setLength(0);
            } else {
                buf.insert(0, m.getName() + "_");
            }
            m = m.getParent();
        }
        if (buf.charAt(buf.length() - 1) == '_') {
            buf.deleteCharAt(buf.length() - 1);
        }
        return buf.toString();
    }

    public static boolean isUnix() {
        return SystemUtils.IS_OS_UNIX;
    }

    public static String getLang() {
        return MdaEnv.getLang();
    }

}
