using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Hazel
{
    /// 
    ///     Holds statistics about the traffic through a .
    /// 
    /// 
    public class ConnectionStatistics
    {
        private const int ExpectedMTU = 1200;
        /// 
        ///     The total number of messages sent.
        /// 
        public int MessagesSent
        {
            get
            {
                return UnreliableMessagesSent + ReliableMessagesSent + FragmentedMessagesSent + AcknowledgementMessagesSent + HelloMessagesSent;
            }
        }
        private int packetsSent;
        public int PacketsSent => this.packetsSent;
        private int reliablePacketsAcknowledged;
        public int ReliablePacketsAcknowledged => this.reliablePacketsAcknowledged;
        /// 
        ///     The number of messages sent larger than 576 bytes. This is smaller than most default MTUs.
        /// 
        /// 
        ///     This is the number of unreliable messages that were sent from the , incremented 
        ///     each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not 
        ///     counted and messages are only counted once all other operations in the send are complete.
        /// 
        public int FragmentableMessagesSent
        {
            get
            {
                return fragmentableMessagesSent;
            }
        }
        /// 
        ///     The number of messages sent larger than 576 bytes.
        /// 
        int fragmentableMessagesSent;
        /// 
        ///     The number of unreliable messages sent.
        /// 
        /// 
        ///     This is the number of unreliable messages that were sent from the , incremented 
        ///     each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not 
        ///     counted and messages are only counted once all other operations in the send are complete.
        /// 
        public int UnreliableMessagesSent
        {
            get
            {
                return unreliableMessagesSent;
            }
        }
        /// 
        ///     The number of unreliable messages sent.
        /// 
        int unreliableMessagesSent;
        /// 
        ///     The number of reliable messages sent.
        /// 
        /// 
        ///     This is the number of reliable messages that were sent from the , incremented 
        ///     each time that LogReliableSend is called by the Connection. Messages that caused an error are not 
        ///     counted and messages are only counted once all other operations in the send are complete.
        /// 
        public int ReliableMessagesSent
        {
            get
            {
                return reliableMessagesSent;
            }
        }
        /// 
        ///     The number of unreliable messages sent.
        /// 
        int reliableMessagesSent;
        /// 
        ///     The number of fragmented messages sent.
        /// 
        /// 
        ///     This is the number of fragmented messages that were sent from the , incremented 
        ///     each time that LogFragmentedSend is called by the Connection. Messages that caused an error are not 
        ///     counted and messages are only counted once all other operations in the send are complete.
        /// 
        public int FragmentedMessagesSent
        {
            get
            {
                return fragmentedMessagesSent;
            }
        }
        /// 
        ///     The number of fragmented messages sent.
        /// 
        int fragmentedMessagesSent;
        /// 
        ///     The number of acknowledgement messages sent.
        /// 
        /// 
        ///     This is the number of acknowledgements that were sent from the , incremented 
        ///     each time that LogAcknowledgementSend is called by the Connection. Messages that caused an error are not 
        ///     counted and messages are only counted once all other operations in the send are complete.
        /// 
        public int AcknowledgementMessagesSent
        {
            get
            {
                return acknowledgementMessagesSent;
            }
        }
        /// 
        ///     The number of acknowledgement messages sent.
        /// 
        int acknowledgementMessagesSent;
        /// 
        ///     The number of hello messages sent.
        /// 
        /// 
        ///     This is the number of hello messages that were sent from the , incremented 
        ///     each time that LogHelloSend is called by the Connection. Messages that caused an error are not 
        ///     counted and messages are only counted once all other operations in the send are complete.
        /// 
        public int HelloMessagesSent
        {
            get
            {
                return helloMessagesSent;
            }
        }
        /// 
        ///     The number of hello messages sent.
        /// 
        int helloMessagesSent;
        /// 
        ///     The number of bytes of data sent.
        /// 
        /// 
        ///     
        ///         This is the number of bytes of data (i.e. user bytes) that were sent from the , 
        ///         accumulated each time that LogSend is called by the Connection. Messages that caused an error are not 
        ///         counted and messages are only counted once all other operations in the send are complete.
        ///     
        ///     
        ///         For the number of bytes including protocol bytes see .
        ///     
        /// 
        public long DataBytesSent
        {
            get
            {
                return Interlocked.Read(ref dataBytesSent);
            }
        }
        /// 
        ///     The number of bytes of data sent.
        /// 
        long dataBytesSent;
        /// 
        ///     The number of bytes sent in total.
        /// 
        /// 
        ///     
        ///         This is the total number of bytes (the data bytes plus protocol bytes) that were sent from the 
        ///         , accumulated each time that LogSend is called by the Connection. Messages that 
        ///         caused an error are not counted and messages are only counted once all other operations in the send are 
        ///         complete.
        ///     
        ///     
        ///         For the number of data bytes excluding protocol bytes see .
        ///     
        /// 
        public long TotalBytesSent
        {
            get
            {
                return Interlocked.Read(ref totalBytesSent);
            }
        }
        /// 
        ///     The number of bytes sent in total.
        /// 
        long totalBytesSent;
        /// 
        ///     The total number of messages received.
        /// 
        public int MessagesReceived
        {
            get
            {
                return UnreliableMessagesReceived + ReliableMessagesReceived + FragmentedMessagesReceived + AcknowledgementMessagesReceived + helloMessagesReceived;
            }
        }
        
        /// 
        ///     The number of unreliable messages received.
        /// 
        /// 
        ///     This is the number of unreliable messages that were received by the , incremented
        ///     each time that LogUnreliableReceive is called by the Connection. Messages are counted before the receive event is invoked.
        /// 
        public int UnreliableMessagesReceived
        {
            get
            {
                return unreliableMessagesReceived;
            }
        }
        /// 
        ///     The number of unreliable messages received.
        /// 
        int unreliableMessagesReceived;
        /// 
        ///     The number of reliable messages received.
        /// 
        /// 
        ///     This is the number of reliable messages that were received by the , incremented
        ///     each time that LogReliableReceive is called by the Connection. Messages are counted before the receive event is invoked.
        /// 
        public int ReliableMessagesReceived
        {
            get
            {
                return reliableMessagesReceived;
            }
        }
        /// 
        ///     The number of reliable messages received.
        /// 
        int reliableMessagesReceived;
        /// 
        ///     The number of fragmented messages received.
        /// 
        /// 
        ///     This is the number of fragmented messages that were received by the , incremented
        ///     each time that LogFragmentedReceive is called by the Connection. Messages are counted before the receive event is invoked.
        /// 
        public int FragmentedMessagesReceived
        {
            get
            {
                return fragmentedMessagesReceived;
            }
        }
        /// 
        ///     The number of fragmented messages received.
        /// 
        int fragmentedMessagesReceived;
        /// 
        ///     The number of acknowledgement messages received.
        /// 
        /// 
        ///     This is the number of acknowledgement messages that were received by the , incremented
        ///     each time that LogAcknowledgemntReceive is called by the Connection. Messages are counted before the receive event is invoked.
        /// 
        public int AcknowledgementMessagesReceived
        {
            get
            {
                return acknowledgementMessagesReceived;
            }
        }
        /// 
        ///     The number of acknowledgement messages received.
        /// 
        int acknowledgementMessagesReceived;
        /// 
        ///     The number of ping messages received.
        /// 
        /// 
        ///     This is the number of hello messages that were received by the , incremented
        ///     each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is invoked.
        /// 
        public int PingMessagesReceived
        {
            get
            {
                return pingMessagesReceived;
            }
        }
        /// 
        ///     The number of hello messages received.
        /// 
        int pingMessagesReceived;
        /// 
        ///     The number of hello messages received.
        /// 
        /// 
        ///     This is the number of hello messages that were received by the , incremented
        ///     each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is invoked.
        /// 
        public int HelloMessagesReceived
        {
            get
            {
                return helloMessagesReceived;
            }
        }
        /// 
        ///     The number of hello messages received.
        /// 
        int helloMessagesReceived;
        /// 
        ///     The number of bytes of data received.
        /// 
        /// 
        ///     
        ///         This is the number of bytes of data (i.e. user bytes) that were received by the , 
        ///         accumulated each time that LogReceive is called by the Connection. Messages are counted before the receive
        ///         event is invoked.
        ///     
        ///     
        ///         For the number of bytes including protocol bytes see .
        ///     
        /// 
        public long DataBytesReceived
        {
            get
            {
                return Interlocked.Read(ref dataBytesReceived);
            }
        }
        /// 
        ///     The number of bytes of data received.
        /// 
        long dataBytesReceived;
        /// 
        ///     The number of bytes received in total.
        /// 
        /// 
        ///     
        ///         This is the total number of bytes (the data bytes plus protocol bytes) that were received by the 
        ///         , accumulated each time that LogReceive is called by the Connection. Messages are 
        ///         counted before the receive event is invoked.
        ///     
        ///     
        ///         For the number of data bytes excluding protocol bytes see .
        ///     
        /// 
        public long TotalBytesReceived
        {
            get
            {
                return Interlocked.Read(ref totalBytesReceived);
            }
        }
        /// 
        ///     The number of bytes received in total.
        /// 
        long totalBytesReceived;
        public int MessagesResent { get { return messagesResent; } }
        int messagesResent;
        /// 
        ///     Logs the sending of an unreliable data packet in the statistics.
        /// 
        /// The number of bytes of data sent.
        /// 
        ///     This should be called after the data has been sent and should only be called for data that is sent sucessfully.
        /// 
        internal void LogUnreliableSend(int dataLength)
        {
            Interlocked.Increment(ref unreliableMessagesSent);
            Interlocked.Add(ref dataBytesSent, dataLength);
            
        }
        /// The total number of bytes sent.
        internal void LogPacketSend(int totalLength)
        {
            Interlocked.Increment(ref this.packetsSent);
            Interlocked.Add(ref totalBytesSent, totalLength);
            if (totalLength > ExpectedMTU)
            {
                Interlocked.Increment(ref fragmentableMessagesSent);
            }
        }
        /// 
        ///     Logs the sending of a reliable data packet in the statistics.
        /// 
        /// The number of bytes of data sent.
        /// 
        ///     This should be called after the data has been sent and should only be called for data that is sent sucessfully.
        /// 
        internal void LogReliableSend(int dataLength)
        {
            Interlocked.Increment(ref reliableMessagesSent);
            Interlocked.Add(ref dataBytesSent, dataLength);
        }
        /// 
        ///     Logs the sending of a fragmented data packet in the statistics.
        /// 
        /// The number of bytes of data sent.
        /// The total number of bytes sent.
        /// 
        ///     This should be called after the data has been sent and should only be called for data that is sent sucessfully.
        /// 
        internal void LogFragmentedSend(int dataLength)
        {
            Interlocked.Increment(ref fragmentedMessagesSent);
            Interlocked.Add(ref dataBytesSent, dataLength);
        }
        /// 
        ///     Logs the sending of a acknowledgement data packet in the statistics.
        /// 
        /// The total number of bytes sent.
        /// 
        ///     This should be called after the data has been sent and should only be called for data that is sent sucessfully.
        /// 
        internal void LogAcknowledgementSend()
        {
            Interlocked.Increment(ref acknowledgementMessagesSent);
        }
        /// 
        ///     Logs the sending of a hellp data packet in the statistics.
        /// 
        /// The total number of bytes sent.
        /// 
        ///     This should be called after the data has been sent and should only be called for data that is sent sucessfully.
        /// 
        internal void LogHelloSend()
        {
            Interlocked.Increment(ref helloMessagesSent);
        }
        /// 
        ///     Logs the receiving of an unreliable data packet in the statistics.
        /// 
        /// The number of bytes of data received.
        /// The total number of bytes received.
        /// 
        ///     This should be called before the received event is invoked so it is up to date for subscribers to that event.
        /// 
        internal void LogUnreliableReceive(int dataLength, int totalLength)
        {
            Interlocked.Increment(ref unreliableMessagesReceived);
            Interlocked.Add(ref dataBytesReceived, dataLength);
            Interlocked.Add(ref totalBytesReceived, totalLength);
        }
        /// 
        ///     Logs the receiving of a reliable data packet in the statistics.
        /// 
        /// The number of bytes of data received.
        /// The total number of bytes received.
        /// 
        ///     This should be called before the received event is invoked so it is up to date for subscribers to that event.
        /// 
        internal void LogReliableReceive(int dataLength, int totalLength)
        {
            Interlocked.Increment(ref reliableMessagesReceived);
            Interlocked.Add(ref dataBytesReceived, dataLength);
            Interlocked.Add(ref totalBytesReceived, totalLength);
        }
        /// 
        ///     Logs the receiving of a fragmented data packet in the statistics.
        /// 
        /// The number of bytes of data received.
        /// The total number of bytes received.
        /// 
        ///     This should be called before the received event is invoked so it is up to date for subscribers to that event.
        /// 
        internal void LogFragmentedReceive(int dataLength, int totalLength)
        {
            Interlocked.Increment(ref fragmentedMessagesReceived);
            Interlocked.Add(ref dataBytesReceived, dataLength);
            Interlocked.Add(ref totalBytesReceived, totalLength);
        }
        /// 
        ///     Logs the receiving of an acknowledgement data packet in the statistics.
        /// 
        /// The total number of bytes received.
        /// 
        ///     This should be called before the received event is invoked so it is up to date for subscribers to that event.
        /// 
        internal void LogAcknowledgementReceive(int totalLength)
        {
            Interlocked.Increment(ref acknowledgementMessagesReceived);
            Interlocked.Add(ref totalBytesReceived, totalLength);
        }
        /// 
        ///     Logs the unique acknowledgement of a ping or reliable data packet.
        /// 
        internal void LogReliablePacketAcknowledged()
        {
            Interlocked.Increment(ref this.reliablePacketsAcknowledged);
        }
        /// 
        ///     Logs the receiving of a hello data packet in the statistics.
        /// 
        /// The total number of bytes received.
        /// 
        ///     This should be called before the received event is invoked so it is up to date for subscribers to that event.
        /// 
        internal void LogPingReceive(int totalLength)
        {
            Interlocked.Increment(ref pingMessagesReceived);
            Interlocked.Add(ref totalBytesReceived, totalLength);
        }
        /// 
        ///     Logs the receiving of a hello data packet in the statistics.
        /// 
        /// The total number of bytes received.
        /// 
        ///     This should be called before the received event is invoked so it is up to date for subscribers to that event.
        /// 
        internal void LogHelloReceive(int totalLength)
        {
            Interlocked.Increment(ref helloMessagesReceived);
            Interlocked.Add(ref totalBytesReceived, totalLength);
        }
        internal void LogMessageResent()
        {
            Interlocked.Increment(ref messagesResent);
        }
    }
}