#include <errno.h>
#include <stdio.h>
#include <sysprof-capture.h>
#include <gio/gio.h>

typedef struct {
  const char *group;
  gint64 value;
} Data;

static bool
callback (const SysprofCaptureFrame *frame,
          gpointer              user_data)
{
  Data *data = user_data;

  if (frame->type == SYSPROF_CAPTURE_FRAME_MARK)
    {
      SysprofCaptureMark *mark = (SysprofCaptureMark *)frame;
      if (strcmp (mark->group, "gtk") == 0 &&
          strcmp (mark->name, data->group) == 0)
        {
          data->value = mark->duration;
          return FALSE;
        }
    }

  return TRUE;
}

#define MILLISECONDS(v) ((v) / (1000.0 * G_TIME_SPAN_MILLISECOND))

static int opt_rep = 10;

static GOptionEntry options[] = {
  { "runs", 'r', G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &opt_rep, "Number of runs", "COUNT" },
  { NULL, }
};

int
main (int argc, char *argv[])
{
  GOptionContext *context;
  GError *error = NULL;
  Data data;
  SysprofCaptureFrameType type;
  char fd_str[20];
  gint64 *values;
  gint64 min, max, total;
  int i;

  context = g_option_context_new ("COMMANDLINE");
  g_option_context_add_main_entries (context, options, NULL);
  if (!g_option_context_parse (context, &argc, &argv, &error))
    g_error ("Parsing options: %s", error->message);

  if (argc < 2)
    {
      g_print ("Usage: testperf [OPTIONS] COMMANDLINE\n");
      exit (1);
    }

  if (opt_rep < 1)
    g_error ("COUNT must be a positive number");

  values = g_new (gint64, opt_rep);

  for (i = 0; i < opt_rep; i++)
    {
      GSubprocessLauncher *launcher;
      GSubprocess *subprocess;
      int fd;
      char *name;
      SysprofCaptureReader *reader;
      SysprofCaptureCursor *cursor;
      SysprofCaptureCondition *condition;

      fd = g_file_open_tmp ("gtk.XXXXXX.syscap", &name, &error);
      if (error)
        g_error ("Create syscap file: %s", error->message);

      launcher = g_subprocess_launcher_new (0);
      g_subprocess_launcher_take_fd (launcher, fd, fd);
      g_snprintf (fd_str, sizeof (fd_str), "%d", fd);
      g_subprocess_launcher_setenv (launcher, "GTK_TRACE_FD", fd_str, TRUE);
      g_subprocess_launcher_setenv (launcher, "GTK_DEBUG_AUTO_QUIT", "1", TRUE);

      subprocess = g_subprocess_launcher_spawnv (launcher, (const char *const *)argv + 1, &error);
      if (error)
        g_error ("Launch child: %s", error->message);

      if (!g_subprocess_wait (subprocess, NULL, &error))
        g_error ("Run child: %s", error->message);

      g_object_unref (subprocess);
      g_object_unref (launcher);

      reader = sysprof_capture_reader_new (name);
      if (!reader)
        g_error ("Opening syscap file: %s", g_strerror (errno));

      data.group = "style";
      data.value = 0;

      cursor = sysprof_capture_cursor_new (reader);

      type = SYSPROF_CAPTURE_FRAME_MARK;
      condition = sysprof_capture_condition_new_where_type_in (1, &type);
      sysprof_capture_cursor_add_condition (cursor, condition);

      sysprof_capture_cursor_foreach (cursor, callback, &data);

      values[i] = data.value;

      sysprof_capture_cursor_unref (cursor);
      sysprof_capture_reader_unref (reader);

      remove (name);

      g_free (name);
    }

  min = G_MAXINT64;
  max = 0;
  total = 0;

  for (i = 0; i < opt_rep; i++)
    {
      if (min > values[i])
        min = values[i];
      if (max < values[i])
        max = values[i];
      total += values[i];
    }

  g_print ("%d runs, min %g, max %g, avg %g\n",
           opt_rep,
           MILLISECONDS (min),
           MILLISECONDS (max),
           MILLISECONDS (total / opt_rep));
}