// This is a truncated, mutilated version of rsvg-convert.c,
// plus necessary bits from the rsvg header files,
// taken from https://gitlab.gnome.org/GNOME/librsvg.git
// plus some changes to make it interact better with wxWidgets

/*
   Copyright (C) 2005 Red Hat, Inc.
   Copyright (C) 2005 Dom Lachowicz <cinamod@hotmail.com>
   Copyright (C) 2005 Caleb Moore <c.moore@student.unsw.edu.au>
  
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.
  
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
  
   You should have received a copy of the GNU Library General Public
   License along with this program; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
  
   Authors: Carl Worth <cworth@cworth.org>, 
            Caleb Moore <c.moore@student.unsw.edu.au>,
            Dom Lachowicz <cinamod@hotmail.com>
*/
#ifdef __WXGTK__

#include <gtk/gtk.h>
#include <gio/gio.h>
#include <cairo/cairo.h>
#include <dlfcn.h>

#include "wx/log.h"


typedef struct _RsvgHandle RsvgHandle;
typedef struct RsvgHandlePrivate RsvgHandlePrivate;
typedef struct _RsvgDimensionData RsvgDimensionData;
struct _RsvgHandle {
    GObject parent;
    RsvgHandlePrivate *priv;
    gpointer _abi_padding[15];
};

typedef enum /*< flags >*/ 
{
    RSVG_HANDLE_FLAGS_NONE           = 0,
    RSVG_HANDLE_FLAG_UNLIMITED       = 1 << 0,
    RSVG_HANDLE_FLAG_KEEP_IMAGE_DATA = 1 << 1
} RsvgHandleFlags;

RsvgHandle *rsvg_handle_new_from_stream_sync (GInputStream   *input_stream,
                                              GFile          *base_file,
                                              RsvgHandleFlags flags,
                                              GCancellable   *cancellable,
                                              GError        **error);
struct _RsvgDimensionData {
    int width;
    int height;
    gdouble em;
    gdouble ex;
};

void rsvg_handle_set_dpi_x_y	(RsvgHandle * handle, double dpi_x, double dpi_y);
gboolean rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimension_data, const char *id);
gboolean rsvg_handle_render_cairo_sub (RsvgHandle * handle, cairo_t * cr, const char *id);

static cairo_status_t
rsvg_cairo_write_func (void *closure, const unsigned char *data, unsigned int length)
{
    if (fwrite (data, 1, length, (FILE *) closure) == length)
        return CAIRO_STATUS_SUCCESS;
    return CAIRO_STATUS_WRITE_ERROR;
}

static void
display_error (GError * err)
{
    if (err) {
        g_printerr ("%s\n", err->message);
        g_error_free (err);
    }
}


bool SvgToPng(const wxString& svgfilepath, const wxString& outputfilepath, void* dlhandle) // Renders an svg file to an image
{
  double dpi_x = 90.0;
  double dpi_y = 90.0;
  int width = -1;
  int height = -1;

  GError *error = NULL;

  wxCHECK_MSG(dlhandle, false, "null dlopen handle");
  typedef decltype(rsvg_handle_new_from_stream_sync)* PF_rsvg_handle_new_from_stream_sync;
  typedef decltype(rsvg_handle_set_dpi_x_y)* PF_rsvg_handle_set_dpi_x_y;
  typedef decltype(rsvg_handle_get_dimensions_sub)* PF_rsvg_handle_get_dimensions_sub;
  typedef decltype(rsvg_handle_render_cairo_sub)* PF_rsvg_handle_render_cairo_sub;

  dlerror();
  PF_rsvg_handle_new_from_stream_sync rsvg_handle_new_from_stream_sync = (PF_rsvg_handle_new_from_stream_sync)dlsym(dlhandle, wxString("rsvg_handle_new_from_stream_sync").ToUTF8());
  if(!rsvg_handle_new_from_stream_sync){
    wxString err(dlerror(), wxConvUTF8);
    wxLogDebug(err);
    return false;
  }
  PF_rsvg_handle_set_dpi_x_y rsvg_handle_set_dpi_x_y = (PF_rsvg_handle_set_dpi_x_y)dlsym(dlhandle, wxString("rsvg_handle_set_dpi_x_y").ToUTF8());
  if(!rsvg_handle_set_dpi_x_y){
    wxString err(dlerror(), wxConvUTF8);
    wxLogDebug(err);
    return false;
  }
  PF_rsvg_handle_get_dimensions_sub rsvg_handle_get_dimensions_sub = (PF_rsvg_handle_get_dimensions_sub)dlsym(dlhandle, wxString("rsvg_handle_get_dimensions_sub").ToUTF8());
  if(!rsvg_handle_get_dimensions_sub){
    wxString err(dlerror(), wxConvUTF8);
    wxLogDebug(err);
    return false;
  }
  PF_rsvg_handle_render_cairo_sub rsvg_handle_render_cairo_sub = (PF_rsvg_handle_render_cairo_sub)dlsym(dlhandle, wxString("rsvg_handle_render_cairo_sub").ToUTF8());
  if(!rsvg_handle_render_cairo_sub){
    wxString err(dlerror(), wxConvUTF8);
    wxLogDebug(err);
    return false;
  }


  RsvgHandle *rsvg = NULL;
  cairo_surface_t *surface = NULL;
  cairo_t *cr = NULL;
  RsvgDimensionData dimensions;
  FILE *output_file = stdout;
  char *export_lookup_id;

  output_file = fopen (outputfilepath.ToUTF8(), "wb");
  if (!output_file) return false;

  GFile *file;
  GInputStream *stream;

  file = g_file_new_for_path (svgfilepath.ToUTF8());
  stream = (GInputStream *) g_file_read (file, NULL, &error);
  if (!stream)
    { g_clear_object (&file);
      fclose (output_file);
      return false;
    }
    
  rsvg = rsvg_handle_new_from_stream_sync(stream, file, RSVG_HANDLE_FLAGS_NONE, NULL, &error);

  g_clear_object (&stream);
  g_clear_object (&file);
  if (!rsvg)
    { fclose (output_file); return false; }

  bool success(false);
  if (error != NULL)
    {
      wxLogDebug("Error reading SVG");
      display_error (error);
      g_printerr ("\n");
    }
   else
    { rsvg_handle_set_dpi_x_y (rsvg, dpi_x, dpi_y);

      export_lookup_id = NULL;
      if (!rsvg_handle_get_dimensions_sub (rsvg, &dimensions, export_lookup_id))
        { g_printerr ("Could not get dimensions for file\n"); }
       else
        { surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                                    dimensions.width, dimensions.height);
          cr = cairo_create (surface);
          if (!rsvg_handle_render_cairo_sub (rsvg, cr, export_lookup_id))
            g_printerr ("Could not render file\n");
           else
            { cairo_surface_write_to_png_stream (surface, rsvg_cairo_write_func, output_file);
              success = true;
            }
  
          cairo_destroy (cr);
          cairo_surface_destroy (surface);
        }
          
      g_object_unref (rsvg);
    }

  fclose (output_file);

  return success;
}
#endif //ifdef __WXGTK__
