/* vim: set sw=3 ts=3 sts=3 expandtab: */
#include "ecdb.h"

static void
_widget_focus_handle(Evas_Object *o)
{
   static Evas_Object *old_object;

   if (old_object)
   {
      if (old_object != o)
         edje_object_signal_emit(old_object, "ecdb,focus,out", "ecdb");
   }

   old_object = o;

   // Send focus to the freshly clicked widget
   evas_object_focus_set(o, 1);
}

static void
_mouse_down_edje(void *data, Evas_Object *o, const char *emission,
																		const char *source)
{
   _widget_focus_handle(o);
}

static void
_mouse_down_evas(void *data, Evas *e __UNUSED__, Evas_Object *eo,
                                             void *ev_data __UNUSED__)
{
   _widget_focus_handle(eo);
}

void
ecdb_widget_focus_callback_add(Evas_Object *o, const char *name)
{
   evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN,
                        _mouse_down_evas, (void *)name);
}

Evas_Object *
ecdb_widget_add(Evas_Object *parent, const char *name)
{
   Evas_Object *o;
   int x, y, w, h;

   o = edje_object_add(evas_object_evas_get(parent));
   if (!o)
   {
      EINA_ERROR_PWARN("NULL return!\n");
      return NULL;
   }

   edje_object_signal_callback_add(o, "ecdb,activate", "*",
                                                _mouse_down_edje, NULL);

   if (name)
   {
      edje_object_part_geometry_get(parent, name, &x, &y, &w, &h);
      evas_object_move(o, x, y);
      evas_object_resize(o, w, h);
      edje_object_part_swallow(parent, name, o);
   }

   return o;
}

/************************** BUTTON ******************************************/

Evas_Object *
ecdb_button_add(Evas_Object *parent, const char *name)
{
   Evas_Object *b;

   b = ecdb_widget_add(parent, name);
   if (!b)
   {
      EINA_ERROR_PWARN("NULL return!\n");
      return NULL;
   }

   edje_object_file_set(b, em->theme_path, "ecdb/button");

   return b;
}

void
ecdb_button_label_set(Evas_Object *b, const char *label)
{
   if (!b)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }
   edje_object_part_text_set(b, "ecdb.label", label);
}

void
ecdb_button_icon_set(Evas_Object *b, const char *group)
{
   Evas_Object *icon;

   if (!b)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   icon = ecdb_widget_add(b, "ecdb.swallow.icon");
   if (!icon)
   {
      EINA_ERROR_PWARN("NULL icon!\n");
      return;
   }
   if (edje_object_file_set(icon, em->theme_path, group))
      edje_object_signal_emit(b, "ecdb,button,icon,swallow", "ecdb");
   evas_object_show(icon);
}

const char *
ecdb_button_label_get(Evas_Object *b)
{
   if (!b)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return NULL;
   }
   return edje_object_part_text_get(b, "ecdb.label");
}

/************************* COMBO ITEM ****************************************/
Evas_Object *
ecdb_combo_item_add(Evas_Object *parent, const char *name)
{
   Evas_Object *ci;

   ci = ecdb_widget_add(parent, name);
   if (!ci)
   {
      EINA_ERROR_PWARN("NULL return!\n");
      return NULL;
   }
   edje_object_file_set(ci, em->theme_path, "ecdb/combo_item");

   return ci;
}

void
ecdb_combo_item_label_set(Evas_Object *ci, const char *label)
{
   if (!ci)
   {
      EINA_ERROR_PWARN("NULL ci!\n");
      return;
   }
   edje_object_part_text_set(ci, "ecdb.label", label);
}

void
ecdb_combo_item_icon_set(Evas_Object *ci, const char *group)
{
   Evas_Object *icon;

   if (!ci)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   icon = ecdb_widget_add(ci, "ecdb.swallow.icon");
   if (!icon)
   {
      EINA_ERROR_PWARN("NULL icon!\n");
      return;
   }
   edje_object_file_set(icon, em->theme_path, group);
   evas_object_show(icon);
}

const char *
ecdb_combo_item_label_get(Evas_Object *ci)
{
   return edje_object_part_text_get(ci, "ecdb.label");
}

/************************* CHECK *********************************************/

typedef struct _Check_Data Check_Data;
struct _Check_Data
{
   unsigned int checked;
};

static void
_check_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Check_Data *cd;
   cd = evas_object_data_get(data, "cd");
   FREE(cd);
}

