{{>licenseInfo}}
{{#operations}}/*
 * {{classname}}.h
 *
 * {{description}}
 */

#ifndef {{classname}}_H_
#define {{classname}}_H_

{{{defaultInclude}}}
#include <memory>
#include <utility>
#include <exception>
#include <functional>

#include <corvusoft/restbed/session.hpp>
#include <corvusoft/restbed/resource.hpp>
#include <corvusoft/restbed/request.hpp>
#include <corvusoft/restbed/service.hpp>
#include <corvusoft/restbed/settings.hpp>

{{#imports}}{{{import}}}
{{/imports}}

{{#apiNamespaceDeclarations}}
namespace {{this}} {
{{/apiNamespaceDeclarations}}

using namespace {{modelNamespace}};

///
/// Exception to flag problems in the handlers
///
class {{declspec}} {{classname}}Exception: public std::exception
{
public:
    {{classname}}Exception(int status_code, std::string what);

    int getStatus() const;
    const char* what() const noexcept override;

private:
    int m_status;
    std::string m_what;
};

namespace {{classname}}Resources {
{{#operation}}
/// <summary>
/// {{summary}}
/// </summary>
/// <remarks>
/// {{notes}}
/// </remarks>
class {{declspec}} {{vendorExtensions.x-codegen-resource-name}}Resource: public restbed::Resource
{
public:
    {{vendorExtensions.x-codegen-resource-name}}Resource(const std::string& context = "{{contextPath}}");
    virtual ~{{vendorExtensions.x-codegen-resource-name}}Resource() = default;

    {{vendorExtensions.x-codegen-resource-name}}Resource(
        const {{vendorExtensions.x-codegen-resource-name}}Resource& other) = default; // copy constructor
    {{vendorExtensions.x-codegen-resource-name}}Resource({{vendorExtensions.x-codegen-resource-name}}Resource&& other) noexcept = default; // move constructor

    {{vendorExtensions.x-codegen-resource-name}}Resource& operator=(const {{vendorExtensions.x-codegen-resource-name}}Resource& other) = default; // copy assignment
    {{vendorExtensions.x-codegen-resource-name}}Resource& operator=({{vendorExtensions.x-codegen-resource-name}}Resource&& other) noexcept = default; // move assignment

    /////////////////////////////////////////////////////
    // Set these to implement the server functionality //
    /////////////////////////////////////////////////////
    std::function<{{#returnType}}std::pair<int, {{{.}}}>{{/returnType}}{{^returnType}}int{{/returnType}}(
        {{#allParams}}{{{dataType}}} & {{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})> handler_{{httpMethod}}_func =
            []({{#allParams}}{{{dataType}}} &{{^-last}}, {{/-last}}{{/allParams}}) -> {{#returnType}}std::pair<int, {{{.}}}>{{/returnType}}{{^returnType}}int{{/returnType}}
                { throw {{classname}}Exception(501, "Not implemented"); };

    {{#vendorExtensions.x-codegen-other-methods}}
    std::function<{{#returnType}}std::pair<int, {{{.}}}>{{/returnType}}{{^returnType}}int{{/returnType}}(
        {{#allParams}}{{{dataType}}} & {{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})> handler_{{httpMethod}}_func =
            []({{#allParams}}{{{dataType}}} &{{^-last}}, {{/-last}}{{/allParams}}) -> {{#returnType}}std::pair<int, {{{.}}}>{{/returnType}}{{^returnType}}int{{/returnType}}
                { throw {{classname}}Exception(501, "Not implemented"); };

    {{/vendorExtensions.x-codegen-other-methods}}

protected:
    //////////////////////////////////////////////////////////
    // As an alternative to setting the `std::function`s    //
    // override these to implement the server functionality //
    //////////////////////////////////////////////////////////

    virtual {{#returnType}}std::pair<int, {{{.}}}>{{/returnType}}{{^returnType}}int{{/returnType}} handler_{{httpMethod}}(
        {{#allParams}}{{{dataType}}} & {{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}});

    {{#vendorExtensions.x-codegen-other-methods}}
    virtual {{#returnType}}std::pair<int, {{{.}}}>{{/returnType}}{{^returnType}}int{{/returnType}} handler_{{httpMethod}}(
        {{#allParams}}{{{dataType}}} & {{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}});
    {{/vendorExtensions.x-codegen-other-methods}}

protected:
    //////////////////////////////////////
    // Override these for customization //
    //////////////////////////////////////

    virtual std::string extractBodyContent(const std::shared_ptr<restbed::Session>& session);
    virtual std::string extractFormParamsFromBody(const std::string& paramName, const std::string& body);

    virtual std::pair<int, std::string> handle{{classname}}Exception(const {{classname}}Exception& e);
    virtual std::pair<int, std::string> handleStdException(const std::exception& e);
    virtual std::pair<int, std::string> handleUnspecifiedException();

    virtual void setResponseHeader(const std::shared_ptr<restbed::Session>& session,
        const std::string& header);

    virtual void returnResponse(const std::shared_ptr<restbed::Session>& session,
        const int status, const std::string& result, std::multimap<std::string, std::string>& contentType);
    virtual void defaultSessionClose(const std::shared_ptr<restbed::Session>& session,
        const int status, const std::string& result);

private:
    void handler_{{httpMethod}}_internal(const std::shared_ptr<restbed::Session> session);
    {{#vendorExtensions.x-codegen-other-methods}}
    void handler_{{httpMethod}}_internal(const std::shared_ptr<restbed::Session> session);
    {{/vendorExtensions.x-codegen-other-methods}}
};

{{/operation}}
} /* namespace {{classname}}Resources */

{{#operation}}
using {{classname}}{{vendorExtensions.x-codegen-resource-name}}Resource [[deprecated]] = {{classname}}Resources::{{vendorExtensions.x-codegen-resource-name}}Resource;
{{/operation}}

//
// The restbed service to actually implement the REST server
//
class {{declspec}} {{classname}}
{
public:
    explicit {{classname}}(std::shared_ptr<restbed::Service> const& restbedService);
    virtual ~{{classname}}();

    {{#operation}}
    std::shared_ptr<{{classname}}Resources::{{vendorExtensions.x-codegen-resource-name}}Resource> get{{vendorExtensions.x-codegen-resource-name}}Resource();
    {{/operation}}

    {{#operation}}
    void setResource(std::shared_ptr<{{classname}}Resources::{{vendorExtensions.x-codegen-resource-name}}Resource> resource);
    {{/operation}}
    {{#operation}}
    [[deprecated("use setResource()")]]
    virtual void set{{classname}}{{vendorExtensions.x-codegen-resource-name}}Resource(std::shared_ptr<{{classname}}Resources::{{vendorExtensions.x-codegen-resource-name}}Resource> sp{{classname}}{{vendorExtensions.x-codegen-resource-name}}Resource);
    {{/operation}}

    virtual void publishDefaultResources();

    virtual std::shared_ptr<restbed::Service> service();

protected:
    {{#operation}}
    std::shared_ptr<{{classname}}Resources::{{vendorExtensions.x-codegen-resource-name}}Resource> m_sp{{vendorExtensions.x-codegen-resource-name}}Resource;
    {{/operation}}

private:
    std::shared_ptr<restbed::Service> m_service;
};


{{#apiNamespaceDeclarations}}
}
{{/apiNamespaceDeclarations}}

#endif /* {{classname}}_H_ */

{{/operations}}
