// utils for draga and drop handling
static Eina_Bool
_cb_dnd_scroll_timer(void *data)
{
   Smart_Data *sd = data;
   Evas_Coord fmx, fmy, sx, sy, sw, sh, x, y;
   Evas_Coord scr_edge_x, scr_edge_y, scr_mul;

   evas_object_geometry_get(sd->o_smart, &fmx, &fmy, NULL, NULL);
   evas_object_geometry_get(sd->o_scroller, &sx, &sy, &sw, &sh);
   scr_mul = 4;
   scr_edge_x = sd->icon_min_w / 2;
   scr_edge_y = sd->icon_min_h / 2;
   if      (sd->dnd_scroll_x < scr_edge_x)
     x = sx - fmx + sd->dnd_scroll_x - scr_edge_x - ((scr_edge_x - sd->dnd_scroll_x) * scr_mul);
   else if (sd->dnd_scroll_x > (sw - scr_edge_x))
     x = sx - fmx + sd->dnd_scroll_x + scr_edge_x + ((sd->dnd_scroll_x - (sw - scr_edge_x)) * scr_mul);
   else
     x = sx - fmx + sd->dnd_scroll_x;
   if      (sd->dnd_scroll_y < scr_edge_y)
     y = sy - fmy + sd->dnd_scroll_y - scr_edge_y - ((scr_edge_y - sd->dnd_scroll_y) * scr_mul);
   else if (sd->dnd_scroll_y > (sh - scr_edge_y))
     y = sy - fmy + sd->dnd_scroll_y + scr_edge_y + ((sd->dnd_scroll_y - (sh - scr_edge_y)) * scr_mul);
   else
     y = sy - fmy + sd->dnd_scroll_y;
   printf("SSS %i %i     | %i %i %ix%i | %i %i\n", x, y, sx, sy, sw, sh, sd->dnd_scroll_x, sd->dnd_scroll_y);
   elm_scroller_region_bring_in(sd->o_scroller, x, y, 1, 1);
   return EINA_TRUE;
}

static void
_dnd_scroll_handle(Smart_Data *sd, Evas_Coord x, Evas_Coord y)
{
   sd->dnd_scroll_x = x;
   sd->dnd_scroll_y = y;
   if (!sd->dnd_scroll_timer)
     sd->dnd_scroll_timer = ecore_timer_add
       (SCROLL_DND_TIMER, _cb_dnd_scroll_timer, sd);
}

static void
_dnd_scroll_end_handle(Smart_Data *sd)
{
   if (sd->dnd_scroll_timer)
     {
        ecore_timer_del(sd->dnd_scroll_timer);
        sd->dnd_scroll_timer = NULL;
     }
}

static void
_dnd_over(Icon *icon)
{
   _icon_over_on(icon);
}

static void
_dnd_over_none_handle(Smart_Data *sd)
{
   if (sd->over_icon) _icon_over_off(sd->over_icon);
}

static void
_dnd_over_handle(Smart_Data *sd, Evas_Coord x, Evas_Coord y)
{
   Icon *icon;
   Eina_List *bl, *il;
   Block *block;

   EINA_LIST_FOREACH(sd->blocks, bl, block)
     {
        if (!eina_rectangle_coords_inside(&(block->bounds), x, y)) continue;
        EINA_LIST_FOREACH(block->icons, il, icon)
          {
             if (!eina_rectangle_coords_inside(&(icon->geom), x, y)) continue;
             _dnd_over(icon);
             return;
          }
     }
   _dnd_over_none_handle(sd);
}

// drop handling
static void
_cb_drop_in(void *data EINA_UNUSED, Evas_Object *o EINA_UNUSED)
{
//   Smart_Data *sd = data;
   printf("XXX: drop in.....\n");
   // XXX: call drop in smart callback}
}

static void
_cb_drop_out(void *data, Evas_Object *o EINA_UNUSED)
{
   Smart_Data *sd = data;
   _dnd_scroll_end_handle(sd);
   _dnd_over_none_handle(sd);
   printf("XXX: drop out.....\n");
   // XXX: call drop out smart callback}
}

void
_cb_drop_pos(void *data, Evas_Object *o EINA_UNUSED, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action EINA_UNUSED)
{
   Smart_Data *sd = data;
   Evas_Coord fmx, fmy, fmw, fmh;
   Evas_Coord sx, sy, sw, sh;

   sd->dnd_action = action;
   evas_object_geometry_get(sd->o_smart, &fmx, &fmy, &fmw, &fmh);
   evas_object_geometry_get(sd->o_scroller, &sx, &sy, &sw, &sh);
   _dnd_scroll_handle(sd, x - sx, y - sy);
   if (((x - sx) > 0) && ((y - sy) > 0) &&
       ((x - sx) < sw) && ((y - sy) < sh))
     _dnd_over_handle(sd, x - fmx, y - fmy);
   else
     _dnd_over_none_handle(sd);
   if (sd->over_icon) sd->drop_over = sd->over_icon;
   else sd->drop_over = NULL;
}

