using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using SystemX.Common;
using SystemX.Common.Serialization;
using SystemX.Net.BaseProtocol;
using SystemX.Net.Schedule;

using static SystemX.Net.MiddlewareUI.MainForm;

namespace SystemX.Net.MiddlewareUI.UIM.Protocol_Method
{
    public class PROCESS_QUERY : ProtocolShell, IProtocol
    {
        protected enum ISSUANCE_TYPE
        {
            NONE = 0,
            ISSUANCE = 1,
            REISSUANCE = 2
        }

        ISSUANCE_TYPE eTypeIssuance;

        string strGetMacAddress;

        string strReturnMessage;

        string strGetProductID;

        Int64 nAbrogateMacUQNo;
        Int64 nReIssuanceProductUQNo;

        DataSet ds;

        public PROCESS_QUERY(MainForm parent, int iPos, byte nLabel)
        : base(parent, iPos, nLabel)
        {
            eTypeIssuance = ISSUANCE_TYPE.NONE;

            strGetMacAddress = string.Empty;

            strReturnMessage = string.Empty;

            strGetProductID = string.Empty;

            ds = null;
        }

        public override void ExecuteProtocol(BASE_PROTOCOL GET_PROTOCOL,
            BASE_PROTOCOL.PROTOCOL_CODE CODE,
            HEADER_PACKET getHeader,
            object objData)
        {
            //QUERY PALLET INFO
            PROCESS_PACKET ppPacket = (PROCESS_PACKET)objData;

            byte[] ucQueryByteArray = null;

            ConnectInfoStore thisConnInfo = Parent_.GetConnectInfo(nPos) as ConnectInfoStore;

