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

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.impl.DatafieldImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.*;

import static com.brilliance.mda.runtime.mda.Constants.NO_ERROR;
import static com.brilliance.mda.runtime.mda.Constants.NULLSTR;

public class Datas {

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

    public static String DEFAULT_SECTION = "DEFAULT";
    public static String LAST_LOAD_CONTENT = "LAST_LOAD_CONTENT";


    public static void saveData(IModule module, IStream os) {
//        ObjectMapper mapper = new ObjectMapper();
//        try{
////            mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
////            mapper.writeValue(os.getOutputStream(),module);
//            String data = mapper.writeValueAsString(module);
//            saveData();
//        }
//        catch (Exception e)
//        {
//            log.error("模型序列化异常",e);
//        }
        saveData(module, os, "");
    }

    public static <T extends IModule> void saveData(IModuleList<T> list, IStream os) {
        ObjectMapper mapper = Modules.getObjectMapper();
        try {
            mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            mapper.writeValue(os.getOutputStream(), list);
        } catch (Exception e) {
            log.error("模型序列化异常", e);
        }
    }

    public static void saveData(IModule module, IStream stream, String section, String prefix) {
//        TODO
        /**
         * 1、 V20
         * 2、 S+section
         * 3、F+tllldddn +全路径名 = dataValue（DV,Dx,De,DL） +值
         * 4、MC +nnnnn +moduleList name
         */

        if (MdaUtils.isEmpty(section) && prefix.equals("")) {
            section = "DEFAULT";
        } else {
            section = prefix;
        }
        String tempValue = Modules.module2Data(module);
        for (int i = 1; i <= stream.countLines(); i++) {
            if (stream.getLine(i).equals(section)) {
                if (i == stream.countLines())
                    stream.addLine(tempValue);
                else
                    stream.setLine(i + 1, tempValue);
                return;
            }
        }
        //写入区块
        stream.addLine(section);
        stream.addLine(tempValue);
    }

    public static void saveData(IBaseObject moduleOrList, IStream stream, String section) {
        if (MdaUtils.isEmpty(section))
            section = "DEFAULT";
        String tempValue = Modules.module2Data(moduleOrList);
        for (int i = 1; i <= stream.countLines(); i++) {
            if (stream.getLine(i).equals(section)) {
                if (i == stream.countLines())
                    stream.addLine(tempValue);
                else
                    stream.setLine(i + 1, tempValue);
                return;
            }
        }
        //写入区块
        stream.addLine(section);
        stream.addLine(tempValue);
    }

    public static void loadData(IModule module, IStream stream, String section) {
        if (MdaUtils.isEmpty(section))
            section = "DEFAULT";
        for (int i = 1; i <= stream.countLines(); i++) {
            if (stream.getLine(i).equals(section) && i < stream.countLines()) {
                String dataString = stream.getLine(i + 1);
                IModule tempModule = (IModule) Modules.data2Module(module.getClass(), dataString);
                if (tempModule != null)
                    module.copyValues(tempModule);
            }
        }
        MdaEnv.getContext().setErrorCode(NO_ERROR);
    }


    public static <T> IDatafield<T> getField(String target) {
        return getContentField(target);
    }

    public static <T> IDatafield<T> getField(IModule module, String target) {
        if (target != null && target.startsWith("\\")) {
            return getContentField(MdaEnv.getContext().getRoot(), target);
        }
        return getContentField(module, target);
    }

    public static void setFieldValue(IDatafield field, String value) {
        field.setValue(value);
    }

    public static <T> void setFieldValue(String fieldTarget, T value) {
        IDatafield<T> field = getContentField(fieldTarget);
        if (field == null) return;
        if (field.getDataType() == IStream.class) {
//            if (value instanceof String) {
//                IStream stm = new StreamImpl();
//                stm.setRows(streamStrSplit((String) value));
//                ((IDatafield<IStream>) field).setValue(stm);
//                return;
//            }
        }
        //TODO 应该为设置码表，并不是设置值
        //field.setValue(value);


    }

    public static <T> void setFieldValue(IModule parent, String fieldTarget, T value) {
        IDatafield<T> field = getContentField(parent, fieldTarget);
        field.setValue(value);
    }

    public static <T> IDatafield<T> getContentField(String target) {
        return MdaDriver.getDatafield(target);
    }

    public static <T> IDatafield<T> getContentField(IModule parent, String target) {
        return MdaDriver.getDatafield(parent, target);
    }