static void
_check_toggle_cb_call(void *data, Evas_Object *obj, const char *emission,
                                                            const char *source)
{
   Check_Data *cd;

   cd = evas_object_data_get(obj, "cd");
   if (!strcmp(emission, "ecdb,check,checked"))
   {
      evas_object_smart_callback_call(obj, "checked", NULL);
      cd->checked = 1;
   }
   else
   {
      evas_object_smart_callback_call(obj, "unchecked", NULL);
      cd->checked = 0;
   }
}

Evas_Object *
ecdb_check_add(Evas_Object *parent, const char *name)
{
   Evas_Object *c;
   Check_Data *cd;

   c = ecdb_widget_add(parent, name);
   if (!c)
   {
      EINA_ERROR_PWARN("NULL return!\n");
      return NULL;
   }

   edje_object_file_set(c, em->theme_path, "ecdb/check");
   edje_object_signal_callback_add(c, "ecdb,check,*", "ecdb",
                                    _check_toggle_cb_call, c);
   evas_object_event_callback_add(c, EVAS_CALLBACK_DEL, _check_del, c);

   cd = calloc(1, sizeof(Check_Data));
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return NULL;
   }
   evas_object_data_set(c, "cd", cd);

   return c;
}

void
ecdb_check_label_set(Evas_Object *c, const char *label)
{
   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   edje_object_part_text_set(c, "ecdb.label", label);
}

void
ecdb_check_states_set(Evas_Object *c, const char *ystate, const char *nstate)
{
   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   edje_object_part_text_set(c, "ecdb.ystate", ystate);
   edje_object_part_text_set(c, "ecdb.nstate", nstate);
}

void
ecdb_check_checked_set(Evas_Object *c, int state)
{
   Check_Data *cd;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   cd = evas_object_data_get(c, "cd");
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return;
   }

   if (cd->checked == state)
      return;

   if (state)
   {
      cd->checked = 1;
      edje_object_signal_emit(c, "ecdb,check,on", "ecdb");
   }
   else
   {
      cd->checked = 0;
      edje_object_signal_emit(c, "ecdb,check,off", "ecdb");
   }
}

int
ecdb_check_checked_get(Evas_Object *c)
{
   Check_Data *cd;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return 0;
   }

   cd = evas_object_data_get(c, "cd");
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return 0;
   }

   return cd->checked;
}

/************************** ENTRY *******************************************/

/* Shamelessly stolen from Elementary... */
static char *
_entry_str_append(char *str, const char *txt, int *len, int *alloc)
{
   int txt_len = strlen(txt);
   if (txt_len <= 0) return str;
   if ((*len + txt_len) >= *alloc)
     {
        char *str2;
        int alloc2;
        
        alloc2 = *alloc + txt_len + 128;
        str2 = realloc(str, alloc2);
        if (!str2) return str;
        *alloc = alloc2;
        str = str2;
     }
   strcpy(str + *len, txt);
   *len += txt_len;
   return str;
}

