#ifndef WEBSERVERMANAGER_H
#define WEBSERVERMANAGER_H

#include <WiFiServer.h>
#include <WiFiClient.h>
#include "SDCardManager.h"
#include "definition.h"
#include "Dictionary.h"

struct HttpRequestData;

class WEBServerManager
{
  public:
    enum ClientStatus {NOT_HANDLED, HANDLED, NEW, WAITING_FOR_CLIENT, QUERY_PARSED, RESPONSE_SENT};
    enum HttpRequestMethod {UNDEFINED, GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH};
    enum HttpVersion {UNKNOWN, HTTP_0_9, HTTP_1_1, HTTP_1_0, HTTP_2_0};
    enum HttpParserStatus {INIT, LINE_BREAK, HTTP_VERB_SECTION, HTTP_RESOURCE_SECTION, HTTP_RESOURCE_PARAM_SECTION, HTTP_VER_SECTION, PARAMETER_SECTION, BODY_SECTION, IGNORED, ERROR};
    enum HttpMIMEType{UNKNOWN_MIME, TEXT_PLAIN, TEXT_CSS, TEXT_HTML, TEXT_JAVASCRIPT, APPLICATION_JSON, APPLICATION_X_WWW_FORM_URLENCODED, IMAGE_PNG, IMAGE_JPEG, AUDIO_MPEG, APPLICATION_OCTET_STREAM};
    struct HttpRequestData{
      HttpRequestMethod HRM;
      HttpVersion HV;
      HttpMIMEType HMT;
      Dictionary<DictionaryHelper::StringEntity> getParams;
      Dictionary<DictionaryHelper::StringEntity> postParams;
      char *httpResource;
      char *httpBody;
    };
  
    WEBServerManager(unsigned int port = 80, SDCardManager *sdCardManager = NULL);

    boolean runServer();
    unsigned int getPort() const;
    boolean addApiRoutine(const char *uri, boolean (*apiRoutine)(HttpRequestData&, WiFiClient*, void*), void *pData, HttpRequestMethod HRM = UNDEFINED);
    void clearApiRoutine();
    boolean removeApiRoutine(const char *uri);
  protected:
  private:
    struct ApiRoutine
    {
      boolean (*apiRoutine)(HttpRequestData&, WiFiClient*, void*);
      void *pData;
      HttpRequestMethod HRM;
    };
    
    boolean parseQuery(WiFiClient *wifiClient);
    boolean sendPageToClientFromSdCard(WiFiClient *wifiClient);
    boolean sendPageToClientFromApiDictio(WiFiClient *wifiClient);
    HttpRequestMethod getHttpVerbEnumValue(const char *parseBuffer);
    HttpVersion getHttpVersionEnumValue(const char *parseBuffer);
    char *getFilePathByHttpResource(char *res);
    char *getFileExtension(char *name);
    HttpMIMEType getMIMETypeByExtension(const char *extension);
    char *getHTTPHeader(HttpMIMEType httpMIMEType, unsigned long size);
    void clearHttpRequestData();
    
    WiFiServer _wifiServer;
    WiFiClient _wifiClient;//One client only, may be replaced with a fifo in the future
    SDCardManager *_sdCardManager;
    HttpRequestData _httpRequestData;
    Dictionary<ApiRoutine> _apiDictionary;
    
    ClientStatus _clientState;
    HttpParserStatus _httpParserState;
    unsigned long _clientTimeout;
    unsigned int _port;
};

#endif //WEBSERVERMANAGER_H