            switch (GET_PROTOCOL.GetOptionCode())
            {
                case BASE_PROTOCOL.OPTION_CODE.QUERY_TESTLIST:
                    {
                        IsByteList = true;

                        string strGetQuery = cp.QueryFindTestList(ppPacket);

                        int nLoadPosition = 0;

                        getStreamList = Parent_.QueryStreamProcess(strGetQuery, out ucQueryByteArray, out ds);

                        if (XCommons.isHasRow(ds) == true)
                        {
                            nLoadPosition = Convert.ToInt32(ds.Tables[0].Rows[0]["UseTLPosition"]);

                            if (nLoadPosition > 0)
                            {
                                strGetQuery = cp.QuerySelectTestListData(ppPacket, nLoadPosition);

                                getStreamList = Parent_.QueryStreamProcess(strGetQuery, out ucQueryByteArray, out ds);
                            }
                        }

                        thisConnInfo.strResultTestListCntID = string.Empty;

                        string GetTestListCntID = string.Empty;

                        for (int n = 0; n < 2; n++)
                        {
                            GetTestListCntID = Parent_.SetQueryTestListInfo(nPos, thisConnInfo.strConnectHostID, thisConnInfo.strConnectSection, ppPacket, ds);

                            if ((GetTestListCntID.IndexOf("[FAIL]") >= 0) ||
                                (GetTestListCntID.IndexOf("[CHECK]") >= 0) ||
                                (GetTestListCntID.IndexOf("[ERROR]") >= 0))
                                break;

                            thisConnInfo.strResultTestListCntID = GetTestListCntID;

                            if (string.IsNullOrEmpty(GetTestListCntID) == false)
                            {
                                getStreamList = Parent_.QueryStreamProcess(strGetQuery, out ucQueryByteArray, out ds, thisConnInfo.strResultTestListCntID);

                                break;
                            }
                        }

                        nByteListSize = getStreamList.Count;

                        /*
                        if (string.IsNullOrEmpty(GetTestListCntID) == true)
                            this.bThisShellSendOn = false;
                        */
                    }
                    break;
                case BASE_PROTOCOL.OPTION_CODE.CHECK_VAILD_TESTLIST:
                    {
                        IsByteList = true;

                        string strGetQuery = cp.QueryFindTestList(ppPacket, true);

                        getStreamList = Parent_.QueryStreamProcess(strGetQuery, out ucQueryByteArray, out ds);

                        nByteListSize = getStreamList.Count;
                    }
                    break;
                case BASE_PROTOCOL.OPTION_CODE.GET_ISSUANCE_MACADDRESS:
                    {
                        //Query 결과 : DataSet, RecordsAffectedCnt, FieldCnt, HasRow
                        var vResult = new Tuple<DataSet, int, int, bool>(null, 0, 0, false);

                        //Param 1 : Query 문 Param 2 : Table Return 위치
                        var vMakeQueryText = new Tuple<string, string>(string.Empty, string.Empty);

                        int nErrCode = 0;

                        try
                        {
                            strGetProductID = ppPacket.objProductID[0].Data;

                            eTypeIssuance = (ISSUANCE_TYPE)Enum.Parse(typeof(ISSUANCE_TYPE), ppPacket.objTestCode[0].Data);

                            vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("ID_IsIssued", new List<string>() { strGetProductID });

                            vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                            ds = vResult.Item1;

                            //발행된 이력이 존재 만약 재발행 옵션이라면
                            if (XCommons.isHasRow(ds) == true)
                            {
                                //발행된 맥어드레스 리턴
                                vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("LookUpMacAddress_ByID", new List<string>() { strGetProductID });

                                //Query Text, Return Field Pos or Field Name 
                                vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                                //Data Set, Field Cnt, Records Affected Cnt, Has Row
                                ds = vResult.Item1;

                                strGetMacAddress = GetTableValue(ds, vMakeQueryText.Item2);

                                if (eTypeIssuance == ISSUANCE_TYPE.ISSUANCE)
                                {
                                    strReturnMessage = "[ERROR] ID [" + strGetProductID + "] that has already been issued. The issued MAC address is as follows [" + strGetMacAddress + "].";

                                    nErrCode = -2;

                                    throw new Exception(strReturnMessage);
                                }
                                else if (eTypeIssuance == ISSUANCE_TYPE.REISSUANCE)
                                {
                                    string strGetMacUQNo = ds.Tables[0].Rows[0][0].ToString();
                                    string strGetProductUQNo = ds.Tables[0].Rows[0][3].ToString();

                                    nAbrogateMacUQNo = Int64.MaxValue;
                                    nReIssuanceProductUQNo = Int64.MaxValue;

                                    Int64.TryParse(strGetMacUQNo, out nAbrogateMacUQNo);
                                    Int64.TryParse(strGetProductUQNo, out nReIssuanceProductUQNo);
                                }
                            }
                            else
                            {
                                //발행된 이력이 없을때 재발행 옵션일시 재발행 에러 처리
                                if (eTypeIssuance == ISSUANCE_TYPE.REISSUANCE)
                                {
                                    //실패 발행된 맥어드레스 리턴 및 에러 문구 
                                    vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("LookUpMacAddress_ByID", new List<string>() { strGetProductID });

                                    //Query Text, Return Field Pos or Field Name 
                                    vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                                    //Data Set, Field Cnt, Records Affected Cnt, Has Row
                                    ds = vResult.Item1;

                                    strGetMacAddress = string.Empty;

                                    strReturnMessage = "[ERROR] ID [" + strGetProductID + "] There is no published history. In the case of the reissue option, only the issued ID can be processed.";

                                    nErrCode = -3;

                                    throw new Exception(strReturnMessage);
                                }
                            }

                            //현재 발행갯수 확인 및 Index Seek
                            int nCurrentMacNum = GetCurrentMacQuantity();

                            if (nCurrentMacNum == int.MinValue)
                            {
                                strReturnMessage = "[ERROR] Failed to get internal index start number.(MacAddress)";

                                nErrCode = -12;

                                throw new Exception(strReturnMessage);
                            }

                            string strGetProductNo = string.Empty;
                            Int64 nGetProductNo = Int64.MaxValue;

                            if (eTypeIssuance == ISSUANCE_TYPE.ISSUANCE)
                            {
                                //현재 제품 발행갯수 확인 및 Index Seek
                                int nCurrentProductNum = GetCurrentProductQuantity();

                                if (nCurrentProductNum == int.MinValue)
                                {
                                    strReturnMessage = "[ERROR] Failed to get internal index start number.(Product)";

                                    nErrCode = -13;

                                    throw new Exception(strReturnMessage);
                                }
                                else
                                {
                                    //등록될 제품 위치 가져오기
                                    vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("Product_ToBeRegisterCheck", new List<string>() { nCurrentProductNum.ToString() });

                                    vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                                    ds = vResult.Item1;

                                    //미등록 제품 위치 가져오기 실패시(조회 실패)
                                    if (XCommons.isHasRow(ds) == false)
                                    {
                                        strReturnMessage = "[ERROR] ID [" + strGetProductID + "] Failed to look up register position.";

                                        nErrCode = -14;

                                        throw new Exception(strReturnMessage);
                                    }

                                    //해당 맥 어드레스 번호 학인
                                    strGetProductNo = ds.Tables[0].Rows[0][0].ToString();

                                    nGetProductNo = Int64.MaxValue;
                                    Int64.TryParse(strGetProductNo, out nGetProductNo);
                                }
                            }
                            else if (eTypeIssuance == ISSUANCE_TYPE.REISSUANCE)
                            {
                                nGetProductNo = nReIssuanceProductUQNo;
                                strGetProductNo = nGetProductNo.ToString();
                            }

                            //맥 어드레스 하나 가져오기
                            vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("MacAddress_ToBeIssuedCheck", new List<string>() { nCurrentMacNum.ToString() });

                            vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                            ds = vResult.Item1;

                            //미지정 맥 어드레스 가져오기 실패시(조회 실패)
                            if (XCommons.isHasRow(ds) == false)
                            {
                                strReturnMessage = "[ERROR] ID [" + strGetProductID + "] Failed to look up unissued MAC address.";

                                nErrCode = -15;

                                throw new Exception(strReturnMessage);
                            }

                            //해당 맥 어드레스 번호 학인
                            string strGetMacNo = ds.Tables[0].Rows[0][0].ToString();

                            Int64 nGetMacNo = Int64.MaxValue;
                            Int64.TryParse(strGetMacNo, out nGetMacNo);

                            //해당 맥 어드레스 발급 여부 확인
                            vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("CheckMacAddressIsItemState", new List<string>() { strGetMacNo });

                            vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                            ds = vResult.Item1;

                            //발급 여부 관련 쿼리 실패시
                            if (XCommons.isHasRow(ds) == false)
                            {
                                strReturnMessage = "[ERROR] ID [" + strGetProductID + "] Failed to look up unissued MAC address.";

                                nErrCode = -16;

                                throw new Exception(strReturnMessage);
                            }

                            //발급 여부 확인
                            bool bIsIssuedState = Convert.ToBoolean(ds.Tables[0].Rows[0][0]);
                            bool bIsAbrogateState = Convert.ToBoolean(ds.Tables[0].Rows[0][1]);
                            strGetMacAddress = ds.Tables[0].Rows[0][2].ToString();

                            //이미 발급된 맥 어드레스
                            if (bIsIssuedState)
                            {
                                strReturnMessage = "[ERROR] ID [" + strGetProductID + "] It was searched by the MAC address that was already issued.";

                                nErrCode = -17;

                                strGetMacAddress = string.Empty;

                                throw new Exception(strReturnMessage);
                            }
                            //이미 폐기된 맥 어드레스
                            if (bIsAbrogateState)
                            {
                                strReturnMessage = "[ERROR] ID [" + strGetProductID + "] It was searched by the MAC address that was abrogate.";

                                nErrCode = -18;

                                strGetMacAddress = string.Empty;

                                throw new Exception(strReturnMessage);
                            }

                            //해당 맥 어드레스 발급 여부 발급 상태로 변경
                            vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("ChangeIsIssuedState", new List<string>() { strGetMacNo });

                            Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                            //해당 맥 어드레스 발급 여부 확인
                            vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("CheckMacAddressIsItemState", new List<string>() { strGetMacNo });

                            vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                            ds = vResult.Item1;

                            //발급 여부 관련 쿼리 실패시
                            if (XCommons.isHasRow(ds) == false)
                            {
                                strReturnMessage = "[ERROR] ID [" + strGetProductID + "] Failed to check whether the MAC address is issued.";

                                nErrCode = -19;

                                strGetMacAddress = string.Empty;

                                throw new Exception(strReturnMessage);
                            }

                            //발급 여부 확인
                            bIsIssuedState = Convert.ToBoolean(ds.Tables[0].Rows[0][0]);

                            //발급이 안되었다면
                            if (bIsIssuedState == false)
                            {
                                strReturnMessage = "[ERROR] ID [" + strGetProductID + "] Failed to change whether to issue the MAC address.";

                                nErrCode = -20;

                                strGetMacAddress = string.Empty;

                                throw new Exception(strReturnMessage);
                            }

                            if (eTypeIssuance == ISSUANCE_TYPE.ISSUANCE)
                            {
                                //해당 위치 받은 제품 ID 정보로 변경
                                vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("NewUpdateProductIDInfo", new List<string>() { strGetProductID, strGetProductNo });

                                Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);
                            }
                            else if (eTypeIssuance == ISSUANCE_TYPE.REISSUANCE)
                            {
                                //해당 위치 받은 제품 ID 정보로 변경
                                vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("GetProductInfo", new List<string>() { strGetProductNo });

                                vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                                ds = vResult.Item1;

                                //제품 전체 정보 조회 실패
                                if (XCommons.isHasRow(ds) == false)
                                {
                                    strReturnMessage = "[ERROR] ID [" + strGetProductID + "] Product all information inquiry failed.";

                                    nErrCode = -21;

                                    strGetMacAddress = string.Empty;

                                    throw new Exception(strReturnMessage);
                                }

                                bool bReIssued = Convert.ToBoolean(ds.Tables[0].Rows[0][4]);
                                int  nIssuedNumber = int.Parse(ds.Tables[0].Rows[0][5].ToString());

                                nIssuedNumber += 1;

                                vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("SetProductIssueInfo", new List<string>() { nIssuedNumber.ToString(), strGetProductNo });

                                Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);
                            }

                            //해당 위치 제품 ID 정보 일치 확인
                            vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("CheckProductIDInfo", new List<string>() { strGetProductNo });

                            vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                            ds = vResult.Item1;

                            //제품 ID 정보 조회 실패
                            if (XCommons.isHasRow(ds) == false)
                            {
                                strReturnMessage = "[ERROR] ID [" + strGetProductID + "] Product ID information inquiry failed.";

                                nErrCode = -22;

                                strGetMacAddress = string.Empty;

                                throw new Exception(strReturnMessage);
                            }

                            string strID = ds.Tables[0].Rows[0][0].ToString();

                            //제품 ID 정보 불 일치
                            if (strID.CompareTo(strGetProductID) != 0)
                            {
                                strReturnMessage = "[ERROR] ID [" + strGetProductID + "] Failed to change ID information owned by the MAC address.";

                                nErrCode = -23;

                                strGetMacAddress = string.Empty;

                                throw new Exception(strReturnMessage);
                            }

                            //맥어드레스 참조 제품 관계 번호(UNIQUE) 업데이트
                            vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("UpdateMacAddressRelationNumber", new List<string>() { strGetProductNo, strGetMacNo });

                            Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                            //제품 참조 맥 어드레스 관계 번호(UNIQUE) 업데이트
                            vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("UpdateProductIDRelationNumber", new List<string>() { strGetMacNo, strGetProductNo });

                            Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                            if (eTypeIssuance == ISSUANCE_TYPE.ISSUANCE)
                            {
                                //서머리 기록
                                SetPublishSummary("Issued", nGetMacNo, "Issuance processing by MAC address issuance request.");

                                //제품 등록 INDEX SEEK
                                SetProductQuantity();
                            }
                            else if (eTypeIssuance == ISSUANCE_TYPE.REISSUANCE)
                            {
                                vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("ChangeIsAbrogateState", new List<string>() { nAbrogateMacUQNo.ToString() });

                                Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                                //서머리 기록
                                SetPublishSummary("Abrogate", nAbrogateMacUQNo, "Abrogate of previously registered mac address information by requesting MAC address reissuance.");

                                //서머리 기록
                                SetPublishSummary("Reissued", nGetMacNo, "Reissuance processing by MAC address reissuance request.");
                            }

                            //맥 어드레스 등록 가능 갯수 변경
                            SetMacQuantity();

                            //처리된 해당 제품 ID 관련 맥 어드레스 재 조회
                            vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("LookUpMacAddress_ByID", new List<string>() { strGetProductID });

                            vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

                            ds = vResult.Item1;

                            //strReturnMessage = strGetMacAddress;

                        }
                        catch (Exception e)
                        {
                            //Error Process
                            if (strReturnMessage == string.Empty)
                                strReturnMessage = e.Message;
                        }
                        finally
                        {
                            //결과 보내기
                            Parent_.QueryResultRemake(ds,
                            vResult.Item2,
                            vResult.Item3,
                            vResult.Item4,
                            out ucSendByteInfo,
                            vMakeQueryText.Item2,
                            strReturnMessage,
                            nErrCode.ToString());
                        }
                    }
                    break;
            }
        }

        private bool SetPublishSummary(string strSetResult, Int64 nReferenceNo = Int64.MaxValue, string strSetDesc = "")
        {
            bool bSummaryResult = true;

            var vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("PublishSummaryNumberCheck");

            var vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

            ds = vResult.Item1;

            Int64 nSummaryNo = Int64.MaxValue;

            try
            {
                if (Int64.TryParse(ds.Tables[0].Rows[0][0].ToString(), out nSummaryNo) == false)
                    throw new Exception();

                string strNowTime = DateTime.Now.ToString("yyyyMMddHHmmssfff");

                nSummaryNo += 1;

                ConnectInfoStore thisConnInfo = Parent_.GetConnectInfo(nPos) as ConnectInfoStore;

                string strQueryID = nSummaryNo + "-" + strNowTime;
                string strRefNum = nReferenceNo == Int64.MaxValue ? null : nReferenceNo.ToString();

                List<string> lstParam = new List<string>();

                lstParam.Add(strQueryID);
                lstParam.Add(strRefNum);

                lstParam.Add(thisConnInfo.strConnectHostID);
                lstParam.Add(thisConnInfo.strConnectSection);

                lstParam.Add(strGetProductID);

                lstParam.Add(strSetResult);
                lstParam.Add(strSetDesc);

                vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("PublishSummaryInsert", lstParam);

                vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);
            }
            catch
            {
                bSummaryResult = false;
            }

            return bSummaryResult;
        }

        private int GetCurrentMacQuantity()
        {
            int nCurCnt = int.MaxValue;

            var vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("Check_Mac_Quantity");

            var vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

            ds = vResult.Item1;

            try
            {
                if (int.TryParse(ds.Tables[0].Rows[0][0].ToString(), out nCurCnt) == false)
                    throw new Exception();
            }
            catch
            {
                nCurCnt = int.MinValue;
            }

            return nCurCnt;
        }

        private bool SetMacQuantity()
        {
            bool bResult = true;

            var vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("Check_Mac_Quantity");

            var vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

            ds = vResult.Item1;

            try
            {
                Int64 nCurCnt = Int64.MaxValue;

                if (Int64.TryParse(ds.Tables[0].Rows[0][0].ToString(), out nCurCnt) == false)
                    throw new Exception();

                nCurCnt += 1;

                vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("Set_Mac_Quantity", new List<string>() { nCurCnt.ToString() });

                vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);
            }
            catch
            {
                bResult = false;
            }

            return bResult;
        }

        private int GetCurrentProductQuantity()
        {
            int nCurCnt = int.MaxValue;

            var vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("Check_Product_Quantity");

            var vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

            ds = vResult.Item1;

            try
            {
                if (int.TryParse(ds.Tables[0].Rows[0][0].ToString(), out nCurCnt) == false)
                    throw new Exception();
            }
            catch
            {
                nCurCnt = int.MinValue;
            }

            return nCurCnt;
        }

        private bool SetProductQuantity()
        {
            bool bResult = true;

            var vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("Check_Product_Quantity");

            var vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);

            ds = vResult.Item1;

            try
            {
                Int64 nCurCnt = Int64.MaxValue;

                if (Int64.TryParse(ds.Tables[0].Rows[0][0].ToString(), out nCurCnt) == false)
                    throw new Exception();

                nCurCnt += 1;

                vMakeQueryText = Parent_.GetUsetQueryInfo().GetUserQueryText("Set_Product_Quantity", new List<string>() { nCurCnt.ToString() });

                vResult = Parent_.QueryProcess(vMakeQueryText.Item1, out ucSendByteInfo);
            }
            catch
            {
                bResult = false;
            }

            return bResult;
        }
    }
}
