#ifndef __DCL_HTTP_SERVLET_H__
#define __DCL_HTTP_SERVLET_H__      20050530

// HTTP Server -let
#ifndef __DCL_OBJECT_H__
#include <dcl/core/Object.h>
#endif

#ifndef __DCL_EXCEPTION_H__
#include <dcl/core/Exception.h>
#endif
#ifndef __DCL_COLLECTION_H__
#include <dcl/core/Collection.h>
#endif

#ifndef __DCL_HTTP_SERVER_EXTENSION_H__
#include <dcl/net/HttpServerExtension.h>
#endif
#ifndef __DCL_HTTP_HEADER_H__
#include <dcl/net/HttpHeader.h>
#endif

__DCL_BEGIN_NAMESPACE

/*
Object
    HttpServletContext;
        HttpServletContextEx;
    HttpServlet;
        HttpServletEx;
*/

class DCLNAPI HttpServletContext : public Object
{
    DECLARE_CLASSINFO(HttpServletContext)
public :
    HttpServletContext(
        const DCL_HTTP_SERVER_API* pSAPI,
        const DCL_HTTP_SERVLET_CONTEXT* pContext
        );
    virtual ~HttpServletContext();

    // request
    const char* remoteAddr() const;
    UINT32 remotePort() const;
    const char* method() const;
    UINT32 methodNo() const;
    const char* path() const;
    const char* queryString() const;
    const char* contentType() const;
    unsigned int contentLength() const;

    const char* scriptFile() const;
    const void* scriptData() const;
    size_t scriptLength() const;

    const String& resContentType() const;

    String getHttpHeader(const char* pszHeaderName = NULL) const;   // NULL is ALL Headers
    String getCgiVariable(const char* pszVarName) const;
    size_t read(void* pv, size_t n) __DCL_THROWS1(IOException*);

    // response
    void setStatusCode(unsigned int uHttpStatusCode);
    void setContentType(const char* pszContentType, const char* pszCharset = NULL);
    void addHeader(const HttpHeader& httpHeader);
    void flushHeader();

    void write(const void* pv, size_t n) __DCL_THROWS1(IOException*);

protected:
    const DCL_HTTP_SERVER_API*      m_pSAPI;
    const DCL_HTTP_SERVLET_CONTEXT* m_pContext;

    String          m_strContentType;   // response Content-Type
    UINT32          m_uHttpStatusCode;
    String          m_strResponseHeaders;
    bool            m_bHeaderFlushed;
};

class DCLNAPI HttpServlet : public Object
{
    DECLARE_CLASSINFO(HttpServlet)
public:
    HttpServlet();
    String getIniFileName(const char* pszBaseName = NULL) const;

protected:
    // implement
    virtual void onInitialize()
                    __DCL_THROWS1(Exception*);
    virtual void onCleanup()
                    __DCL_THROWS1(Exception*);
    virtual void onHttpService(
                    const DCL_HTTP_SERVLET_CONTEXT* pContext
                    ) = 0 __DCL_THROWS1(Exception*);


protected:
    String  m_strModuleName;
    const DCL_HTTP_SERVER_API* m_pSAPI;

public:
    // internal function
    static BOOL __initialize(
                    HttpServlet* pServlet, 
                    const char* pszModuleName,
                    const DCL_HTTP_SERVER_API* pSAPI,
                    void* hErrorReport
                    );

    static BOOL __cleanup(
                    HttpServlet* pServlet,
                    void* hErrorReport
                    );

    static BOOL __httpService(
                    HttpServlet* pServlet,
                    const DCL_HTTP_SERVLET_CONTEXT* pContext,
                    void* hErrorReport
                    );
};

#define HTTP_SERVLET_INSTANCE(ServletClass, Description) \
static HttpServlet* __pServlet = NULL; \
static BOOL ModuleInitialize( \
            const char* pszModuleName, \
            const DCL_HTTP_SERVER_API*  pSAPI, \
            void* hErrorReport \
            ) \
{ \
    __pServlet = new ServletClass; \
    if (!__pServlet) \
    { \
        pSAPI->pfnReportError( \
                hErrorReport, \
                "Out of Memory", \
                13); \
        return FALSE; \
    } \
    else \
    { \
        if (!HttpServlet::__initialize( \
                __pServlet, \
                pszModuleName, \
                pSAPI, \
                hErrorReport \
                ) \
            ) \
        { \
            delete __pServlet; \
            __pServlet = NULL; \
            return FALSE; \
        } \
    } \
    return TRUE; \
} \
\
static BOOL ModuleCleanup( \
            void* hErrorReport \
            ) \
{ \
    BOOL bResult = HttpServlet::__cleanup( \
                    __pServlet, \
                    hErrorReport \
                    ); \
    delete __pServlet; \
    __pServlet = NULL; \
    return bResult; \
} \
\
static BOOL ModuleHttpService( \
            const DCL_HTTP_SERVLET_CONTEXT* pContext, \
            void* hErrorReport \
            ) \
{ \
    return HttpServlet::__httpService( \
                __pServlet, \
                pContext, \
                hErrorReport \
                ); \
}\
\
extern "C" { \
DCL_DSO_EXPORT \
DCL_HTTP_SERVLET DCL_DSO_ENTRY_POINT = { \
    sizeof(DCL_HTTP_SERVLET), \
    DCL_VERSION, \
    __TIMESTAMP__, \
    DCL_BUILD_FLAG, \
    DCL_HTTP_SERVLET_MODULE, \
    Description, \
    DCL_HTTP_SERVER_VERSION, \
    ModuleInitialize, \
    ModuleCleanup, \
    ModuleHttpService \
}; \
} \

#include "HttpServlet.inl"

__DCL_END_NAMESPACE


#endif  // __DCL_HTTP_SERVLET_H__