// 
// KHttpServerResponse.h
// 
// Copyright (C) 2014-2022 by LMI Technologies Inc.
// Licensed under the MIT License.
// Redistributed files must retain the above copyright notice.
// 
#ifndef K_API_NET_HTTP_SERVER_RESPONSE_H
#define K_API_NET_HTTP_SERVER_RESPONSE_H

#include <kApi/Io/kHttpServerResponse.h>
#include "kApiNet/KAlloc.h"
#include "kApiNet/Data/KString.h"
#include "kApiNet/Io/KStream.h"

namespace Lmi3d
{
    namespace Zen 
    {
        namespace Io
        {
            /// <summary>Supports HTTP server response formatting.</summary>
            ///
            /// <remarks>
            /// <para>Default KRefStyle: None</para>
            /// </remarks>
            public ref class KHttpServerResponse : public KObject
            {
                KDeclareNoneClass(KHttpServerResponse, kHttpServerResponse)

            public:
                /// <summary>Initializes a new instance of the KHttpServerResponse class with the specified Zen object handle.</summary>           
                /// <param name="handle">Zen object handle.</param>
                KHttpServerResponse(IntPtr handle)
                    : KObject(handle, DefaultRefStyle)
                {}

                /// <summary>Sets the version associated with this HTTP response.</summary>
                /// 
                /// <remarks>
                /// <para>By default, version 1.1 is assumed.</para>
                /// 
                /// <para>This method can only be called prior to writing the message body.</para>
                /// </remarks>
                /// 
                /// <param name="version">Message version.</param>
                void SetVersion(KVersion version)
                {
                    KCheck(kHttpServerResponse_SetVersion(Handle, version)); 
                }

                /// <summary>Sets the HTTP status code associated with this response.</summary>
                /// 
                /// <remarks>
                /// <para>By default, status code 200 (OK) is assumed.</para>
                /// 
                /// <para>This method can only be called prior to writing the message body.</para>
                /// </remarks>
                /// 
                /// <param name="status">HTTP status code.</param>
                void SetStatus(KHttpStatus status)
                {
                    KCheck(kHttpServerResponse_SetStatus(Handle, status));
                }

                /// <summary>Sets the HTTP status description associated with this response.</summary>
                /// 
                /// <remarks>
                /// <para>If a custom description is not provided, a default description based on the status code will be sent.</para>
                /// 
                /// <para>This method can only be called prior to writing the message body.</para>
                /// </remarks>
                /// 
                /// <param name="reason">HTTP status description.</param>
                void SetReason(String^ reason)
                {
                    KString reasonStr(reason); 

                    KCheck(kHttpServerResponse_SetReason(Handle, reasonStr.CharPtr));
                }

                /// <summary>Instructs the HTTP server to close this connection when message processing is complete.</summary>
                /// 
                /// <remarks>
                /// <para>This method can only be called prior to writing the message body.</para>
                /// 
                /// <para>Use of this method will automatically add the 'connection: closed' header.</para>
                /// </remarks>
                /// 
                /// <param name="closed">true to close the connection; false otherwise.</param>
                void SetClosed(bool closed)
                {
                    KCheck(kHttpServerResponse_SetClosed(Handle, closed));
                }

                /// <summary>Adds a header value to the response.</summary>
                /// 
                /// <remarks>
                /// <para>Headers that can be determined from the information provided in other methods (e.g. 'Content-Length',
                /// 'Transfer-Encoding', 'Connection') will be generated automatically and should not normally be provided via this method.</para>
                /// 
                /// <para>If multiple headers with the same field name are provided, each subsequent header value will be
                /// added to the previous header values (comma-separated).</para>
                /// 
                /// <para>Leading headers should be added prior to writing the message body. Trailing headers can be generated by
                /// calling this method after writing at least one chunk-encoded body segment.</para>
                /// </remarks>
                /// 
                /// <param name="name">Header field name.</param>
                /// <param name="value">Header field value.</param>
                void AddHeader(String^ name, String^ value)
                {
                    KString nameStr(name); 
                    KString valueStr(value); 

                    KCheck(kHttpServerResponse_AddHeader(Handle, nameStr.CharPtr, valueStr.CharPtr)); 
                }

                /// <summary>Sets the value of a header in the response.</summary>
                /// 
                /// <remarks>
                /// <para>Headers that can be determined from the information provided in other methods (e.g. 'Content-Length',
                /// 'Transfer-Encoding', 'Connection') will be generated automatically and should not normally be provided via this method.</para>
                /// 
                /// <para>Leading headers should be added prior to writing the message body. Trailing headers can be generated by
                /// calling this method after writing at least one chunk-encoded body segment.</para>
                /// </remarks>
                /// 
                /// <param name="name">Header field name.</param>
                /// <param name="value">Header field value.</param>
                void SetHeader(String^ name, String^ value)
                {
                    KString nameStr(name);
                    KString valueStr(value);

                    KCheck(kHttpServerResponse_SetHeader(Handle, nameStr.CharPtr, valueStr.CharPtr));
                }

                /// <summary>Begins writing a simple message body.</summary>
                /// 
                /// <remarks>
                /// <para>Use the stream provided by this method to write the message body.</para>
                /// 
                /// <para>Use of this method will automatically add the 'Content-Length' header.</para>
                ///
                /// <para>The returned stream is owned by this object and should not be explicitly disposed.</para>
                /// </remarks>
                /// 
                /// <param name="length">Total length of the message body, in bytes.</param>
                /// <returns>Stream object that should be used to write the message body.</returns>
                KStream^ BeginWriteContent(k64s length)
                {
                    kStream stream; 

                    KCheck(kHttpServerResponse_BeginWriteContent(Handle, (k64u)length, &stream)); 

                    return KToObject<KStream^>(stream, KRefStyle::None);
                }

                /// <summary>Begins writing a chunk-encoded message body segment.</summary>
                /// 
                /// <remarks>
                /// <para>Use the stream provided by this function to write the message chunk. Call this function with a length
                /// of zero to signify that writing is complete.</para>
                /// 
                /// <para>Use of this method will automatically add the 'Transfer-Encoding: chunked' header.</para>
                ///
                /// <para>The returned stream is owned by this object and should not be explicitly disposed.</para>
                /// </remarks>
                /// 
                /// <param name="length">Length of the message chunk, in bytes.</param>
                /// <returns>Stream object that should be used to write the message chunk.</returns>
                KStream^ BeginWriteChunk(k64s length)
                {
                    kStream stream;

                    KCheck(kHttpServerResponse_BeginWriteChunk(Handle, (k64u)length, &stream));

                    return KToObject<KStream^>(stream, KRefStyle::None);
                }

            protected:
                KHttpServerResponse() : KObject(DefaultRefStyle){}
            };
        }
    }
}

#endif
