package com.brilliance.isc.common.util;

import cn.hutool.json.JSONObject;
import com.brilliance.isc.bo.Cbb;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.exception.CommonServiceException;
import com.brilliance.isc.common.vo.PtsptaVo;
import com.brilliance.isc.utils.DateUtils;
import com.brilliance.mda.runtime.mda.IStream;
import com.brilliance.mda.runtime.mda.impl.StreamImpl;
import com.brilliance.mda.runtime.mda.util.*;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.brilliance.mda.runtime.mda.Constants.*;

public class Utils {

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

    private static final Map<String, String> tbletyetgMap = new HashMap<>();

    static {
        tbletyetgMap.put("IRT", "G");
        tbletyetgMap.put("ACT", "G");
        tbletyetgMap.put("CUR", "G");
        tbletyetgMap.put("IRS", "G");
        tbletyetgMap.put("FEC", "G");
        tbletyetgMap.put("FEE", "G");
        tbletyetgMap.put("USR", "Y");
        tbletyetgMap.put("ORD", "B");
        tbletyetgMap.put("TRS", "Y");
        tbletyetgMap.put("SMH", "Y");
        tbletyetgMap.put("SPT", "B");
        tbletyetgMap.put("QUE", "B");
        tbletyetgMap.put("PTM", "Y");
        tbletyetgMap.put("USG", "Y");
        tbletyetgMap.put("ACK", "G");
    }

    public static String recGetObj(Object obj) {
        return obj.getClass().getSimpleName().toUpperCase();
    }

    public static String recGetInr(Object obj) {
        Object objInr = getFieldValue(obj, "inr");
        if (objInr == null) {
            return "";
        } else {
            return objInr.toString();
        }
    }

    /**
     * 如果传入的对象 项下包含rec 则返回   obj类名 + “/REC”
     * 否则  ； 如果 argRec 为Sysobj  返回 OBJFULLPATH
     * 否则 返回 argRec的类名大写
     **/
    public static String recGetPath(Object obj) {
        //TD中 固定查询的 rec属性
        if (Utils.existField(obj, "rec")) {
            return obj.getClass().getSimpleName().toUpperCase() + "/REC";
        }
        //TODO 补充SYSOBJ情况
//        if( obj instanceof Sysobj){
//            return ((Sysobj) obj).getObjfullpath();
//        }
        return obj.getClass().getSimpleName().toUpperCase();
    }

    /**
     * 判断对象 obj  是否包含 fieldName 的属性名
     **/
    public static boolean existField(Object obj, String fieldName) {
        int index = -1;
        if (obj == null || StringUtils.isEmpty(fieldName)) {
            return false;
        }
        //获取这个类的所有属性
        Field[] fields = obj.getClass().getDeclaredFields();
        boolean flag = false;
        //循环遍历所有的fields

        for (int i = 0; i < fields.length; i++) {
            if (fields[i].getName().equals(fieldName)) {
                index = i;
                break;
            }
        }
        return index != -1;
    }

//    static Map<Class<?>,Field[]> fieldCache = new ConcurrentHashMap<>();
//    public Field[] getDeclaredFields(Class<?> clazz){
//        if(fieldCache.containsKey(clazz)){
//            return fieldCache.get(clazz);
//        }
//        Field[] fields = clazz.getDeclaredFields();
//        fieldCache.put(clazz,fields);
//        return fields;
//    }

    public static String getLCType(String transName) {
        String simpleTransName = transName.substring(0, 2);
        if ("DI".equals(simpleTransName)
                || "DE".equals(simpleTransName)
                || "BD".equals(simpleTransName)
                || "BF".equals(simpleTransName)) {
            return "D";
        }
        return "";
    }

    /**
     * Actmod.getdsp
     *
     * @param type
     * @return
     */
    public static String getdsp(String type) {
        //----新一代需求---------------
        //   根据选择的账户类型返回账户类型代码
        //
        //  -----------------------------
//        String dsp = type.substring(0, 2);
        String dsp = Strings.mid(type, 0, 2);
        if (MdaUtils.compareTo(dsp, "PA") == 0) {
            dsp = "SP";
        }
        return dsp;
    }

    public static String replaceCRtoChar(String inputtext, String charArg) {
        /*String rtn = "";
        String cr = "";
        IStream stm = new StreamImpl();
        Streams.streamClear(stm);
        Streams.streamSet(stm,inputtext);
        String line = NULLSTR;
        for(int  i = 1;i <= Streams.streamCount(stm);i++)
        {
            line = Strings.getLine(stm,i);
            rtn = rtn + cr + line;
            cr = charArg;
        }
        return  rtn;*/
        return inputtext.replace(CR, charArg);
    }

    public static String replaceChartoCR(String inputtext, String charArg) {
        return inputtext.replace(charArg, CR);
    }

    public static String fmtDate(Date date) {
        return fmtDate(date, "yyyyMMdd");
    }

    public static String fmtDateSwift(Date date) {
        return fmtDate(date, "yyMMdd");
    }

    public static String fmtDate(Date date, String fmt) {
        if (date == null) {
            return "";
        } else {
            SimpleDateFormat format = new SimpleDateFormat(fmt);
            return format.format(date);
        }
    }