static char *
_entry_markup_to_text(const char *mkup)
{
   char *str = NULL;
   int str_len = 0, str_alloc = 0;
   // FIXME: markup -> text
   char *s, *p;
   char *tag_start, *tag_end, *esc_start, *esc_end, *ts;
   
   tag_start = tag_end = esc_start = esc_end = NULL;
   if (!mkup)
      return NULL;

   p = (char *)mkup;
   s = p;
   for (;;)
     {
        if ((*p == 0) ||
            (tag_end) || (esc_end) ||
            (tag_start) || (esc_start))
          {
             if (tag_end)
               {
                  char *ttag;
                  
                  ttag = malloc(tag_end - tag_start);
                  if (ttag)
                    {
                       strncpy(ttag, tag_start + 1, tag_end - tag_start - 1);
                       ttag[tag_end - tag_start - 1] = 0;
                       /*
                       if (!strcmp(ttag, "br"))
                         str = _str_append(str, "\n", &str_len, &str_alloc);
                       */
                       if (!strcmp(ttag, "\n"))
                         str = _entry_str_append(str, "\n", &str_len,
                                                               &str_alloc);
                       else if (!strcmp(ttag, "\\n"))
                         str = _entry_str_append(str, "\n", &str_len,
                                                               &str_alloc);
                       else if (!strcmp(ttag, "\t"))
                         str = _entry_str_append(str, "\t", &str_len,
                                                               &str_alloc);
                       else if (!strcmp(ttag, "\\t"))
                         str = _entry_str_append(str, "\t", &str_len,
                                                               &str_alloc);
                       free(ttag);
                    }
                  tag_start = tag_end = NULL;
               }
             else if (esc_end)
               {
                  ts = malloc(esc_end - esc_start + 1);
                  if (ts)
                    {
                       const char *esc;
                       strncpy(ts, esc_start, esc_end - esc_start); 
                       ts[esc_end - esc_start] = 0;
                       esc = evas_textblock_escape_string_get(ts);
                       if (esc)
                         str = _entry_str_append(str, esc, &str_len,
                                                                  &str_alloc);
                       free(ts);
                    }
                  esc_start = esc_end = NULL;
               }
             else if (*p == 0)
               {
                  ts = malloc(p - s + 1);
                  if (ts)
                    {
                       strncpy(ts, s, p - s);
                       ts[p - s] = 0;
                       str = _entry_str_append(str, ts, &str_len, &str_alloc);
                       free(ts);
                    }
                  s = NULL;
               }
             if (*p == 0)
               break;
          }
        if (*p == '<')
          {
             if (!esc_start)
               {
                  tag_start = p;
                  tag_end = NULL;
                  ts = malloc(p - s + 1);
                  if (ts)
                    {
                       strncpy(ts, s, p - s);
                       ts[p - s] = 0;
                       str = _entry_str_append(str, ts, &str_len, &str_alloc);
                       free(ts);
                    }
                  s = NULL;
               }
          }
        else if (*p == '>')
          {
             if (tag_start)
               {
                  tag_end = p;
                  s = p + 1;
               }
          }
        else if (*p == '&')
          {
             if (!tag_start)
               {
                  esc_start = p;
                  esc_end = NULL;
                  ts = malloc(p - s + 1);
                  if (ts)
                    {
                       strncpy(ts, s, p - s);
                       ts[p - s] = 0;
                       str = _entry_str_append(str, ts, &str_len, &str_alloc);
                       free(ts);
                    }
                  s = NULL;
               }
          }
        else if (*p == ';')
          {
             if (esc_start)
               {
                  esc_end = p;
                  s = p + 1;
               }
          }
        p++;
     }
   return str;
}

static void
_entry_click_cb_call(void *data, Evas_Object *obj, const char *emission,
                                                            const char *source)
{
   evas_object_focus_set(obj, 1);
}

Evas_Object *
ecdb_entry_add(Evas_Object *parent, const char *name)
{
   Evas_Object *e;

   e = ecdb_widget_add(parent, name);
   if (!e)
   {
      EINA_ERROR_PWARN("NULL return!\n");
      return NULL;
   }
   edje_object_file_set(e, em->theme_path, "ecdb/entry");
   em->evas_dnd_candidates = eina_list_append(em->evas_dnd_candidates, e);
   evas_object_data_set(e, "dnd_call_func", ecdb_dnd_entry_dnd_set);
   edje_object_signal_callback_add(e, "clicked", "ecdb", _entry_click_cb_call,
                                                                           e);

   return e;
}

void
ecdb_entry_text_set(Evas_Object *e, const char *text)
{
   edje_object_part_text_set(e, "ecdb.text", text);
}

char *
ecdb_entry_text_get(Evas_Object *e)
{
   return _entry_markup_to_text(edje_object_part_text_get(e, "ecdb.text"));
}

/****************************** COMBO ****************************************/

typedef struct _Combo_Data Combo_Data;
struct _Combo_Data
{
   Evas_Object *parent;
   Evas_Object *back;
   Evas_Object *popup;
   unsigned int expanded;
   unsigned int count;
   int selected;
   const char *name;
   const char *header;
   void *data;
   void (*create_header)(Evas_Object *, const char *name, void *data,
                                                         Evas_Object *, int);
};

static void
_combo_min_size(Evas_Object *o, Evas_Object_Box_Data *p, void *data)
{
   Eina_List *l;
   Evas_Object_Box_Option *opt;
   int x, y, w, h;
   int xc, yc, wc, hc;

   if (eina_list_count(p->children) <= 0)
      return;

   evas_object_geometry_get(o, &x, &y, &w, &h);
   p->children = eina_list_nth_list(p->children, 0);
   h /= eina_list_count(p->children);
   if (h < 1) h = 1;
   EINA_LIST_FOREACH(p->children, l, opt)
   {
      evas_object_geometry_get(opt->obj, &xc, &yc, &wc, &hc);
      if ((wc != w) || (hc != h))
         evas_object_resize(opt->obj, w, h);
      if ((xc != x) || (yc != y))
         evas_object_move(opt->obj, x, y);
      y += h;
   }
}

