/*
 * Edje Theme Editor
 * Copyright (C) 2013-2014 Samsung Electronics.
 *
 * This file is part of Edje Theme Editor.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; If not, see www.gnu.org/licenses/lgpl.html.
 */
#ifndef EO_BETA_API
# define EO_BETA_API
#endif

#ifndef EFL_BETA_API_SUPPORT
# define EFL_BETA_API_SUPPORT
#endif

#ifndef EFL_EO_API_SUPPORT
# define EFL_EO_API_SUPPORT
#endif

#include "main_window.h"
#include "validator.h"
#include "project_manager2.h"
#include "modal_window.h"

static Elm_Genlist_Item_Class *_itc_ccl = NULL;

typedef struct _Colorclasses_Manager Colorclasses_Manager;
typedef struct _Search_Data Search_Data;

struct _Search_Data
{
   Evas_Object *search_entry;
   Elm_Object_Item *last_item_found;
};

struct _Colorclasses_Manager
{
   Evas_Object *win;
   Evas_Object *panes;
   Evas_Object *layout;
   Evas_Object *genlist;
   Evas_Object *edje_preview, *preview_layout;
   Evas_Object *entry, *popup;
   Evas_Object *del_button;
   Evas_Object *item;
   Resource_Name_Validator *name_validator;
   Search_Data style_search_data;
   Colorclass_Item *current_ccl;
   struct {
        Evas_Object *black;
        Evas_Object *tile;
        Evas_Object *white;
   } bg_switcher;
};

static Colorclasses_Manager mng;

static void
_validation(void *data,
            Evas_Object *obj,
            void *event_info EINA_UNUSED)
{
   Evas_Object *popup = data;

   assert(popup != NULL);

   if (ELM_REG_NOERROR != resource_name_validator_status_get(mng.name_validator))
     {
        popup_button_disabled_set(popup, BTN_OK, true);
        elm_object_signal_emit(obj, "validation,default,fail", "elm");
     }
   else
     {
        popup_button_disabled_set(popup, BTN_OK, false);
        elm_object_signal_emit(obj, "validation,default,pass", "elm");
     }
}

static Evas_Object *
_add_colorclass_content_get(void *data EINA_UNUSED, Evas_Object *popup, Evas_Object **to_focus)
{
   Evas_Object *item = NULL;

   LAYOUT_PROP_ADD(ap.win, _("Color class name: "), "popup", "1swallow")
   ENTRY_ADD(item, mng.entry, true);
   efl_event_callback_add(mng.entry, ELM_ENTRY_EVENT_VALIDATE, resource_name_validator_helper, mng.name_validator);
   evas_object_smart_callback_add(mng.entry, signals.elm.entry.changed, _validation, popup);
   elm_object_part_text_set(mng.entry, "guide", _("Type new color class name here"));
   elm_object_part_content_set(item, "elm.swallow.content", mng.entry);
   mng.item = item;
   if (to_focus) *to_focus = mng.entry;
   popup_button_disabled_set(popup, BTN_OK, true);

   return mng.item;
}

static void
_colorclass_add_popup_close_cb(void *data,
                               Evas_Object *obj EINA_UNUSED,
                               void *event_info)
{
   Attribute attribute = ATTRIBUTE_STATE_COLOR_CLASS;
   Colorclasses_Manager *edit = (Colorclasses_Manager *)data;
   Colorclass_Item *it = NULL;
   Elm_Object_Item *glit_ccl = NULL;
   Popup_Button btn_res = (Popup_Button)event_info;

   assert(edit != NULL);

   if (BTN_OK == btn_res)
     {
        it = (Colorclass_Item *)mem_calloc(1, sizeof(Colorclass_Item));
        it->name = elm_entry_entry_get(mng.entry);

        CRIT_ON_FAIL(editor_color_class_add(ap.project->global_object, eina_stringshare_add(it->name), true));

        glit_ccl = elm_genlist_item_append(mng.genlist, _itc_ccl, it, NULL,
                                           ELM_GENLIST_ITEM_NONE, NULL, NULL);
        elm_genlist_item_selected_set(glit_ccl, EINA_TRUE);

        evas_object_del(mng.popup);
        mng.popup = NULL;

        evas_object_smart_callback_call(ap.win, SIGNAL_EDITOR_ATTRIBUTE_CHANGED, &attribute);
     }
   resource_name_validator_free(mng.name_validator);
   evas_object_del(mng.item);
}

