using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Text;
using System.IO;
using EasyDevCore.Common;

#pragma warning disable CS8601 // Possible null reference assignment.
#pragma warning disable CS8602 // Dereference of a possibly null reference.
#pragma warning disable CS8603 // Possible null reference return.
#pragma warning disable CS8604 // Possible null reference argument.
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
namespace EasyDevCore.Common.Wrapper
{
    /// <summary>
    /// 
    /// </summary>
    public class XMLWrapper: IDisposable
    {
        /// <summary>
        /// Gets the text.
        /// </summary>
        /// <value>
        /// The text.
        /// </value>
        public string Text { get; private set; }
        /// <summary>
        /// The m_ disposed
        /// </summary>
        private bool m_Disposed = false;
        /// <summary>
        /// The m_ reader
        /// </summary>
        private StringReader m_Reader = null;

        /// <summary>
        /// Gets the X doc.
        /// </summary>
        /// <value>
        /// The X doc.
        /// </value>
        public XDocument XDoc { get; private set; }

        /// <summary>
        /// Creates the intance.
        /// </summary>
        /// <param name="xml">The XML.</param>
        /// <returns></returns>
        public XMLWrapper CreateIntance(string xml)
        {
            return new XMLWrapper(xml);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="XMLWrapper"/> class.
        /// </summary>
        /// <param name="xml">The XML.</param>
        public XMLWrapper(string xml)
        {
            Text = xml;
            m_Reader = new StringReader(xml);
            XDoc = XDocument.Load(m_Reader);
        }

        /// <summary>
        /// Gets the elements.
        /// </summary>
        /// <param name="xPathExpression">The x path expression ("./Customer/CompanyName" ~ Element("Customer").Elements("CompanyName")).</param>
        /// <param name="descendantElement">The descendant element.</param>
        /// <returns></returns>
        public IEnumerable<XElement> GetElements(string xPathExpression, XElement descendantElement = null)
        {
            if(descendantElement != null) descendantElement.XPathSelectElements(xPathExpression);
            return XDoc.XPathSelectElements(xPathExpression);
        }
        
        /// <summary>
        /// Gets the element.
        /// </summary>
        /// <param name="xPathExpression">The x path expression ("./Customer/CompanyName" ~ Element("Customer").Elements("CompanyName")).</param>
        /// <param name="descendantElement">The descendant element.</param>
        /// <returns></returns>
        public XElement GetElement(string xPathExpression, XElement descendantElement = null)
        {
            if (descendantElement != null) descendantElement.XPathSelectElement(xPathExpression);
            return XDoc.XPathSelectElement(xPathExpression);
        }

        /// <summary>
        /// Gets the element XML.
        /// </summary>
        /// <param name="xPathExpression">The x path expression ("./Customer/CompanyName" ~ Element("Customer").Elements("CompanyName")).</param>
        /// <param name="descendantElement">The descendant element.</param>
        /// <returns></returns>
        public IEnumerable<string> GetElementsXML(string xPathExpression, XElement descendantElement = null)
        {
            return GetElements(xPathExpression, descendantElement).Select(e => e.ToString());
        }

        /// <summary>
        /// Gets the element XML.
        /// </summary>
        /// <param name="xPathExpression">The x path expression ("./Customer/CompanyName" ~ Element("Customer").Elements("CompanyName")).</param>
        /// <param name="descendantElement">The descendant element.</param>
        /// <returns></returns>
        public string GetElementXML(string xPathExpression, XElement descendantElement = null)
        {
            return GetElement(xPathExpression, descendantElement).ToString();
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources.
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.m_Disposed)
            {
                if (disposing)
                {
                    m_Reader.Close();
                    m_Reader = null;
                    XDoc = null;
                }
                m_Disposed = true;
            }
        }

    }
}
