#include "e.h"

static void *_create_data(E_Config_Dialog *cfd);
static void _free_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata);
static int _basic_apply_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata);
static Evas_Object *_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata);

struct _E_Config_Dialog_Data
{
   E_Config_Dialog *cfd;

   Eina_List *env_vars;

   char *var_str, *val_str;
   int unset;

   struct {
      Evas_Object *var_en, *val_en, *unset, *list;
   } gui;
};

E_Config_Dialog *
e_int_config_env(Evas_Object *parent EINA_UNUSED, const char *params EINA_UNUSED)
{
   E_Config_Dialog *cfd;
   E_Config_Dialog_View *v;

   if (e_config_dialog_find("E", "advanced/environment_variables")) return NULL;
   v = E_NEW(E_Config_Dialog_View, 1);

   v->create_cfdata           = _create_data;
   v->free_cfdata             = _free_data;
   v->basic.create_widgets    = _basic_create_widgets;
   v->basic.apply_cfdata      = _basic_apply_data;

   cfd = e_config_dialog_new(NULL, _("Environment Variables"),
                             "E", "advanced/environment_variables",
                             "preferences-system", 0, v, NULL);
   return cfd;
}

static void
_fill_data(E_Config_Dialog_Data *cfdata)
{
   Eina_List *l;
   E_Config_Env_Var *evr, *evr2;

   EINA_LIST_FOREACH(e_config->env_vars, l, evr)
     {
        evr2 = E_NEW(E_Config_Env_Var, 1);
        evr2->var = eina_stringshare_add(evr->var);
        if (evr->val) evr2->val = eina_stringshare_add(evr->val);
        evr2->unset = evr->unset;
        cfdata->env_vars = eina_list_append(cfdata->env_vars, evr2);
     }
}

static void *
_create_data(E_Config_Dialog *cfd)
{
   E_Config_Dialog_Data *cfdata;

   cfdata = E_NEW(E_Config_Dialog_Data, 1);
   cfdata->cfd = cfd;
   _fill_data(cfdata);
   return cfdata;
}

static void
_free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
{
   E_Config_Env_Var *evr;

   EINA_LIST_FREE(cfdata->env_vars, evr)
     {
        eina_stringshare_del(evr->var);
        if (evr->val) eina_stringshare_del(evr->val);
        E_FREE(evr);
     }
   free(cfdata->var_str);
   free(cfdata->val_str);
   E_FREE(cfdata);
}

static int
_basic_apply_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
{
   Eina_List *l, *l2;
   E_Config_Env_Var *evr, *evr2;
   int same;

   // old env vars removed from new set - unset
   EINA_LIST_FOREACH(e_config->env_vars, l, evr)
     {
        same = 0;
        EINA_LIST_FOREACH(cfdata->env_vars, l2, evr2)
          {
             if (!strcmp(evr->var, evr2->var))
               {
                  same = 1;
                  break;
               }
          }
        if (!same) e_env_unset(evr->var);
     }
   EINA_LIST_FREE(e_config->env_vars, evr)
     {
        eina_stringshare_del(evr->var);
        if (evr->val) eina_stringshare_del(evr->val);
        E_FREE(evr);
     }
   EINA_LIST_FOREACH(cfdata->env_vars, l, evr)
     {
        evr2 = E_NEW(E_Config_Env_Var, 1);

        evr2->var = eina_stringshare_add(evr->var);
        if (evr->val) evr2->val = eina_stringshare_add(evr->val);
        evr2->unset = evr->unset;
        e_config->env_vars = eina_list_append(e_config->env_vars, evr2);
     }
   // set all env vars (or unset as needed)
   EINA_LIST_FOREACH(e_config->env_vars, l, evr)
     {
        if (evr->unset)
           e_env_unset(evr->var);
        else
           e_env_set(evr->var, evr->val);
     }
   efreet_lang_reset();
   e_config_save_queue();
   return 1;
}