static void
_colorclass_add_cb(void *data,
                   Evas_Object *obj EINA_UNUSED,
                   void *event_info EINA_UNUSED)
{
   Evas_Object *popup;
   mng.name_validator = resource_name_validator_new(NAME_REGEX, NULL);
   resource_name_validator_list_set(mng.name_validator, &ap.project->RM.colorclasses, true);
   popup = popup_add(_("Create a new layout"), NULL, BTN_OK|BTN_CANCEL, _add_colorclass_content_get, mng.entry);
   evas_object_smart_callback_add(popup, POPUP_CLOSE_CB, _colorclass_add_popup_close_cb, data);
}

static void
_colorclass_del_cb(void *data EINA_UNUSED,
                   Evas_Object *obj EINA_UNUSED,
                   void *event_info EINA_UNUSED)
{
   Attribute attribute = ATTRIBUTE_STATE_COLOR_CLASS;

   Elm_Object_Item *it = elm_genlist_selected_item_get(mng.genlist);
   Elm_Object_Item *next = elm_genlist_item_next_get(it);
   Colorclass_Item *ccl = elm_object_item_data_get(it);
   if (!next) next = elm_genlist_item_prev_get(it);

   CRIT_ON_FAIL(editor_color_class_del(ap.project->global_object, ccl->name, true));
   elm_object_item_del(it);
   evas_object_smart_callback_call(ap.win, SIGNAL_EDITOR_ATTRIBUTE_CHANGED, &attribute);

#if 0
   State *state;
   char buf[BUFF_MAX];
   int symbs = 0;
   Eina_List *l;
   if (!res->used_in)
     {
        edje_edit_color_class_del(ap.project->global_object, ccl->name);
        ap.project->colorclasses = pm_resource_del(ap.project->colorclasses, res);
        elm_object_item_del(it);
     }
   else
     {
        snprintf(buf, BUFF_MAX, _("Colorclass is used in:"));
        symbs = strlen_safe(buf);
        EINA_LIST_FOREACH(res->used_in, l, state)
          {
             snprintf(buf + symbs, BUFF_MAX - symbs, _("<br>group: %s<br>part: %s<br>state: \"%s\" %2.1f"),
                      state->part->group->name, state->part->name, state->parsed_name, state->parsed_val);
             symbs += strlen_safe(res->common.name);
             break; TODO("remove this break after warning style remake")
          }
        WARN("%s", buf);
        return;
     }
#endif

   if (next)
      elm_genlist_item_selected_set(next, EINA_TRUE);
   else
     {
        mng.current_ccl = NULL;
        elm_object_disabled_set(mng.del_button, EINA_TRUE);
        elm_object_signal_emit(mng.preview_layout, "entry,hide", "eflete");
        evas_object_smart_callback_call(ap.win, SIGNAL_COLOR_SELECTED, NULL);
     }
}

/* Callback on colorclass (un)selection in list */
static void
_on_unselected(void *data EINA_UNUSED,
             Evas_Object *obj EINA_UNUSED,
             void *event_info EINA_UNUSED)
{
   elm_object_disabled_set(mng.del_button, EINA_TRUE);
   evas_object_smart_callback_call(ap.win, SIGNAL_COLOR_SELECTED, NULL);
}

static void
_on_selected(void *data EINA_UNUSED,
             Evas_Object *obj EINA_UNUSED,
             void *event_info)
{
   Elm_Object_Item *glit = (Elm_Object_Item *)event_info;
   Colorclass_Item *ccl = elm_object_item_data_get(glit);
   elm_object_disabled_set(mng.del_button, EINA_FALSE);

   assert(ccl != NULL);

   ColorClassData *current_color_data = (ColorClassData *)mem_calloc(1, sizeof(ColorClassData));

   mng.current_ccl = ccl;

   edje_object_color_class_set(mng.edje_preview,
                               "colorclass_manager/text_example_colorclass",
                               ccl->r1, ccl->g1,
                               ccl->b1, ccl->a1,
                               ccl->r2, ccl->g2,
                               ccl->b2, ccl->a2,
                               ccl->r3, ccl->g3,
                               ccl->b3, ccl->a3);

   current_color_data->current_ccl = ccl;
   current_color_data->edje_preview = mng.edje_preview;
   elm_object_signal_emit(mng.preview_layout, "entry,show", "eflete");
   evas_object_smart_callback_call(ap.win, SIGNAL_COLOR_SELECTED, current_color_data);
}

