using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace OSHttpServer
{
    /// <summary>
    /// Contains a connection to a browser/client.
    /// </summary>
    public interface IHttpClientContext
    {

        /// <summary>
        /// Get SSL commonName of remote peer
        /// </summary>
        string SSLCommonName { get; }

        IPEndPoint LocalIPEndPoint {get; set;}

        /// <summary>
        /// Using SSL or other encryption method.
        /// </summary>
        bool IsSecured { get; }

        int contextID {get;}
        int TimeoutKeepAlive {get; set; }
        int MaxRequests{get; set; }

        bool CanSend();
        bool IsSending();
        bool IsClosing {get ;}

        /// <summary>
        /// Disconnect from client
        /// </summary>
        /// <param name="error">error to report in the <see cref="Disconnected"/> event.</param>
        void Disconnect(SocketError error);

        /// <summary>
        /// Send a response.
        /// </summary>
        /// <param name="httpVersion">Either <see cref="HttpHelper.HTTP10"/> or <see cref="HttpHelper.HTTP11"/></param>
        /// <param name="statusCode">HTTP status code</param>
        /// <param name="reason">reason for the status code.</param>
        /// <param name="body">HTML body contents, can be null or empty.</param>
        /// <param name="contentType">A content type to return the body as, i.e. 'text/html' or 'text/plain', defaults to 'text/html' if null or empty</param>
        /// <exception cref="ArgumentException">If <paramref name="httpVersion"/> is invalid.</exception>
        void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType);

        /// <summary>
        /// Send a response.
        /// </summary>
        /// <param name="httpVersion">Either <see cref="HttpHelper.HTTP10"/> or <see cref="HttpHelper.HTTP11"/></param>
        /// <param name="statusCode">HTTP status code</param>
        /// <param name="reason">reason for the status code.</param>
        void Respond(string httpVersion, HttpStatusCode statusCode, string reason);

        /// <summary>
        /// send a whole buffer
        /// </summary>
        /// <param name="buffer">buffer to send</param>
        /// <exception cref="ArgumentNullException"></exception>
        bool Send(byte[] buffer);

        /// <summary>
        /// Send data using the stream
        /// </summary>
        /// <param name="buffer">Contains data to send</param>
        /// <param name="offset">Start position in buffer</param>
        /// <param name="size">number of bytes to send</param>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        bool Send(byte[] buffer, int offset, int size);
        Task<bool> SendAsync(byte[] buffer, int offset, int size);

        /// <summary>
        /// Closes the streams and disposes of the unmanaged resources
        /// </summary>
        void Close();

        /// <summary>
        /// The context have been disconnected.
        /// </summary>
        /// <remarks>
        /// Event can be used to clean up a context, or to reuse it.
        /// </remarks>
        event EventHandler<DisconnectedEventArgs> Disconnected;

        /// <summary>
        /// A request have been received in the context.
        /// </summary>
        event EventHandler<RequestEventArgs> RequestReceived;

        HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing();

        void StartSendResponse(HttpResponse response);
        void ContinueSendResponse(bool notThrottled);
        Task EndSendResponse(uint requestID, ConnectionType connection);
        bool TrySendResponse(int limit);
    }

    public class HTTPNetworkContext
    {
        public NetworkStream Stream;
        public Socket Socket;
    }

    /// <summary>
    /// A <see cref="IHttpClientContext"/> have been disconnected.
    /// </summary>
    public class DisconnectedEventArgs : EventArgs
    {
        /// <summary>
        /// Gets reason to why client disconnected.
        /// </summary>
        public SocketError Error { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="DisconnectedEventArgs"/> class.
        /// </summary>
        /// <param name="error">Reason to disconnection.</param>
        public DisconnectedEventArgs(SocketError error)
        {
            Error = error;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class RequestEventArgs : EventArgs
    {
        /// <summary>
        /// Gets received request.
        /// </summary>
        public IHttpRequest Request { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="RequestEventArgs"/> class.
        /// </summary>
        /// <param name="request">The request.</param>
        public RequestEventArgs(IHttpRequest request)
        {
            Request = request;
        }
    }



}