    public static String fmtChineseDate(Date date) {
        if (date == null) {
            return "";
        } else {
            return fmtDate(date, "yyyy") + "年" + fmtDate(date, "MM") + "月" + fmtDate(date, "dd") + "日";
        }
    }

    public static Date parseDate(String dateStr) {
        return parseDate(dateStr, "yyyyMMdd");
    }

    public static Date getMaxDate() {
        return parseDate("22991231");
    }

    public static Date getMinDate() {
        return parseDate("19000101");
    }

    public static Date parseDate(String dateStr, String fmt) {
        if (StringUtils.isEmpty(dateStr)) {
            return null;
        } else {
            try {
                SimpleDateFormat format = new SimpleDateFormat(fmt);
                return format.parse(dateStr);
            } catch (ParseException e) {
                throw new CommonServiceException(e.getMessage());
            }

        }
    }

    public static int compareDate(Date date1, Date date2) {
        if (date1 == null && date2 == null) {
            return 0;
        }
        if (date1 == null) {
            return -1;
        }
        if (date2 == null) {
            return 1;
        }
        String date1Str = fmtDate(date1);
        String date2Str = fmtDate(date2);
        return date1Str.compareTo(date2Str);
    }

    /**
     * 增加ETG ETY实体表的关联查询sql语句
     *
     * @param tblName
     * @param argSql
     * @return
     */
    public static String sdbEtyGenSql(String tblName, String argSql) {
        String etFlag = tbletyetgMap.get(tblName);
        String addSql = "";
        if ("G".equals(etFlag)) {
            addSql = "ETGEXTKEY = '" + SettleContext.getUserEtg().getExtkey() + "'";
        } else if ("Y".equals(etFlag)) {
            addSql = "ETYEXTKEY = '" + SettleContext.getUserEty().getExtkey() + "'";
        } else if ("B".equals(etFlag)) {
            addSql = "ETGEXTKEY = '" + SettleContext.getUserEtg().getExtkey() + "'"
                    + " and ETYEXTKEY = '" + SettleContext.getUserEty().getExtkey() + "'";
        }
        return sqlAndCondition(argSql, addSql);
    }

    /**
     * 增加ETG ETY实体表的关联查询sql语句
     *
     * @param tblName
     * @param argSql
     * @return
     */
    public static String sdbEtyGenInsSql(String tblName, String ins, String argSql) {
        String etFlag = tbletyetgMap.get(tblName);
        String addSql = "";
        if ("G".equals(etFlag)) {
            addSql = ins + ".ETGEXTKEY = '" + SettleContext.getUserEtg().getExtkey() + "'";
        } else if ("Y".equals(etFlag)) {
            addSql = ins + ".ETYEXTKEY = '" + SettleContext.getUserEty().getExtkey() + "'";
        } else if ("B".equals(etFlag)) {
            addSql = ins + ".ETGEXTKEY = '" + SettleContext.getUserEtg().getExtkey() + "'"
                    + " and " + ins + ".ETYEXTKEY = '" + SettleContext.getUserEty().getExtkey() + "'";
        }
        return sqlAndCondition(argSql, addSql);
    }

    /**
     * 反射get方法取值
     *
     * @param obj
     * @param fieldName
     * @return
     */
    public static Object invokeGetMethod(Object obj, String fieldName) {
        String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        try {
            Class<?> clazz = obj.getClass();
            Method method = clazz.getDeclaredMethod(methodName, null);
            if (method != null) {
                return method.invoke(obj, null);
            }
        } catch (Exception e) {
            //throw new CommonServiceException(e.getMessage());
            return null;
        }
        return null;
    }

    /**
     * 通过反射 得到对象属性值 (多层用//表示)
     *
     * @param obj
     * @param fieldName
     * @return
     */
    public static <T> T getFieldValue(Object obj, String fieldName) {
        if (obj == null || StringUtils.isEmpty(fieldName)) {
            return null;
        }
        T getObj = (T) obj;
        String[] paths = fieldName.split("//");
        for (int i = 0; i < paths.length; i++) {
            getObj = (T) invokeGetMethod(getObj, paths[i]);
        }
        return getObj;
    }

    public static <T> T getFieldValue(Object obj, String fieldName, T defaultValue) {
        T val = getFieldValue(obj, fieldName);
        return val == null ? defaultValue : val;
    }

    public static void setFieldValue(Object rec, String name, Object value) {
        try {
            BeanUtils.setProperty(rec, name, value);
        } catch (Exception e) {
            log.warn("setFieldValue exception: rec:{},name:{}", rec, name);
        }
    }


    public static String firstUpper(String s) {
        return s.length() == 1 ? s.toUpperCase() : s.substring(0, 1).toUpperCase() + s.substring(1);
    }