/* Search functions and creatings */
ITEM_SEARCH_FUNC(genlist,ELM_GENLIST_ITEM_SCROLLTO_MIDDLE, "elm.text")
static inline Evas_Object *
_manager_search_field_create(Evas_Object *parent)
{
   Evas_Object *entry;

   assert(parent != NULL);

   ENTRY_ADD(parent, entry, true);
   elm_object_part_text_set(entry, "guide", _("Search"));
#ifndef HAVE_TIZEN
   Evas_Object *icon;
   ICON_STANDARD_ADD(entry, icon, true, "search");
   elm_object_part_content_set(entry, "elm.swallow.end", icon);
#else
   elm_object_style_set(entry, "search");
#endif
   return entry;
}
static void
_search_changed(void *data EINA_UNUSED,
                Evas_Object *obj EINA_UNUSED,
                void *event_info EINA_UNUSED)
{
   _genlist_item_search(mng.genlist, &(mng.style_search_data),
                        mng.style_search_data.last_item_found);
}
static void
_search_nxt_gd_item(void *data EINA_UNUSED,
                    Evas_Object *obj EINA_UNUSED,
                    void *event_info EINA_UNUSED)
{
   Elm_Object_Item *start_from = NULL;

   if (mng.style_search_data.last_item_found)
     start_from = elm_genlist_item_next_get(mng.style_search_data.last_item_found);

   _genlist_item_search(mng.genlist, &(mng.style_search_data), start_from);
}

static void
_search_reset_cb(void *data,
                 Evas_Object *obj EINA_UNUSED,
                 void *event_info EINA_UNUSED)
{
   Search_Data *search_data = data;

   assert(search_data != NULL);

   search_data->last_item_found = NULL;
}

static char *
_item_ccl_label_get(void *data,
                    Evas_Object *obj EINA_UNUSED,
                    const char *part EINA_UNUSED)
{
   Colorclass_Item *ccl_it = (Colorclass_Item *)data;
   return strdup(ccl_it->name);
}
static void
_item_ccl_del(void *data,
                    Evas_Object *obj EINA_UNUSED)
{
   Colorclass_Item *ccl_it = (Colorclass_Item *)data;
   eina_stringshare_del(ccl_it->name);
   free(ccl_it);
   ccl_it = NULL;
}

#ifndef HAVE_TIZEN
static void
_bg_cb(void *data,
       Evas_Object *obj,
       void *event_info EINA_UNUSED)
{
   Bg_Preview bg_mode;
   const char *signal = NULL;
   Evas_Object *entry_prev = data;

   Evas_Object *bg = elm_object_part_content_get(entry_prev, "elm.swallow.background");
   bg_mode = elm_radio_value_get(obj);
   switch (bg_mode)
     {
      case BG_PREVIEW_WHITE:
         signal = "elm,bg,white";
         break;
      case BG_PREVIEW_TILE:
         signal = "elm,bg,tile";
         break;
      case BG_PREVIEW_BLACK:
         signal = "elm,bg,black";
         break;
     }

   elm_layout_signal_emit(bg, signal, "eflete");
}

static Evas_Object *
_radio_switcher_add(Evas_Object *obj,
                    const char *style,
                    Evas_Smart_Cb func,
                    int state_value,
                    Evas_Object *group)
{
   Evas_Object *radio;

   radio = elm_radio_add(ap.win);
   evas_object_show(radio);
   elm_object_style_set(radio, style);
   elm_radio_state_value_set(radio, state_value);
   evas_object_smart_callback_add(radio, signals.elm.radio.changed, func, obj);
   elm_radio_group_add(radio, group);

   return radio;
}
#endif

