/*---------------------------------------------------------------------------*/
/* json_api.h                                                                */
/* copyright (c) innovaphone 2017                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

class UJsonApiContext {
public:
    virtual class JsonApi * CreateJsonApi(class IJsonApiConnection * connection, class json_io & msg, word base) = 0;
    virtual class JsonApi * JsonApiRequested(class IJsonApiConnection * connection) { return 0; };
    virtual const char * Name() = 0;
    class UJsonApiContext * next;
};

class IJsonApiConnection {
public:
    virtual ~IJsonApiConnection() {}
    virtual void RegisterJsonApi(class JsonApi * api, bool uniqueSrc = false) = 0;
    virtual void UnRegisterJsonApi(class JsonApi * api) = 0;
    virtual void JsonApiMessage(class json_io & msg, char * buffer, JsonApi * response = 0) = 0;
    virtual void JsonApiMessageText(const char * buffer, JsonApi * response = 0) = 0;
    virtual void JsonApiMessageComplete() = 0;
    virtual bool JsonApiPermission(const char * api) = 0;
    virtual const char * JsonApiUserDomain() { return 0; };
    virtual const char * JsonApiUserSip() { return 0; };
    virtual const char * JsonApiUserDn() { return 0; };
    virtual const char * JsonApiUserGuid() { return 0; };
    virtual const char * JsonApiApp() { return 0; };
    virtual const char * JsonApiInfo() { return 0; };
    virtual const char * JsonApiRemoteAddr() { return 0; };
    virtual const char * JsonApiXForwaredFor() { return 0; };
    virtual bool JsonApiUnlicensed() { return true; };
    virtual void AppWebsocketEncrypt(const char * seed, const char * data, char * out, size_t outLen) = 0;
    virtual void AppWebsocketDecrypt(const char * seed, const char * data, char * out, size_t outLen) = 0;
    virtual void AppWebsocketHash(const char * seed, const char * data, char * out, size_t outLen) = 0;
};

class JsonApiContext {
public:
    JsonApiContext() {
        providers = 0;
    }
    void RegisterJsonApi(class UJsonApiContext * provider) {
        provider->next = providers;
        providers = provider;
    }
    class JsonApi * CreateJsonApi(const char * name, class IJsonApiConnection * connection, class json_io & msg, word base) {
        for (class UJsonApiContext * p = providers; p; p = p->next) {
            if (!strcmp(name, p->Name())) return p->CreateJsonApi(connection, msg, base);
        }
        return 0;
    }
    class JsonApi * JsonApiRequested(const char * name, class IJsonApiConnection * connection) {
        if (connection->JsonApiPermission(name)) {
            for (class UJsonApiContext * p = providers; p; p = p->next) {
                if (!strcmp(name, p->Name())) return p->JsonApiRequested(connection);
            }
        }
        return 0;
    }
    class UJsonApiContext * providers;
};

struct JsonApiSrc {
    const char * api;
    const char * src;
};

class JsonApi : public btree {
    int btree_compare(void * key) override { int r = strcmp(((struct JsonApiSrc *)key)->api, Name()); return r ? r : strcmp(((struct JsonApiSrc *)key)->src, src); };
    int btree_compare(class btree * b) override { int r = strcmp(((class JsonApi *)b)->Name(), Name()); return r ? r : strcmp(((class JsonApi *)b)->src, src); };
public:
    // An JsonApi instance will be managed by an AppWebsocket object. The app must not delete
    // the JsonApi object by itself.
    virtual ~JsonApi() { free(src); };
public:
    JsonApi() { responsePending = 0; src = 0; };
    virtual const char * Name() = 0;
    virtual void JsonApiStart() {};
    virtual void Message(class json_io & msg, word base, const char * mt, const char * src) = 0;
    virtual void BinaryMessage(void * buffer, size_t len) {}
    virtual void JsonApiResponseSent() {};
    virtual void JsonApiConnectionClosed() = 0;

    unsigned responsePending;
    char * src;
};