    /**
     * 通过反射为实体类设置 etgextkey 和 etyextkey
     *
     * @param obj
     * @param objType
     * @param argEtg  如果原始入参是“” ，替换为SettleContext.getUserEtg().getExtkey()
     * @param argEty  如果原始入参是“” ，替换为SettleContext.getUserEty().getExtkey()
     */
    public static void sdbEtySetRec(Object obj, String objType, String argEtg, String argEty) {
        if (obj == null) {
            return;
        }
        String etFlag = tbletyetgMap.get(objType);
        if (StringUtils.isEmpty(etFlag)) {
            return;
        }
        try {
            Class<?> clazz = obj.getClass();
            if ("G".equals(etFlag) && StringUtils.isNotEmpty(argEtg)) {
                String methodName = "setEtgextkey";
                Method method = clazz.getDeclaredMethod(methodName, String.class);
                if (method != null) {
                    method.invoke(obj, argEtg);
                }
            } else if ("Y".equals(etFlag) && StringUtils.isNotEmpty(argEty)) {
                String methodName = "setEtyextkey";
                Method method = clazz.getDeclaredMethod(methodName, String.class);
                if (method != null) {
                    method.invoke(obj, argEty);
                }
            } else if ("B".equals(etFlag)) {
                if (StringUtils.isNotEmpty(argEtg)) {
                    String methodName = "setEtgextkey";
                    Method method = clazz.getDeclaredMethod(methodName, String.class);
                    if (method != null) {
                        method.invoke(obj, argEtg);
                    }
                }
                if (StringUtils.isNotEmpty(argEty)) {
                    String methodName = "setEtyextkey";
                    Method method = clazz.getDeclaredMethod(methodName, String.class);
                    if (method != null) {
                        method.invoke(obj, argEty);
                    }
                }
            }
        } catch (NoSuchMethodException e) {
            throw new CommonServiceException(e.getMessage());
        } catch (InvocationTargetException e) {
            throw new CommonServiceException(e.getMessage());
        } catch (IllegalAccessException e) {
            throw new CommonServiceException(e.getMessage());
        }
    }

    public static String sqlAndCondition(String argSql, String argCon) {
        //! function to put a condition above an existing condition.
        //! ArgSql holds the combined sql condition incl. a potential leading where clause
        //! (Normaly the base condition)
        //! ArgCon holds the condition which should be logically put above the condition described in the SQL.
        //! (Normally the multientity selector condition created by SdbEtyGenInsSql or SdbEtyGenTblSql)
        //! The function returns a SQL condition incl. a leading where clause with optional parenthesis around the existing sql and logically ANDed condition.
        boolean argWhrFlg = false;
        if (!StringUtils.isEmpty(argSql) && (argSql.startsWith("WHERE") || argSql.startsWith("where"))) {
            argWhrFlg = true;
        } else {
            argWhrFlg = false;
        }
        String sql = "";
        if (StringUtils.isEmpty(argCon)) {
            if (argWhrFlg || StringUtils.isEmpty(argSql)) {
                // if the passed sql is empty or already holds the where clause
                // the argument is directly returned
                sql = StringUtils.trim(argSql);
            } else {
                // if no where was passed it has to be added
                sql = "WHERE " + StringUtils.trim(argSql);
            }
        } else {
            // If one of the two fields exists, the necessary query has to be
            // inserted after the leading where, if it exists, or at the
            // beginning of the query, if no where clause exists.
            // In both cases the rest of the command has to be put into brakets.
            if (argWhrFlg) {
                sql = "WHERE " + argCon + " and ( " + argSql.substring(5) + " )";
            } else {
                if (MdaUtils.isEmpty(argSql)) {
                    sql = "WHERE " + argCon;
                } else {
                    sql = "WHERE " + argCon + " and ( " + StringUtils.trim(argSql) + " )";
                }
            }
        }
        return sql;

    }