    public static void setFieldValue(IStream stream, String str) {
        if (str == null) return;
        String[] args = null;
        if (str.indexOf("\r\n") != -1) {
            str = Strings.trimEnd(str, "\r\n");
            args = str.split("\r\n");
        } else if (str.indexOf("\n") != -1) {
            str = Strings.trimEnd(str, "\n");
            args = str.split("\n");
        } else {
            args = new String[]{str};
        }
        stream.setRows(Arrays.asList(args));
        List<String> rows = stream.getRows();
    }


    public static <T> void setContentNumeric(String target, T val) {
        IDatafield<T> datafield = getContentField(target);
        if (datafield == null)
            return;
        Class<T> dataType = datafield.getDataType();
        if (dataType == long.class && val instanceof BigDecimal) {
            BigDecimal val1 = (BigDecimal) val;
            datafield.setValue((T) Long.valueOf(val1.longValue()));
        } else {
            datafield.setValue(val);
        }
    }

    public static <T> void setContentNumeric(IModule _this, String target, T val) {
        if (!target.startsWith("\\") && _this != null) {
            target = _this.getPath() + "\\" + target;
        }
        setContentNumeric(target, val);
    }

    public static BigDecimal getContentNumeric(String target) {
        // IDatafield datafield = getContentField(target);
        // if (datafield == null)
        //     return BigDecimal.ZERO;
        // if(datafield.getValue() instanceof Integer)
        //     return new BigDecimal(datafield.getValue().toString());
        // return (BigDecimal) datafield.getValue();

        IBaseObject baseObject = MdaDriver.getBaseObject(null, target);
        if (baseObject == null) {
            return BigDecimal.ZERO;
        }
        if (baseObject instanceof IDatafield) {
            IDatafield datafield = (IDatafield) baseObject;
            if (datafield.getValue() instanceof Number) {
                return new BigDecimal(datafield.getValue().toString());
            }
            return (BigDecimal) datafield.getValue();
        }
        MdaEnv.getContext().setErrorCode(27);
        return BigDecimal.ZERO;
    }

    public static BigDecimal getContentNumeric(IModule _this, String target) {
        if (!target.startsWith("\\") && _this != null) {
            target = _this.getPath() + "\\" + target;
        }
        return getContentNumeric(target);
    }

    public static String getContent(String target) {
        IDatafield datafield = getContentField(target);
        if (datafield == null) {
            MdaEnv.getContext().setErrorCode(Constants.NO_SUCH_FIELD);
            return NULLSTR;
        }
        MdaEnv.getContext().setErrorCode(Constants.NO_ERROR);
        if (datafield.getValue() == null)
            return NULLSTR;
        return datafield.getValue().toString();
    }

    public static String getContent(IModule _this, String target) {
        if (!target.startsWith("\\") && _this != null) {
            String path = _this.getPath();
            target = path.equals("\\") ? "\\" + target : path + "\\" + target;
        }
        return getContent(target);
    }

    public static void setContentText(String target, String value) {
        IDatafield<String> datafield = getContentField(target);
        if (datafield == null) {
            return;
        }
        datafield.setValue(value);
    }

    public static void setContentText(IModule _this, String target, String value) {
        if (!target.startsWith("\\") && _this != null) {
            IDatafield<String> datafield = MdaDriver.getDatafield(_this, target);
            if (datafield == null) {
                return;
            }
            datafield.setValue(value);
            return;
        }
        setContentText(target, value);
    }

    public static void setContentDate(String target, Date value) {
        IDatafield<Date> datafield = getContentField(target);
        if (datafield == null)
            return;
        datafield.setValue(value);
    }

    public static void setContentDate(IModule _this, String target, Date value) {
        if (!target.startsWith("\\") && _this != null) {
            IDatafield<Date> datafield = MdaDriver.getDatafield(_this, target);
            if (datafield == null) {
                return;
            }
            datafield.setValue(value);
            return;
        }
        setContentDate(target, value);
    }

    public static Date getContentDate(String target) {
        IDatafield<Date> datafield = getContentField(target);
        if (datafield == null)
            return null;
        return datafield.getValue();
    }

    public static Date getContentDate(IModule _this, String target) {
        if (!target.startsWith("\\") && _this != null) {
            target = _this.getPath() + "\\" + target;
        }
        return getContentDate(target);
    }

    public static void setContentDateTime(String fieldname, Date datetime) {
        setContentDate(fieldname, datetime);
    }

    public static void setContentDateTime(IModule _this, String fieldname, Date datetime) {
        if (!fieldname.startsWith("\\") && _this != null) {
            fieldname = _this.getPath() + "\\" + fieldname;
        }
        setContentDateTime(fieldname, datetime);
    }

    public static Date getContentDateTime(String field) {
        return getContentDate(field);
    }