static void
_mw_cancel_cb(void *data EINA_UNUSED,
              Evas_Object *obj EINA_UNUSED,
              void *event_info EINA_UNUSED)
{
   Evas_Object *content;

   /* unset and hide the image manager content */
   content = elm_object_content_unset(mng.win);
   evas_object_hide(content);
}

static void
_mw_done_cb(void *data EINA_UNUSED,
            Evas_Object *obj EINA_UNUSED,
            void *event_info EINA_UNUSED)
{
   Evas_Object *content;

   /* unset and hide the image manager content */
   content = elm_object_content_unset(mng.win);
   evas_object_hide(content);
}

static Eina_Bool
_colorclass_manager_init(void)
{
   Eina_List *l = NULL;
   Colorclass_Item *it = NULL;
   Colorclass2 *res;

   assert(ap.project != NULL);

   EINA_LIST_FOREACH(ap.project->RM.colorclasses, l, res)
     {
        it = (Colorclass_Item *)mem_calloc(1, sizeof(Colorclass_Item));

        it->r1 = res->color1.r;
        it->g1 = res->color1.g;
        it->b1 = res->color1.b;
        it->a1 = res->color1.a;

        it->r2 = res->color2.r;
        it->g2 = res->color2.g;
        it->b2 = res->color2.b;
        it->a2 = res->color2.a;

        it->r3 = res->color3.r;
        it->g3 = res->color3.g;
        it->b3 = res->color3.b;
        it->a3 = res->color3.a;

        it->name = eina_stringshare_add(res->common.name);
        elm_genlist_item_append(mng.genlist, _itc_ccl, it, NULL,
                                ELM_GENLIST_ITEM_NONE, NULL, NULL);
     }

   evas_object_smart_callback_call(ap.win, SIGNAL_COLOR_SELECTED, NULL);
   return true;
}

