#pragma once

#include <napi.h>
#include "mapnik_palette.hpp"

namespace mapnik {
    struct image_any;
    enum image_dtype : std::uint8_t;
}

using image_ptr = std::shared_ptr<mapnik::image_any>;

class Image : public Napi::ObjectWrap<Image>
{
public:
    // initializer
    static Napi::Object Initialize(Napi::Env env, Napi::Object exports, napi_property_attributes attr);
    // ctor
    explicit Image(Napi::CallbackInfo const& info);
    // methods
    Napi::Value getType(Napi::CallbackInfo const& info);

    Napi::Value getPixel(Napi::CallbackInfo const& info);
    void setPixel(Napi::CallbackInfo const& info);

    Napi::Value encodeSync(Napi::CallbackInfo const& info);
    Napi::Value encode(Napi::CallbackInfo const& info);
    Napi::Value setGrayScaleToAlpha(Napi::CallbackInfo const& info);
    Napi::Value width(Napi::CallbackInfo const& info);
    Napi::Value height(Napi::CallbackInfo const& info);
    void saveSync(Napi::CallbackInfo const& info);
    void save(Napi::CallbackInfo const& info);
    Napi::Value data(Napi::CallbackInfo const& info);
    Napi::Value buffer(Napi::CallbackInfo const& info);
    static Napi::Value openSync(Napi::CallbackInfo const& info);
    static Napi::Value open(Napi::CallbackInfo const& info);
    static Napi::Value fromBytesSync(Napi::CallbackInfo const& info);
    static Napi::Value fromBytes(Napi::CallbackInfo const& info);
    static Napi::Value fromBufferSync(Napi::CallbackInfo const& info);
    static Napi::Value fromSVGSync(Napi::CallbackInfo const& info);
    static Napi::Value fromSVG(Napi::CallbackInfo const& info);
    static Napi::Value fromSVGBytesSync(Napi::CallbackInfo const& info);
    static Napi::Value fromSVGBytes(Napi::CallbackInfo const& info);

    Napi::Value painted(Napi::CallbackInfo const& info);
    Napi::Value view(Napi::CallbackInfo const& info);
    Napi::Value composite(Napi::CallbackInfo const& info);
    Napi::Value filterSync(Napi::CallbackInfo const& info);
    Napi::Value filter(Napi::CallbackInfo const& info);
    Napi::Value fillSync(Napi::CallbackInfo const& info);
    Napi::Value fill(Napi::CallbackInfo const& info);
    Napi::Value premultiplySync(Napi::CallbackInfo const& info);
    Napi::Value premultiply(Napi::CallbackInfo const& info);
    Napi::Value demultiplySync(Napi::CallbackInfo const& info);
    Napi::Value demultiply(Napi::CallbackInfo const& info);
    Napi::Value premultiplied(Napi::CallbackInfo const& info);
    Napi::Value clearSync(Napi::CallbackInfo const& info);
    Napi::Value clear(Napi::CallbackInfo const& info);
    Napi::Value compare(Napi::CallbackInfo const& info);
    Napi::Value isSolid(Napi::CallbackInfo const& info);
    Napi::Value isSolidSync(Napi::CallbackInfo const& info);
    Napi::Value copy(Napi::CallbackInfo const& info);
    Napi::Value copySync(Napi::CallbackInfo const& info);
    Napi::Value resize(Napi::CallbackInfo const& info);
    Napi::Value resizeSync(Napi::CallbackInfo const& info);

    // accessors
    Napi::Value scaling(Napi::CallbackInfo const& info);
    void scaling(Napi::CallbackInfo const& info, Napi::Value const& value);
    Napi::Value offset(Napi::CallbackInfo const& info);
    void offset(Napi::CallbackInfo const& info, Napi::Value const& value);
    inline image_ptr impl() const { return image_; }
    static Napi::FunctionReference constructor;
private:
    static void encode_common_args_(Napi::CallbackInfo const& info, std::string& format, palette_ptr& palette);
    static Napi::Value from_svg_sync_impl(Napi::CallbackInfo const& info, bool from_file);
    image_ptr image_;
};
