using System;
using System.Xml;
using JWH;

namespace JWH.TIB
{

    public class XmlData
    {

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

        private XmlDocument Document { get; set; } = null;

        #endregion

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

        public bool SendRequestFlag { get; set; } = false;

        public XmlNode Message { get; set; } = null;

        public XmlNode Header { get; set; } = null;

        public XmlNode Body { get; set; } = null;


        #region [ Header Items ] -----------------------------------------------

        /// <summary>
        /// Header.MessageName
        /// </summary>
        public string MessageName
        {
            get { return this.GetValue("MessageName"); }
            set { this.SetValue("MessageName", value); }
        }

        /// <summary>
        /// Header.TransationID
        /// </summary>
        public string TransactionID
        {
            get { return this.GetValue("TransactionID"); }
            set { this.SetValue("TransactionID", value); }
        }

        /// <summary>
        /// Header.SendSubjectName
        /// </summary>
        public string SendSubjectName
        {
            get { return this.GetValue("SendSubjectName"); }
            set { this.SetValue("SendSubjectName", value); }
        }

        /// <summary>
        /// Header.ReplySubjectName
        /// </summary>
        public string ReplySubjectName
        {
            get { return this.GetValue("ReplySubjectName"); }
            set { this.SetValue("ReplySubjectName", value); }
        }

        #endregion

        #region [ Body Items ] -------------------------------------------------

        /// <summary>
        /// Body.SITEID
        /// </summary>
        public string SITEID
        {
            get { return this.GetValue("SITEID"); }
            set { this.SetValue("SITEID", value); }
        }

        /// <summary>
        /// Body.EquipmentID
        /// </summary>
        public string EquipmentID
        {
            get { return this.GetValue("EquipmentID"); }
            set { this.SetValue("EquipmentID", value); }
        }

        /// <summary>
        /// Body.DateTime
        /// </summary>
        public string DateTime
        {
            get { return this.GetValue("DateTime"); }
            set { this.SetValue("DateTime", value); }
        }

        /// <summary>
        /// Body.ControlMode
        /// </summary>
        public string ControlMode
        {
            get { return this.GetValue("ControlMode"); }
            set { this.SetValue("ControlMode", value); }
        }

        #endregion

        #region [ Return Items ] -----------------------------------------------

        /// <summary>
        /// Return.ReturnCode
        /// </summary>
        public string ReturnCode
        {
            get { return this.GetValue("ReturnCode"); }
            set { this.SetValue("ReturnCode", value); }
        }

        /// <summary>
        /// Return.ReturnMessage
        /// </summary>
        public string ReturnMessage
        {
            get { return this.GetValue("ReturnMessage"); }
            set { this.SetValue("ReturnMessage", value); }
        }

        #endregion

        #endregion

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

        public XmlData()
        {
            if (this.Document == null) this.Document = new XmlDocument();
            XmlDocument document = this.Document;
            XmlNode node = null;
            
            this.Message = document.CreateNode("element", "message", "");
            document.AppendChild(this.Message);

            this.Header = document.CreateNode("element", "header", "");
            this.Message.AppendChild(this.Header);
            node = document.CreateNode("element", "messagename", ""); this.Header.AppendChild(node);
            node = document.CreateNode("element", "transactionid", ""); this.Header.AppendChild(node);
            node.InnerXml = Guid.NewGuid().ToString();
            node = document.CreateNode("element", "sendSubjectName", ""); this.Header.AppendChild(node);
            node = document.CreateNode("element", "replySubjectName", ""); this.Header.AppendChild(node);

            this.Body = document.CreateNode("element", "body", "");
            this.Message.AppendChild(this.Body);
            node = document.CreateNode("element", "SITEID", ""); this.Body.AppendChild(node);
            node = document.CreateNode("element", "EQUIPMENTID", ""); this.Body.AppendChild(node);
            node = document.CreateNode("element", "DATETIME", ""); this.Body.AppendChild(node);
            node.InnerXml = System.DateTime.Now.ToString("yyyyMMddHHmmss");
            node = document.CreateNode("element", "CONTROLMODE", ""); this.Body.AppendChild(node);
        }

        public XmlData(string xmlData)
        {
            this.FromString(xmlData);
        }

        public override string ToString()
        {
            return $"{this.MessageName} - {this.TransactionID}";
        }

        #endregion

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

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

        /// <summary>
        /// FromString
        /// </summary>
        /// <param name="xmlData"></param>
        public void FromString(string xmlData)
        {
            XmlDocument document = new XmlDocument();
            this.Document = document;
            if (string.IsNullOrEmpty(xmlData)) return;

            document.LoadXml(xmlData.XMLUnescape());
            this.Message = document.GetSingleNodeByName("Message");
            this.Header = document.GetSingleNodeByName("Header");
            this.Body = document.GetSingleNodeByName("Body");

            XmlNode msgName = this.Header.GetSingleNodeByName("MessageName");
            if (msgName.GetText().ToUpper().EndsWith("REQUEST")) this.SendRequestFlag = true;
            else this.SendRequestFlag = false;

            // SendRequest 파일에 정의된 속성값을 읽고, 메모리에서는 제거한다.
            XmlNode msgNode = this.Document.GetSingleNodeByName("Message");
            XmlAttribute attSendRequestFlag = msgNode.GetAttribute("SendRequestFlag");
            if (attSendRequestFlag != null)
            {
                bool isSendRequestFlag = this.SendRequestFlag;
                if (bool.TryParse(attSendRequestFlag.Value, out isSendRequestFlag)) this.SendRequestFlag = isSendRequestFlag;
                msgNode.Attributes.Remove(attSendRequestFlag);
            }
        }

        #endregion

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

        public string GetText()
        {
            return this.Document?.GetBeautify(4, false);
        }

        /// <summary>
        /// 지정된 노드의 값을 반환한다
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string GetValue(string name)
        {
            if (this.Document == null) return string.Empty;

            return this.Document.GetSingleNodeByName(name)?.InnerXml;
        }

        /// <summary>
        /// 지정된 노드의 값을 변경한다
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public XmlNode SetValue(string name, string value)
        {
            XmlNode node = this.GetNode(name);
            if (node == null) return null;

            node.InnerXml = value;
            return node;
        }

        /// <summary>
        /// 지정된 노드를 반환한다
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public XmlNode GetNode(string name)
        {
            if (this.Document == null) return null;
            XmlNode node = this.Document.GetSingleNodeByName(name);

            return node;
        }

        /// <summary>
        /// 지정된 노드들을 반환한다
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public XmlNode[] GetNodes(string name)
        {
            if (this.Document == null) return null;
            XmlNode[] nodes = this.Document.GetNodesByName(name);

            return nodes;
        }

        /// <summary>
        /// 참조된 노드의 하위에 노드를 추가한다
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public XmlNode AddChildNode(XmlNode node, string name, string value = "")
        {
            XmlNode newNode = this.Document.CreateNode("element", name, "");
            if (!string.IsNullOrEmpty(value)) newNode.InnerXml = value;
            node.AppendChild(newNode);

            return newNode;
        }

        /// <summary>
        /// 참조된 노드의 앞에 노드를 추가한다
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public XmlNode InsertBefore(XmlNode node, string name, string value = "")
        {
            XmlNode newNode = this.Document.CreateNode("element", name, "");
            if (!string.IsNullOrEmpty(value)) newNode.InnerXml = value;
            this.Document.InsertBefore(newNode, node);

            return newNode;
        }

        /// <summary>
        /// 참조된 노드의 뒤에 노드를 추가한다
        /// </summary>
        /// <param name="node"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public XmlNode InsertAfter(XmlNode node, string name, string value = "")
        {
            XmlNode newNode = this.Document.CreateNode("element", name, "");
            if (!string.IsNullOrEmpty(value)) newNode.InnerXml = value;
            this.Document.InsertAfter(newNode, node);

            return newNode;
        }

        /// <summary>
        /// return 노드를 반환한다
        /// </summary>
        /// <returns></returns>
        public XmlNode GetReturn()
        {
            XmlNode node = this.GetNode("return");
            if (node != null) return node;

            return InsertAfter(this.Body, "return");
        }

        #endregion

    }

}