Evas_Object *
colorclass_manager_add(void)
{
   Evas_Object *bg, *box_bg, *search, *ic, *button;

   assert(ap.project != NULL);

   if (!_itc_ccl)
     {
        _itc_ccl = elm_genlist_item_class_new();
        _itc_ccl->item_style = "default";
        _itc_ccl->func.text_get = _item_ccl_label_get;
        _itc_ccl->func.del = _item_ccl_del;
     }

   /* Creating main layout of window */
   mng.win = mw_add();
   mw_title_set(mng.win, _("Color class manager"));
   evas_object_smart_callback_add(mng.win, signals.eflete.modal_window.cancel, _mw_cancel_cb, NULL);
   evas_object_smart_callback_add(mng.win, signals.eflete.modal_window.done, _mw_done_cb, NULL);
#ifndef HAVE_TIZEN
   ic = elm_icon_add(mng.win);
   elm_icon_standard_set(ic, "color");
#else
   IMAGE_ADD_NEW(mng.win, ic, "icon", "logo");
#endif
   mw_icon_set(mng.win, ic);
   mng.layout = elm_layout_add(ap.win);
   elm_layout_theme_set(mng.layout, "layout", "manager", "internal");
   elm_layout_text_set(mng.layout, "elm.text", _("Preview"));
   elm_layout_text_set(mng.layout, "elm.subtext", _("Color classes list"));
   mng.panes = elm_panes_add(mng.win);
   elm_panes_content_right_size_set(mng.panes, 0);
   elm_panes_content_right_min_size_set(mng.panes, 400);
   elm_object_content_set(mng.win, mng.panes);
   elm_object_part_content_set(mng.panes, "left", mng.layout);
   elm_object_part_content_set(mng.panes, "right", ap.property.color_manager);

   mng.genlist = elm_genlist_add(mng.layout);
#ifdef HAVE_TIZEN
   elm_object_style_set(mng.panes, "manager");
   elm_object_style_set(mng.genlist, "manager");
#endif
   evas_object_show(mng.genlist);
   elm_object_part_content_set(mng.layout, "elm.swallow.list", mng.genlist);
   evas_object_smart_callback_add(mng.genlist, signals.elm.genlist.selected, _on_selected, NULL);
   evas_object_smart_callback_add(mng.genlist, signals.elm.genlist.unselected, _on_unselected, NULL);
   evas_object_smart_callback_add(mng.genlist, signals.elm.genlist.pressed, _search_reset_cb, &(mng.style_search_data));

   search = _manager_search_field_create(mng.layout);
   elm_object_part_content_set(mng.layout, "elm.swallow.search", search);
   evas_object_smart_callback_add(search, signals.elm.entry.changed, _search_changed, NULL);
   evas_object_smart_callback_add(search, signals.elm.entry.activated, _search_nxt_gd_item, NULL);
   mng.style_search_data.search_entry = search;
   mng.style_search_data.last_item_found = NULL;

   /* Controls (add, remove) of colorclasses */
   button = elm_button_add(mng.layout);
   elm_object_style_set(button, "plus_managers");
   evas_object_smart_callback_add(button, signals.elm.button.clicked, _colorclass_add_cb, &mng);
   elm_object_part_content_set(mng.layout, "elm.swallow.btn_add", button);

   mng.del_button = elm_button_add(mng.layout);
   elm_object_style_set(mng.del_button, "minus_managers");
   evas_object_smart_callback_add(mng.del_button, signals.elm.button.clicked, _colorclass_del_cb, NULL);
   elm_object_part_content_set(mng.layout, "elm.swallow.btn_del", mng.del_button);
   elm_object_disabled_set(mng.del_button, EINA_TRUE);

   mng.preview_layout = elm_layout_add(mng.layout);
   elm_layout_theme_set(mng.preview_layout, "layout", "manager", "preview");
   elm_object_signal_emit(mng.preview_layout, "entry,hide", "eflete");

   /* Entry preview to show colorclass */
   bg = elm_layout_add(mng.preview_layout);
   elm_layout_theme_set(bg, "layout", "workspace", "bg");
   elm_object_part_content_set(mng.preview_layout, "elm.swallow.background", bg);
   evas_object_show(bg);

   mng.edje_preview = edje_object_add(evas_object_evas_get(mng.preview_layout));
   if (!edje_object_file_set(mng.edje_preview, ap.path.theme_edj,
                             "elm/layout/colorclass_manager/preview"))
     {
        ERR("Couldn't load layout for text example field!");
        abort();
     }
   edje_object_part_text_set(mng.edje_preview, "text_example",
                       _("The quick brown fox jumps over the lazy dog"));
   evas_object_size_hint_align_set(mng.edje_preview, -1, -1);
   evas_object_show(mng.edje_preview);
   elm_object_part_content_set(mng.preview_layout, "elm.swallow.entry", mng.edje_preview);

   elm_object_part_content_set(mng.layout, "elm.swallow.preview", mng.preview_layout);

   /* Background changing radios */
   BOX_ADD(mng.layout, box_bg, true, false);
   elm_box_padding_set(box_bg, 6, 0);
   elm_box_align_set(box_bg, 1.0, 0.5);

   /* add to toolbar bg switcher */
#ifndef HAVE_TIZEN
   mng.bg_switcher.white = _radio_switcher_add(mng.preview_layout, "bg_white", _bg_cb, BG_PREVIEW_WHITE, NULL);
   elm_box_pack_end(box_bg, mng.bg_switcher.white);

   mng.bg_switcher.tile = _radio_switcher_add(mng.preview_layout, "bg_tile", _bg_cb, BG_PREVIEW_TILE, mng.bg_switcher.white);
   elm_box_pack_end(box_bg, mng.bg_switcher.tile);

   mng.bg_switcher.black = _radio_switcher_add(mng.preview_layout, "bg_black", _bg_cb, BG_PREVIEW_BLACK, mng.bg_switcher.white);
   elm_box_pack_end(box_bg, mng.bg_switcher.black);

   elm_radio_value_set(mng.bg_switcher.white, BG_PREVIEW_TILE);

   elm_object_part_content_set(mng.layout, "elm.swallow.menu", box_bg);
#endif

   if (!_colorclass_manager_init())
     {
        ERR(_("Failed initialize colorclasses manager"));
        abort();
     }

   evas_object_show(mng.win);
   return mng.win;
}