// Axis preferential -- for now vertical
const char *
_combo_best_location(Evas_Object *c)
{
   int x, y, w, h;
   int ww, wh;

   ecore_evas_geometry_get(em->main_win_ee, NULL, NULL, &ww, &wh);
   evas_object_geometry_get(c, &x, &y, &w, &h);

   if ((y + h) > (wh - y - h))
   {
      return "top";
   }
   else
   {
      return "bottom";
   }
}

static void
_combo_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Combo_Data *cd;
   cd = evas_object_data_get(data, "cd");

   eina_stringshare_del(cd->header);
   FREE(cd);
}


static void
_combo_resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Combo_Data *cd;

   cd = evas_object_data_get(data, "cd");
   if (cd->expanded)
      ecdb_combo_collapse(data);
}

static void
_combo_hide(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Combo_Data *cd;

   cd = evas_object_data_get(data, "cd");
   if (cd->expanded)
      ecdb_combo_collapse(data);
}

static void
_combo_clicked(void *data, Evas_Object *obj, const char *emission __UNUSED__,
                                             const char *source __UNUSED__)
{
   Combo_Data *cd;
   Evas_Object *swallow, *header;
   Eina_Iterator *it;
   int i = 0;
   
   cd = evas_object_data_get(data, "cd");
   swallow = edje_object_part_swallow_get(data, "ecdb.header.swallow");
   if (swallow)
      evas_object_del(swallow);

   it = evas_object_box_iterator_new(edje_object_part_object_get(cd->popup,
                                                               "ecdb.box"));
   if (!it)
   {
      EINA_ERROR_PWARN("NULL iterator!\n");
      return;
   }

   while (eina_iterator_next(it, (void **)&swallow))
   {
      if (swallow == obj)
         break;
      i++;
   }
   eina_iterator_free(it);

   cd->selected = i;

   header = edje_object_part_swallow_get(data, "ecdb.header.swallow");
   if (header)
   {
      edje_object_part_unswallow(data, header);
      evas_object_del(header);
   }

   if (cd->create_header)
      cd->create_header(data, "ecdb.header.swallow", cd->data, swallow, i);

   edje_object_signal_emit(data, "ecdb,combo,header,swallow", "ecdb");
   ecdb_combo_collapse(data);
}

static void
_combo_moveable_click_cb(void *data, Evas_Object *obj, const char *emission,
                                                            const char *source)
{
   Combo_Data *cd;

   cd = evas_object_data_get(data, "cd");
   if (cd->expanded)
      ecdb_combo_collapse(data);
}

static void
_combo_click_cb(void *data, Evas_Object *obj, const char *emission,
                                                            const char *source)
{
   Evas_Object *c;
   Combo_Data *cd;

   c = data;
   cd = evas_object_data_get(c, "cd");
   if ((cd) && (!cd->expanded))
         ecdb_combo_expand(c);
   else
      ecdb_combo_collapse(c);
}

Evas_Object *
ecdb_combo_add(Evas_Object *parent, const char *name)
{
   Evas_Object *c;
   Combo_Data *cd;

   c = ecdb_widget_add(parent, name);

   if (!c)
   {
      EINA_ERROR_PWARN("NULL return!\n");
      return NULL;
   }
   edje_object_file_set(c, em->theme_path, "ecdb/combo");
   evas_object_event_callback_add(parent, EVAS_CALLBACK_RESIZE, _combo_resize,
                                                                           c);
   evas_object_event_callback_add(parent, EVAS_CALLBACK_HIDE, _combo_hide, c);
   evas_object_event_callback_add(c, EVAS_CALLBACK_DEL, _combo_del, c);
   edje_object_signal_callback_add(c, "ecdb,clicked", "ecdb",
                                                      _combo_click_cb, c);

   cd = calloc(1, sizeof(Combo_Data));
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return NULL;
   }

   cd->back = edje_object_add(evas_object_evas_get(parent));
   edje_object_file_set(cd->back, em->theme_path, "ecdb/combo/background");
   edje_object_signal_callback_add(cd->back, "ecdb,combo,back,dismiss", "ecdb",
                                                   _combo_moveable_click_cb, c);
   evas_object_pass_events_set(cd->back, 1);
   evas_object_show(cd->back);

   cd->popup = edje_object_add(evas_object_evas_get(parent));
   edje_object_file_set(cd->popup, em->theme_path, "ecdb/combo/popup");
   edje_object_signal_callback_add(cd->back, "ecdb,combo,back,dismiss", "ecdb",
                                                   _combo_moveable_click_cb, c);
   edje_box_layout_register("min_size", _combo_min_size, NULL, NULL, NULL,
                                                                     NULL);
   evas_object_pass_events_set(cd->popup, 1);
   evas_object_show(cd->popup);

   cd->parent = parent;
   cd->selected = -1;
   evas_object_data_set(c, "cd", cd);

   return c;
}

