#include <Elementary.h>
#include <Ecore_X.h>
static Evas_Object *win, *bg, *o[8], *b0, *b1, *b2, *b3, *b4;
static int pos = 0;

static Eina_Bool show_loop = EINA_TRUE;
static Eina_Bool show_anim = EINA_TRUE;
static Eina_Bool show_vsync = EINA_TRUE;
static Eina_Bool show_main = EINA_TRUE;

#define HIST 64

static Evas_Object *
vg_add(Evas_Object *w)
{
   Evas_Object *o;
   Evas_Vg_Container *con;
   Evas_Vg_Shape *sh;

   o = evas_object_vg_add(evas_object_evas_get(w));
   con = evas_vg_container_add(o);
   sh = evas_vg_shape_add(con);
   evas_object_vg_root_node_set(o, con);
   evas_object_show(o);
   evas_object_data_set(o, "con", con);
   evas_object_data_set(o, "shape", sh);
   return o;
}

static void
vg_fill(Evas_Object *o, int w, int h, double *ft, int hfr, int r, int g, int b, int a)
{
   Evas_Vg_Shape *sh;
   int i;
   double v;

   evas_object_resize(o, w, h);
   sh = evas_object_data_get(o, "shape");
   evas_vg_shape_reset(sh);
   evas_vg_shape_stroke_width_set(sh, 1.0);
   evas_vg_shape_stroke_color_set(sh, r, g, b, a);
   evas_vg_shape_append_move_to(sh, 0, (h / 2));
   for (i = 0; i < w; i++)
     {
        v = (ft[i] - (1.0/60.0)) * 1000.0 * hfr;
        if      (v < (-h / 2)) v = -h / 2;
        else if (v > ( h / 2)) v =  h / 2;
        evas_vg_shape_append_line_to(sh, i, (h / 2) - v);
     }
   evas_vg_node_origin_set(evas_object_data_get(0, "shape"), 0, 0);
}

static void
position_gr_list(Eina_List *list, int w, int h, int offset)
{
   Evas_Object *o;
   Eina_List *l, *ll;
   int x = w - 1 - offset;

   EINA_LIST_FOREACH_SAFE(list, l, ll, o)
     {
        if ((x + HIST) < 0)
          {
             evas_object_del(o);
             list = eina_list_remove_list(list, l);
          }
        else
          {
             evas_object_move(o, x, 0);
             evas_object_resize(o, HIST, h);
          }
        x -= HIST;
     }
}

typedef struct
{
   double history[HIST];
   double val, prev;
   Eina_List *blocks;
} Source;

static void
src_store(Source *s, double t, int pos)
{
   s->val = t;
   s->history[pos] = s->val - s->prev;
}

static void
src_update(Source *s, int pos, int w, int h, int hfr, int r, int g, int b, int a)
{
   Evas_Object *o;
   int i;

   if (pos == 0)
     {
        for (i = 0; i < HIST; i++) s->history[i] = 1.0/60.0;
        o = vg_add(win);
        s->blocks = eina_list_prepend(s->blocks, o);
     }
   o = s->blocks->data;
   vg_fill(o, HIST, h, s->history, hfr, r, g, b, a);
   position_gr_list(s->blocks, w, h, pos);
}

static void
src_move_along(Source *s)
{
   s->prev = s->val;
}

