#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include "shmfile.h"
#include "timeout.h"

#include <Eina.h>

#include <librsvg/rsvg.h>
#ifndef LIBRSVG_CHECK_VERSION
# include <librsvg/librsvg-features.h>
#endif
#if LIBRSVG_CHECK_VERSION(2,36,2)
#else
# include <librsvg/rsvg-cairo.h>
#endif

#define DATA32 unsigned int

static RsvgHandle *rsvg = NULL;
static int width = 0;
static int height = 0;
static RsvgDimensionData dim;

static inline Eina_Bool evas_image_load_file_is_svg(const char *file)
{
   int i, len = strlen(file);
   Eina_Bool is_gz = EINA_FALSE;

   for (i = len - 1; i > 0; i--)
     {
	if (file[i] == '.')
	  {
	     if (is_gz)
	       break;
	     else if (strcasecmp(file + i + 1, "gz") == 0)
	       is_gz = EINA_TRUE;
	     else
	       break;
	  }
     }

   if (i < 1) return EINA_FALSE;
   i++;
   if (i >= len) return EINA_FALSE;
   if (strncasecmp(file + i, "svg", 3) != 0) return EINA_FALSE;
   i += 3;
   if (is_gz)
     {
	if (file[i] == '.') return EINA_TRUE;
	else return EINA_FALSE;
     }
   else
     {
	if (file[i] == '\0') return EINA_TRUE;
	else if (((file[i] == 'z') || (file[i] == 'Z')) && (!file[i + 1])) return EINA_TRUE;
	else return EINA_FALSE;
     }
}

static int
_svg_init(const char *file)
{
#ifdef HAVE_SVG_2_36
# if !defined(GLIB_VERSION_2_36)
   g_type_init();
# endif
#else
   rsvg_init();
#endif

   if (!evas_image_load_file_is_svg(file)) return 0;

   rsvg = rsvg_handle_new_from_file(file, NULL);
   if (!rsvg) return 0;

   return 1;
}

static void
_svg_shutdown(void)
{
   if (rsvg)
     {
// we don't really need this it seems and it's deprecated in 2.46
//        rsvg_handle_close(rsvg, NULL);
        g_object_unref(rsvg);
     }
   // Maybe it's not crashing anymore, let's try it.
#ifndef HAVE_SVG_2_36
   rsvg_term();
#endif
}

static int
read_svg_header(int scale_down, double dpi, int size_w, int size_h)
{
   rsvg_handle_set_dpi(rsvg, 75.0);
   rsvg_handle_get_dimensions(rsvg, &dim);
   width = dim.width;
   height = dim.height;

   if ((width < 1) || (height < 1)) return 0;

   if (scale_down > 1)
     {
        width /= scale_down;
        height /= scale_down;
     }
   else if (dpi > 0.0)
     {
        width = (width * dpi) / 75;
        height = (height * dpi) / 75;
     }
   else if (size_w > 0 && size_h > 0)
     {
        int w, h;

        w = size_w;
        h = (size_w * height) / width;
        if (h > size_h)
          {
             h = size_h;
             w = (size_h * width) / height;
          }
        width = w;
        height = h;
     }
   if (width < 1) width = 1;
   if (height < 1) height = 1;

   return 1;
}

static int
read_svg_data(void)
{
   cairo_surface_t *surface;
   cairo_t *cr;

   shm_alloc(width * height * (sizeof(DATA32)));
   if (!shm_addr) return 0;

   memset(shm_addr, 0, width * height * sizeof (DATA32));
   surface = cairo_image_surface_create_for_data((unsigned char *)shm_addr, CAIRO_FORMAT_ARGB32,
                                                 width, height, width * sizeof(DATA32));;
   if (!surface) return 0;

   cr = cairo_create(surface);
   if (!cr) return 0;

   cairo_scale(cr, (double) width / dim.em, (double) height / dim.ex);
   rsvg_handle_render_cairo(rsvg, cr);
   cairo_surface_destroy(surface);
   cairo_destroy(cr);

   return 1;
}

int main(int argc, char **argv)
{
   char *file;
   int i;
   int head_only = 0;
   int scale_down = 0;
   double dpi = 0.0;
   int size_w = 0, size_h = 0;

   if (argc < 2) return -1;
   file = argv[1];

   for (i = 2; i < argc; ++i)
     {
        if (!strcmp(argv[i], "-head"))
          head_only = 1;
        else if (!strcmp(argv[i], "-key"))
          { // not used by svg loader
             i++;
             // const char *key = argv[i];
          }
        else if (!strcmp(argv[i], "-opt-scale-down-by"))
          {
             i++;
             scale_down = atoi(argv[i]);
          }
        else if (!strcmp(argv[i], "-opt-dpi"))
          {
             i++;
             dpi = ((double)atoi(argv[i])) / 1000.0;
          }
        else if (!strcmp(argv[i], "-opt-size"))
          {
             i++;
             size_w = atoi(argv[i]);
             i++;
             size_h = atoi(argv[i]);
          }
     }

   timeout_init(5);

   if (!_svg_init(file)) return -1;
   if (!read_svg_header(scale_down, dpi, size_w, size_h)) return -1;

   if (head_only != 0)
     {
        printf("size %d %d\n", width, height);
        printf("alpha 1\n");
        printf("done\n");
     }
   else
     {
        if (read_svg_data())
          {
             printf("size %d %d\n", width, height);
             printf("alpha 1\n");
#ifdef _WIN32
             if (shm_fd) printf("shmfile %s\n", shmfile);
#else
             if (shm_fd >= 0) printf("shmfile %s\n", shmfile);
#endif
             else
               {
                  printf("data\n");
                  if (fwrite(shm_addr, width * height * sizeof(DATA32), 1, stdout) != 1)
                    {
                       // nothing much to do, the receiver will simply ignore the
                       // data as it's too short
                       //D("fwrite failed (%d bytes): %m\n", width * height * sizeof(DATA32));
                    }
               }
             shm_free();
          }
     }
   _svg_shutdown();
   fflush(stdout);
   return 0;

}

