package com.munjaon.client.server.service;

import com.munjaon.client.model.MunjaonMsg;
import com.munjaon.client.server.config.ErrorCode;
import com.munjaon.client.server.packet.*;
import com.munjaon.client.service.DatabaseTypeWorker;
import com.munjaon.client.util.MessageCheckUtil;
import com.munjaon.client.util.MessageUtil;
import org.json.simple.JSONObject;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;

public class CollectClientService extends Service {
    /* 서비스 타입
    * RunnerConfiguration에서 서비스 타입 지정
    * SMS, LMS, MMS, KAT, KFT
    *  */
    private final String serviceType;
    private DatabaseTypeWorker worker;      // 서비스 타입별 DAO 호출
    private SocketChannel socketChannel;    // 클라이언트 SocketChannel
    private long lastPacketSendTime = 0;    // 마지막 패킷을 전송 및 응답 시간
    private String address;                 // 서비스별 서버 주소
    private int port;                       // 서비스별 포트 정보
    private String id;                      // 접속 아이디
    private String pwd;                     // 접속 비밀번호

    private List<String> deliverList = null;
    private boolean IS_ERROR = false;

    public CollectClientService(String serviceName, String serviceType) {
        super(serviceName);
        this.serviceType = serviceType;
    }

    /**
     * DBMS 테이블 생성여부 확인
     */
    @Override
    public void checkReady() {
        worker = DatabaseTypeWorker.find(System.getProperty("DBMS"));
        if (worker == null) {
            saveSystemLog("[checkReady][DBMS : " + System.getProperty("DBMS") + " is not ready]");
            return;
        }

        this.IS_READY_YN = worker.checkTableExists();
        if (this.IS_READY_YN) {
            saveSystemLog("[checkReady][DBMS : " + System.getProperty("DBMS") + " is ready]");
        } else {
            saveSystemLog("[checkReady][DBMS : " + System.getProperty("DBMS") + " is not ready]");
        }
    }

    @Override
    public void initResources() {
        saveSystemLog("Resource is initializing ... ...");
        this.address = getProp("HOST");
        this.port = Integer.parseInt(getProp("DELIVER.PORT"));
        this.id = getProp("ID");
        this.pwd = getProp("PASSWORD");
        saveSystemLog("Try Connect to [ADDRESS : " + this.address + "] [PORT : " + this.port + "] [ID : " + this.id + "]");
        try {
            /* 클라이언트 소켓 오픈, nonblocking 모드 설정 */
            socketChannel = SocketChannel.open(new InetSocketAddress(this.address, this.port));
            socketChannel.configureBlocking(false);

            /* 연결이 완료되었는지 체크
            * 3초간 서버와의 연결이 완료되었는지 체크
            *  */
            boolean isConnected = false;
            long connectStartTime = System.currentTimeMillis();
            while (true) {
                if (socketChannel.finishConnect()) {
                    isConnected = true;
                    break;
                }
                if (System.currentTimeMillis() - connectStartTime > 3000) {
                    break;
                }
            }
            if (isConnected) {
                saveSystemLog("Connected to [ADDRESS : " + this.address + "] [PORT : " + this.port + "] [ID : " + this.id + "]");
            } else {
                throw new IOException("Connection Timeout");
            }
        } catch (IOException e) {
            saveSystemLog("Connect Fail to [ADDRESS : " + this.address + "] [PORT : " + this.port + "] [ID : " + this.id + "]");
            saveSystemLog("ERROR [" + e.getMessage() + "]");
            throw new RuntimeException(e);
        }
    }