static Eina_Bool
anim(void *data EINA_UNUSED)
{
   static int hist = 0;
   static Source src_anim, src_vsync, src_main, src_loop;
   double hfr;
   Evas_Coord w, h;
   int i;

   src_store(&src_anim,  ecore_time_get(), hist);
   src_store(&src_loop,  ecore_loop_time_get(), hist);
   src_store(&src_vsync, _ecore_x_vsync_wakeup_time_get(), hist);
   src_store(&src_main,  _ecore_main_loop_wakeup_time_get(), hist);

   evas_object_geometry_get(win, NULL, NULL, &w, &h);
   hfr = h / 32;

   if (show_anim) // orange animator time called at
     src_update(&src_anim,  hist, w, h, hfr, 255, 153, 51, 255);
   if (show_vsync) // purple vsync wakeup
     src_update(&src_vsync, hist, w, h, hfr, 255, 51, 153, 255);
   if (show_main) // green mainloop wakeup
     src_update(&src_main,  hist, w, h, hfr, 153, 255, 51, 255);
   if (show_loop) // blue vblank timestamp for loop time
     src_update(&src_loop,  hist, w, h, hfr, 51, 153, 255, 255);

   evas_object_move(b0, 0, h / 2);
   evas_object_resize(b0, w, 1);
   evas_object_raise(b0);

   evas_object_move(b1, 0, (h / 2) - (hfr * 1));
   evas_object_resize(b1, w, 1);
   evas_object_raise(b1);

   evas_object_move(b2, 0, (h / 2) + (hfr * 1));
   evas_object_resize(b2, w, 1);
   evas_object_raise(b2);

   evas_object_move(b3, 0, (h / 2) - (hfr * 8));
   evas_object_resize(b3, w, 1);
   evas_object_raise(b3);

   evas_object_move(b4, 0, (h / 2) + (hfr * 8));
   evas_object_resize(b4, w, 1);
   evas_object_raise(b4);

   for (i = 0; i < 8; i++)
     {
        evas_object_move(o[i], (i * (w / 5)) - pos, 0);
        evas_object_resize(o[i], w / 5, h);
     }

   pos++;
   if (pos >= ((w / 5) * 2)) pos = 0;

   hist++;
   if (hist >= HIST) hist = 0;

   src_move_along(&src_anim);
   src_move_along(&src_loop);
   src_move_along(&src_vsync);
   src_move_along(&src_main);
   return EINA_TRUE;
}

EAPI int
elm_main(int argc, char **argv)
{
   int i;

   for (i = 1; i < argc; i++)
     {
        if      (!strcmp(argv[i], "-anim")) show_anim = EINA_FALSE;
        else if (!strcmp(argv[i], "+anim")) show_anim = EINA_TRUE;
        else if (!strcmp(argv[i], "-vsync")) show_vsync = EINA_FALSE;
        else if (!strcmp(argv[i], "+vsync")) show_vsync = EINA_TRUE;
        else if (!strcmp(argv[i], "-main")) show_main = EINA_FALSE;
        else if (!strcmp(argv[i], "+main")) show_main = EINA_TRUE;
        else if (!strcmp(argv[i], "-loop")) show_loop = EINA_FALSE;
        else if (!strcmp(argv[i], "+loop")) show_loop = EINA_TRUE;
     }
   win = elm_win_add(NULL, "main", ELM_WIN_BASIC);
   if (!win)
     {
        elm_exit();
        return 1;
     }
   evas_object_resize(win, 300, 200);
   elm_win_autodel_set(win, EINA_TRUE);
   elm_win_title_set(win, "Smood Vsync Stability");
   elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);

   bg = evas_object_rectangle_add(evas_object_evas_get(win));
   evas_object_color_set(bg, 64, 64, 64, 255);
   evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   elm_win_resize_object_add(win, bg);
   evas_object_show(bg);

   for (i = 0; i < 8; i++)
     {
        o[i] = evas_object_rectangle_add(evas_object_evas_get(win));
        if (i & 0x1)
          evas_object_color_set(o[i], 64, 64, 64, 255);
        else
          evas_object_color_set(o[i], 32, 32, 32, 255);
        evas_object_show(o[i]);
     }

   b0 = evas_object_rectangle_add(evas_object_evas_get(win));
   evas_object_color_set(b0, 64, 64, 64, 64);
   evas_object_show(b0);

   b1 = evas_object_rectangle_add(evas_object_evas_get(win));
   evas_object_color_set(b1, 64, 64, 0, 64);
   evas_object_show(b1);

   b2 = evas_object_rectangle_add(evas_object_evas_get(win));
   evas_object_color_set(b2, 64, 64, 0, 64);
   evas_object_show(b2);

   b3 = evas_object_rectangle_add(evas_object_evas_get(win));
   evas_object_color_set(b3, 64, 0, 0, 64);
   evas_object_show(b3);

   b4 = evas_object_rectangle_add(evas_object_evas_get(win));
   evas_object_color_set(b4, 64, 0, 0, 64);
   evas_object_show(b4);

   ecore_animator_add(anim, NULL);

   evas_object_show(win);
   elm_run();
   return 0;
}
ELM_MAIN()
