// SPDX-License-Identifier: GPL-2.0-or-later
/**
 * SVG to Pixbuf renderer
 *
 * Author:
 *   Michael Kowalski
 *
 * Copyright (C) 2020-2021 Michael Kowalski
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#include "svg-renderer.h"

#include <stdexcept>
#include <utility>
#include <vector>

#include <cairomm/surface.h>
#include <glibmm/ustring.h>
#include <giomm/file.h>
#include <gdkmm/pixbuf.h>
#include <gdkmm/rgba.h>

#include "document.h"

#include "display/cairo-utils.h"
#include "helper/pixbuf-ops.h"
#include "io/file.h"
#include "object/sp-root.h"
#include "util/safe-printf.h"
#include "util/units.h"
#include "xml/repr.h"

namespace Inkscape {

Glib::ustring rgba_to_css_color(double r, double g, double b) {
    char buffer[16];
    safeprintf(buffer, "#%02x%02x%02x",
        static_cast<int>(r * 0xff + 0.5),
        static_cast<int>(g * 0xff + 0.5),
        static_cast<int>(b * 0xff + 0.5)
    );
    return Glib::ustring(buffer);
}

Glib::ustring rgba_to_css_color(const Gdk::RGBA& color) {
    return rgba_to_css_color(color.get_red(), color.get_green(), color.get_blue());
}

Glib::ustring rgba_to_css_color(const SPColor& color) {
    float rgb[3];
    color.get_rgb_floatv(rgb);
    return rgba_to_css_color(rgb[0], rgb[1], rgb[2]);
}

Glib::ustring double_to_css_value(double value) {
    char buffer[32];
    // arbitrarily chosen precision
    safeprintf(buffer, "%.4f", value);
    return Glib::ustring(buffer);
}

std::shared_ptr<SPDocument> load_document(const char* svg_file_path) {
    auto file = Gio::File::create_for_path(svg_file_path);
    return std::shared_ptr<SPDocument>(ink_file_open(file, nullptr));
}

svg_renderer::svg_renderer(const char * const svg_file_path)
: svg_renderer(load_document(svg_file_path))
{
}

svg_renderer::svg_renderer(std::shared_ptr<SPDocument> document)
    : _document{std::move(document)}
{
    if (_document) {
        _root = _document->getRoot();
    }

    if (!_root) throw std::runtime_error("Cannot find root element in svg document");
}

size_t svg_renderer::set_style(const Glib::ustring& selector, const char* name, const Glib::ustring& value) {
    auto objects = _document->getObjectsBySelector(selector);
    for (auto el : objects) {
        if (SPCSSAttr* css = sp_repr_css_attr(el->getRepr(), "style")) {
            sp_repr_css_set_property(css, name, value.c_str());
            el->changeCSS(css, "style");
            sp_repr_css_attr_unref(css);
        }
    }
    return objects.size();
}

double svg_renderer::get_width_px() const {
    return _document->getWidth().value("px");
}

double svg_renderer::get_height_px() const {
    return _document->getHeight().value("px");
}

Inkscape::Pixbuf* svg_renderer::do_render(double device_scale) {
    if (!_document) return nullptr;

    auto dpi = 96 * device_scale * _scale;
    auto area = *(_document->preferredBounds());

    auto checkerboard_ptr = _checkerboard ? &*_checkerboard : nullptr;
    return sp_generate_internal_bitmap(_document.get(), area, dpi, {}, false, checkerboard_ptr, device_scale);
}

Glib::RefPtr<Gdk::Pixbuf> svg_renderer::render(double scale) {
    auto pixbuf = do_render(scale);
    if (!pixbuf) return Glib::RefPtr<Gdk::Pixbuf>();

    // ref it
    auto raw = Glib::wrap(pixbuf->getPixbufRaw(), true);
    delete pixbuf;
    return raw;
}

Cairo::RefPtr<Cairo::ImageSurface> svg_renderer::render_surface(double scale) {
    auto pixbuf = do_render(scale);
    if (!pixbuf) return Cairo::RefPtr<Cairo::ImageSurface>();

    // ref it by saying that we have no reference
    auto surface = Cairo::RefPtr<Cairo::ImageSurface>(new Cairo::ImageSurface(pixbuf->getSurfaceRaw(), false));
    delete pixbuf;
    return surface;
}

void svg_renderer::set_checkerboard_color(unsigned int rgba) {
    _checkerboard.emplace(rgba);
}

void svg_renderer::set_scale(double scale) {
    if (scale > 0) {
        _scale = scale;
    }
}

} // namespace Inkscape

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim:filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99:
