package com.tsi.comm.server.process.packet;

import com.tsi.app.common.app.AppUtils;
import com.tsi.comm.server.config.TsiCvimServerConfig;
import com.tsi.comm.server.kafka.KafkaProducerService;
import com.tsi.comm.server.process.AbstractTsiCvimProcess;
import com.tsi.comm.server.process.AbstractTsiCvimWorker;
import com.tsi.comm.server.protocol.AbstractTsiPacket;
import com.tsi.comm.server.repository.TsiNodeManager;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

@Slf4j
@Getter
@Service
public class TsiCvimPacketProcess extends AbstractTsiCvimProcess {

    private final KafkaProducerService kafkaProducerService;

    public TsiCvimPacketProcess(KafkaProducerService kafkaProducerService) {
        this.kafkaProducerService = kafkaProducerService;
    }

    @PostConstruct
    void init() {
        ThreadGroup workerGroup = new ThreadGroup("packetProcess");
        TsiCvimServerConfig tsiCvimServerConfig = (TsiCvimServerConfig) AppUtils.getBean(TsiCvimServerConfig.class);

        this.workers = tsiCvimServerConfig.getPacketWorkers();
        if (this.workers <= 0) this.workers = 1;
        int nodes = TsiNodeManager.getInstance().size();
        int qSize = tsiCvimServerConfig.getQueueSize();
        if (nodes > qSize) {
            qSize = nodes;
        }
        qSize *= 4;
        qSize /= this.workers;
        for (int ii = 0; ii < this.workers; ii++) {
            TsiCvimPacketWorker packetWorker = new TsiCvimPacketWorker(ii, qSize, this.kafkaProducerService);
            this.workerList.add(packetWorker);
            Thread worker = new Thread(workerGroup, packetWorker);
            worker.setName(String.format("pktWorker-%02d.%02d", this.workers, ii+1));
            worker.setDaemon(true);
            this.threadList.add(worker);
        }
        for (Thread worker : this.threadList) {
            worker.start();
        }
    }

    public boolean add(Object object, int idx) {
        boolean offer = false;
        AbstractTsiPacket packet = (AbstractTsiPacket)object;
        try {
            idx = idx % this.workers;
            offer = this.workerList.get(idx).add(packet);
        }
        catch (Exception e) {
            MDC.put("id", Long.toString(packet.getNodeId()));
            log.error("QUEUE_DATA.add: Exception: {}, {}", packet.getNodeId(), e.getMessage());
            MDC.clear();
        }
        return offer;
    }

    public void stop() {

    }

    public void report() {
        for (AbstractTsiCvimWorker worker : this.workerList) {
            worker.report();
        }
    }
}
