package com.tsi.comm.server.repository;

import com.tsi.app.common.utils.Counter;
import com.tsi.app.common.xnet.NettyUtils;
import com.tsi.comm.server.vo.TsiNodeVo;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

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

@Slf4j
public class TsiSessionManager {

    public static final AttributeKey<TsiNodeVo> TSI_NODE_ATTRIBUTE_KEY = AttributeKey.valueOf("TsiNode");

    private static TsiSessionManager _instance = null;

    public static TsiSessionManager getInstance() {
        if (_instance == null) {
            synchronized (TsiSessionManager.class) {
                if (_instance == null)
                    _instance = new TsiSessionManager();
            }
        }
        return _instance;
    }

    private TsiSessionManager() {
        this.sessions = new Counter();
        this.channelNodeMap = new ConcurrentHashMap<>();
    }

    private volatile boolean serverRun;
    private Counter sessions;
    private ConcurrentHashMap<Channel, TsiNodeVo> channelNodeMap;

    public int add() {
        return (int) this.sessions.increment();
    }
    public int remove() {
        return (int) this.sessions.decrement();
    }
    public int get() {
        return (int) this.sessions.get();
    }

    public void addChannel(Channel channel, TsiNodeVo vo) {
        this.channelNodeMap.put(channel, vo);
    }
    public void removeChannel(Channel channel) {
        this.channelNodeMap.remove(channel);
    }

    public TsiNodeVo getNodeVo(Channel channel) {
        return this.channelNodeMap.get(channel);
    }

    public void start() {
        this.serverRun = true;
    }
    public void stop() {
        this.serverRun = false;
    }
    public boolean isServerRun() {
        return this.serverRun;
    }

    public void reportChannelSessions() {
        log.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
        log.info("Report Channel Sessions: {} Sessions.", this.sessions.get());
        log.info("{}", String.format("%10s %7s  Remote-Address", "ID", "Active"));
        log.info("----------------------------------------------------------------------------------------------------------------");
        for (Map.Entry<Channel, TsiNodeVo> obj : this.channelNodeMap.entrySet()) {
            Channel channel = obj.getKey();
            TsiNodeVo node = obj.getValue();
            log.info("{}", String.format("%10s %7s  %s", node.getNodeId(), channel.isActive(), NettyUtils.getRemoteAddress(channel)));
        }
        log.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
    }

}
