/***********************************************************************************

    Copyright (C) 2007-2018 Ahmet Öztürk (aoz_2@yahoo.com)

    This file is part of Lifeograph.

    Lifeograph is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Lifeograph 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Lifeograph.  If not, see <http://www.gnu.org/licenses/>.

***********************************************************************************/


#ifndef LIFEOGRAPH_WIDGETTAGS_HEADER
#define LIFEOGRAPH_WIDGETTAGS_HEADER


#include <gtkmm/drawingarea.h>
#include <gtkmm/builder.h>

#include "strings.hpp"
#include "entry.hpp"
#include "panel_extra.hpp"


namespace LIFEO
{

// TAGWIDGET FOR ENTERING TAG NAMES WITH AUTOCOMPLETION
class WidgetTagEdit : public EntryClear
{
    public:
        enum TagOperation { TO_NONE, TO_INVALID,
                            TO_ADD, TO_REMOVE, TO_CHANGE_VALUE,
                            TO_CREATE_BOOLEAN, TO_CREATE_CUMULATIVE };

        typedef sigc::signal< void, TagOperation, Tag* > SignalUpdated;

                                    WidgetTagEdit( BaseObjectType*,
                                                   const Glib::RefPtr< Gtk::Builder >& );
        virtual                     ~WidgetTagEdit() {} // to satisfy Eclipse

        void                        set_entry( LIFEO::Entry* );
        void                        set_text( const Ustring& text ) = delete;
        void                        set_text( const Tag* tag )
        { Gtk::Entry::set_text( tag->get_name_and_value( m_ptr2entry, true, true ) ); }
        void                        clear()
        { Gtk::Entry::set_text( "" ); }
        void                        populate( const TagSet* );
        void                        populate();
        TagOperation                get_status() const
        { return m_tag_op_cur; }
        NameAndValue                get_nav() const
        { return m_nav; }

        void                        on_changed() override;
        void                        handle_event_after( GdkEvent* );

        SignalUpdated               signal_updated()
        { return m_signal_updated; }

    protected:
        bool                        compare_text( const Glib::ustring&,
                                                  const Gtk::TreeModel::const_iterator& );

        LIFEO::Entry*               m_ptr2entry{ nullptr };
        TagOperation                m_tag_op_cur;
        NameAndValue                m_nav;
        Ustring                     m_text_last;
        bool                        m_flag_append_op{ false };

        TreeStoreExtra::Colrec      colrec;
        Glib::RefPtr< Gtk::EntryCompletion >
                                    m_completion;
        Glib::RefPtr< Gtk::ListStore >
                                    m_liststore;

        SignalUpdated               m_signal_updated;
};

// TAG WIDGET FOR LISTING TAGS OF AN ENTRY
class WidgetEntryTags : public Gtk::DrawingArea
{
    public:
        typedef sigc::signal< void, const Tag* > Signal_void_Tag;
        typedef sigc::signal< void > Signal_void;
        struct TagItem { int xl, xr, yl, yr; };
        typedef std::map< const Tag*, TagItem > TagItemList;

        WidgetEntryTags( BaseObjectType*, const Glib::RefPtr< Gtk::Builder >& );

        void                        set_entry( Entry* );
        void                        clear()
        {
            m_W_tag_edit->clear();
            set_entry( nullptr );
        }
        void                        redraw();
        void                        hide_popover();

        void                        start_editing();

        void                        set_editable( bool flag_editable )
        { m_flag_editable = flag_editable; }

        Signal_void                 signal_theme_changed()
        { return m_signal_theme_changed; }
        //Signal_void_Tag             signal_tag_selected()
        //{ return m_signal_tag_selected; }
        Signal_void_Tag             signal_tag_double_clicked()
        { return m_signal_tag_double_clicked; }

    protected:
        // CONSTANTS
        static constexpr float      MARGIN = 18.0;
        static constexpr float      HSPACING = 10.0;
        static constexpr float      VSPACING = 14.0;
        static constexpr float      LABEL_OFFSET = 2.0;
        static constexpr float      TEXT_HEIGHT = 12.0;
        static constexpr float      ITEM_BORDER = 4.0;  // must be < MARGIN
        static constexpr int        ICON_SIZE = 16;
        static constexpr float      ITEM_HEIGHT =  24.0;
        static constexpr float      HALF_HEIGHT = 12.0;

        class AddTagItem : public Tag
        {
            public:
                AddTagItem() : Tag( nullptr, _( "Add Tag" ), nullptr ) {}
        };

        void                        on_size_allocate( Gtk::Allocation& );
        bool                        on_scroll_event( GdkEventScroll* );
        bool                        on_button_press_event( GdkEventButton* );
        //bool                        on_button_release_event( GdkEventButton* );
        bool                        on_motion_notify_event( GdkEventMotion* );
        bool                        on_leave_notify_event( GdkEventCrossing* );
        bool                        on_draw( const Cairo::RefPtr< Cairo::Context >& );

        void                        add_item( const Cairo::RefPtr< Cairo::Context >&,
                                              const Tag* );

        void                        handle_W_tag_updated( WidgetTagEdit::TagOperation, Tag* );
        void                        focus_tag_entry();
        void                        handle_button_tag_clicked();
        void                        handle_change_value();
        void                        handle_set_theme();
        void                        handle_remove();

        bool                        check_point( int, int );

        // DATA
        Entry*                      m_ptr2entry{ nullptr };
        Gdk::RGBA                   m_color_text_default;

        // GEOMETRY
        int                         m_width{ 0 };
        int                         m_height{ 0 };
        float                       m_pos_x{ MARGIN };
        float                       m_pos_y{ MARGIN };

        TagItemList                 m_items;
        const Tag*                  m_hovered_tag{ nullptr };
        AddTagItem                  m_add_tag_item;

        Cairo::RefPtr< Cairo::ToyFontFace >
                                    m_font_theme;
        Cairo::RefPtr< Cairo::ToyFontFace >
                                    m_font_system;
        Cairo::RefPtr< Cairo::Context >
                                    m_image_context;
        Cairo::RefPtr< Cairo::ImageSurface >
                                    m_image_surface_add;

        Gtk::Popover*               m_Po_tag_edit;
        Gtk::Box*                   m_Bx_tag_name;
        WidgetTagEdit*              m_W_tag_edit;
        Gtk::Button*                m_B_tag_operation;
        Gtk::ModelButton*           m_B_set_theme;

        Gtk::Box*                   m_Bx_tag_value;
        Gtk::Entry*                 m_E_tag_value;
        Gtk::Label*                 m_L_tag_unit;
        Gtk::Button*                m_B_tag_value;
        Gtk::ModelButton*           m_B_tag_remove;

        bool                        m_flag_editable{ true };    // not read-only

        Signal_void                 m_signal_theme_changed;
        Signal_void_Tag             m_signal_tag_selected;
        Signal_void_Tag             m_signal_tag_double_clicked;
};

} // end of namespace LIFEO

#endif