static Eina_Bool
_cb_drop(void *data, Evas_Object *o EINA_UNUSED, Elm_Selection_Data *ev)
{
   Smart_Data *sd = data;
   char **plist, **p, *esc, *tmp;

   if (sd->drop_over) printf("XXX: DND DROP OVER [%s]\n", sd->drop_over->info.file);
   else printf("XXX: DND DROP ...\n");
   tmp = malloc(ev->len + 1);
   if (!tmp) goto err;
   memcpy(tmp, ev->data, ev->len);
   tmp[ev->len] = 0;
   plist = eina_str_split(tmp, "\n", -1);
   for (p = plist; *p != NULL; ++p)
     {
        if (**p)
          {
             esc = _escape_parse(*p);
             if (!esc) continue;
             printf("XXX: DROP FILE: [%s]\n", esc);
          }
     }
   free(*plist);
   free(plist);
   free(tmp);
err:
   sd->drop_over = NULL;
   return EINA_TRUE;
}

static void
_drop_init(Smart_Data *sd)
{ // called once we have our elm scroller around our file view
   elm_drop_target_add(sd->o_scroller,
                       ELM_SEL_FORMAT_URILIST,
                       _cb_drop_in,  sd,
                       _cb_drop_out, sd,
                       _cb_drop_pos, sd,
                       _cb_drop,     sd);
}

// drag handling
static Evas_Object *
_cb_drag_icon_add(void *data, Evas_Object *parent, Evas_Coord *xoff, Evas_Coord *yoff)
{
   Icon *icon = data;
   Icon *icon2;
   Block *block;
   Evas_Object *obj = icon->sd->o_smart;
   Evas_Object *o;
   const char *theme_edj_file;
   Evas *e;
   ENTRY NULL;
   Eina_List *bl, *il;
   int num = 0;

   if (sd->config.view_mode >= EFM_VIEW_MODE_LIST)
     {
        EINA_LIST_FOREACH(sd->blocks, bl, block)
          {
             if (block->realized_num <= 0)
               {
                  num += eina_list_count(block->icons);
                  continue;
               }
             EINA_LIST_FOREACH(block->icons, il, icon2)
               {
                  if (icon == icon2) goto found;
                  num++;
               }
             num += eina_list_count(block->icons);
          }
     }
found:
   e = evas_object_evas_get(parent);
   theme_edj_file = elm_theme_group_path_find(NULL,
                                              "e/fileman/default/icon/fixed");
   _icon_object_add(icon, icon->sd, e, theme_edj_file, EINA_FALSE, num);
   o = icon->o_base;
   evas_object_resize(o, icon->geom.w, icon->geom.h);
   if (xoff) *xoff = (icon->geom.x + icon->sd->geom.x);
   if (yoff) *yoff = (icon->geom.y + icon->sd->geom.y);
   if (xoff && yoff)
     printf("DND: drag begin %p %p  off: %i %i\n", obj, o, *xoff, *yoff);
   else
     printf("DND: drag begin %p %p\n", obj, o);
   return o;
}

static void
_cb_drag_pos(void *data EINA_UNUSED, Evas_Object *obj_drag EINA_UNUSED, Evas_Coord x, Evas_Coord y, Elm_Xdnd_Action action)
{
   printf("DND: %i %i act=%i\n", x, y, action);
}

static void
_cb_drag_accept(void *data EINA_UNUSED, Evas_Object *obj_drag EINA_UNUSED, Eina_Bool accept)
{
   printf("DND: accept %i\n", accept);
}

static void
_cb_drag_done(void *data, Evas_Object *obj_drag EINA_UNUSED)
{
   Icon *icon = data;
   Evas_Object *obj;

   if (icon->sd)
     {
        obj = icon->sd->o_smart;
        ENTRY;

        printf("DND: drag done %p %p\n", obj, obj_drag);
        sd->drag = EINA_FALSE;
        icon->o_base = NULL; // try and not del this as dnd will do it
        icon->sd->drag_icon = NULL;
     }
   _icon_free(icon);
}

static void
_drag_start(Icon *icon)
{
   Eina_Strbuf *strbuf;
   Icon *icon_dup;

   strbuf = eina_strbuf_new();
   if (!strbuf) return;
   icon_dup = _icon_dup(icon);
   if (!icon_dup) goto err;

   if (icon->sd->rename_icon) _icon_rename_end(icon->sd->rename_icon);
   printf("XXX: begin dnd\n");

   icon->sd->drag = EINA_TRUE;
   icon->sd->just_dragged = EINA_TRUE;
   icon->sd->drag_icon = icon_dup;
   if (_selected_icons_uri_strbuf_append(icon->sd, strbuf))
     { // begin the drag with that list of files
        // XXX: if you use no modifier - do default (move)
        // XXX: if you hold ctrl then do copy
        // XXX: on win ... to/from removable drive it copies always
        // XXX: if you hold shift then do move
        // XXX; on mac option key forces a copy normally except from
        //      removable device then it forces a move
        // XXX: this "except to/from removable drive" is bad/inconsistent imho
        elm_drag_start(icon_dup->sd->o_scroller,
                       ELM_SEL_FORMAT_URILIST,
                       eina_strbuf_string_get(strbuf),
                       ELM_XDND_ACTION_MOVE,
                       _cb_drag_icon_add, icon_dup,
                       _cb_drag_pos,      icon_dup,
                       _cb_drag_accept,   icon_dup,
                       _cb_drag_done,     icon_dup);
     }
err:
   eina_strbuf_free(strbuf);
}
