using System;
using Renci.SshNet.Common;
using Renci.SshNet.Messages.Connection;
namespace Renci.SshNet.Channels
{
    internal abstract class ClientChannel : Channel
    {
        /// 
        /// Occurs when  message is received.
        /// 
        public event EventHandler OpenConfirmed;
        /// 
        /// Occurs when  message received
        /// 
        public event EventHandler OpenFailed;
        /// 
        /// Initializes the channel.
        /// 
        /// The session.
        /// Size of the window.
        /// Size of the packet.
        internal override void Initialize(Session session, uint localWindowSize, uint localPacketSize)
        {
            base.Initialize(session, localWindowSize, localPacketSize);
            Session.ChannelOpenConfirmationReceived += OnChannelOpenConfirmation;
            Session.ChannelOpenFailureReceived += OnChannelOpenFailure;
        }
        /// 
        /// Called when channel is opened by the server.
        /// 
        /// The remote channel number.
        /// Initial size of the window.
        /// Maximum size of the packet.
        protected virtual void OnOpenConfirmation(uint remoteChannelNumber, uint initialWindowSize, uint maximumPacketSize)
        {
            InitializeRemoteInfo(remoteChannelNumber, initialWindowSize, maximumPacketSize);
            //  Channel is consider to be open when confirmation message was received
            this.IsOpen = true;
            var openConfirmed = OpenConfirmed;
            if (openConfirmed != null)
                openConfirmed(this, new ChannelOpenConfirmedEventArgs(remoteChannelNumber, initialWindowSize, maximumPacketSize));
        }
        /// 
        /// Send message to open a channel.
        /// 
        /// Message to send
        protected void SendMessage(ChannelOpenMessage message)
        {
            Session.SendMessage(message);
        }
        /// 
        /// Called when channel failed to open.
        /// 
        /// The reason code.
        /// The description.
        /// The language.
        protected virtual void OnOpenFailure(uint reasonCode, string description, string language)
        {
            var openFailed = OpenFailed;
            if (openFailed != null)
                openFailed(this, new ChannelOpenFailedEventArgs(LocalChannelNumber, reasonCode, description, language));
        }
        private void OnChannelOpenConfirmation(object sender, MessageEventArgs e)
        {
            if (e.Message.LocalChannelNumber == this.LocalChannelNumber)
            {
                this.OnOpenConfirmation(e.Message.RemoteChannelNumber, e.Message.InitialWindowSize, e.Message.MaximumPacketSize);
            }
        }
        private void OnChannelOpenFailure(object sender, MessageEventArgs e)
        {
            if (e.Message.LocalChannelNumber == this.LocalChannelNumber)
            {
                this.OnOpenFailure(e.Message.ReasonCode, e.Message.Description, e.Message.Language);
            }
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                var session = Session;
                if (session != null)
                {
                    session.ChannelOpenConfirmationReceived -= OnChannelOpenConfirmation;
                    session.ChannelOpenFailureReceived -= OnChannelOpenFailure;
                }
            }
        }
    }
}