using System;
using System.Collections.Generic;
using System.Threading;
using JWH;
using TIBCO.Rendezvous;

namespace JWH.TIB
{

    /// <summary>
    /// TIBCO.Message & XmlData를 관리
    /// </summary>
    public class XmlMessage : IDisposable
    {

        #region [ Event ] =====================================================

        public event EventHandler OnTimeOver;

        #endregion

        #region [ Variable ] ==================================================

        public Timer SendReplyTimer { get; protected set; } = null;

        private Message m_Message = null;

        #endregion

        #region [ Properties ] ================================================

        /// <summary>
        /// 수신된 RequestMessage
        /// </summary>
        public XmlMessage RequestMessage { get; set; } = null;

        /// <summary>
        /// TIBCO.Message
        /// </summary>
        public Message Message { get { return GetMessage(); } }

        /// <summary>
        /// SendRequestFlag
        /// </summary>
        public bool SendRequestFlag { get; set; } = false;

        /// <summary>
        /// IsReply
        /// </summary>
        public bool IsReply { get; set; } = false;

        /// <summary>
        /// XmlData
        /// </summary>
        public XmlData XmlData { get; set; } = null;

        /// <summary>
        /// TIBCO.Message.SendSubject (!=XmlData.SendSubjectName)
        /// </summary>
        public string SendSubject { get; set; } = string.Empty;

        /// <summary>
        /// TIBCO.Message.ReplySubject (!=XmlData.ReplySubjectName)
        /// </summary>
        public string ReplySubject { get; set; } = string.Empty;

        /// <summary>
        /// TIBCO.Rendezvous.Message.Fields
        /// </summary>
        public Dictionary<string, object> Fields { get; set; } = new Dictionary<string, object>();

        #endregion

        #region [ Constructor ] ===============================================

        /// <summary>
        /// XmlMessage
        /// </summary>
        public XmlMessage()
        {
            this.XmlData = new XmlData();
        }

        /// <summary>
        /// 메시지 파일을 기준으로 생성
        /// </summary>
        /// <param name="xmlData"></param>
        public XmlMessage(string xmlData)
        {
            this.XmlData = new XmlData(xmlData);
            this.SendRequestFlag = this.XmlData.SendRequestFlag;
        }

        /// <summary>
        /// TIBCO.Message 정보를 기준으로 생성
        /// </summary>
        /// <param name="message"></param>
        public XmlMessage(Message message)
        {
            this.m_Message = message;

            for (uint i = 0; i < message.FieldCount; i++)
            {
                MessageField field = message.GetFieldByIndex(i);

                switch (field.Name.ToUpper())
                {
                    case "XMLDATA":
                        if (field.Value != null && field.Value.GetType() == typeof(string)) this.XmlData = new XmlData(field.Value.ToString());
                        break;
                    case "SENDREQUESTFLAG":
                        if (field.Value != null && field.Value.GetType() == typeof(bool)) this.SendRequestFlag = (bool)Convert.ChangeType(field.Value, typeof(bool));
                        break;
                    default:
                        this.Fields.Add(field.Name, field.Value);
                        break;
                }
            }

            this.SendSubject = message.SendSubject;
            this.ReplySubject = message.ReplySubject;
        }

        ~XmlMessage()
        {
            XLogger.Instance.Debug($"{this.XmlData?.MessageName} {this.XmlData?.TransactionID}");
            this.Dispose();
        }

        public void Dispose()
        {
            try
            {
                if (this.SendReplyTimer != null)
                {
                    this.SendReplyTimer.Dispose();
                    this.SendReplyTimer = null;
                }

                if (this.RequestMessage != null)
                {
                    this.RequestMessage.Dispose();
                    this.RequestMessage = null;
                }

                if (this.m_Message != null)
                {
                    XLogger.Instance.Debug($"{m_Message}");
                    this.m_Message.Dispose();
                    this.m_Message = null;
                }
            }
            catch (Exception ex)
            {
                XLogger.Instance.Fatal(ex);
            }
        }

        public override string ToString()
        {
            return $"{this.XmlData?.ToString()}";
        }

        #endregion

        #region [ Raise_Events ] ==============================================

        private void Raise_OnTimeOut()
        {
            this.OnTimeOver?.Invoke(this, new EventArgs());
        }

        #endregion

        #region [ Public Method ] =============================================

        public void SetRequstMessage(XmlMessage xmlRequest)
        {
            this.RequestMessage = xmlRequest;
            this.IsReply = true;
            this.SendSubject = xmlRequest.XmlData.ReplySubjectName;
            this.ReplySubject = xmlRequest.ReplySubject;
            //if (!string.IsNullOrEmpty(xmlRequest.ReplySubject)) this.SendSubject = xmlRequest.ReplySubject;

            this.XmlData.TransactionID = xmlRequest.XmlData.TransactionID;
            this.XmlData.SendSubjectName = xmlRequest.XmlData.ReplySubjectName;
            this.XmlData.ReplySubjectName = xmlRequest.XmlData.SendSubjectName;
        }

        /// <summary>
        /// SendReply Timeout 체크를 시작한다
        /// </summary>
        /// <param name="interval"></param>
        public void TimerStart(int interval = 30)
        {
            interval = interval * 1000;
            this.SendReplyTimer = new Timer(this.SendReplyTimer_TimeOut, null, interval, Timeout.Infinite);
        }

        /// <summary>
        /// SendReply Timeout 체크를 중지한다
        /// </summary>
        public void TimerStop()
        {
            if (this.SendReplyTimer != null)
            {
                this.SendReplyTimer.Dispose();
                this.SendReplyTimer = null;
            }
        }

        /// <summary>
        /// SendReply Timeout
        /// </summary>
        /// <param name="state"></param>
        private void SendReplyTimer_TimeOut(object state)
        {
            this.SendReplyTimer.Dispose();
            this.SendReplyTimer = null;
            this.Raise_OnTimeOut();
        }

        #endregion

        #region [ Method ] ====================================================

        /// <summary>
        /// 현 객체의 정보를 TIBCO.Message로 반환한다
        /// </summary>
        /// <returns></returns>
        private Message GetMessage()
        {
            try
            {
                if (this.m_Message != null) return this.m_Message;

                Message message = new Message();
                if (!string.IsNullOrEmpty(this.SendSubject)) message.SendSubject = this.SendSubject;
                if (!string.IsNullOrEmpty(this.ReplySubject)) message.ReplySubject = this.ReplySubject;
                message.AddField("xmlData", this.XmlData.GetText());
                message.AddField("SendRequestFlag", this.SendRequestFlag);

                return message;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        #endregion

    }

}
