package com.docus.server.common.netty.server;

import com.docus.core.util.json.JSON;
import com.docus.server.common.CommMsg;
import com.docus.server.common.netty.state.DeviceStateContext;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 采集器id和终端
 * 通信信道的映射
 */
@Component
@Slf4j
public class CollectorChannelCacheMap {

    /**
     * <collectorId-Channel>
     */
    private final static Map<String, Channel> COLLECTOR_ID_CHANNEL_CACHE_MAP = new ConcurrentHashMap<>();

    /**
     * 采集器上线
     */
    public void put(String collectorId, Channel channel) {

        //缓存
        COLLECTOR_ID_CHANNEL_CACHE_MAP.put(collectorId, channel);

        AttributeKey<String> attributeKey = AttributeKey.valueOf("collectorId");
        channel.attr(attributeKey).set(collectorId);
    }

    /**
     * 根据channel获取采集器id
     */
    public String getClientKey(Channel channel) {

        AttributeKey<String> key = AttributeKey.valueOf("collectorId");

        if (channel.hasAttr(key)) {
            return channel.attr(key).get();
        }
        return null;
    }

    public void writeAndFlush(String collectorId, CommMsg commMsg) {
        Channel channel = this.get(collectorId);
        if (null != channel && channel.isOpen()) {
            channel.writeAndFlush(Unpooled.copiedBuffer(JSON.toJSON(commMsg), CharsetUtil.UTF_8));
        }
    }

    public Channel get(String key) {
        return COLLECTOR_ID_CHANNEL_CACHE_MAP.get(key);
    }

    public Map<String, Channel> getAll() {
        return COLLECTOR_ID_CHANNEL_CACHE_MAP;
    }

    /**
     * 终端离线
     */
    public void remove(String key) {
        COLLECTOR_ID_CHANNEL_CACHE_MAP.remove(key);
    }

    /**
     * 设置属性
     *
     * @param ctx   通道上下文
     * @param value 值
     */
    public void setAttribute(ChannelHandlerContext ctx, DeviceStateContext value) {
        Attribute<DeviceStateContext> attribute = getAttribute(ctx);
        attribute.set(value);
    }

    /**
     * 获取属性值
     *
     * @param ctx 通道上下文
     * @return 属性值  有可能为 null
     */
    public DeviceStateContext getAttributeValue(ChannelHandlerContext ctx) {
        Attribute<DeviceStateContext> attribute = getAttribute(ctx);
        DeviceStateContext value = attribute.get();
        return value;
    }

    /**
     * 永远不会返回 null
     *
     * @param ctx channel 上下
     * @return ctx 关联的 channle 的 attribute
     */
    private Attribute<DeviceStateContext> getAttribute(ChannelHandlerContext ctx) {
        return ctx.channel().attr(AttributeKey.valueOf("state"));
    }
}