    /**
     * socket 연결 해제
     */
    @Override
    public void releaseResources() {
        if (socketChannel != null) {
            try {
                socketChannel.close();
            } catch (IOException e) {
                saveSystemLog("ERROR [" + e.getMessage() + "]");
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 패킷을 송수신한 마지막 시간 체크
     * @return
     */
    private boolean checkTimeOut() {
        return System.currentTimeMillis() - lastPacketSendTime >= Packet.LIMIT_PACKET_TIMEOUT;
    }

    @Override
    public void doService() {
        IS_ERROR = false;   // 에러체크 초기화
        bind(); // 바이드 요청
        while (isRun()) {
            if (IS_ERROR) {
                break;
            }
            try {
                if (checkTimeOut()) {
                    saveSystemLog("[checkTimeOut : Expired ... ... ... ... ... ... ...]");
                    break;
                };
                messageService();       // 메시지 전송 처리
                linkCheckService();     // alive 체크
            } catch (Exception e) {
                saveSystemLog("ERROR [" + e.getMessage() + "]");
                saveSystemLog("ERROR DETAIL");
                saveSystemLog(e.toString());
                throw new RuntimeException(e);
            }
        }
    }

    private void bind() {
        try {
            ByteBuffer sendBuffer = Bind.makeBindBuffer(id, pwd);
            ByteBuffer recvBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + Bind.BIND_ACK_BODY_LENGTH);

            saveSystemLog("[BIND REQUEST] [IP : " + this.address + "] [PORT : " + this.port + "] [ID : " + this.id + "]");
            socketChannel.write(sendBuffer);
            long BIND_SEND_TIME = System.currentTimeMillis();
            while (true) {
                if (System.currentTimeMillis() - BIND_SEND_TIME >= Packet.LIMIT_PACKET_SEND_TIMEOUT) {
                    saveSystemLog("[bindTimeOut : Expired ... ... ... ... ... ... ...]");
                    throw new RuntimeException("bindTimeOut : Expired ... ... ... ... ... ... ...");
                }
                int recvCount = socketChannel.read(recvBuffer);
                if (recvCount == -1) {
                    saveSystemLog("[BIND ERROR] [CONNECTION CLOSED]");
                    throw new RuntimeException("BIND ERROR");
                } else if (recvCount > 0) {
                    String resultCode = Bind.getBindAckResultCode(recvBuffer);
                    saveSystemLog("resultCode " + resultCode);
                    if ("00".equals(resultCode)) {
                        lastPacketSendTime = System.currentTimeMillis();
                        saveSystemLog("[BIND SUCCESS] [CONNECTION IS ESTABLISHED]");
                        break;
                    } else {
                        saveSystemLog("[BIND FAIL] [RESULT CODE : " + resultCode + "]");
                        throw new RuntimeException("Bind FAIL");
                    }
                }
            }
        } catch (Exception e) {
            saveSystemLog("ERROR [" + e.getMessage() + "]");
            saveSystemLog("ERROR DETAIL");
            saveSystemLog(e.toString());
            throw new RuntimeException(e);
        }
    }

    private List<MunjaonMsg> selectToDeliver() {
        if ("SMS".equals(this.serviceType)) {
            return worker.selectToDeliver("S");
        } else if ("LMS".equals(this.serviceType)) {
            return worker.selectToDeliver("L");
        } else if ("MMS".equals(this.serviceType)) {
            return worker.selectToDeliver("M");
        } else if ("KAT".equals(this.serviceType)) {
            return worker.selectToDeliver("A");
        } else if ("KFT".equals(this.serviceType)) {
            return worker.selectToDeliver("F");
        }

        return null;
    }

    private void setDeliverMsgId(String msgId) {
        if (msgId == null) {
            return;
        }
        if (this.deliverList == null) {
            this.deliverList = new ArrayList<>();
        }
        this.deliverList.add(msgId);
    }

    private void messageService() {
        List<MunjaonMsg> list = selectToDeliver();
        if (list == null || list.isEmpty()) {
            try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}
            return;
        }

        try {
            for (MunjaonMsg data : list) {
                switch (this.serviceType) {
                    case "SMS": smsMessageService(data); break;
                    case "LMS": lmsMessageService(data); break;
                    case "MMS": mmsMessageService(data); break;
                    case "KAT": katMessageService(data); break;
                    case "KFT": kftMessageService(data); break;
                    default:break;
                }
            }
        } catch (Exception e) {
            IS_ERROR = true;
            saveSystemLog("ERROR [" + e.getMessage() + "]");
            saveSystemLog("ERROR DETAIL");
            saveSystemLog(e.toString());
        }

        if (this.deliverList != null && !this.deliverList.isEmpty()) {
            worker.updateDeliverForList(this.deliverList);
            this.deliverList = null;    // NULL로 초기화
        }

    }

    private void smsMessageService(MunjaonMsg data) throws Exception {
        try {
            /* 공통 메시지 유효성 체크 */
            int checkCommonCode = MessageCheckUtil.validateMessageForCommon(data);
            int checkMsgCode = MessageCheckUtil.validateMessageForSms(data);
            if (checkCommonCode != ErrorCode.OK.getCode() || checkMsgCode != ErrorCode.OK.getCode()) {
                saveLog("[MESSAGE FILTER] [COMMON_CODE : " + checkCommonCode + "] [MSG_CODE : " + checkMsgCode + "]");
                saveLog("[MESSAGE DATA : " + data.toString() + "]");
                /* 전송처리 */
                worker.updateToDeliver(data.getMsgId());
                /* 실패처리 */
                MunjaonMsg errorMsg = null;
                if (checkCommonCode != ErrorCode.OK.getCode()) {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkCommonCode), MessageUtil.getTime(), "ETC");;
                } else {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkMsgCode), MessageUtil.getTime(), "ETC");;
                }
                worker.updateToReport(errorMsg);
                /* 처리완료 */
                return;
            }

            /* 정상인 경우 메시지 전송 */
            ByteBuffer sendBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + SmsMessage.DELIVER_SMS_BODY_LENGTH);
            ByteBuffer recvBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + SmsMessage.DELIVER_SMS_ACK_BODY_LENGTH);
            Header.putHeader(sendBuffer, Header.COMMAND_DELIVER, SmsMessage.DELIVER_SMS_BODY_LENGTH);
            SmsMessage.makeDataForDeliver(sendBuffer, data);
            saveLog("[MESSAGE SEND] [... ...]");
            saveLog("[MESSAGE DATA : " + data.toString() + "]");

            while (sendBuffer.hasRemaining()) {
                socketChannel.write(sendBuffer);
            }

            long MSG_SEND_TIME = System.currentTimeMillis();
            while (true) {
                if (System.currentTimeMillis() - MSG_SEND_TIME >= Packet.LIMIT_PACKET_SEND_TIMEOUT) {
                    saveLog("[messageSendTimeOut : Expired ... ... ... ... ... ... ...]");
                    throw new Exception("messageSendTimeOut : Expired ... ... ... ... ... ... ...");
                }
                int recvCount = socketChannel.read(recvBuffer);
                if (recvCount == -1) {
                    saveLog("[MESSAGE SEND] [FAIL] [SOCKET IS CLOSED]");
                    throw new Exception("DELIVER ERROR");
                } else if (recvCount > 0) {
                    setDeliverMsgId(data.getMsgId());
//                    worker.updateToDeliver(data.getMsgId());
                    saveLog("[MESSAGE SEND] [SUCCESS]");
                    lastPacketSendTime = System.currentTimeMillis();
                    break;
                }
            }
        } catch (Exception e) {
            saveSystemLog("ERROR [" + e.getMessage() + "]");
            saveSystemLog("ERROR DETAIL");
            saveSystemLog(e.toString());
            throw new Exception(e);
        }
    }

    private void lmsMessageService(MunjaonMsg data) throws Exception {
        try {
            /* 공통 메시지 유효성 체크 */
            int checkCommonCode = MessageCheckUtil.validateMessageForCommon(data);
            int checkMsgCode = MessageCheckUtil.validateMessageForMedia(data);
            if (checkCommonCode != ErrorCode.OK.getCode() || checkMsgCode != ErrorCode.OK.getCode()) {
                saveLog("[MESSAGE FILTER] [COMMON_CODE : " + checkCommonCode + "] [MSG_CODE : " + checkMsgCode + "]");
                saveLog("[MESSAGE DATA : " + data.toString() + "]");
                /* 전송처리 */
                worker.updateToDeliver(data.getMsgId());
                /* 실패처리 */
                MunjaonMsg errorMsg = null;
                if (checkCommonCode != ErrorCode.OK.getCode()) {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkCommonCode), MessageUtil.getTime(), "ETC");;
                } else {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkMsgCode), MessageUtil.getTime(), "ETC");;
                }
                worker.updateToReport(errorMsg);
                /* 처리완료 */
                return;
            }

            /* 정상인 경우 메시지 전송 */
            ByteBuffer sendBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + LmsMessage.DELIVER_LMS_BODY_LENGTH);
            ByteBuffer recvBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + LmsMessage.DELIVER_LMS_ACK_BODY_LENGTH);
            Header.putHeader(sendBuffer, Header.COMMAND_DELIVER, LmsMessage.DELIVER_LMS_BODY_LENGTH);
            LmsMessage.makeDataForDeliver(sendBuffer, data);
            saveLog("[MESSAGE SEND] [... ...]");
            saveLog("[MESSAGE DATA : " + data.toString() + "]");

            while (sendBuffer.hasRemaining()) {
                socketChannel.write(sendBuffer);
            }

            long MSG_SEND_TIME = System.currentTimeMillis();
            while (true) {
                if (System.currentTimeMillis() - MSG_SEND_TIME >= Packet.LIMIT_PACKET_SEND_TIMEOUT) {
                    saveLog("[messageSendTimeOut : Expired ... ... ... ... ... ... ...]");
                    throw new Exception("messageSendTimeOut : Expired ... ... ... ... ... ... ...");
                }
                int recvCount = socketChannel.read(recvBuffer);
                if (recvCount == -1) {
                    saveLog("[MESSAGE SEND] [FAIL] [SOCKET IS CLOSED]");
                    throw new Exception("DELIVER ERROR");
                } else if (recvCount > 0) {
                    setDeliverMsgId(data.getMsgId());
//                    worker.updateToDeliver(data.getMsgId());
                    saveLog("[MESSAGE SEND] [SUCCESS]");
                    lastPacketSendTime = System.currentTimeMillis();
                    break;
                }
            }
        } catch (Exception e) {
            saveSystemLog("ERROR [" + e.getMessage() + "]");
            saveSystemLog("ERROR DETAIL");
            saveSystemLog(e.toString());
            throw new Exception(e);
        }
    }

    private void mmsMessageService(MunjaonMsg data) throws Exception {
        try {
            /* 이미지 경로 디폴트 경로 사용 여부 */
            String defaultYn = getProp("MMS", "DEFAULT_PATH_YN");
            /* MMS Image 저장 경로 */
            String path = null;
            if ("Y".equals(defaultYn)) {
                path = System.getProperty("ROOTPATH") + File.separator + "mmsfile" + File.separator;
            } else {
                path = getProp("MMS", "FILEPATH") + File.separator;
            }

            /* 공통 메시지 유효성 체크 */
            int checkCommonCode = MessageCheckUtil.validateMessageForCommon(data);
            int checkMsgCode = MessageCheckUtil.validateMessageForMedia(data);
            int checkImageCode = MessageCheckUtil.validateMessageForImage(data, path);
            if (checkCommonCode != ErrorCode.OK.getCode() || checkMsgCode != ErrorCode.OK.getCode() || checkImageCode != ErrorCode.OK.getCode()) {
                saveLog("[MESSAGE FILTER] [COMMON_CODE : " + checkCommonCode + "] [MSG_CODE : " + checkMsgCode + "] [IMAGE_CODE : " + checkImageCode + "]");
                saveLog("[MESSAGE DATA : " + data.toString() + "]");
                /* 전송처리 */
                worker.updateToDeliver(data.getMsgId());
                /* 실패처리 */
                MunjaonMsg errorMsg = null;
                if (checkCommonCode != ErrorCode.OK.getCode()) {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkCommonCode), MessageUtil.getTime(), "ETC");
                }else if (checkMsgCode != ErrorCode.OK.getCode()) {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkMsgCode), MessageUtil.getTime(), "ETC");
                } else {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkImageCode), MessageUtil.getTime(), "ETC");
                }
                worker.updateToReport(errorMsg);
                /* 처리완료 */
                return;
            }

            /* 정상인 경우 메시지 전송 */
            ByteBuffer sendBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + MmsMessage.DELIVER_MMS_BODY_LENGTH);
            ByteBuffer recvBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + MmsMessage.DELIVER_MMS_ACK_BODY_LENGTH);
            int fileCount = 0;
            /* File check */
            ByteBuffer file01HeadBuffer = MmsMessage.makeImageHeaderForDeliver(path, data.getFilename01());
            if (file01HeadBuffer != null) {
                fileCount++;
            }
            ByteBuffer file02HeadBuffer = MmsMessage.makeImageHeaderForDeliver(path, data.getFilename02());
            if (file02HeadBuffer != null) {
                fileCount++;
            }
            ByteBuffer file03HeadBuffer = MmsMessage.makeImageHeaderForDeliver(path, data.getFilename03());
            if (file03HeadBuffer != null) {
                fileCount++;
            }

            /* fileCount 저장 */
            data.setFileCount(fileCount);

            Header.putHeader(sendBuffer, Header.COMMAND_DELIVER, MmsMessage.DELIVER_MMS_BODY_LENGTH);
            MmsMessage.makeDataForDeliver(sendBuffer, data);
            saveLog("[MESSAGE SEND] [... ...]");
            saveLog("[MESSAGE DATA : " + data.toString() + "]");

            while (sendBuffer.hasRemaining()) {
                socketChannel.write(sendBuffer);
            }

            if (file01HeadBuffer != null) {
                socketChannel.write(file01HeadBuffer);
                uploadFileSend(path + data.getFilename01());
//
//                ByteBuffer fileBodyBuffer = MmsMessage.makeImageBodyForDeliver(path, data.getFilename01());
//                fileBodyBuffer.flip();
//                while(fileBodyBuffer.hasRemaining()){
//                    int bytesWritten = socketChannel.write(fileBodyBuffer);
//                    saveLog("bytesWritten : " + bytesWritten);
//                }
            }
            if (file02HeadBuffer != null) {
                socketChannel.write(file02HeadBuffer);
                uploadFileSend(path + data.getFilename02());

//                ByteBuffer fileBodyBuffer = MmsMessage.makeImageBodyForDeliver(path, data.getFilename02());
//                fileBodyBuffer.flip();
//                while(fileBodyBuffer.hasRemaining()){
//                    int bytesWritten = socketChannel.write(fileBodyBuffer);
//                    saveLog("bytesWritten : " + bytesWritten);
//                }
            }
            if (file03HeadBuffer != null) {
                socketChannel.write(file03HeadBuffer);
                uploadFileSend(path + data.getFilename03());

//                ByteBuffer fileBodyBuffer = MmsMessage.makeImageBodyForDeliver(path, data.getFilename03());
//                fileBodyBuffer.flip();
//                while(fileBodyBuffer.hasRemaining()){
//                    int bytesWritten = socketChannel.write(fileBodyBuffer);
//                    saveLog("bytesWritten : " + bytesWritten);
//                }
            }

            long MSG_SEND_TIME = System.currentTimeMillis();
            while (true) {
                if (System.currentTimeMillis() - MSG_SEND_TIME >= Packet.LIMIT_PACKET_SEND_TIMEOUT) {
                    saveLog("[messageSendTimeOut : Expired ... ... ... ... ... ... ...]");
                    throw new Exception("messageSendTimeOut : Expired ... ... ... ... ... ... ...");
                }
                int recvCount = socketChannel.read(recvBuffer);
                if (recvCount == -1) {
                    saveLog("[MESSAGE SEND] [FAIL] [SOCKET IS CLOSED]");
                    throw new Exception("DELIVER ERROR");
                } else if (recvCount > 0) {
                    setDeliverMsgId(data.getMsgId());
//                    worker.updateToDeliver(data.getMsgId());
                    saveLog("[MESSAGE SEND] [SUCCESS]");
                    lastPacketSendTime = System.currentTimeMillis();
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            saveSystemLog("ERROR [" + e.getMessage() + "]");
            saveSystemLog("ERROR DETAIL");
            saveSystemLog(e.toString());
            throw new Exception(e);
        }
    }

    private void uploadFileSend(String filePath) throws IOException {
        ByteBuffer buff = ByteBuffer.allocate(1024);
        Path src = Paths.get(filePath);

        try (FileChannel rc = FileChannel.open(src, StandardOpenOption.READ)) {
            int num;
            while (true) {
                num = rc.read(buff);
                if (num == -1) {
                    break;
                }

                buff.flip();
                while (buff.hasRemaining()) {
                    socketChannel.write(buff);
                }
                buff.clear();
            }

        } catch (IOException e) {
            throw e;
        }
    }

    private void katMessageService(MunjaonMsg data) throws Exception {
        try {
            /* 이미지 경로 디폴트 경로 사용 여부 */
            String defaultYn = getProp("KAKAO", "DEFAULT_PATH_YN");
            /* Kakao Json 저장 경로 */
            String path = null;
            if ("Y".equals(defaultYn)) {
                path = System.getProperty("ROOTPATH") + File.separator + "kakaofile" + File.separator;
            } else {
                path = getProp("KAKAO", "FILEPATH") + File.separator;
            }
            /* 공통 메시지 유효성 체크 */
            int checkCommonCode = MessageCheckUtil.validateMessageForCommon(data);
            int checkMsgCode = MessageCheckUtil.validateMessageForKakao(data);
            int checkFileCode = MessageCheckUtil.validateJsonFile(path, data.getKakaoJsonFile());

            if (checkCommonCode != ErrorCode.OK.getCode() || checkMsgCode != ErrorCode.OK.getCode() || checkFileCode != ErrorCode.OK.getCode()) {
                saveLog("[MESSAGE FILTER] [COMMON_CODE : " + checkCommonCode + "] [MSG_CODE : " + checkMsgCode + "] [JSON_FILE_CODE : " + checkFileCode + "]");
                saveLog("[MESSAGE DATA : " + data.toString() + "]");
                /* 전송처리 */
                worker.updateToDeliver(data.getMsgId());
                /* 실패처리 */
                MunjaonMsg errorMsg = null;
                if (checkCommonCode != ErrorCode.OK.getCode()) {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkCommonCode), MessageUtil.getTime(), "ETC");
                }else if (checkMsgCode != ErrorCode.OK.getCode()) {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkMsgCode), MessageUtil.getTime(), "ETC");
                } else {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkFileCode), MessageUtil.getTime(), "ETC");
                }
                worker.updateToReport(errorMsg);
                /* 처리완료 */
                return;
            }

            /* 정상인 경우 메시지 전송 */
            ByteBuffer sendBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + KakaoMessage.DELIVER_KAKAO_BODY_LENGTH);
            ByteBuffer recvBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + KakaoMessage.DELIVER_KAKAO_ACK_BODY_LENGTH);

            Header.putHeader(sendBuffer, Header.COMMAND_DELIVER, KakaoMessage.DELIVER_KAKAO_BODY_LENGTH);
            KakaoMessage.makeDataForDeliver(sendBuffer, data);
            saveLog("[MESSAGE SEND] [... ...]");
            saveLog("[MESSAGE DATA : " + data.toString() + "]");

            while (sendBuffer.hasRemaining()) {
                socketChannel.write(sendBuffer);
            }

            /* 파일 전송 */
            ByteBuffer fileHeadBuffer = KakaoMessage.makeJsonHeaderForDeliver(path, data.getKakaoJsonFile());
            socketChannel.write(fileHeadBuffer);
            uploadFileSend(path + data.getKakaoJsonFile());