void
ecdb_combo_header_set(Evas_Object *c, const char *text)
{
   Combo_Data *cd;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   cd = evas_object_data_get(c, "cd");
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return;
   }

   edje_object_part_text_set(c, "ecdb.header", text);
   eina_stringshare_del(cd->header);
   cd->header = eina_stringshare_add(text);
}

void
ecdb_combo_append(Evas_Object *c, Evas_Object *o)
{
   Combo_Data *cd;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   cd = evas_object_data_get(c, "cd");
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return;
   }
   cd->count++;
   edje_object_part_box_append(cd->popup, "ecdb.box", o);
   edje_object_signal_callback_add(o, "ecdb,clicked", "ecdb",
                                                         _combo_clicked, c);
}

void
ecdb_combo_expand(Evas_Object *c)
{
   Combo_Data *cd;
   Eina_Iterator *it;
   Evas_Object *o;
   const Evas_Object *box;
   const char *location, *min_size;
   char buf[1024];
   int x, y, w, h, h2, padding;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   cd = evas_object_data_get(c, "cd");
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return;
   }

   if ((cd->count == 0) || (cd->expanded))
      return;

   edje_object_signal_emit(c, "ecdb,combo,active", "ecdb");

   evas_object_move(cd->back, 0, 0);
   ecore_evas_geometry_get(em->main_win_ee, NULL, NULL, &w, &h);
   evas_object_resize(cd->back, w, h);
   evas_object_pass_events_set(cd->back, 0);
   evas_object_raise(cd->back);
   edje_object_signal_emit(cd->back, "ecdb,combo,back,show", "ecdb");

   location = _combo_best_location(c);
   snprintf(buf, sizeof(buf), "ecdb,combo,popup,show,%s", location);
   evas_object_geometry_get(c, &x, &y, &w, &h);

   box = edje_object_part_object_get(cd->popup, "ecdb.box");
   evas_object_box_padding_get(box, NULL, &padding);
   h2 = -padding;

   it = evas_object_box_iterator_new(edje_object_part_object_get(cd->popup,
                                                               "ecdb.box"));
   if (!it)
   {
      EINA_ERROR_PWARN("NULL iterator!\n");
      return;
   }

   while (eina_iterator_next(it, (void **)&o))
   {
      /* I should probably this into a minimum_size_calc... */
      min_size = edje_object_data_get(o, "ecdb/combo_item/minh");
      if (min_size)
      {
         if (ecore_config_boolean_get("use_scale"))
            h2 += (int)((float)atoi(min_size) * em->scalef);
         else
            h2 += (int)atoi(min_size);
      }
      else
      {
         EINA_ERROR_PWARN("THEME ERROR! MISSING REQUIRED MINIMUM DATA VALUE\n");
      }
      h2 += padding;
   }

   if (!strcmp(location, "top"))
      evas_object_move(cd->popup, x, y - h2);
   else
      evas_object_move(cd->popup, x, y + h);

   eina_iterator_free(it);
   evas_object_resize(cd->popup, w, h2);
   evas_object_pass_events_set(cd->popup, 0);
   evas_object_raise(cd->popup);
   edje_object_signal_emit(cd->popup, buf, "ecdb");

   cd->expanded = 1;
}