static void
_sel_cb(void *data)
{
   E_Config_Dialog_Data *cfdata = data;
   int sel_n = e_widget_ilist_selected_get(cfdata->gui.list);
   E_Config_Env_Var *evr = eina_list_nth(cfdata->env_vars, sel_n);
   if (!evr) return;
   e_widget_check_checked_set(cfdata->gui.unset, evr->unset);
   e_widget_disabled_set(cfdata->gui.val_en, evr->unset);
   e_widget_entry_text_set(cfdata->gui.var_en, evr->var);
   if ((evr->val) && (!evr->unset))
      e_widget_entry_text_set(cfdata->gui.val_en, evr->val);
   else
      e_widget_entry_text_set(cfdata->gui.val_en, "");
}

static const char *
_env_text(E_Config_Env_Var *evr)
{
   static Eina_Slstr *text = "";
   char *val;

   if (evr->val) val = strndup(evr->val, 64);
   else val = strdup("");

   if (val)
     {
        if (strlen(evr->val) > 64)
          text = eina_slstr_printf("%s=%s...", evr->var, val);
        else
          text = eina_slstr_printf("%s=%s", evr->var, val);
        free(val);
     }
   else
     {
        text = eina_slstr_printf("%s", evr->var);
     }

   return text;
}

static void
_add_cb(void *data, void *data2 EINA_UNUSED)
{
   E_Config_Dialog_Data *cfdata = data;
   Eina_List *l;
   E_Config_Env_Var *evr = NULL;
   int i, sel = -1;

   if (!cfdata->var_str) return;

   i = 0;
   EINA_LIST_FOREACH(cfdata->env_vars, l, evr)
     {
        if (!strcmp(cfdata->var_str, evr->var))
          {
             sel = i;
             break;
          }
        evr = NULL;
        i++;
     }
   if (!evr) // new
     {
        evr = E_NEW(E_Config_Env_Var, 1);
        if (evr)
          {
             evr->var = eina_stringshare_add(cfdata->var_str);
             if (cfdata->unset)
                cfdata->unset = 1;
             else
               {
                  if (cfdata->val_str)
                     evr->val = eina_stringshare_add(cfdata->val_str);
                  cfdata->unset = 0;
               }
             cfdata->env_vars = eina_list_append(cfdata->env_vars, evr);
             e_widget_ilist_append(cfdata->gui.list, NULL,
                                   _env_text(evr), _sel_cb, cfdata, NULL);
             e_widget_ilist_go(cfdata->gui.list);
             sel = e_widget_ilist_count(cfdata->gui.list) - 1;
             e_widget_ilist_selected_set(cfdata->gui.list, sel);
             e_widget_ilist_nth_show(cfdata->gui.list, sel, 0);
          }
     }
   else // modify
     {
        if (evr->val) eina_stringshare_del(evr->val);
        evr->val = NULL;
        if (cfdata->unset)
           evr->unset = 1;
        else
          {
             if (cfdata->val_str)
                evr->val = eina_stringshare_add(cfdata->val_str);
             evr->unset = 0;
          }
        if (sel >= 0)
          {
             e_widget_ilist_selected_set(cfdata->gui.list, sel);
             e_widget_ilist_nth_label_set(cfdata->gui.list, sel, _env_text(evr));
             e_widget_ilist_nth_show(cfdata->gui.list, sel, 0);
          }
     }
}