//            ByteBuffer fileBodyBuffer = KakaoMessage.makeJsonBodyForDeliver(path, data.getKakaoJsonFile());
//            fileBodyBuffer.flip();
//            while(fileBodyBuffer.hasRemaining()){
//                int bytesWritten = socketChannel.write(fileBodyBuffer);
//                saveLog("bytesWritten : " + bytesWritten);
//            }

            long MSG_SEND_TIME = System.currentTimeMillis();
            while (true) {
                if (System.currentTimeMillis() - MSG_SEND_TIME >= Packet.LIMIT_PACKET_SEND_TIMEOUT) {
                    saveLog("[messageSendTimeOut : Expired ... ... ... ... ... ... ...]");
                    throw new Exception("messageSendTimeOut : Expired ... ... ... ... ... ... ...");
                }
                int recvCount = socketChannel.read(recvBuffer);
                if (recvCount == -1) {
                    saveLog("[MESSAGE SEND] [FAIL] [SOCKET IS CLOSED]");
                    throw new Exception("DELIVER ERROR");
                } else if (recvCount > 0) {
                    setDeliverMsgId(data.getMsgId());
//                    worker.updateToDeliver(data.getMsgId());
                    saveLog("[MESSAGE SEND] [SUCCESS]");
                    lastPacketSendTime = System.currentTimeMillis();
                    break;
                }
            }
        } catch (Exception e) {
            saveSystemLog("ERROR [" + e.getMessage() + "]");
            saveSystemLog("ERROR DETAIL");
            saveSystemLog(e.toString());
            throw new Exception(e);
        }
    }

    private void kftMessageService(MunjaonMsg data) throws Exception {
        try {
            /* 이미지 경로 디폴트 경로 사용 여부 */
            String defaultYn = getProp("KAKAO", "DEFAULT_PATH_YN");
            /* Kakao Json 저장 경로 */
            String path = null;
            if ("Y".equals(defaultYn)) {
                path = System.getProperty("ROOTPATH") + File.separator + "kakaofile" + File.separator;
            } else {
                path = getProp("KAKAO", "FILEPATH") + File.separator;
            }
            /* 공통 메시지 유효성 체크 */
            int checkCommonCode = MessageCheckUtil.validateMessageForCommon(data);
            int checkMsgCode = MessageCheckUtil.validateMessageForKakao(data);
            int checkFileCode = MessageCheckUtil.validateJsonFile(path, data.getKakaoJsonFile());
            if (checkCommonCode != ErrorCode.OK.getCode() || checkMsgCode != ErrorCode.OK.getCode() || checkFileCode != ErrorCode.OK.getCode()) {
                saveLog("[MESSAGE FILTER] [COMMON_CODE : " + checkCommonCode + "] [MSG_CODE : " + checkMsgCode + "] [JSON_FILE_CODE : " + checkFileCode + "]");
                saveLog("[MESSAGE DATA : " + data.toString() + "]");
                /* 전송처리 */
                worker.updateToDeliver(data.getMsgId());
                /* 실패처리 */
                MunjaonMsg errorMsg = null;
                if (checkCommonCode != ErrorCode.OK.getCode()) {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkCommonCode), MessageUtil.getTime(), "ETC");
                }else if (checkMsgCode != ErrorCode.OK.getCode()) {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkMsgCode), MessageUtil.getTime(), "ETC");
                } else {
                    errorMsg = MessageCheckUtil.setReportMessage(data.getMsgId(), "00", String.valueOf(checkFileCode), MessageUtil.getTime(), "ETC");
                }
                worker.updateToReport(errorMsg);
                /* 처리완료 */
                return;
            }

            /* 정상인 경우 메시지 전송 */
            ByteBuffer sendBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + KakaoMessage.DELIVER_KAKAO_BODY_LENGTH);
            ByteBuffer recvBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + KakaoMessage.DELIVER_KAKAO_ACK_BODY_LENGTH);

            Header.putHeader(sendBuffer, Header.COMMAND_DELIVER, KakaoMessage.DELIVER_KAKAO_BODY_LENGTH);
            KakaoMessage.makeDataForDeliver(sendBuffer, data);
            saveLog("[MESSAGE SEND] [... ...]");
            saveLog("[MESSAGE DATA : " + data.toString() + "]");

            while (sendBuffer.hasRemaining()) {
                socketChannel.write(sendBuffer);
            }

            /* 파일 전송 */
            ByteBuffer fileHeadBuffer = KakaoMessage.makeJsonHeaderForDeliver(path, data.getKakaoJsonFile());
            socketChannel.write(fileHeadBuffer);
            uploadFileSend(path + data.getKakaoJsonFile());