void
ecdb_combo_collapse(Evas_Object *c)
{
   Combo_Data *cd;
   const char *location;
   char buf[1024];
   Eina_Iterator *it;
   Evas_Object *o;

   // If we close the window
   if ((!em) || (!em->main_win_ee))
      return;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   cd = evas_object_data_get(c, "cd");
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return;
   }

   edje_object_signal_emit(cd->back, "ecdb,combo,back,hide", "ecdb");
   evas_object_pass_events_set(cd->back, 1);
   edje_object_signal_emit(c, "ecdb,combo,default", "ecdb");

   location = _combo_best_location(c);
   snprintf(buf, sizeof(buf), "ecdb,combo,popup,hide,%s", location);
   evas_object_pass_events_set(cd->popup, 1);
   edje_object_signal_emit(cd->popup, buf, "ecdb");

   it = evas_object_box_iterator_new(edje_object_part_object_get(cd->popup,
                                                               "ecdb.box"));
   if (!it)
   {
      EINA_ERROR_PWARN("NULL iterator!\n");
      return;
   }

   while ((eina_iterator_next(it, (void **)&o)))
      edje_object_signal_emit(o, "ecdb,focus,out", "ecdb");
   eina_iterator_free(it);

   cd->expanded = 0;
}

void
ecdb_combo_header_create_set(Evas_Object *c, void (*func)
                                             (Evas_Object *c, const char *name,
                                    void *data, Evas_Object *clicked, int idx))
{
   Combo_Data *cd;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   cd = evas_object_data_get(c, "cd");
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return;
   }

   cd->create_header = func;
}

int
ecdb_combo_selected_get(Evas_Object *c)
{
   Combo_Data *cd;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return -1;
   }

   cd = evas_object_data_get(c, "cd");
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return -1;
   }

   return cd->selected;
}

void
ecdb_combo_data_set(Evas_Object *c, void *data)
{
   Combo_Data *cd;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   cd = evas_object_data_get(c, "cd");
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return;
   }
   cd->data = data;
}

void *
ecdb_combo_data_get(Evas_Object *c)
{
   Combo_Data *cd;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return NULL;
   }

   cd = evas_object_data_get(c, "cd");
   if (!cd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return NULL;
   }

   return cd->data;
}

void
ecdb_combo_clear(Evas_Object *c)
{
   Combo_Data *cd;

   if (!c)
   {
      EINA_ERROR_PWARN("NULL object!");
      return;
   }

   cd = evas_object_data_get(c, "cd");
   edje_object_part_box_remove_all(cd->popup, "ecdb.box", 1);
   cd->selected = 1;
   cd->count = 0;
}

/******************************* Label ***************************************/

Evas_Object *
ecdb_label_add(Evas_Object *parent, const char *name)
{
   Evas_Object *l;

   l = ecdb_widget_add(parent, name);
   if (!l)
   {
      EINA_ERROR_PWARN("NULL return!\n");
      return NULL;
   }
   edje_object_file_set(l, em->theme_path, "ecdb/label");

   return l;
}

void
ecdb_label_text_set(Evas_Object *l, const char *text)
{
   if (!l)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }
   edje_object_part_text_set(l, "ecdb.label", text);
}

/************************* Config Inwin **************************************/
typedef struct _Config_Inwin_Data Config_Inwin_Data;
struct _Config_Inwin_Data
{
   Evas_Object *parent;    // Used to calculate the popup layers
   Evas_Object *back;
   Evas_Object *popup;
   unsigned int visible;
};

static void
_config_inwin_resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Config_Inwin_Data *iwd;
   int w, h;

   iwd = data;

   // We get a resize event even though the evas has been destroyed
   if ((!em) || (!em->main_win_ee))
      return;

   ecore_evas_geometry_get(em->main_win_ee, NULL, NULL, &w, &h);
   evas_object_resize(iwd->popup, w, h);
   evas_object_move(iwd->popup, 0, 0);
   evas_object_resize(iwd->back, w, h);
   evas_object_move(iwd->back, 0, 0);
}

static void
_config_inwin_hide(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Config_Inwin_Data *iwd;

   iwd = data;

   if (iwd)
   {
      if (iwd->popup)
         evas_object_hide(iwd->popup);
      if (iwd->back)
         evas_object_hide(iwd->back);
   }
}

static void
_config_inwin_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Config_Inwin_Data *iwd;

   iwd = data;
   if (!evas_object_event_callback_del(iwd->parent, EVAS_CALLBACK_HIDE,
                                                _config_inwin_hide))
   {
      EINA_ERROR_PWARN("EVAS_CALLBACK_HIDE callback removal failure!\n");
   }
   if (!evas_object_event_callback_del(iwd->parent, EVAS_CALLBACK_RESIZE,
                                                _config_inwin_resize))
   {
      EINA_ERROR_PWARN("EVAS_CALLBACK_RESIZE callback removal failure!\n");
   }

   FREE(iwd);
}

