using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Data.SqlClient;
using System.Data;

using Cosmos.Common;
using Cosmos.BaseFrame;
using Cosmos.UserFrame;
using Cosmos.CommonManager;
using Cosmos.ServiceProvider;

using Newtonsoft.Json;

namespace Cosmos.KDS
{
    public class KDSMain : IWatcher
    {
        #region 클래스 변수 선언
        /// <summary>
        /// StateServer Object (StateServer 객체)
        /// </summary>
        private StateServer StateObject = (StateServer)StateServer.GetInstance();

        /// <summary>
        /// POS Status Value (POS 상태값)
        /// </summary>
        private PosStatus m_cPosStatus = null;

        /// <summary>
        /// KPS Thread (KPS 스레드)
        /// </summary>
        private Thread m_tKDSProc = null;

        /// <summary>
        /// KPS Proc Operation Yes/No (KPS Proc 작동여부)
        /// </summary>
        private bool m_KDSProcRunning = true;

        /// <summary>
        /// MSSQL DB 관련 객체
        /// </summary>
        private static SqlDB sqlDb = null;

        // 대기시간
        //private int WAIT_TIME = 3000;
        private int WAIT_TIME = 1000;

        // Delay time to close socket
        private int m_iTimeout = 5000;

        // 전송 소켓
        private static TcpSocket m_sendSocket = null;

        // KDS 전문 헤더 길이
        private const int DATA_LEN_SIZE = 5;

        //17.08.22 dkshin SS 해피오더
        private SManager sManager = new SManager();
        private IHappyOrderList m_cHappyOrder = null;                               // 해피오더 서비스 처리
        private ISaleCompleteUs m_cRecService = null;
        #endregion 클래스 변수 선언

        #region 생성자
        public KDSMain()
        {
            m_cPosStatus = (PosStatus)StateObject.POS;
            m_cHappyOrder = (IHappyOrderList)sManager.InitServiceInstance(ServiceLists.BSV_SALE.DLL, ServiceLists.BSV_SALE.HAPPY_ORDER_LIST);//17.08.22 dkshin SS 해피오더
            m_cRecService = (ISaleCompleteUs)sManager.InitServiceInstance(ServiceLists.ASV_DATA_PROCESS.DLL, ServiceLists.ASV_DATA_PROCESS.SALE_COMPLETE);//17.08.22 dkshin SS 해피오더
        }
        #endregion

        #region KDS 데몬 기동/종료
        public void Start()
        {
            try
            {
                UserLog.WriteLogFile(UserCom.LOG_IOS,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",
                                     "KDS Start");

                // Database Connection
                sqlDb = new SqlDB(m_cPosStatus.Base.LocalDbSource, m_cPosStatus.Base.LocalDbCatalog, m_cPosStatus.Base.LocalDbUserID, m_cPosStatus.Base.LocalDbPassword);

                m_tKDSProc = new Thread(new ThreadStart(KDSExecuteProc));
                m_KDSProcRunning = true;
                m_tKDSProc.Start();
            }
            catch (Exception ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     ex.Message);
            }
        }