//            ByteBuffer fileBodyBuffer = KakaoMessage.makeJsonBodyForDeliver(path, data.getKakaoJsonFile());
//            fileBodyBuffer.flip();
//            while(fileBodyBuffer.hasRemaining()){
//                int bytesWritten = socketChannel.write(fileBodyBuffer);
//                saveLog("bytesWritten : " + bytesWritten);
//            }

            long MSG_SEND_TIME = System.currentTimeMillis();
            while (true) {
                if (System.currentTimeMillis() - MSG_SEND_TIME >= Packet.LIMIT_PACKET_SEND_TIMEOUT) {
                    saveLog("[messageSendTimeOut : Expired ... ... ... ... ... ... ...]");
                    throw new Exception("messageSendTimeOut : Expired ... ... ... ... ... ... ...");
                }
                int recvCount = socketChannel.read(recvBuffer);
                if (recvCount == -1) {
                    saveLog("[MESSAGE SEND] [FAIL] [SOCKET IS CLOSED]");
                    throw new Exception("DELIVER ERROR");
                } else if (recvCount > 0) {
                    setDeliverMsgId(data.getMsgId());
//                    worker.updateToDeliver(data.getMsgId());
                    saveLog("[MESSAGE SEND] [SUCCESS]");
                    lastPacketSendTime = System.currentTimeMillis();
                    break;
                }
            }
        } catch (Exception e) {
            saveSystemLog("ERROR [" + e.getMessage() + "]");
            saveSystemLog("ERROR DETAIL");
            saveSystemLog(e.toString());
            throw new Exception(e);
        }
    }

    private void linkCheckService() {
        if (System.currentTimeMillis() - lastPacketSendTime < Packet.LINK_CHECK_CYCLE) {
            return;
        }

        ByteBuffer recvBuffer = ByteBuffer.allocate(Header.HEADER_LENGTH + LinkCheck.LINK_CHECK_ACK_BODY_LENGTH);
        try {
            saveLog("[LINK_CHECK SEND] [... ...]");
            socketChannel.write(LinkCheck.makeLinkCheckBuffer());
            long LINK_SEND_TIME = System.currentTimeMillis();
            while (true) {
                if (System.currentTimeMillis() - LINK_SEND_TIME >= Packet.LIMIT_PACKET_SEND_TIMEOUT) {
                    saveLog("[LinkcheckTimeOut : Expired ... ... ... ... ... ... ...]");
                    throw new RuntimeException("LinkcheckTimeOut : Expired ... ... ... ... ... ... ...");
                }
                int recvCount = socketChannel.read(recvBuffer);
                if (recvCount == -1) {
                    saveLog("[LINK_CHECK SEND] [FAIL] [SOCKET IS CLOSED]");
                    throw new RuntimeException("LINK_CHECK ERROR");
                } else if (recvCount > 0) {
                    saveLog("[LINK_CHECK SEND] [SUCCESS]");
                    lastPacketSendTime = System.currentTimeMillis();
                    break;
                }
            }
        } catch (Exception e) {
            IS_ERROR = true;
            saveSystemLog("ERROR [" + e.getMessage() + "]");
            saveSystemLog("ERROR DETAIL");
            saveSystemLog(e.toString());
        }
    }

    @Override
    public JSONObject monitorService() {
        return null;
    }
}