Evas_Object *
ecdb_config_inwin_add(Evas_Object *parent, const char *name)
{
   Config_Inwin_Data *iwd;

   iwd = calloc(1, sizeof(Config_Inwin_Data));
   if (!iwd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return NULL;
   }

   iwd->popup = edje_object_add(evas_object_evas_get(parent));
   if (!iwd->popup)
   {
      EINA_ERROR_PWARN("NULL return!\n");
      return NULL;
   }
   edje_object_file_set(iwd->popup, em->theme_path, "ecdb/config_inwin/popup");
   evas_object_pass_events_set(iwd->popup, 1);
   evas_object_show(iwd->popup);

   evas_object_event_callback_add(iwd->popup, EVAS_CALLBACK_DEL,
                                                   _config_inwin_del,
                                                   iwd);
   
   iwd->back = edje_object_add(evas_object_evas_get(parent));
   edje_object_file_set(iwd->back, em->theme_path,
                                          "ecdb/config_inwin/background");
   iwd->parent = parent;
   evas_object_pass_events_set(iwd->back, 1);
   evas_object_show(iwd->back);
   evas_object_data_set(iwd->popup, "iwd", iwd);
   iwd->visible = 0;
   
   /* Add the callbacks used to contain this to the parent */
   evas_object_event_callback_add(parent, EVAS_CALLBACK_RESIZE,
                                                _config_inwin_resize, iwd);
   evas_object_event_callback_add(parent, EVAS_CALLBACK_HIDE,
                                                _config_inwin_hide, iwd);

   return iwd->popup;
}

void
ecdb_config_inwin_show(Evas_Object *inwin)
{
   Config_Inwin_Data *iwd;

   if (!inwin)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   iwd = evas_object_data_get(inwin, "iwd");

   if (!iwd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return;
   }

   evas_object_pass_events_set(iwd->back, 0);
   evas_object_raise(iwd->back);
   edje_object_signal_emit(iwd->back, "ecdb,config_inwin,back,show", "ecdb");
   evas_object_show(iwd->back);
   
   evas_object_pass_events_set(iwd->popup, 0);
   evas_object_raise(iwd->popup);
   edje_object_signal_emit(iwd->popup, "ecdb,config_inwin,popup,show", "ecdb");
   evas_object_show(iwd->popup);
   iwd->visible = 1;
}

void
ecdb_config_inwin_hide(Evas_Object *inwin)
{
   Config_Inwin_Data *iwd;

   if (!inwin)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   iwd = evas_object_data_get(inwin, "iwd");

   if (!iwd)
   {
      EINA_ERROR_PWARN("NULL data!\n");
      return;
   }

   evas_object_pass_events_set(iwd->back, 1);
   edje_object_signal_emit(iwd->back, "ecdb,config_inwin,back,hide", "ecdb");

   evas_object_pass_events_set(iwd->popup, 1);
   edje_object_signal_emit(iwd->popup, "ecdb,config_inwin,popup,hide",
                                                                     "ecdb");
   iwd->visible = 0;
}

void
ecdb_config_inwin_child_add(Evas_Object *inwin, Evas_Object *child,
                                                int c, int r, int cs, int rs)
{
   if (!inwin)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }
   if (!child)
      return;

   if (!edje_object_part_table_pack(inwin, "ecdb.table", child, c, r, cs, rs))
   {
      EINA_ERROR_PWARN("Couldn't append to table!\n");
   }
}


/***************************** Capacity **************************************/
Evas_Object *
ecdb_capacity_add(Evas_Object *parent, const char *name)
{
   Evas_Object *ret;

   ret = ecdb_widget_add(parent, "ecdb/burn_data/capacity");
   if (!ret)
   {
      EINA_ERROR_PWARN("NULL return!\n");
      return NULL;
   }

   edje_object_file_set(ret, em->theme_path, "ecdb/capacity");

   return ret;
}

void
ecdb_capacity_float_set(Evas_Object *cap, float val)
{
   Edje_Message_Float msg;

   if (!cap)
   {
      EINA_ERROR_PWARN("NULL object!\n");
      return;
   }

   msg.val = val;
   edje_object_message_send(cap, EDJE_MESSAGE_FLOAT, 1, &msg);
}