    public static Date getContentDateTime(IModule _this, String field) {
        return getContentDate(_this, field);
    }

    public static void setContentStream(String fieldname, IStream stream) {
        stream.setName(fieldname);
    }

    public static void getContentStream(IStream stream, String fieldname) {
        IDatafield<Object> contentField = getContentField(fieldname);
        try {
            Streams.streamSet(stream, (IStream) contentField.getValue());
        } catch (Exception e) {
            //设置错误码，但是具体应该设置为什么文档上没写，暂时不设置
            //TODO
            log.error("返回类型不对", e);
        }
    }

    public static void getContentStream(IDatafield datafield, String fieldname) {
        if (datafield == null) {
            return;
        }
        datafield.setValue(fieldname);
    }

    public static void setContentStream(IModule _this, String fieldname, IStream stream) {
        if (!fieldname.startsWith("\\") && _this != null) {
            fieldname = _this.getPath() + "\\" + fieldname;
        }
        setContentStream(fieldname, stream);
    }

    public static void getContentStream(IModule _this, IStream stream, String fieldname) {
        if (!fieldname.startsWith("\\") && _this != null) {
            fieldname = _this.getPath() + "\\" + fieldname;
        }
        getContentStream(stream, fieldname);
    }

    public static void getContentStream(IModule _this, IDatafield datafield, String fieldname) {
        if (!fieldname.startsWith("\\") && _this != null) {
            fieldname = _this.getPath() + "\\" + fieldname;
        }
        getContentStream(datafield, fieldname);
    }


    public static List<String> findStreamSectionValue(IStream stream, String section) {
        List<String> valueList = new ArrayList<>();
        for (int i = 0; i < stream.getRows().size(); i++) {
            if (stream.getRows().get(i).indexOf(section) >= 0 && i + 1 < stream.getRows().size()) {
                valueList.add(stream.getRows().get(i + 1));
                break;
            }
        }
        return valueList;
    }


    public static Date loadContentDate() {
        Object val = MdaEnv.getContext().restoreData(LAST_LOAD_CONTENT);
        return (Date) val;
    }

    public static Date loadContentDateTime() {
        return loadContentDate();
    }

    public static BigDecimal loadContentNumeric() {
        Object val = MdaEnv.getContext().restoreData(LAST_LOAD_CONTENT);

        return (BigDecimal) val;
    }

    public static void getDataInfoStream(IStream info, IStream data) {
        getDataInfoStream(info, data, "DEFAULT");
    }

    public static void getDataInfoStream(IStream info, IStream data, String section) {
        if (MdaUtils.isEmpty(section)) {
            section = "DEFAULT";
        }
        for (int i = 0; i < data.getRows().size(); i++) {
//            if(section.equals(data.getRows().get(i)) && i+1<data.getRows().size())
//                data.addLine(data.getRows().get(i+1));
            if (data.getRows().get(i).indexOf(section) < 0 && i + 1 < data.getRows().size() && data.getRows().get(i).indexOf("DN ") == 0) {
                String line = data.getRows().get(i).substring(3);
                info.addLine(line.split(" ")[0]);
            }
        }
    }

    public static <T extends IModule> void loadContentStream(IStream stm) {
        Object val = MdaEnv.getContext().restoreData(LAST_LOAD_CONTENT);
        if (val instanceof Map) {
            Map map = (Map) val;
            List<String> rows = (List<String>) map.get("rows");
            stm.getRows().addAll(rows);
        }
    }

    public static void ddeSetTopic(String str) {
    }

    public static boolean ddeTestTopic(String trigger, String sysmod) {
        return false;
    }

    public static void ddeSend(String trigger, String ddeTopic, IStream argStr) {
    }

    //TODO
    public static void getDataInfoCompare(IModule mod, IStream data, String section, IStream addfldnam, IStream dif) {
        List<IModule> moduleList = mod.getModules();
        List<String> rows = data.getAttribute(section) == null ? null : ((IStream) data.getAttribute(section)).getRows();
        List<String> l1 = new ArrayList<>();
        List<String> l2 = new ArrayList<>();
        for (IModule iModule : moduleList) {
            if (null != rows && !rows.contains(iModule.getName())) {
                l1.add(iModule.getName());
            }
        }
        if (null != rows) {
            for (String row : rows) {
                if (!moduleList.contains(row)) {
                    l2.add(row);
                }
            }
        }
        addfldnam.setRows(l1);
        dif.setRows(l2);
    }


    //基于字段路径返回相应值
    public static Object basePath2Content(String path) {
        DatafieldImpl datafield = MdaDriver.getDatafield(path);
        if (datafield == null) {
            return null;
        }
        return datafield.getValue();
    }

}

