package com.its.pis.xnetudp.codec;

import com.its.app.AppUtils;
import com.its.app.utils.SysUtils;
import com.its.pis.config.ProcessConfig;
import com.its.pis.entity.TbUnitSyst;
import com.its.pis.service.UnitSystService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageEncoder;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class CenterCommClientEncoder extends MessageToMessageEncoder<Object> {

	private String remoteIpAddr;
	private int remotePort;

	public CenterCommClientEncoder(String hostIp, int hostPort) {
		this.remoteIpAddr = hostIp;
		this.remotePort = hostPort;
	}

	@Override
	protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {

		ProcessConfig processConfig = (ProcessConfig) AppUtils.getBean(ProcessConfig.class);

		Channel channel = ctx.channel();
		if (!channel.isOpen()) {
			log.error("SEND: Channel Closed.");
		}
		if (!channel.isActive()) {
			log.error("SEND: Channel InActive.");
			channel.flush();
			return;
		}

		if (!(msg instanceof ByteBuffer)) {
			log.error("SEND: Encoding Data source Unknown Type.");
			return;
		}

		int sendBytes = ((ByteBuffer) msg).array().length;
		if (this.remoteIpAddr == null) {
			log.info("SEND: [ALL], {} Bytes.", sendBytes);
		}
		else {
			log.info("SEND: [{}:{}], {} Bytes.", this.remoteIpAddr, this.remotePort, sendBytes);
		}

		if (processConfig.isCenterDump()) {
			log.info("SEND DUMP: {}", SysUtils.byteArrayToHex(((ByteBuffer) msg).array()));
		}

		// 브로드 캐스팅(모든 운영단말로 전송) 및 개별 메시지 응답
		UnitSystService unitSystService = (UnitSystService) AppUtils.getBean(UnitSystService.class);
		ConcurrentHashMap<String, TbUnitSyst> untiSystMap = unitSystService.getUnitSystMap();
		for (Map.Entry<String, TbUnitSyst> e : untiSystMap.entrySet()) {
			if (this.remoteIpAddr == null || this.remoteIpAddr.equals(e.getValue().getSYST_IP_1())) {
				try {
					ByteBuf byteBuf = Unpooled.buffer(sendBytes);
					byteBuf.writeBytes(((ByteBuffer) msg).array());
					InetSocketAddress addr = new InetSocketAddress(e.getValue().getSYST_IP_1(), e.getValue().getPRGM_PORT());
					DatagramPacket packet = new DatagramPacket(byteBuf, addr);
					out.add(packet);
					if (this.remoteIpAddr == null) {
						log.debug("SEND: [{}] [{}:{}], {} Bytes. OK....", e.getValue().getSYST_ID(), e.getValue().getSYST_IP_1(), e.getValue().getPRGM_PORT(), sendBytes);
					}
					else {
						log.info("SEND: [{}] [{}:{}], {} Bytes. OK....", e.getValue().getSYST_ID(), e.getValue().getSYST_IP_1(), e.getValue().getPRGM_PORT(), sendBytes);
					}
				} catch (Exception e2) {
					log.error("SEND: [{}] [{}:{}], {} Bytes. Failed. Exception: {}", e.getValue().getSYST_ID(), e.getValue().getSYST_IP_1(), e.getValue().getPRGM_PORT(), sendBytes, e2.toString());
				}
			}
		}
	}
}
