using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using Renci.SshNet.Sftp;
using System.Text;
using Renci.SshNet.Common;
using System.Globalization;
using System.Threading;
using Renci.SshNet.NetConf;
using System.Xml;
using System.Diagnostics.CodeAnalysis;
namespace Renci.SshNet
{
    //  TODO:   Please help with documentation here, as I don't know the details, specially for the methods not documented.
    /// 
    /// 
    /// 
    public partial class NetConfClient : BaseClient
    {
        /// 
        /// Holds SftpSession instance that used to communicate to the SFTP server
        /// 
        private NetConfSession _netConfSession;
        private bool _disposeConnectionInfo;
        /// 
        /// Gets or sets the operation timeout.
        /// 
        /// The operation timeout.
        public TimeSpan OperationTimeout { get; set; }
        #region Constructors
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// The connection info.
        ///  is null.
        public NetConfClient(ConnectionInfo connectionInfo)
            : base(connectionInfo)
        {
            this.AutomaticMessageIdHandling = true;
            this.OperationTimeout = new TimeSpan(0, 0, 0, 0, -1);
        }
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Connection host.
        /// Connection port.
        /// Authentication username.
        /// Authentication password.
        ///  is null.
        ///  is invalid, or  is null or contains whitespace characters.
        ///  is not within  and .
        [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
        public NetConfClient(string host, int port, string username, string password)
            : this(new PasswordConnectionInfo(host, port, username, password))
        {
            this._disposeConnectionInfo = true;
        }
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Connection host.
        /// Authentication username.
        /// Authentication password.
        ///  is null.
        ///  is invalid, or  is null or contains whitespace characters.
        public NetConfClient(string host, string username, string password)
            : this(host, 22, username, password)
        {
        }
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Connection host.
        /// Connection port.
        /// Authentication username.
        /// Authentication private key file(s) .
        ///  is null.
        ///  is invalid, -or-  is null or contains whitespace characters.
        ///  is not within  and .
        [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")]
        public NetConfClient(string host, int port, string username, params PrivateKeyFile[] keyFiles)
            : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles))
        {
            this._disposeConnectionInfo = true;
        }
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Connection host.
        /// Authentication username.
        /// Authentication private key file(s) .
        ///  is null.
        ///  is invalid, -or-  is null or contains whitespace characters.
        public NetConfClient(string host, string username, params PrivateKeyFile[] keyFiles)
            : this(host, 22, username, keyFiles)
        {
        }
        #endregion
        /// 
        /// Gets NetConf server capabilities.
        /// 
        /// Client is not connected.
        public XmlDocument ServerCapabilities 
        {
            get
            {
                this.EnsureConnection();
                return this._netConfSession.ServerCapabilities;
            }
        }
        /// 
        /// Gets NetConf client capabilities.
        /// 
        /// Client is not connected.
        public XmlDocument ClientCapabilities
        {
            get
            {
                this.EnsureConnection();
                return this._netConfSession.ClientCapabilities;
            }
        }
        public bool AutomaticMessageIdHandling { get; set; }
        
        /// Client is not connected.
        public XmlDocument SendReceiveRpc(XmlDocument rpc)
        {
            this.EnsureConnection();
            return this._netConfSession.SendReceiveRpc(rpc, this.AutomaticMessageIdHandling);
        }
        public XmlDocument SendReceiveRpc(string xml)
        {
            var rpc = new XmlDocument();
            rpc.LoadXml(xml);
            return SendReceiveRpc(rpc);
        }
        public XmlDocument SendCloseRpc()
        {
            this.EnsureConnection();
            XmlDocument rpc = new XmlDocument();
            rpc.LoadXml("");
            return this._netConfSession.SendReceiveRpc(rpc, this.AutomaticMessageIdHandling);
        }
        /// 
        /// Called when client is connected to the server.
        /// 
        protected override void OnConnected()
        {
            base.OnConnected();
            this._netConfSession = new NetConfSession(this.Session, this.OperationTimeout);
            this._netConfSession.Connect();            
        }
        /// 
        /// Called when client is disconnecting from the server.
        /// 
        protected override void OnDisconnecting()
        {
            base.OnDisconnecting();
            this._netConfSession.Disconnect();
        }
        /// 
        /// Releases unmanaged and - optionally - managed resources
        /// 
        /// true to release both managed and unmanaged resources; false to release only unmanaged ResourceMessages.
        protected override void Dispose(bool disposing)
        {
            if (this._netConfSession != null)
            {
                this._netConfSession.Dispose();
                this._netConfSession = null;
            }
            base.Dispose(disposing);
            if (this._disposeConnectionInfo)
                ((IDisposable)this.ConnectionInfo).Dispose();
        }
    }
}