        public void Stop()
        {
            try
            {
                m_KDSProcRunning = false;

                int count = 0;
                while(count < 10)
                {
                    if (m_tKDSProc != null && m_tKDSProc.IsAlive) m_KDSProcRunning = false;
                    else break;

                    count++;
                    Thread.Sleep(100);
                }

                if (count == 10)
                {
                    UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                         UserCom.INFO_LEVEL,
                                         System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                         System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +
                                         System.Reflection.MethodBase.GetCurrentMethod().Name + "()",
                                         "Force KDS Agent Stop!!!");
                    m_tKDSProc.Abort();
                }

                UserLog.WriteLogFile(UserCom.LOG_IOS,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",
                                     "KDS Stop");
            }
            catch (Exception ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     ex.Message);
            }
        }
        #endregion

        #region Thread Main
        private void KDSExecuteProc()
        {
            string sIp = "";
            int iPort = -1;

            //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 start
            //기존
            //string sSendFlag = "9";
            //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 end

            while (m_KDSProcRunning)
            {
                try
                {
                    //// Set Wait Time
                    //Thread.Sleep((int)WAIT_TIME);

                    /*
                    UserLog.WriteLogFile(UserCom.LOG_IOS,
                                         System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                         System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +
                                         System.Reflection.MethodBase.GetCurrentMethod().Name + "()",
                                         "KDSSendItemMake Start");
                    */
                    // KDS Send Item Make
                    KDSSendItemMake();
                    /*
                    UserLog.WriteLogFile(UserCom.LOG_IOS,
                                         System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,
                                         System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +
                                         System.Reflection.MethodBase.GetCurrentMethod().Name + "()",
                                         "KDSSendItemMake End");
                    */
                    Hashtable htKDSSendItem = new Hashtable();

                    //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 start
                    //기존
                    //string[] saKey = new string[4];
                    //변경
                    string[] saKey = new string[5];
                    //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 end

                    Hashtable htSendJsonData = GetKDSSendItem(ref htKDSSendItem, ref sIp, ref iPort, ref saKey);

                    //if(sIp == "" || iPort == -1 || htSendJsonData == null || htSendJsonData.Count == 0)
                    //{
                    //    continue;
                    //}

                    if (sIp != "" && iPort != -1 && htSendJsonData != null && htSendJsonData.Count != 0)
                    {
                        //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 start
                        string sSendFlag = "9";
                        //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 end

                        string sReturn = SendProcess(sIp, iPort, m_iTimeout, htSendJsonData);

                        if (sReturn == UserCom.RST_OK)
                        {
                            sSendFlag = "1";

                            //#14180 JJ 코엑스_ 2번포스 주방영수증에서 레시피 출력 안되는 증상,phj start
                            //2018-03-06
                            //MST_KTCH_ORD_MSG 테이블은 KPS, KDS 모두 접근하는 테이블인데 (KPS, KDS 기능 모두 사용하는 점포)
                            //먼저 KDS 스레드에서 MST_KTCH_ORD_MSG 검색해서 MST_KDS_ORD_MSG 테이블로 인서트 성공하면 
                            //해당 주방상품 데이터 삭제 시키기 때문에 이 후에 KPS 스레드가 돌면 해당 주방상품의 주방 영수증이 출력 안될 수 있다.
                            //그렇기 때문에 아래에 함수 주석처리한다.
                            /*
                            //17.08.22 dkshin SS 해피오더 - KDS 전송 성공 후 주문 목록 데이타 삭제(KDS 보낼 때 주문 목록 데이타를 검색해서 보내기 때문에)
                            //Hashtable htOrderHeader = (Hashtable)htSendJsonData["ORDERHEADER"];
                            Hashtable htOrderHeader = (Hashtable)htSendJsonData["HEADER"];
                            m_cHappyOrder.DeleteSSHappyOrderMSG(htOrderHeader["TRAN_NO"].ToString());
                            */
                            //#14180 JJ 코엑스_ 2번포스 주방영수증에서 레시피 출력 안되는 증상,phj end
                        }
                        //17.08.22 dkshin SS 해피오더 - KDS 전송 실패 시 영수증 출력
                        else
                        {
                            //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 start
                            //기존
                            /*
                            ArrayList m_sPrintData = new ArrayList();
                            Hashtable[] hsOrderItem = (Hashtable[])htSendJsonData["ORDER_ITEM"];

                            for (int i = 0; i < hsOrderItem.Length; i++)
                            {
                                Column.TR_HPORD.HPORD_ITEM item = new Column.TR_HPORD.HPORD_ITEM();
                                item.GoodsName = hsOrderItem[i]["ITEM_NM"].ToString();
                                item.Qty = hsOrderItem[i]["ITEM_QTY"].ToString();
                                m_sPrintData.Add(item);
                            }
                            
                            m_cRecService.HappyOrderKDSPrint(m_sPrintData);//
                            */
                            //변경
                            if (saKey[4] == "0")
                            {                            
                                ArrayList m_sPrintData = new ArrayList();
                                Hashtable[] hsOrderItem = (Hashtable[])htSendJsonData["ORDER_ITEM"];

                                for (int i = 0; i < hsOrderItem.Length; i++)
                                {
                                    Column.TR_HPORD.HPORD_ITEM item = new Column.TR_HPORD.HPORD_ITEM();
                                    item.GoodsName = hsOrderItem[i]["ITEM_NM"].ToString();
                                    item.Qty = hsOrderItem[i]["ITEM_QTY"].ToString();
                                    m_sPrintData.Add(item);
                                }

                                m_cRecService.HappyOrderKDSPrint(m_sPrintData);//
                            }
                            //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 end

                        }

                        UpdateKDSSendFlag(saKey[0], saKey[1], saKey[2], saKey[3], sSendFlag);
                    }

                    int nNowSleepTerm = 0;
                    while (nNowSleepTerm < WAIT_TIME)
                    {
                        if (m_KDSProcRunning == false) break;
                        Thread.Sleep(100);
                        nNowSleepTerm += 100;
                    }
                }
                catch (Exception ex)
                {
                    UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                         System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                         System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                         System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                         ex.Message);
                }
            }
        }
        #endregion

        #region 데이터 이행 처리(주방주문데이터 -> KDS)
        /// <summary>
        /// MST_KTCH_ORD_MSG(주방주문데이터) 에서 KDS 전송 데이터 조회
        /// </summary>
        public bool KDSSendItemMake()
        {
            bool bRtn = false;
            string sQuery = "";

            Hashtable htKDSSendingItem = new Hashtable();

            try
            {
                #region 복합매장 적용 이전 버전
                //sQuery += "SELECT A.ORD_DIV, A.FLOOR_CD, A.TBL_NO, B.KTCH_SYS_CD, A.SEQ ";
                //sQuery += "     , A.CMP_CD, A.BRAND_CD, A.STOR_CD, A.POS_NO, A.TRADE_NO, A.SALE_DT ";
                //sQuery += "     , A.POS_TYPE, A.ITEM_CD, A.ITEM_DIV, A.SHTCUT_ITEMNM, A.SALE_QTY, A.PACK_DIV ";
                //sQuery += "     , A.SET_MENU_CD, A.ORD_TIME, A.CANCEL_DIV, A.ORG_BILL_POSNO, A.ORG_BILLDT, A.ORG_BILL_NO ";
                //sQuery += "     , A.SUB_MEMO_DIV, A.RESEND_YN, C.KTCH_SYS_USE_DIV, C.KTCH_DSP_IP, C.KTCH_DSP_PORT, C.FILLER1 ";
                //sQuery += "     , C.FILLER2, C.FILLER3, C.FILLER4, C.FILLER5 ";
                //sQuery += "  FROM POSMST..MST_KTCH_ORD_MSG A ";
                //sQuery += "     , POSMST..MST_KTCH_DEVICE_ITEM B ";
                //sQuery += "     , POSMST..MST_KTCH_DEVICE C ";
                //sQuery += " WHERE A.SEND_YN = '0' ";
                //sQuery += "   AND A.ITEM_DIV IN ('0', '1', '2', '3', '4') ";
                //sQuery += "   AND B.ITEM_CD = A.ITEM_CD ";
                //sQuery += "   AND B.FLOOR_CD = A.FLOOR_CD ";
                //sQuery += "   AND B.KTCH_SYS_CD = C.KTCH_SYS_CD ";
                //sQuery += "   AND C.KTCH_SYS_DIV = '" + PosConst.KTCH_SYS_DIV.KDS + "' ";
                //sQuery += "   AND C.USE_YN = '" + PosConst.MST_USE_YN.YES + "' ";

                //DataTable dtData = null;
                //if (sqlDb.DBDataTableSelect(sQuery, CommandType.Text, (SqlParameter[])null, out dtData) != UserCom.OK)
                //{
                //    UserLog.WriteLogFile(UserCom.LOG_DEBUG,
                //                            UserCom.WARNING_LEVEL,
                //                            System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                //                            System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                //                            System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                //                            sQuery);
                //    return;
                //}
                //foreach(DataRow dr in dtData.Rows)
                //{
                //    KDSItem cKDSItem = new KDSItem();

                //    cKDSItem.sOrderType = CmUtil.GetDataRowStr(dr, "ORD_DIV");
                //    cKDSItem.sFloorCd = CmUtil.GetDataRowStr(dr, "FLOOR_CD");
                //    cKDSItem.sTableNo = CmUtil.GetDataRowStr(dr, "TBL_NO");
                //    cKDSItem.sKtchSysCd = CmUtil.GetDataRowStr(dr, "KTCH_SYS_CD");
                //    cKDSItem.nSeq = CmUtil.GetDataRowInt(dr, "SEQ");
                //    cKDSItem.sCmpCd = CmUtil.GetDataRowStr(dr, "CMP_CD");
                //    cKDSItem.sBrandCd = CmUtil.GetDataRowStr(dr, "BRAND_CD");
                //    cKDSItem.sStorCd = CmUtil.GetDataRowStr(dr, "STOR_CD");
                //    cKDSItem.sPosNo = CmUtil.GetDataRowStr(dr, "POS_NO");
                //    cKDSItem.sTradeNo = CmUtil.GetDataRowStr(dr, "TRADE_NO");
                //    cKDSItem.sSaleDt = CmUtil.GetDataRowStr(dr, "SALE_DT");
                //    cKDSItem.sPosType = CmUtil.GetDataRowStr(dr, "POS_TYPE");
                //    cKDSItem.sItemCd = CmUtil.GetDataRowStr(dr, "ITEM_CD");
                //    cKDSItem.sItemDiv = CmUtil.GetDataRowStr(dr, "ITEM_DIV");
                //    cKDSItem.sItemNm = CmUtil.GetDataRowStr(dr, "SHTCUT_ITEMNM");
                //    cKDSItem.nQty = CmUtil.GetDataRowInt(dr, "SALE_QTY");
                //    cKDSItem.sPackDiv = CmUtil.GetDataRowStr(dr, "PACK_DIV");
                //    cKDSItem.sSetMenuCd = CmUtil.GetDataRowStr(dr, "SET_MENU_CD");
                //    cKDSItem.sOrdTime = CmUtil.GetDataRowStr(dr, "ORD_TIME");
                //    cKDSItem.sCancelDiv = CmUtil.GetDataRowStr(dr, "CANCEL_DIV");
                //    cKDSItem.sOrgBillPosNo = CmUtil.GetDataRowStr(dr, "ORG_BILL_POSNO");
                //    cKDSItem.sOrgBillDt = CmUtil.GetDataRowStr(dr, "ORG_BILL_DT");
                //    cKDSItem.sOrgBillNo = CmUtil.GetDataRowStr(dr, "ORG_BILL_NO");
                //    cKDSItem.sKtchSysUseDiv = CmUtil.GetDataRowStr(dr, "KTCH_SYS_USE_DIV");
                //    cKDSItem.sKtchKdsIp = CmUtil.GetDataRowStr(dr, "KTCH_DSP_IP");
                //    cKDSItem.sKtchKdsPort = CmUtil.GetDataRowStr(dr, "KTCH_DSP_PORT");
                //    cKDSItem.sResendYn = CmUtil.GetDataRowStr(dr, "RESEND_YN");
                //    cKDSItem.sFiller1 = CmUtil.GetDataRowStr(dr, "FILLER1");
                //    cKDSItem.sFiller2 = CmUtil.GetDataRowStr(dr, "FILLER2");
                //    cKDSItem.sFiller3 = CmUtil.GetDataRowStr(dr, "FILLER3");
                //    cKDSItem.sFiller4 = CmUtil.GetDataRowStr(dr, "FILLER4");
                //    cKDSItem.sFiller5 = CmUtil.GetDataRowStr(dr, "FILLER5");

                //    cKDSItem.sSendYn = "0";
                //    cKDSItem.sErrorCd = "0000";

                //    htKDSSendingItem.Add(htKDSSendingItem.Count, cKDSItem);
                //}

                //if (htKDSSendingItem.Count > 0)
                //{
                //    InsertIntoKDS(htKDSSendingItem);
                //}
                #endregion 복합매장 적용 이전 버전

                #region 연습모드 적용 이전 버전 
                //sQuery = "SELECT A.ORD_DIV, A.FLOOR_CD, A.TBL_NO, A.SEQ, A.CMP_CD, A.BRAND_CD, A.STOR_CD, A.SUB_STOR_CD, A.POS_NO, A.TRADE_NO, A.SALE_DT, A.POS_TYPE, A.ITEM_CD, A.ITEM_DIV, A.SHTCUT_ITEMNM \n"
                //       + "     , A.SALE_QTY, A.PACK_DIV, A.SET_MENU_CD, A.ORD_TIME, A.CANCEL_DIV, A.SUB_MEMO_DIV, A.RESEND_YN \n"
                //       + "     , A.MSG1, A.MSG2, A.MSG3, A.FILLER2 AS ETC_ORD_FLAG, A.FILLER3 AS ADD_ORD_FLAG \n"
                //       + "     , C.SUB_STOR_CD, C.KTCH_SYS_CD \n"
                //       + "     , C.KTCH_SYS_USE_DIV, C.KTCH_DSP_IP, C.KTCH_DSP_PORT, C.FILLER1, C.FILLER2, A.FILLER3, C.FILLER4, C.FILLER5 \n"
                //       + "  FROM POSMST..MST_KTCH_ORD_MSG     A              \n"
                //       + "     , POSMST..MST_KTCH_DEVICE_ITEM B WITH(NOLOCK) \n"
                //       + "     , POSMST..MST_KTCH_DEVICE      C WITH(NOLOCK) \n"
                //       + " WHERE A.CMP_CD = B.CMP_CD AND A.STOR_CD = B.STOR_CD AND A.SUB_STOR_CD = B.SUB_STOR_CD AND A.ITEM_CD = B.ITEM_CD \n"
                //       + "   AND (A.FLOOR_CD = B.FLOOR_CD OR '999' = B.FLOOR_CD) \n"
                //       + "   AND B.CMP_CD = C.CMP_CD AND B.STOR_CD = C.STOR_CD   \n"
                //       + "   AND B.SUB_STOR_CD = C.SUB_STOR_CD AND B.KTCH_SYS_CD = C.KTCH_SYS_CD \n"
                //       + "   AND A.ORD_DIV = '0' \n"
                //       + "   AND A.SEND_YN = '0' \n"
                //       + "   AND A.ITEM_DIV IN ('0', '1', '2', '3', '4') \n"
                //       + "   AND A.CMP_CD = '" + m_cPosStatus.Base.CmpCd + "' \n"
                //       + "   AND A.STOR_CD = '" + m_cPosStatus.Base.StoreNo + "' \n"
                //       + "   AND B.USE_YN = '" + PosConst.MST_USE_YN.YES + "' \n"
                //       + "   AND C.USE_YN = '" + PosConst.MST_USE_YN.YES + "' \n"
                //       + "   AND C.KTCH_SYS_DIV = '" + PosConst.KTCH_SYS_DIV.KDS + "' \n"
                //       + " ORDER BY C.SUB_STOR_CD, C.KTCH_SYS_CD \n"
                //       ; 
                #endregion

                #region KPS + KDS 중복사용 적용 이전 버전
                ////sQuery = "SELECT A.ORD_DIV, A.FLOOR_CD, A.TBL_NO, A.SEQ, A.CMP_CD, A.BRAND_CD, A.STOR_CD, A.SUB_STOR_CD, A.POS_NO, A.TRADE_NO, A.SALE_DT, A.POS_TYPE, A.ITEM_CD, A.ITEM_DIV, A.SHTCUT_ITEMNM \n"
                //sQuery = "SELECT A.ORD_DIV, A.FLOOR_CD, A.TBL_NO, A.SEQ, A.CMP_CD, A.BRAND_CD, A.STOR_CD, A.POS_NO, A.TRADE_NO, A.SALE_DT, A.POS_TYPE, A.ITEM_CD, A.ITEM_DIV, A.SHTCUT_ITEMNM \n"
                //       + "     , A.SALE_QTY, A.PACK_DIV, A.SET_MENU_CD, A.ORD_TIME, A.CANCEL_DIV, A.SUB_MEMO_DIV, A.RESEND_YN \n"
                //       + "     , A.MSG1, A.MSG2, A.MSG3, A.FILLER2 AS ETC_ORD_FLAG, A.FILLER3 AS ADD_ORD_FLAG \n"
                //       + "     , C.SUB_STOR_CD, C.KTCH_SYS_CD \n"
                //       + "     , C.KTCH_SYS_USE_DIV, C.KTCH_DSP_IP, C.KTCH_DSP_PORT, C.FILLER1, C.FILLER2, A.FILLER3, C.FILLER4, C.FILLER5 \n"
                //       + "  FROM POSMST..MST_KTCH_ORD_MSG     A              \n"
                //       + "     , POSMST..MST_KTCH_DEVICE_ITEM B WITH(NOLOCK) \n"
                //       + "     , POSMST..MST_KTCH_DEVICE      C WITH(NOLOCK) \n"
                //       + " WHERE A.CMP_CD = B.CMP_CD AND A.STOR_CD = B.STOR_CD AND A.SUB_STOR_CD = B.SUB_STOR_CD AND A.ITEM_CD = B.ITEM_CD \n"
                //       + "   AND (A.FLOOR_CD = B.FLOOR_CD OR '999' = B.FLOOR_CD) \n"
                //       + "   AND B.CMP_CD = C.CMP_CD AND B.STOR_CD = C.STOR_CD   \n"
                //       + "   AND B.SUB_STOR_CD = C.SUB_STOR_CD AND B.KTCH_SYS_CD = C.KTCH_SYS_CD \n"
                //       + "   AND A.TRAIN_MODE_YN = '" + ItemConst.TRAINING_FLAG.TRAINING_NO + "' \n"                    // Add, 2017.03.03, 연습모드    KDS는 연습모드 없음.
                //       + "   AND A.ORD_DIV = '0' \n"
                //       + "   AND A.SEND_YN = '0' \n"
                //       + "   AND A.ITEM_DIV IN ('0', '1', '2', '3', '4') \n"
                //       + "   AND A.CMP_CD = '" + m_cPosStatus.Base.CmpCd + "' \n"
                //       + "   AND A.STOR_CD = '" + m_cPosStatus.Base.StoreNo + "' \n"
                //       + "   AND B.USE_YN = '" + PosConst.MST_USE_YN.YES + "' \n"
                //       + "   AND C.USE_YN = '" + PosConst.MST_USE_YN.YES + "' \n"
                //       //+ "   AND C.KTCH_SYS_DIV = '" + PosConst.KTCH_SYS_DIV.KDS + "' \n"
                //       + "   AND C.KTCH_SYS_DIV IN ('" + PosConst.KTCH_SYS_DIV.KDS + "', '" + PosConst.KTCH_SYS_DIV.KVS + "') \n"
                //       + " ORDER BY C.SUB_STOR_CD, C.KTCH_SYS_CD \n"
                //       ;  
                #endregion

                sQuery = "SELECT A.ORD_DIV, A.FLOOR_CD, A.TBL_NO, A.SEQ, A.CMP_CD, A.BRAND_CD, A.STOR_CD, A.POS_NO, A.TRADE_NO, A.SALE_DT, A.POS_TYPE, A.ITEM_CD, A.ITEM_DIV, A.SHTCUT_ITEMNM \n"
                       + "     , A.SALE_QTY, A.PACK_DIV, A.SET_MENU_CD, A.ORD_TIME, A.CANCEL_DIV, A.SUB_MEMO_DIV, A.RESEND_YN \n"
                       + "     , A.MSG1, A.MSG2, A.MSG3, A.FILLER2 AS ETC_ORD_FLAG, A.FILLER3 AS ADD_ORD_FLAG \n"
                       + "     , C.SUB_STOR_CD, C.KTCH_SYS_CD \n"
                       //17.09.13 dkshin SS 해피오더 수정
                       + "    , A.ORG_BILL_POSNO, A.ORG_BILL_NO \n"
                       //17.08.22 dkshin SS 해피오더
                       //+ "     , C.KTCH_SYS_USE_DIV, C.KTCH_DSP_IP, C.KTCH_DSP_PORT, C.FILLER1, C.FILLER2, A.FILLER3, C.FILLER4, C.FILLER5 \n"
                       
                       //#20170915 KVS 전송 안되는 현상 수정 start
                       //KTCH_SYS_DIV가 장비 구분인데 KTCH_SYS_USE_DIV값으로 가져와서 전송이 안됨.
                       //기존
                       //+ "     , C.KTCH_SYS_USE_DIV, C.KTCH_DSP_IP, C.KTCH_DSP_PORT, C.FILLER1, A.FILLER2, A.FILLER3, A.FILLER4, C.FILLER5 \n"
                       //변경
                       + "     , C.KTCH_SYS_DIV as KTCH_SYS_USE_DIV, C.KTCH_DSP_IP, C.KTCH_DSP_PORT, C.FILLER1, A.FILLER2, A.FILLER3, A.FILLER4, C.FILLER5 \n"
                       //#20170915 KVS 전송 안되는 현상 수정 end

                       + "  FROM POSMST..MST_KTCH_ORD_MSG     A                   \n"

                       //#20180208 거래데이터 저장 실패시 KDS 키중복 에러 발생할수 있어 NOLOCK 제거 start
                       //기존
                       + "     , POSMST..MST_KTCH_DEVICE      C WITH(NOLOCK)      \n"
                       //변경
                       //+ "     , POSMST..MST_KTCH_DEVICE      C      \n"
                       //#20180208 거래데이터 저장 실패시 KDS 키중복 에러 발생할수 있어 NOLOCK 제거 end

                       + " WHERE A.CMP_CD = C.CMP_CD AND A.STOR_CD = C.STOR_CD AND A.SUB_STOR_CD = C.SUB_STOR_CD \n"
                       + "   AND A.TRAIN_MODE_YN = '" + ItemConst.TRAINING_FLAG.TRAINING_NO + "'                 \n"
                       + "   AND A.ORD_DIV     = '0'                                \n"
                       + "   AND A.KDS_SEND_YN = '0'                                \n"
                       + "   AND A.ITEM_DIV   IN ('0', '1', '2', '3', '4')          \n"
                       + "   AND A.CMP_CD      = '" + m_cPosStatus.Base.CmpCd + "'  \n"
                       + "   AND A.STOR_CD     = '" + m_cPosStatus.Base.StoreNo + "'\n"
                       //#20170913 SS해피오더 KDS 미전송 수정 start
                       //기존
                       //+ "   AND A.ORD_POS_NO  = '" + m_cPosStatus.Base.PosNo + "'  \n"
                       //#20170913 SS해피오더 KDS 미전송 수정 end
                       + "   AND C.USE_YN      = '" + PosConst.MST_USE_YN.YES + "'  \n"
                       + "   AND C.KTCH_SYS_DIV IN ('" + PosConst.KTCH_SYS_DIV.KDS + "', '" + PosConst.KTCH_SYS_DIV.KVS + "') \n"
                       + " ORDER BY C.SUB_STOR_CD, C.KTCH_SYS_CD \n"
                       ; 

 

                // 조회
                DataTable dtData = null;
                if(sqlDb.DBDataTableSelect(sQuery, CommandType.Text, (SqlParameter[])null, out dtData) != UserCom.OK)
                {
                    //if (dtData != null && dtData.Rows.Count != 0)
                    //{
                    //    UserLog.WriteLogFile(UserCom.LOG_ERROR,
                    //                         UserCom.WARNING_LEVEL,
                    //                         System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                    //                         System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                    //                         System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                    //                         sQuery);
                    //}
                    return bRtn;
                }

                if (dtData.Rows.Count > 0)
                {
                    foreach (DataRow dr in dtData.Rows)
                    {
                        KDSItem cKDSItem = new KDSItem();

                        cKDSItem.sOrderType = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "ORD_DIV"));
                        cKDSItem.sFloorCd = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "FLOOR_CD"));
                        cKDSItem.sTableNo = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "TBL_NO"));
                        cKDSItem.sKtchSysCd = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "KTCH_SYS_CD"));
                        cKDSItem.nSeq = CmUtil.GetDataRowInt(dr, "SEQ");

                        if (cKDSItem.sOrderType == string.Empty || cKDSItem.sFloorCd == string.Empty || cKDSItem.sTableNo == string.Empty ||
                            cKDSItem.sKtchSysCd == string.Empty)
                        {
                            continue;
                        }

                        cKDSItem.sCmpCd = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "CMP_CD"));
                        cKDSItem.sBrandCd = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "BRAND_CD"));
                        // 복합매장일 경우를 대비하여 점포코드에는 서브점포코드를 넣는다.(2017.02.10)
                        cKDSItem.sStorCd = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "SUB_STOR_CD"));
                        cKDSItem.sPosNo = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "POS_NO"));
                        cKDSItem.sTradeNo = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "TRADE_NO"));
                        cKDSItem.sSaleDt = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "SALE_DT"));
                        cKDSItem.sPosType = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "POS_TYPE"));
                        cKDSItem.sItemCd = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "ITEM_CD"));
                        cKDSItem.sItemDiv = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "ITEM_DIV"));
                        // KDS, KVS 의 경우 부가메뉴 표시 문자를 삭제 함(안호성C, 20170420)
                        cKDSItem.sItemNm = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "SHTCUT_ITEMNM")).TrimStart(new char[] {'>'});
                        cKDSItem.nQty = CmUtil.GetDataRowInt(dr, "SALE_QTY");
                        cKDSItem.sPackDiv = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "PACK_DIV"));
                        cKDSItem.sSetMenuCd = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "SET_MENU_CD"));
                        cKDSItem.sOrdTime = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "ORD_TIME"));
                        cKDSItem.sCancelDiv = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "CANCEL_DIV"));
                        cKDSItem.sOrgBillPosNo = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "ORG_BILL_POSNO"));
                        cKDSItem.sOrgBillDt = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "ORG_BILL_DT"));
                        cKDSItem.sOrgBillNo = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "ORG_BILL_NO"));
                        cKDSItem.sKtchSysUseDiv = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "KTCH_SYS_USE_DIV"));
                        cKDSItem.sKtchKdsIp = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "KTCH_DSP_IP"));
                        cKDSItem.sKtchKdsPort = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "KTCH_DSP_PORT"));
                        cKDSItem.sResendYn = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "RESEND_YN"));
                        cKDSItem.sFiller1 = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "FILLER1"));
                        cKDSItem.sFiller2 = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "FILLER2"));
                        cKDSItem.sFiller3 = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "FILLER3"));
                        cKDSItem.sFiller4 = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "FILLER4"));
                        cKDSItem.sFiller5 = CmUtil.StringNullEmpty(CmUtil.GetDataRowStr(dr, "FILLER5"));

                        cKDSItem.sSendYn = "0";
                        cKDSItem.sErrorCd = "0000";

                        htKDSSendingItem.Add(htKDSSendingItem.Count, cKDSItem);
                    }

                    if (htKDSSendingItem.Count > 0)
                    {
                        InsertIntoKDS(htKDSSendingItem);
                        bRtn = true;
                    }
                }
            }
            catch (Exception ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     ex.Message);
            }

            return bRtn;
        }
        /// <summary>
        /// Insert into MST_KDS_ORD_MSG
        /// </summary>
        /// <param name="htKDSItem"></param>
        private void InsertIntoKDS(Hashtable htKDSItem)
        {
            string sQuery = "";

            try
            {
                if(htKDSItem.Count > 0)
                {
                    //#20170111 트랜젝션 위치 변경 start
                    //기존
                    //sqlDb.DBBeginTransaction();
                    //#20170111 트랜젝션 위치 변경 end

                    for(int nLoop = 0;nLoop < htKDSItem.Count;nLoop++)
                    {
                        KDSItem cKDSItem = (KDSItem)htKDSItem[nLoop];

                        sQuery  = "INSERT INTO POSMST..MST_KDS_ORD_MSG ";
                        sQuery += "       ( ORD_DIV, FLOOR_CD, TBL_NO, KTCH_SYS_CD, SEQ, CMP_CD, BRAND_CD, STOR_CD, POS_NO, TRADE_NO, SALE_DT, POS_TYPE, ITEM_CD, ITEM_DIV, SHTCUT_ITEMNM ";
                        sQuery += "       , SALE_QTY, PACK_DIV, SET_MENU_CD, ORD_TIME, CANCEL_DIV, ORG_BILL_POSNO, ORG_BILLDT ";
                        sQuery += "       , ORG_BILL_NO, KTCH_SYS_USE_DIV, KTCH_KDS_IP, KTCH_KDS_PORT, ERROR_CD, SEND_YN, RESEND_YN ";
                        sQuery += "       , FILLER1, FILLER2, FILLER3, FILLER4, FILLER5, UPD_DT, REG_DT ) ";
                        sQuery += "VALUES ";
                        sQuery += "       ( '{0}', '{1}', '{2}', '{3}', {4}, '{5}', '{6}', '{7}', '{8}', '{9}', '{10}', '{11}', '{12}', '{13}', N'{14}' ";
                        sQuery += "       , {15}, '{16}', '{17}', '{18}', '{19}', '{20}', '{21}' ";
                        sQuery += "       , '{22}', '{23}', '{24}', '{25}', '{26}', '{27}', '{28}' ";
                        sQuery += "       , '{29}', '{30}', '{31}', '{32}', '{33}', '{34}', '{35}' ) ";

                        string[] saQuery = new string[1];
                        saQuery[0] = string.Format(sQuery
                                                  , cKDSItem.sOrderType
                                                  , cKDSItem.sFloorCd
                                                  , cKDSItem.sTableNo
                                                  , cKDSItem.sKtchSysCd
                                                  , cKDSItem.nSeq
                                                  , cKDSItem.sCmpCd
                                                  , cKDSItem.sBrandCd
                                                  , cKDSItem.sStorCd
                                                  , cKDSItem.sPosNo
                                                  , cKDSItem.sTradeNo
                                                  , cKDSItem.sSaleDt
                                                  , cKDSItem.sPosType
                                                  , cKDSItem.sItemCd
                                                  , cKDSItem.sItemDiv
                                                  , cKDSItem.sItemNm
                                                  , cKDSItem.nQty
                                                  , cKDSItem.sPackDiv
                                                  , cKDSItem.sSetMenuCd
                                                  , cKDSItem.sOrdTime
                                                  , cKDSItem.sCancelDiv
                                                  , cKDSItem.sOrgBillPosNo
                                                  , cKDSItem.sOrgBillDt
                                                  , cKDSItem.sOrgBillNo
                                                  , cKDSItem.sKtchSysUseDiv
                                                  , cKDSItem.sKtchKdsIp
                                                  , cKDSItem.sKtchKdsPort
                                                  , cKDSItem.sErrorCd
                                                  , "0"
                                                  , cKDSItem.sResendYn
                                                  , cKDSItem.sFiller1
                                                  , cKDSItem.sFiller2
                                                  , cKDSItem.sFiller3
                                                  , cKDSItem.sFiller4
                                                  , cKDSItem.sFiller5
                                                  , DateTime.Now.ToString("yyyyMMddHHmmss")
                                                  , DateTime.Now.ToString("yyyyMMddHHmmss")
                                                  );

                        //#20170111 트랜젝션 위치 변경 start
                        //변경

                        //#20180302 KDS 처리시 트랜젝션 제거 start
                        //적용시 아래 소스주석
                        //sqlDb.DBBeginTransaction();
                        //#20180302 KDS 처리시 트랜젝션 제거 end

                        //#20170111 트랜젝션 위치 변경 end

                        if (sqlDb.DBExecuteNonQuery(saQuery, CommandType.Text, (SqlParameter[])null) != UserCom.OK)
                        {
                            // Rollback

                            //#20180302 KDS 처리시 트랜젝션 제거 start
                            //적용시 아래 소스주석
                            //sqlDb.DBTransactionRollback();
                            //#20180302 KDS 처리시 트랜젝션 제거 end

                            UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                                 UserCom.WARNING_LEVEL,
                                                 System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                                 System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (클래스명)
                                                 System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (함수명)
                                                 "Query=" + sQuery);

                            //#20170111 트랜젝션 위치 변경 start
                            //변경

                            //#20180302 KDS 처리시 트랜젝션 제거 start
                            //적용시 아래 소스주석
                            //sqlDb.DBBeginTransaction();
                            //#20180302 KDS 처리시 트랜젝션 제거 end

                            sQuery = "UPDATE POSMST..MST_KTCH_ORD_MSG ";
                            sQuery += "   SET KDS_SEND_YN = '1' ";
                            sQuery += " WHERE TRAIN_MODE_YN = '" + ItemConst.TRAINING_FLAG.TRAINING_NO + "' ";              // Add, 2017.03.03, 연습모드 
                            sQuery += "   AND ORD_DIV = '" + cKDSItem.sOrderType + "' ";
                            sQuery += "   AND FLOOR_CD = '" + cKDSItem.sFloorCd + "' ";
                            sQuery += "   AND TBL_NO = '" + cKDSItem.sTableNo + "' ";
                            sQuery += "   AND SEQ = " + cKDSItem.nSeq + " ";

                            if (sqlDb.DBExecuteNonQuery(new string[] { sQuery }, CommandType.Text, (SqlParameter[])null) != UserCom.OK)
                            {
                                // Rollback

                                //#20180302 KDS 처리시 트랜젝션 제거 start
                                //적용시 아래 소스주석
                                //sqlDb.DBTransactionRollback();
                                //#20180302 KDS 처리시 트랜젝션 제거 end

                                UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                                     UserCom.WARNING_LEVEL,
                                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (클래스명)
                                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (함수명)
                                                     "Query=" + sQuery);
                                return;
                            }

                            //#20180302 KDS 처리시 트랜젝션 제거 start
                            //적용시 아래 소스주석
                            //sqlDb.DBTransactionCommit();
                            //#20180302 KDS 처리시 트랜젝션 제거 end

                            //#20170111 트랜젝션 위치 변경 end

                            //#20170929 KDS 데이터 INSERT 실패해도 상태 업데이트 하도록 수정(key error) start
                            //#20180105 트랜젝션 오류로 원복 start
                            //기존
                            return;
                            //#20170929 KDS 데이터 INSERT 실패해도 상태 업데이트 하도록 수정(key error) end
                        }

                        sQuery  = "UPDATE POSMST..MST_KTCH_ORD_MSG ";
                        sQuery += "   SET KDS_SEND_YN = '1' ";
                        sQuery += " WHERE TRAIN_MODE_YN = '" + ItemConst.TRAINING_FLAG.TRAINING_NO + "' ";              // Add, 2017.03.03, 연습모드 
                        sQuery += "   AND ORD_DIV = '" + cKDSItem.sOrderType + "' ";
                        sQuery += "   AND FLOOR_CD = '" + cKDSItem.sFloorCd + "' ";
                        sQuery += "   AND TBL_NO = '" + cKDSItem.sTableNo + "' ";
                        sQuery += "   AND SEQ = " + cKDSItem.nSeq + " ";

                        if(sqlDb.DBExecuteNonQuery(new string[] {sQuery}, CommandType.Text, (SqlParameter[])null) != UserCom.OK)
                        {
                            // Rollback

                            //#20180302 KDS 처리시 트랜젝션 제거 start
                            //적용시 아래 소스주석
                            //sqlDb.DBTransactionRollback();
                            //#20180302 KDS 처리시 트랜젝션 제거 end

                            UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                                 UserCom.WARNING_LEVEL,
                                                 System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                                 System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (클래스명)
                                                 System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (함수명)
                                                 "Query=" + sQuery);
                            return;
                        }

                        //#20170111 트랜젝션 위치 변경 start
                        //변경

                        //#20180302 KDS 처리시 트랜젝션 제거 start
                        //적용시 아래 소스주석
                        //sqlDb.DBTransactionCommit();
                        //#20180302 KDS 처리시 트랜젝션 제거 end

                        //#20170111 트랜젝션 위치 변경 end
                    }

                    // Commit
                    //#20170111 트랜젝션 위치 변경 start
                    //기존
                    //sqlDb.DBTransactionCommit();
                    //#20170111 트랜젝션 위치 변경 end
                }
            }
            catch (Exception ex)
            {
                // Rollback

                //#20180302 KDS 처리시 트랜젝션 제거 start
                //적용시 아래 소스주석
                //sqlDb.DBTransactionRollback();
                //#20180302 KDS 처리시 트랜젝션 제거 end

                UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     ex.Message);
            }
        }
        #endregion 데이터 이행 처리(주방주문데이터 -> KDS)

        #region 전송 데이터 생성
        /// <summary>
        /// KDS 전송 데이터 생성
        /// </summary>
        /// <param name="htKDSSendItem"></param>
        /// <returns></returns>
        private Hashtable GetKDSSendItem(ref Hashtable htKDSSendItem, ref string sIp, ref int iPort, ref string[] saKey)
        {
            string sQuery = "";

            DataTable dtKey = null;
            DataTable dtData = null;

            Hashtable htSendData = null;
            try
            {
                Hashtable htCommHeader = null;
                Hashtable htOrderHeader = null;
                Hashtable[] htOrderItem = null;
                Hashtable[] htOrderMsg = new Hashtable[3];

                #region 01.전송할 거래 조회

                //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 start
                //기존
                /*
                sQuery = "SELECT TOP 1 ORD_DIV, FLOOR_CD, TBL_NO, KTCH_SYS_CD ";
                sQuery += "  FROM POSMST..MST_KDS_ORD_MSG ";
                sQuery += " WHERE SEND_YN IN ('0', '9') ";
                sQuery += " AND RESEND_YN ='0' ";//17.08.22 dkshin SS 해피오더 - KDS 전송 체크
                sQuery += " ORDER BY SEND_YN ";
                */
                //변경
                sQuery = "SELECT TOP 1 ORD_DIV, FLOOR_CD, TBL_NO, KTCH_SYS_CD, ISNULL(F_CNT,0) F_CNT ";
                sQuery += "  FROM POSMST..MST_KDS_ORD_MSG ";
                sQuery += " WHERE SEND_YN IN ('0', '9') ";
                sQuery += " AND RESEND_YN ='0' ";//17.08.22 dkshin SS 해피오더 - KDS 전송 체크
                sQuery += " AND F_CNT <= 3 ";
                sQuery += " ORDER BY SEND_YN ";
                //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 end

                if(sqlDb.DBDataTableSelect(sQuery, CommandType.Text, (SqlParameter[])null, out dtKey) != UserCom.OK)
                {
                    if (dtKey != null && dtKey.Rows.Count != 0)
                    {
                        UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                             UserCom.WARNING_LEVEL,
                                             System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                             System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (클래스명)
                                             System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (함수명)
                                             "Query=" + sQuery);
                    }
                    return htSendData;
                }

                saKey[0] = CmUtil.GetDataRowStr(dtKey.Rows[0], "ORD_DIV");
                saKey[1] = CmUtil.GetDataRowStr(dtKey.Rows[0], "FLOOR_CD");
                saKey[2] = CmUtil.GetDataRowStr(dtKey.Rows[0], "TBL_NO");
                saKey[3] = CmUtil.GetDataRowStr(dtKey.Rows[0], "KTCH_SYS_CD");
                //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 start
                saKey[4] = CmUtil.GetDataRowStr(dtKey.Rows[0], "F_CNT");
                //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 end

                #endregion 01.전송할 거래 조회

                #region 02.동일 거래의 데이터 조회
                sQuery  = "SELECT ORD_DIV, FLOOR_CD, TBL_NO, KTCH_SYS_CD, SEQ, CMP_CD, BRAND_CD, STOR_CD, POS_NO, TRADE_NO, SALE_DT, POS_TYPE, ITEM_CD, ITEM_DIV, SHTCUT_ITEMNM, SALE_QTY ";
                sQuery += "     , PACK_DIV, SET_MENU_CD, ORD_TIME, CANCEL_DIV, ORG_BILL_POSNO, ORG_BILLDT, ORG_BILL_NO, KTCH_SYS_USE_DIV ";
                sQuery += "     , KTCH_KDS_IP, KTCH_KDS_PORT, ERROR_CD, SEND_YN, RESEND_YN, FILLER1, FILLER2, FILLER3, FILLER4, FILLER5 ";
                sQuery += "  FROM POSMST..MST_KDS_ORD_MSG ";
                sQuery += " WHERE ORD_DIV = '" + CmUtil.GetDataRowStr(dtKey.Rows[0], "ORD_DIV") + "' ";
                sQuery += "   AND FLOOR_CD = '" + CmUtil.GetDataRowStr(dtKey.Rows[0], "FLOOR_CD") + "' ";
                sQuery += "   AND TBL_NO = '" + CmUtil.GetDataRowStr(dtKey.Rows[0], "TBL_NO") + "' ";
                sQuery += "   AND KTCH_SYS_CD = '" + CmUtil.GetDataRowStr(dtKey.Rows[0], "KTCH_SYS_CD") + "' ";
                //17.08.22 dkshin SS 해피오더
                sQuery += "   AND SEND_YN IN ('0', '9') ";
                sQuery += "   AND RESEND_YN ='0' ";

                sQuery += " ORDER BY KTCH_SYS_CD, ORD_DIV, FLOOR_CD, TBL_NO, CANCEL_DIV, SEQ ";

                if(sqlDb.DBDataTableSelect(sQuery, CommandType.Text, (SqlParameter[])null, out dtData) != UserCom.OK)
                {
                    if (dtData != null && dtData.Rows.Count != 0)
                    {
                        UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                             UserCom.WARNING_LEVEL,
                                             System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                             System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (클래스명)
                                             System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (함수명)
                                             "Query=" + sQuery);
                    }
                    return htSendData;
                }

                sIp = CmUtil.GetDataRowStr(dtData.Rows[0], "KTCH_KDS_IP");
                iPort = CmUtil.GetDataRowInt(dtData.Rows[0], "KTCH_KDS_PORT");
                #endregion 02.동일 거래의 데이터 조회

                #region 03.COMM_HEADER - 통신헤더 생성
                // 통신 헤더 생성
                htCommHeader = new Hashtable();
                htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.MSG_TYPE, "70");
                //17.08.22 dkshin SS 해피오더
                //170914 dkshin KDS: PC, KVS: PCKR
                //htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.CO_CD, CmUtil.GetDataRowStr(dtData.Rows[0], "CMP_CD"));
                if (CmUtil.GetDataRowStr(dtData.Rows[0], "KTCH_SYS_USE_DIV") == PosConst.KTCH_SYS_DIV.KDS)
                {
                    if (CmUtil.GetDataRowStr(dtData.Rows[0], "CMP_CD") == "PCKR")
                        htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.CO_CD, "PC");
                }
                else
                    htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.CO_CD, CmUtil.GetDataRowStr(dtData.Rows[0], "CMP_CD"));

                htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.BRAND_CD, CmUtil.GetDataRowStr(dtData.Rows[0], "BRAND_CD"));
                htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.STORE_CD, CmUtil.GetDataRowStr(dtData.Rows[0], "STOR_CD"));
                htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.POS_NO, CmUtil.GetDataRowStr(dtData.Rows[0], "POS_NO"));
                htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.TRAN_NO, CmUtil.GetDataRowStr(dtData.Rows[0], "TBL_NO"));
                htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.TRAN_YMD, CmUtil.GetDataRowStr(dtData.Rows[0], "SALE_DT"));
                htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.SYS_YMD, DateTime.Now.ToString("yyyyMMdd"));
                htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.SYS_HMS, DateTime.Now.ToString("HHmmss"));
                htCommHeader.Add(Column.IQ_KDS_HEADER_REQ.DATA.ERR_CD, "000");
                #endregion 03.COMM_HEADER - 통신헤더 생성

                #region 04.ORDER_HEADER - 주문헤더 생성
                // 주문 헤더 생성
                htOrderHeader = new Hashtable();
                htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.TR_HEADER_ID, "70");
                htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.POS_NO, CmUtil.GetDataRowStr(dtData.Rows[0], "FLOOR_CD"));
                // 주문번호를 사용하면 TRAN_NO에 주문번호 대입, 아닐 경우 TRAN_NO에 거래번호 대입
                if (PosMstManager.GetPosOption(POS_OPTION.OPT008) == "1")
                {
                    htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.TRAN_NO, CmUtil.GetDataRowStr(dtData.Rows[0], "TRADE_NO"));
                }
                else
                {
                    htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.TRAN_NO, CmUtil.GetDataRowStr(dtData.Rows[0], "TBL_NO"));
                }
                htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.DEAL_TY, CmUtil.GetDataRowStr(dtData.Rows[0], "CANCEL_DIV"));
                htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.POS_TY, CmUtil.GetDataRowStr(dtData.Rows[0], "POS_TYPE"));
                //17.08.22 dkshin SS 해피오더
                //htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.TABLE_NM, "");

                htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.ORDER_CUST_NM, "");
              //htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.VIP_TY, CmUtil.GetDataRowStr(dtData.Rows[0], "FILLER3"));
                //17.08.22 dkshin SS 해피오더
                //htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.VIP_TY, CmUtil.GetDataRowStr(dtData.Rows[0], "FILLER4"));
                if (CmUtil.GetDataRowStr(dtData.Rows[0], "FILLER2") == "2")
                {
                    htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.TABLE_NM, CmUtil.GetDataRowStr(dtData.Rows[0], "ORD_TIME"));//픽업시간 ex) 03-29 17:30
                    htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.VIP_TY, "3");
                    htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.ORDER_TY, "2");
                }
                else
                {
                    htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.TABLE_NM, "");
                    htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.VIP_TY, CmUtil.GetDataRowStr(dtData.Rows[0], "FILLER4"));
                    htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.ORDER_TY, CmUtil.GetDataRowStr(dtData.Rows[0], "PACK_DIV"));
                }
                //17.08.22 dkshin SS 해피오더
                //htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.ORDER_TY, CmUtil.GetDataRowStr(dtData.Rows[0], "PACK_DIV"));

                htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.ORG_POS_NO, CmUtil.GetDataRowStr(dtData.Rows[0], "ORG_BILL_POSNO"));
                htOrderHeader.Add(Column.IQ_KDS_ORDER_HEADER_REQ.DATA.ORG_TRAN_NO, CmUtil.GetDataRowStr(dtData.Rows[0], "ORG_BILL_NO"));
                #endregion 04.ORDER_HEADER - 주문헤더 생성

                #region 05.ORDER_ITEM - 주문명세 생성
                // 주문 명세 생성
                htOrderItem = new Hashtable[dtData.Rows.Count];
                for(int nLoop = 0;nLoop < dtData.Rows.Count;nLoop++)
                {
                    DataRow dr = dtData.Rows[nLoop];
                    htOrderItem[nLoop] = new Hashtable();
                    htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.TR_ITEM_ID, "71");
                    htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.SEQ_NO, (nLoop + 1).ToString());
                    htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.DEAL_TY, CmUtil.GetDataRowStr(dr, "CANCEL_DIV"));
                    switch(CmUtil.GetDataRowStr(dr, "ITEM_DIV"))
                    {
                        case ItemConst.PLU_ITEM_DIV.NORMAL:
                        case ItemConst.PLU_ITEM_DIV.SET_DIS:
                        case ItemConst.PLU_ITEM_DIV.GIFT:
                            htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.MENU_TY, "1");     // 제품
                            break;
                        case ItemConst.PLU_ITEM_DIV.OPT_MENU:
                            htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.MENU_TY, "2");     // 부가메뉴
                            break;
                        case ItemConst.PLU_ITEM_DIV.SET_MAIN:
                        case ItemConst.PLU_ITEM_DIV.SET_DETL:
                            htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.MENU_TY, "3");     // 세트
                            break;                        
                    }
                    htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.ITEM_CD, CmUtil.GetDataRowStr(dr, "ITEM_CD"));
                    htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.ITEM_NM, CmUtil.GetDataRowStr(dr, "SHTCUT_ITEMNM"));
                    htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.ITEM_QTY, CmUtil.GetDataRowInt(dr, "SALE_QTY"));
                    htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.MSG_1, "");
                    htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.MSG_2, "");
                    htOrderItem[nLoop].Add(Column.IQ_KDS_ORDER_ITEM_REQ.DATA.MSG_3, "");
                }
                #endregion 05.ORDER_ITEM - 주문명세 생성

                #region 06.ORDER_MESSAGE - 주문 전달 메시지 생성
                // 주문 전달 메시지 생성
                for(int nLoop = 0;nLoop < 3;nLoop++)
                {
                    htOrderMsg[nLoop] = new Hashtable();
                }
                #endregion 06.ORDER_MESSAGE - 주문 전달 메시지 생성

                #region 07.JSON 데이터 생성
                htSendData = new Hashtable();
                htSendData.Add("HEADER", htCommHeader);
                htSendData.Add("ORDERHEADER", htOrderHeader);
                htSendData.Add("ORDER_ITEM", htOrderItem);
                htSendData.Add("ORDERMSG", htOrderMsg);
                #endregion 07.JSON 데이터 생성
            }
            catch (Exception ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     ex.Message);
            }

            return htSendData;
        }
        #endregion 전송 데이터 생성

        #region KDS 전송 플래그 업데이트 처리
        public int UpdateKDSSendFlag(string sOrdDiv, string sFloorCd, string sTblNo, string sKtchSysCd, string sSendFlag)
        {
            int iRet = UserCom.NG;
            string sQuery = "";
            try
            {
                if (sOrdDiv.Trim() == "") return iRet;
                if (sFloorCd.Trim() == "") return iRet;
                if (sTblNo.Trim() == "") return iRet;
                if (sKtchSysCd.Trim() == "") return iRet;

                sQuery += " UPDATE POSMST..MST_KDS_ORD_MSG ";
                sQuery += "    SET SEND_YN = '" + sSendFlag + "' ";
                sQuery += "      , RESEND_YN = '1' ";//17.08.22 dkshin SS 해피오더 - KDS 전송 체크
                sQuery += "      , UPD_DT = '" + DateTime.Now.ToString("yyyyMMddHHmmss") + "' ";
                //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 start
                sQuery += "      , F_CNT = CASE WHEN '" + sSendFlag + "' = '9' THEN ISNULL(F_CNT,0) + 1 ELSE ISNULL(F_CNT,0) END ";
                //#20180202 KDS 전송 실패시 3회 재시도, 최초 한번 영수증 출력 end
                sQuery += "  WHERE ORD_DIV = '" + sOrdDiv + "' ";
                sQuery += "    AND FLOOR_CD = '" + sFloorCd + "' ";
                sQuery += "    AND TBL_NO = '" + sTblNo + "' ";
                sQuery += "    AND KTCH_SYS_CD = '" + sKtchSysCd + "' ";

                if (sqlDb.DBExecuteNonQuery(new string[] { sQuery }, CommandType.Text, (SqlParameter[])null) != UserCom.OK)
                {
                    UserLog.WriteLogFile(UserCom.LOG_DEBUG,
                                         UserCom.WARNING_LEVEL,
                                         System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                         System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (클래스명)
                                         System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (함수명)
                                         "Query=" + sQuery);
                }
                else
                {
                    iRet = UserCom.OK;
                }
            }
            catch (Exception ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_DEBUG,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     ex.Message);
            }

            return iRet;
        }
        #endregion KDS 전송 플래그 업데이트 처리

        #region 전송 모듈
        private string SendProcess(string sSvrIp, int iPort, int iTimeout, Hashtable htSendData)
        {
            string sRet = UserCom.RST_ERR;

            try
            {
                // JSON 객체로 변환
                string sJsonSendData = JsonConvert.SerializeObject(htSendData);
                // JSON string 길이를 구하기 위해 byte로 변환
                //Byte[] arTempData = Encoding.ASCII.GetBytes(sJsonSendData);
                Byte[] arTempData = (Encoding.GetEncoding("euc-kr")).GetBytes(sJsonSendData);

                string header = string.Format("KDS{0:00000}", arTempData.Length);

                string sJsonRecvData = string.Empty;

                int iRet = DataSendReceive(sSvrIp, iPort, iTimeout, header + sJsonSendData);

                if(iRet == UserCom.OK)
                {
                    sRet = UserCom.RST_OK;
                }
            }
            catch (Exception ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     ex.Message);
            }

            return sRet;
        }

        private int DataSendReceive(string sIp, int iPort, int iTimeout, string sSendData)
        {
            int iRet = UserCom.NG;
            int nRecvLen = 0;
            string sRecvData = string.Empty;

            try
            {
                m_sendSocket = new TcpSocket(sIp, iPort);

                UserLog.WriteLogFile(UserCom.LOG_SOCK,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (Project Name (프로젝트명))
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명)), 
                                     CmUtil.RPadH("[SEND" + ":" + sIp + ":" + iPort, 27) + "] " + sSendData);

                // Data Send & Receive
                nRecvLen = m_sendSocket.KDSSendReceiveData(sSendData, ref sRecvData, m_iTimeout, DATA_LEN_SIZE, 3);

                UserLog.WriteLogFile(UserCom.LOG_SOCK, System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (Project Name (프로젝트명))
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명)), 
                                     CmUtil.RPadH("[RECV" + ":" + sIp + ":" + iPort, 27) + "] " + sRecvData);

                if(sRecvData.Length > 0)
                {
                    //Hashtable htJsonRecvData = JsonConvert.DeserializeObject<Hashtable>(sRecvData);

                    //if(htJsonRecvData["HEADER"].ToString().Length > 0)
                    //{
                    //    Hashtable htCommHeader = JsonConvert.DeserializeObject<Hashtable>(htJsonRecvData["HEADER"].ToString());

                    //    if (htCommHeader.ContainsKey("ERR_CD") == true)
                    //    {
                    //        if(htCommHeader["ERR_CD"].ToString() == "000")
                    //        {
                    //            iRet = UserCom.OK;
                    //        }
                    //    }
                    //}

                    if(sRecvData.Substring(8, 5).Equals("OK!!!") == true)
                    {
                        iRet = UserCom.OK;
                    }
                }

            }
            catch (Exception ex)
            {
                UserLog.WriteLogFile(UserCom.LOG_ERROR,
                                     System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name,      // Project Name (프로젝트명)
                                     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." +  // Class Name (Class Name (클래스명))
                                     System.Reflection.MethodBase.GetCurrentMethod().Name + "()",                // Function Name (Function Name (함수명))
                                     ex.Message);
            }
            return iRet;
        }
        #endregion
    }
}