    public static String dbSqlDate(Date date) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        StringBuilder builder = new StringBuilder();
        //oracle 语法
//        builder.append(" to_date('").append(df.format(date)).append("','YYYY-MM-DD')");
        //mysql 语法
        builder.append(" date_format('").append(df.format(date)).append("','%y%m%d')");
        return builder.toString();
    }

    public static String sdbRngSelectValidInRange(String table, Date beginDate, Date endDate, String objinr, String objtyp, String otherArgSql) {
        String begSql = "";
        if (beginDate != null) {
            begSql = "( BEGDAT <= " + Utils.dbSqlDate(beginDate) + " AND ENDDAT > " + Utils.dbSqlDate(beginDate) + " )";
        }
        String endSql = "";
        if (endDate != null) {
            endSql = "( BEGDAT <= " + Utils.dbSqlDate(endDate) + " AND ENDDAT > " + Utils.dbSqlDate(endDate) + " )";
        }
        String rngSql = "( ";
        String and = "";
        if (beginDate != null) {
            rngSql = rngSql + " BEGDAT >= " + Utils.dbSqlDate(beginDate);
            and = " AND ";
        }
        if (endDate != null) {
            rngSql = rngSql + and + " ENDDAT <= " + Utils.dbSqlDate(endDate);
        } else {
            rngSql = rngSql + and + " ENDDAT <= " + Utils.dbSqlDate(parseDate("22991231"));
        }
        rngSql = rngSql + " )";
        String argSql = "OBJINR = '" + objinr + "' AND OBJTYP = '" + objtyp + "'";
        String sql = Utils.sdbEtyGenSql(table.toUpperCase(), argSql + otherArgSql);
        sql += " And ( " + begSql + " Or " + endSql + " Or " + rngSql + " ) ORDER BY BEGDAT, INR";
        return sql;
    }

    public static void getTabValues(IStream stm, String valList) {
        int lastTabPos = 0;
        int nxtTabPos = Strings.pos(Strings.mid(valList, lastTabPos + 1, Strings.len(valList)), TAB);
        int cnt = 0;
        String val = NULLSTR;
        while (nxtTabPos > 0 && nxtTabPos < Strings.len(valList) || cnt > 30) {
            val = Strings.mid(valList, lastTabPos + 1, nxtTabPos - 1);
            Streams.streamInsert(stm, 0, val);
            lastTabPos = lastTabPos + nxtTabPos;
            nxtTabPos = Strings.pos(Strings.mid(valList, lastTabPos + 1, Strings.len(valList)), TAB);
            cnt = cnt + 1;
        }
    }

    /**
     * source:actmod.0005.script
     */
    public static boolean isAccountTypNostro(String argtyp) {
        if (StringUtils.isEmpty(argtyp)) {
            return false;
        }
        if (argtyp.startsWith("N")) {
            return true;
        } else {
            return false;
        }
    }

    public static String fmtAmountSwift(BigDecimal amt, String cur) {
        BigDecimal absAmt = Numerics.abs(amt);
        String dectxt = NULLSTR;
        if (Decimals.remainderOne(absAmt).compareTo(BigDecimal.ZERO) == 0) {
            dectxt = "";
        } else {
            dectxt = fmtAmount(Decimals.remainderOne(absAmt), cur);
            dectxt = Strings.mid(dectxt, 3, Strings.len(dectxt) - 2);
        }
        if (MdaUtils.compareTo(amt, 0) < 0) {
            SettleExceptionUtils.sysDump("TRNMOD.FmtAmountSwift: Called with a negative amount ");
        } else {
            return MdaUtils.toString(Numerics.floor(absAmt)) + "," + dectxt;
        }
        return NULLSTR;
    }

    public static String fmtAmountPdf(BigDecimal fmtamtold, String cur) {
        BigDecimal fmtamt = fmtamtold.setScale(2, RoundingMode.HALF_UP);//保留两位小数
        if (fmtamt == null) {
            fmtamt = BigDecimal.ZERO;
        }
        String minus = NULLSTR;
        if (fmtamt.compareTo(BigDecimal.ZERO) < 0) {
            BigDecimal temp = BigDecimal.ZERO;
            temp = fmtamt.abs();
            fmtamt = temp;
            minus = "-";
        }
        String amt = fmtamt.toPlainString();
        String intVal;
        String fractionVal;
        if (amt.contains(".")) {
            String[] split = amt.split("\\.");
            intVal = split[0];
            fractionVal = split[1];
        } else {
            intVal = amt;
            fractionVal = "00";
        }

        int length = intVal.length();
        int num = length / 3;
        int md = length % 3;
        StringBuilder sb = new StringBuilder();
        sb.append(intVal, 0, md);

        for (int i = 0; i < num; ++i) {
            if (md != 0 || i != 0) {
                sb.append(",");
            }
            sb.append(intVal, 3 * i + md, 3 * (i + 1) + md);
        }
        if (!"JPY".equals(cur)) {
            sb.append(".").append(fractionVal);
        }
        return minus + sb.toString();
    }

    public static String fmtAmount(BigDecimal fmtamt, String cur) {
        if (fmtamt == null) {
            fmtamt = BigDecimal.ZERO;
        }
        String minus = NULLSTR;
        if (fmtamt.compareTo(BigDecimal.ZERO) < 0) {
            BigDecimal temp = BigDecimal.ZERO;
            temp = fmtamt.abs();
            fmtamt = temp;
            minus = "-";
        }
        String amt = fmtamt.toPlainString();
        String intVal;
        String fractionVal;
        if (amt.contains(".")) {
            String[] split = amt.split("\\.");
            intVal = split[0];
            fractionVal = split[1];
            //新国结保留两位小数
            fractionVal = fractionVal.length() > 2 ? fractionVal.substring(0, 2) : fractionVal;
        } else {
            intVal = amt;
            fractionVal = "00";
        }

        int length = intVal.length();
        int num = length / 3;
        int md = length % 3;
        StringBuilder sb = new StringBuilder();
        sb.append(intVal, 0, md);

        for (int i = 0; i < num; ++i) {
            if (md != 0 || i != 0) {
                sb.append(",");
            }
            sb.append(intVal, 3 * i + md, 3 * (i + 1) + md);
        }
        if (!"JPY".equals(cur)) {
            sb.append(".").append(fractionVal);
        }
        return minus + sb.toString();
    }

    public static String formatAmt4Swt(BigDecimal amt, String ccy) {
        if (amt == null) {
            throw new RuntimeException("Source Amt cannot be null.");
        }
        IStream currndinf = new StreamImpl();
        String curblk = Inis.getIniBlock("TDPARA.INI", "CURRENCY", "CURRENCY");
        Streams.streamSet(currndinf, curblk);
        int line = Streams.streamSearch(currndinf, ccy);
        int places = 0;
        if (line > 0) {
            places = Strings.parseInt(Strings.mid(Strings.getLine(currndinf, line), 24, 1));
        } else {
            places = 2;
        }
        // Round argument according to decimal places
        amt = Numerics.round(amt, places);
        String amtStr = amt.toPlainString();
        String pointSuffiex = ".";
        for (int i = 0; i < places; i++) {
            pointSuffiex += "0";
        }
        if (amtStr.indexOf(pointSuffiex) > -1) { //like 1000.00 -> 1000,
            return amtStr.replace(pointSuffiex, ",");
        } else {
            // JPY1300 -> JPY1300,
            if (amtStr.indexOf(".") == -1) {
                return amtStr + ",";
            } else {
                return amtStr.replace(".", ",");//like 1000.01 -> 1000,01
            }
        }
    }

    public static String fmtTime(BigDecimal argNum) {
        //取得上下文
//        IContext ctx = MdaEnv.getContext();
//        ctx.setErrorCode(NO_ERROR);
        //! returns the passed number in displayable time format
        //!
        //! ArgNum is the time in format hh,mmss
        //!
        //! the result is a text in format hh:mm:ss
        //!
        //! Corresponding function: FmtTimeShort
        int num = Numerics.toInt(Decimals.mul(argNum, 1000000));
        String time = MdaUtils.toString(num, -8);
        return Strings.mid(time, 1, 2) + ":" + Strings.mid(time, 3, 2) + ":" + Strings.mid(time, 5, 2);

    }

    public static String getPathofName(String argPth) {
        //! Function to extract the path portion of a filename or a field reference.
        //! The part of the string up to the last Backslash is returned.
        //! On absolute names the leading backslash is not eliminated.
        //! If no backslash is found an empty string is returned.
        //!
        //! Corresponding functions: AddExtensionToName, AddNodeToPath, GetLastNode, Basename (TradeDesign function), GetFileExtension, GetNormalizedNodename
        // search for a backslash starting at the end
        String chr = NULLSTR;
        for (int idx = Strings.len(argPth); idx >= 1; idx--) {
            chr = Strings.mid(argPth, idx, 1);
            if (MdaUtils.compareTo(chr, "\\") == 0 || MdaUtils.compareTo(chr, "/") == 0) {
                if (idx > 1) {
                    // return all characters up to the character before the found backslash
                    return Strings.trim(Strings.mid(argPth, 1, idx - 1));
                } else {
                    // if the only backslash is the first character, return it
                    return chr;
                }
            }
        }
        // When no backslash is found, return an empty path
        return "";
    }


    public static String toJson(Object dataMap) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writeValueAsString(dataMap);
        } catch (Exception e) {
            log.error("转换JSON异常", e);
        }
        return "";
    }

    public static String toPrettyJson(Object dataMap) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(dataMap);
        } catch (Exception e) {
            log.error("转换JSON异常", e);
        }
        return "";
    }

    public static <T> List<T> toListObject(Class<T> clazz, String dataString) {
        if (StringUtils.isEmpty(dataString)) {
            return null;
        }
        try {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.readValue(dataString, mapper.getTypeFactory().constructParametricType(List.class, clazz));
        } catch (JsonMappingException e) {
            throw new CommonServiceException(e.getMessage());
        } catch (JsonProcessingException e) {
            throw new CommonServiceException(e.getMessage());
        }
    }

    public static <T> T toObject(Class<T> clazz, String dataString) {
        if (StringUtils.isEmpty(dataString)) {
            return null;
        }
        try {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.readValue(dataString, clazz);
        } catch (JsonMappingException e) {
            throw new CommonServiceException(e.getMessage());
        } catch (JsonProcessingException e) {
            throw new CommonServiceException(e.getMessage());
        }
    }

    public static String getModuleInfoFullName(String module) {
        String fullName = "";
        switch (module) {
            case "FECISM":
                fullName = "";
                break;
            default:
                fullName = "";
                break;
        }
        return fullName;
    }

    public static String getBchkinrList(String arg) {
        // search for single quotes as they have to be doubled
        int pos = Strings.pos(arg, "|");
        int nxt = pos;
        while (nxt > 0) {
            arg = Strings.mid(arg, 1, pos - 1) + "'" + "," + "'" + Strings.mid(arg, pos + 1);
            nxt = Strings.pos(Strings.mid(arg, pos + 2), "|");
            pos = pos + nxt + 1;
        }
        return "'" + arg + "'";
    }

    public static String getIniStr(String argFil, String argSec, String argLab) {
        //! Function to get an INI-File entry and put it into the cache for further usage without
        //! further access to the ini-file.
        //! ArgFil
        //! ArgSec
        //! ArgLab
        String rtn = "";
        String fil = Strings.toLower(argFil);
        String sec = Strings.toLower(argSec);
        String lab = Strings.toLower(argLab);
        return Inis.getIniStr(fil, sec, lab);
    }

    public static <T> Optional<T> getField(Object obj, String fildName) {
        Object res = null;
        try {
            res = BeanUtils.getProperty(obj, fildName.toLowerCase());
        } catch (Exception e) {
            return Optional.empty();
        }
        return Optional.ofNullable((T) res);
    }

    public static <T> T loadData(Class<T> clazz, 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()) {
                try {
                    String dataString = stream.getLine(i + 1);
                    ObjectMapper mapper = new ObjectMapper();
                    return mapper.readValue(dataString, clazz);
                } catch (JsonMappingException e) {
                    throw new CommonServiceException(e.getMessage());
                } catch (JsonProcessingException e) {
                    throw new CommonServiceException(e.getMessage());
                }
            }
        }
        return null;
    }

    public static void saveData(Object object, IStream stream, String section, String prefix) {
        if (MdaUtils.isEmpty(section) && prefix.equals("")) {
            section = "DEFAULT";
        } else {
            section = prefix;
        }
        String tempValue = toJson(object);
        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 String getBoType(Object bo) {
        return bo == null ? "" : bo.getClass().getSimpleName().toUpperCase();
    }

    public static String getMapperName(Object bo) {
        if (bo == null) {
            return null;
        }
        return firstUpper(bo.getClass().getSimpleName().toLowerCase()) + "Mapper";
    }


    public static String addNodeToPath(String argPth, String argNode) {
        String path = NULLSTR;
        String chr = NULLSTR;
        if (MdaUtils.isEmpty(argNode)) {
            path = Strings.trim(argPth);
        } else {
            // Get the last character of path
            argNode = argNode.toUpperCase().replace("\\", Files.separator);
            chr = Strings.mid(argPth, Strings.len(argPth), 1);
            if (MdaUtils.compareTo(chr, "\\") == 0 || MdaUtils.compareTo(chr, "/") == 0) {
                path = Strings.trim(argPth) + Strings.trim(argNode);
            } else {
                if (MdaUtils.isEmpty(argPth)) {
                    path = Strings.trim(argNode);
                } else {
                    // determine the delimiter used
                    path = Strings.trim(argPth) + Files.separator + Strings.trim(argNode);
                }
            }
        }
        // Check for trailing delimiter
        chr = Strings.mid(path, Strings.len(path), 1);
        if (MdaUtils.compareTo(chr, "\\") == 0 || MdaUtils.compareTo(chr, "/") == 0) {
            path = Strings.mid(path, 1, Strings.len(path) - 1);
        }
        return path;

    }

    public static String getFileWithoutPrefix(String argNam) {
        //! The function strips leading "server:", "client:" and "db:" from ArgNam
        String pfx = Strings.toLower(Strings.mid(argNam, 1, 7));
        if ((MdaUtils.compareTo(pfx, "server:") == 0) || (MdaUtils.compareTo(pfx, "client:") == 0)) {
            return Strings.trim(Strings.mid(argNam, 8));
        } else {
            if (MdaUtils.compareTo(Strings.mid(pfx, 1, 3), "db:") == 0) {
                return Strings.trim(Strings.mid(argNam, 4));
            } else {
                return Strings.trim(argNam);
            }
        }

    }

    public static boolean ptsIsPtaAdrRequired(String argrol) {
        if (MdaUtils.compareTo(argrol, "OTH") == 0 &&
                MdaUtils.compareTo(Strings.mid(SettleContext.getTransName(), 4, 3), "FRE") == 0) {
            return false;
        } else {
            return true;
        }
    }

    public static Object getFieldValueByObject(Object object, String targetFieldName) throws Exception {

        // 获取该对象的Class
        Class objClass = object.getClass();

        // 初始化返回值
        Object result = null;

        // 获取所有的属性数组
        Field[] fields = objClass.getDeclaredFields();
        for (Field field : fields) {
            // 属性名称
            String currentFieldName = "";
            // 获取属性上面的注解 import com.fasterxml.jackson.annotation.JsonProperty;
            try {
                boolean has_JsonProperty = field.isAnnotationPresent(JsonProperty.class);

                if (has_JsonProperty) {
                    currentFieldName = field.getAnnotation(JsonProperty.class).value();
                } else {
                    currentFieldName = field.getName();
                }

                if (currentFieldName.equals(targetFieldName)) {
                    field.setAccessible(true);
                    result = field.get(object);

                    return result; // 通过反射拿到该属性在此对象中的值(也可能是个对象)
                }

            } catch (SecurityException e) {
                // 安全性异常
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // 非法参数
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // 无访问权限
                e.printStackTrace();
            }
        }

        return result;
    }

    public static String cacheGetIniStr(String argFil, String argSec, String argLab) {
        String rtn = "";
        String fil = Strings.toLower(argFil);
        String sec = Strings.toLower(argSec);
        String lab = Strings.toLower(argLab);
        rtn = Inis.getIniStr(fil, sec, lab);
        return rtn;
    }


    public static String replacealltrndoc(String argtxt, String frmtxt, String totxt) {
        //!use totxt replace argtxt contain all frmtxt,
        int pos = Strings.pos(argtxt, frmtxt);
        while (pos > 0) {
            argtxt = Strings.mid(argtxt, 1, pos - 1) + totxt + Strings.mid(argtxt, pos + Strings.len(frmtxt));
            pos = Strings.pos(argtxt, frmtxt);
        }
        return argtxt;
    }

    public static void streamSave(IStream stream, String fileName) {
        try {
            fileName = Strings.convertPrefix(fileName);
            File file = Files.mkdirs(fileName);
            stream.saveLines(file);
        } catch (Exception var3) {
            log.error("streamSave error.", var3);
        }
    }

    //通过工具类获取cbe，若通过map.get获取的cbe为null则默认new一个对象
    public static Cbb getCbeByCbsMap(Map<String, Cbb> cbsMap, String var1) {
        Cbb cbb = cbsMap.get(var1);
        if (cbb == null && !cbsMap.containsKey(var1)) {
            cbb = new Cbb();
        }
        return cbb;
    }

    public static String replacePath(String filPath) {
        if (StringUtils.isEmpty(filPath))
            return "";
        return filPath.replaceAll("\\\\", "/");
    }

    public static Object getObjectByMap(String className, Map<String, Object> objectMap) {
        try {
            Class clazz = Class.forName(className);
            objectMap.remove("modifySet");
            JSONObject json = new JSONObject(objectMap);
            Object obj = toObject(clazz, json.toString());
            //utils直接转换日期格式有问题
//            Object obj = clazz.newInstance();
//            objectMap.entrySet().stream().forEach(e->{
//                Utils.setFieldValue(obj,e.getKey(),e.getValue());
//            });
            return obj;
        } catch (Exception e) {
            throw new CommonServiceException(e.getMessage());
        }
    }

    public static List<Object> getObjectByListMap(String className, List<Map<String, Object>> objectList) {
        List<Object> list = new ArrayList<>();
        objectList.forEach(item -> {
            try {
                Class clazz = Class.forName(className);
                Object obj = clazz.newInstance();
                item.entrySet().stream().forEach(e -> {
                    Utils.setFieldValue(obj, e.getKey(), e.getValue());
                });
                list.add(obj);
            } catch (Exception e) {
                throw new CommonServiceException(e.getMessage());
            }
        });
        return list;
    }

    public static boolean isEmpty(Object object) {
        //用于对象INR判空和数组 size=0判空处理
        if (object == null)
            return true;
        if ((object instanceof Collection)) {
            if (((Collection<?>) object).size() == 0) {
                return true;
            } else {
                return ((Collection) object).isEmpty();
            }
        }
        if (StringUtils.isEmpty(getFieldValue(object, "inr"))) {
            return true;
        }
        return false;
    }

    public static String convertDateToWords(Date date) {
        if (date == null) {
            return "";
        }
        // 格式化日期
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MMMM.yyyy", Locale.ENGLISH);
        String formattedDate = dateFormat.format(date);
        return formattedDate;
    }


    public static String ptsmodGetAdrLine(PtsptaVo argptspta) {
        //! returns the Addressline of address ARGPTSPTA delimited by ","
        String res = "";
        String dlm = "";
        IStream adrstm = new StreamImpl();
        Streams.streamSet(adrstm, argptspta.getPts().getAdrblk());
        int cnt = Streams.streamCount(adrstm);
        String lin = NULLSTR;
        for (int i = 1; i <= cnt; i++) {
            lin = Strings.getLine(adrstm, i);
            if (!MdaUtils.isEmpty(lin)) {
                res = res + dlm + lin;
                dlm = ", ";
            }
        }
        return res;
    }

    public static String adrLine1(String adrblk) {
        String res = " ";
        int v2 = 0;
        String dlm = NULLSTR;
        for (int i = 1; i <= 4; i++) {
            v2 = v2 + 1;
            if (!MdaUtils.isEmpty(Strings.getLine(adrblk, i))) {
                dlm = " ";
                if (v2 > 1) {
                    dlm = ", ";
                } else {
                    dlm = " ";
                }
                res = res + dlm + Strings.getLine(adrblk, i);
            }
        }
        return Strings.trim(res);

    }

    //计算日期
    public static Date calcDate(Date argDate, int unt, String pertyp, String calcType) {
        Date date = argDate;
        if (StringUtils.isNotEmpty(pertyp) && unt > 0) {
            if ("start".equals(calcType)) {
                switch (pertyp) {
                    //case "n":
                    case "d":
                        date = DateUtils.addDays(argDate, -unt);
                        break;
                    case "m":
                        date = DateUtils.addDays(argDate, -(unt * 30));
                        break;
                    case "CALQTR":
                        date = DateUtils.addDays(argDate, -(unt * 90));
                        break;
                    case "y":
                        date = DateUtils.addMonths(argDate, -(unt * 12));
                        break;
                    case "CALMON":
                        date = DateUtils.addMonths(argDate, -unt);
                        break;
                    case "q":
                        date = DateUtils.addMonths(argDate, -(unt * 3));
                        break;
                    case "DURHLF":
                        date = DateUtils.addMonths(argDate, -(unt * 6));
                        break;
                }
            } else {
                switch (pertyp) {
                    //case "n":
                    case "d":
                        date = DateUtils.addDays(argDate, unt);
                        break;
                    case "m":
                        date = DateUtils.addDays(argDate, (unt * 30));
                        break;
                    case "CALQTR":
                        date = DateUtils.addDays(argDate, (unt * 90));
                        break;
                    case "y":
                        date = DateUtils.addMonths(argDate, (unt * 12));
                        break;
                    case "CALMON":
                        date = DateUtils.addMonths(argDate, unt);
                        break;
                    case "q":
                        date = DateUtils.addMonths(argDate, (unt * 3));
                        break;
                    case "DURHLF":
                        date = DateUtils.addMonths(argDate, (unt * 6));
                        break;
                }
            }
        }
        return date;
    }

    //计算份数
    public static int calcUnt(Date from, Date till, String pertyp) {
        int unit = 0;
        if (com.brilliance.isc.utils.StringUtils.isNotEmpty(pertyp)) {
            if ("d".equals(pertyp)) {
                //与日期无关 或者 周期类型 days
                unit = Dates.diff(till, from);
            } else {
                int per = Dates.diff(till, from);
                if ("m".equals(pertyp)) {
                    //周期类型 30天
                    unit = Numerics.ceil(Decimals.div(per, 30));
                    if (unit == 0) {
                        unit = 1;
                    }
                } else if ("CALQTR".equals(pertyp)) {
                    //周期类型 90天
                    unit = Numerics.ceil(Decimals.div(per, 90));
                    if (unit == 0) {
                        unit = 1;
                    }
                } /*else if ("y".equals(pertyp)) {
                    //周期类型 360天
                    unit = Numerics.ceil(Decimals.div(per, 360));
                }*/ else {
                    Date beginDate = from;
                    while (compareDate(beginDate, till) < 0) {
                        unit += 1;
                        int one = 1;
                        if ("CALMON".equals(pertyp)) {
                            //周期类型 日历月
                            one = 1;
                        } else if ("q".equals(pertyp)) {
                            //周期类型 日历季
                            one = 3;
                        } else if ("DURHLF".equals(pertyp)) {
                            //周期类型 日历6个月
                            one = 6;
                        } else if ("y".equals(pertyp)) {
                            //周期类型 日历年
                            one = 12;
                        }
                        beginDate = DateUtils.addMonths(from, one * unit);
                    }
                }
            }
        }
        return unit;
    }

    public static <T> Map<String, Object> convertObjectToMap(T object) {
        if (object instanceof Map) {
            Map<?, ?> objMap = (Map<?, ?>) object;
            Map<String, Object> map = new HashMap<>();
            for (Map.Entry<?, ?> entry : objMap.entrySet()) {
                if (entry.getKey() instanceof String) {
                    String key = (String) entry.getKey();
                    Object value = entry.getValue();
                    map.put(key, value);
                }
            }
            return map;
        }
        throw new IllegalArgumentException("Object is not of type Map");
    }

    /**
     * 获取对象制定位置的注解
     *
     * @param object javabean
     * @param path   指定路径
     * @param anno   注解类
     * @param <T>    具体注解的泛型
     * @return 注解实例
     */
    public static <T extends Annotation> T getTargetFieldAnnotationByPath(Object object, String path, Class<T> anno) {
        Field field = getTargetFieldByPath(object, path);
        if (field != null && field.isAnnotationPresent(anno)) {
            return field.getAnnotation(anno);
        }
        return null;
    }

    /**
     * 获取对象制定位置的Field，常用语展报
     *
     * @param object javabean
     * @param path   指定路径
     * @return 字段field
     */
    public static Field getTargetFieldByPath(Object object, String path) {
        int idx = path.indexOf('.');
        if (idx < 0) {
            idx = path.indexOf('/');
        }
        String filedName = null;
        if (idx > 0) {
            filedName = path.substring(0, idx);

        } else {
            filedName = path;
        }
        try {
            Field field = object.getClass().getDeclaredField(filedName);
            field.setAccessible(true);
            if (idx > 0) {
                Object subObject = field.get(object);
                if (subObject instanceof Collection) {
                    subObject = CollectionUtils.get(subObject, 0);
                } else if (subObject instanceof Object[]) {
                    subObject = Array.get(subObject, 0);
                }
                return getTargetFieldByPath(subObject, path.substring(idx + 1));
            } else {
                //递归出口，
                return field;
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            return null;
        }
    }

    public static Long fmtAmtToWgLong(BigDecimal amt) {
        if (amt == null) {
            return 0L;
        } else {
            return amt.multiply(new BigDecimal(100)).longValue();
        }
    }

    public static String changeWgAmt(Long amt, String cur) {
        if (amt == null) {
            return "0.00";
        } else {
            BigDecimal newamt = (new BigDecimal(String.valueOf(amt))).divide(new BigDecimal(100));
            if (cur != null) {
                return fmtAmount(newamt, cur);
            } else {
                return (new BigDecimal(String.valueOf(amt))).divide(new BigDecimal(100)).toPlainString();
            }
        }
    }
}
