package net.northking.cctp.element.internal.protocol.socket.cups8583.internal;

import com.alibaba.fastjson.JSONObject;
import net.northking.cctp.element.core.APIFactory;
import net.northking.cctp.element.core.exception.ComponentRuntimeException;
import net.northking.cctp.element.internal.protocol.socket.cups8583.CupsUtils;
import net.northking.cctp.element.log.Logger;
import org.apache.commons.lang3.ArrayUtils;

import java.nio.charset.Charset;
import java.util.Map;

/**
 * 报文域解码类
 *
 * @author fengxiang.zhang
 * @since 1.0
 */
public class CupsMsgBodyDecoder {

    /**
     * 组件日志
     */
    private Logger logger = APIFactory.getLogger();
    /**
     * 字符集编码
     */
    private Charset charset;
    /**
     * 域定义
     */
    private Map<String, CupsField> defMap;

    public CupsMsgBodyDecoder(Map<String, CupsField> defMap, Charset charset) {
        this.defMap = defMap;
        this.charset = charset;
    }

    /**
     * 响应报文解码
     */
    public Map<String, Object> decode(byte[] bytes) {
        JSONObject bodyFields = new JSONObject(true);
        // 位图解析
        int bitMapLength = CupsUtils.byte2BinaryStr(bytes[0]).charAt(0) == '0' ? 8 : 16;
        byte[] bitMapBytes = ArrayUtils.subarray(bytes, 0, bitMapLength);
        String bitMapStr = CupsUtils.bytes2BinaryStr(bitMapBytes);
        logger.debug("<-- 响应位图Hex:{}, 二进制:{}", CupsUtils.bytes2HexString(bitMapBytes), bitMapStr);
        logger.debug("<-- 响应字段域Hex:{}", CupsUtils.bytes2HexString(ArrayUtils.subarray(bytes, bitMapLength, bytes.length)));

        // 域字段解析
        CupsField f;
        int point = bitMapLength; // 记录当前位置
        for (int i = 1; i < bitMapStr.length(); i++) {
            if (bitMapStr.charAt(i) == '1') {
                f = this.defMap.get((i + 1) + "");
                if (f == null) {
                    throw new ComponentRuntimeException("位元" + (i + 1) + "未定义，请联系管理员");
                }
                byte[] valueBytes = null;
                try {
                    int realAllLen;
                    String value;
                    switch (f.fieldType) {
                        case LLVAR: {
                            int contentLength = Integer.valueOf(new String(bytes, point, 2));
                            realAllLen = 2 + contentLength;
                            valueBytes = new byte[contentLength];
                            System.arraycopy(bytes, point + 2, valueBytes, 0, valueBytes.length);
                            value = new String(valueBytes, this.charset);
                            break;
                        }
                        case LLLVAR: {
                            int contentLength = Integer.valueOf(new String(bytes, point, 3));
                            realAllLen = 3 + contentLength;
                            valueBytes = new byte[contentLength];
                            System.arraycopy(bytes, point + 3, valueBytes, 0, valueBytes.length);
                            value = new String(valueBytes, this.charset);
                            break;
                        }
                        default: {
                            realAllLen = f.length;
                            valueBytes = new byte[realAllLen];
                            System.arraycopy(bytes, point, valueBytes, 0, valueBytes.length);
                            value = new String(valueBytes, this.charset);
                        }
                    }
                    point += realAllLen;
                    addParseSuccessField(bodyFields, f, value);
                } catch (Exception e) {
                    addParseFailField(bodyFields, f, CupsUtils.bytes2HexString(valueBytes), "域解析失败:" + e.getMessage());
                    break;
                }
            }
        }
        return bodyFields;
    }


    public void addParseSuccessField(JSONObject bodyFields, CupsField f, String value) {
        JSONObject json = new JSONObject(true);
        String name =  f.code;
        json.put("domain", name);
        json.put("chName", f.chName);
        json.put("dataValue", value);
        bodyFields.put(name, json);
    }

    public void addParseFailField(JSONObject bodyFields, CupsField f, String hex, String error) {
        JSONObject json = new JSONObject(true);
        String name = f.code;
        json.put("domain", name);
        json.put("chName", f.chName);
        json.put("dataValue", hex);
        bodyFields.put(name, json);
    }

}