static void
_del_cb(void *data, void *data2 EINA_UNUSED)
{
   E_Config_Dialog_Data *cfdata = data;
   Eina_List *l;
   E_Config_Env_Var *evr = NULL;
   int sel_n;
/*
   int i, sel = -1;

   EINA_LIST_FOREACH(cfdata->env_vars, l, evr)
     {
        if (!strcmp(cfdata->var_str, evr->var))
          {
             sel = i;
             break;
          }
        evr = NULL;
        i++;
     }
*/
   sel_n = e_widget_ilist_selected_get(cfdata->gui.list);
   if (sel_n != -1)
     evr = eina_list_nth(cfdata->env_vars, sel_n);

   if (evr && strcmp(cfdata->var_str, evr->var)) evr = NULL;
   if (evr)
     {
        cfdata->env_vars = eina_list_remove(cfdata->env_vars, evr);
        e_env_unset(evr->var);
        eina_stringshare_del(evr->var);
        if (evr->val) eina_stringshare_del(evr->val);
        E_FREE(evr);
//        cfdata->env_vars = eina_list_remove_list(cfdata->env_vars, l);
        e_widget_ilist_clear(cfdata->gui.list);
        e_widget_ilist_freeze(cfdata->gui.list);
        EINA_LIST_FOREACH(cfdata->env_vars, l, evr)
          {
             e_widget_ilist_append(cfdata->gui.list, NULL, _env_text(evr),
                                   _sel_cb, cfdata, NULL);
          }
        e_widget_ilist_go(cfdata->gui.list);
        e_widget_ilist_thaw(cfdata->gui.list);
     }
}

static void
_mod_cb(void *data, void *data2 EINA_UNUSED)
{
   _add_cb(data, data2);
}

static void
_unset_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Config_Dialog_Data *cfdata = data;
   if (cfdata->unset) e_widget_entry_text_set(cfdata->gui.val_en, "");
   e_widget_disabled_set(cfdata->gui.val_en, cfdata->unset);
}


static Evas_Object *
_basic_create_widgets(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata)
{
   Evas_Object *o, *ol, *oe, *ob, *oc;
   Eina_List *l;
   E_Config_Env_Var *evr;

   e_dialog_resizable_set(cfd->dia, 1);

   o = e_widget_table_add(e_win_evas_win_get(evas), 0);

   ol = e_widget_ilist_add(evas, 0, 0, NULL);
   cfdata->gui.list = ol;
   e_widget_ilist_freeze(ol);
   EINA_LIST_FOREACH(cfdata->env_vars, l, evr)
     {
        e_widget_ilist_append(ol, NULL, _env_text(evr), _sel_cb, cfdata, NULL);
     }
   e_widget_ilist_go(ol);
   e_widget_ilist_thaw(ol);
   e_widget_size_min_set(ol, 200, 160);
   e_widget_table_object_append(o, ol, 0, 0, 3, 1, 1, 1, 1, 1);

   oe = e_widget_entry_add(cfd->dia->win, &(cfdata->var_str), NULL, NULL, NULL);
   cfdata->gui.var_en = oe;
   e_widget_table_object_append(o, oe, 0, 1, 1, 1, 1, 1, 1, 0);

   oe = e_widget_entry_add(cfd->dia->win, &(cfdata->val_str), NULL, NULL, NULL);
   cfdata->gui.val_en = oe;
   e_widget_table_object_append(o, oe, 1, 1, 1, 1, 1, 1, 1, 0);

   oc = e_widget_check_add(evas, _("Unset"), &(cfdata->unset));
   cfdata->gui.unset = oc;
   e_widget_table_object_append(o, oc, 2, 1, 1, 1, 1, 1, 1, 0);
   evas_object_smart_callback_add(oc, "changed", _unset_cb, cfdata);

   ob = e_widget_button_add(evas, _("Add"), "list-add", _add_cb, cfdata, NULL);
   e_widget_table_object_append(o, ob, 0, 2, 1, 1, 1, 1, 0, 0);

   ob = e_widget_button_add(evas, _("Modify"), NULL, _mod_cb, cfdata, NULL);
   e_widget_table_object_append(o, ob, 1, 2, 1, 1, 1, 1, 0, 0);

   ob = e_widget_button_add(evas, _("Delete"), "list-remove", _del_cb, cfdata, NULL);
   e_widget_table_object_append(o, ob, 2, 2, 1, 1, 1, 1, 0, 0);

   return o;
}
