
/*---------------------------------------------------------------------------*/
/* webserver_message_handler.h                                               */
/* copyright (c) innovaphone 2016                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

class UWebserverMessageHandler {
public:
    virtual ~UWebserverMessageHandler() {}
    virtual void RegisterHandler(class WebserverMessageHandler * handler) = 0;
    virtual void UnregisterHandler(class WebserverMessageHandler * handler) = 0;
	virtual class WebserverDigestAuthenticator * GetDigestAuthenticator(dword connectionID, const char * host) = 0;
	virtual const char * GetAppWebRoot() = 0;
	virtual const std::string & GetDigestAuthenticationRealmAsStr() = 0;
};

typedef enum {
    MSG_HANDLER_GET,
    MSG_HANDLER_POST,
    MSG_HANDLER_COPY,
    MSG_HANDLER_DELETE,
    MSG_HANDLER_MKCOL,
    MSG_HANDLER_MOVE,
    MSG_HANDLER_PUT,
    MSG_HANDLER_PROPFIND,
    MSG_HANDLER_OPTIONS,
    MSG_HANDLER_LOCK,
    MSG_HANDLER_UNLOCK,
    MSG_HANDLER_PROPPATCH,
	// Everything below is not qualified to be used for the IDigestAuthenticaotr interface.
    MSG_HANDLER_WEBSOCKET,
    MSG_HANDLER_PASSTHROUGH,
    MSG_HANDLER_SET_CERTIFICATE
} msg_handler_type_t;


inline const char * WSPHandlerTypeToStr(msg_handler_type_t h)
{
    switch (h)
    {
    case MSG_HANDLER_GET: return "MSG_HANDLER_GET";
    case MSG_HANDLER_POST: return "MSG_HANDLER_POST";
    case MSG_HANDLER_COPY: return "MSG_HANDLER_COPY";
    case MSG_HANDLER_DELETE: return "MSG_HANDLER_DELETE";
    case MSG_HANDLER_MKCOL: return "MSG_HANDLER_MKCOL";
    case MSG_HANDLER_MOVE: return "MSG_HANDLER_MOVE";
    case MSG_HANDLER_PUT: return "MSG_HANDLER_PUT";
    case MSG_HANDLER_PROPFIND: return "MSG_HANDLER_PROPFIND";
    case MSG_HANDLER_OPTIONS: return "MSG_HANDLER_OPTIONS";
    case MSG_HANDLER_WEBSOCKET: return "MSG_HANDLER_WEBSOCKET";
    case MSG_HANDLER_PASSTHROUGH: return "MSG_HANDLER_PASSTHROUGH";
    case MSG_HANDLER_LOCK: return "MSG_HANDLER_LOCK";
    case MSG_HANDLER_UNLOCK: return "MSG_HANDLER_UNLOCK";
    case MSG_HANDLER_PROPPATCH: return "MSG_HANDLER_PROPPATCH";
    case MSG_HANDLER_SET_CERTIFICATE: return "MSG_HANDLER_SET_CERTIFICATE";
    }
    return "<unkown msg_handler_type_t>"; // Make the compiler happy
}

// This is the base class used by all webserver message handlers.
class WebserverMessageHandler : public btree {
protected:
    class IInstanceLog * const log;
    class UWebserverMessageHandler * const baseUser;
    class IWebserverMessage * const webserverMessageSend;
	class WebserverDigestAuthenticator * digestAuthenticator;
    class ExtendedHeader extHeader;
    word protocolVersion;

    const char * interfaceName;
    const msg_handler_type_t handlerType;
    dword connectionID;
	std::string resourceName;
	std::string reqRegPath;
    ulong64 dataSize;
    int sendCount;
    bool recvCalled;

    char ** fieldNames;
    char ** fieldValues;
    size_t fieldCount;

    char * headerFieldsToSend;
    size_t headerFieldsToSendSize;

    byte * userBuffer;
    size_t userBufferSize;

    bool handlerIsRegistered;
    bool closeHandler;
    bool userSet;

    connection_flags_t connFlags;
    byte * extHeaderBuffer;
    
    std::string remoteAddress;
    word remotePort;

    // Functions a succesor of this class need to be implement...
    virtual void SendResult() {}
    virtual void * RecvBuffer(size_t size) { return NULL; }
    virtual void RecvResult(byte * buffer, size_t len) {}
    virtual void RecvCanceled(byte * buffer) {}
    virtual void CloseComplete() {}
    virtual bool InterfaceUserSet() { return userSet; }
    virtual void DoClose(bool sendCloseMsg);

public:
    WebserverMessageHandler(const char * interfaceName,
                            msg_handler_type_t handlerType,
                            UWebserverMessageHandler * baseUser,
                            byte * extHeaderBuffer,
                            dword connectionID,
                            ulong64 dataSize,
                            IWebserverMessage * const webserverMessageSend,
                            char * resourceName,
                            char * reqPathForRequest,
                            class IInstanceLog * const log,
                            class ExtendedHeader & extHeader,
                            word protocolVersion);
    virtual ~WebserverMessageHandler();

    msg_handler_type_t GetHandlerType() { return handlerType; }
    const char * InterfaceName() { return this->interfaceName; }
    virtual bool IsWebdavHandler() { return false; }
    void RegisterHandler();

    void * GetUserBuffer(size_t size);
    dword GetConnectionID() { return connectionID; }
    ulong64 GetDataSize() { return (dataSize == WS_RESPONSE_CHUNKED ? 0 : dataSize); }
	const char * GetResourceName() { return resourceName.c_str(); }
	const char * GetRegisteredPathForRequest() { return reqRegPath.c_str(); }
	const std::string GetRequestTarget();
    const char * GetRemoteAddress() { return this->remoteAddress.empty() ? nullptr : this->remoteAddress.c_str(); }
    word GetRemotePort() { return this->remotePort; }
    bool DataIsChunkEncoded() { return dataSize == WS_RESPONSE_CHUNKED; }
    bool NeedFreeBuffer(void * buffer) { return buffer != userBuffer; }
    virtual void SetFieldList(char * fieldListBuffer, size_t fieldListBufferSize);
    virtual const char * GetHeaderFieldValue(const char * fieldName);
	virtual class IDigestAuthenticator * GetAuthenticator();
	virtual void SetTransferInfo(wsr_type_t resourceType, ulong64 dataSize, wsr_flags_t flags, const char * etag = nullptr);

    virtual int btree_compare(void * key) { return (dword)(((byte *) key) - ((byte *) 0)) - connectionID; }
    virtual int btree_compare(class btree * b)
    {
        return this->btree_compare((void *)(uintp)(static_cast<WebserverMessageHandler * >(b)->connectionID));
    }

    virtual void HandleMessage(IWebserverMessage * const message, void * buffer, size_t l);

    virtual void SetHeaderField(const char * fname, const char * fvalue);
	virtual void SetStatusCode(dword code, const char * description = nullptr);
    virtual void Send(const void * buffer, size_t len);
    virtual void Recv(byte * buffer, size_t size);
    virtual void Cancel(wsr_cancel_type_t reason);
    virtual void Close();
    virtual void WebserverPluginRecvCanceled(void * buffer);
    virtual void WebserverPluginWillClose(wsp_close_reason_t reason);
    virtual void AcceptComplete() = 0;
  
	const std::string & GetDigestAuthRealm() { return this->baseUser->GetDigestAuthenticationRealmAsStr(); }
};