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

    Copyright (C) 2007-2026 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_CODE_COMPLETION_HEADER
#define LIFEOGRAPH_CODE_COMPLETION_HEADER


#include <gtkmm.h>

#include "../lifeograph.hpp"
#include "../helpers.hpp"
#include "gtkmm/textview.h"
#include "po_completion_proto.hpp"


namespace LoG
{

// WIDGET FOR SELECTING FROM DEFINED FILTERS IN THE DIARY ==========================================
class PoCodeCompletion : public PoCompletionProto
{
    struct RowItem
    {
        String  code;
        int     repl_len;
        Ustring description;
        RowItem( const String& c, int len, const Ustring& d )
        : code( c ), repl_len( len ), description( d ) { }
    };

    public:
        using VecElems = std::vector< RowItem >;

        PoCodeCompletion( Gtk::Widget& parent )
        : PoCompletionProto( parent )
        { 
            m_builder       = Lifeograph::create_gui( Lifeograph::SHAREDIR +
                                                      "/ui/po_code_compl.ui" );

            auto Bx_main    = m_builder->get_widget< Gtk::Box >( "Bx_main" );
            m_LB            = m_builder->get_widget< Gtk::ListBox >( "LB_list" );
            m_TV_desc       = m_builder->get_widget< Gtk::TextView >( "TV_desc" );

            m_LB->signal_row_activated().connect(
                    [ this ]( Gtk::ListBoxRow* row )
                    {
                        if( !m_F_internal )
                        {
                            emit_completion();
                            popdown();
                        }
                    } );

            set_child( *Bx_main );
        }

        void
        clear()
        { m_items.clear(); }

        void
        add_item_to_map( const String& code, int len, const Ustring& desc )
        { m_items.push_back( { code, len, desc } ); }

        void
        popup( const Gdk::Rectangle& rect )
        {
            if( !update_LB() ) // means: if empty
                return;

            set_pointing_to( rect );
            Gtk::Popover::popup();
        }

        sigc::signal< void( const String&, int ) >  m_Sg_item_activated;

    protected:
        void
        add_item_to_LB( const String& code )
        {
            auto Bx_item     { Gtk::manage( new Gtk::Box( Gtk::Orientation::HORIZONTAL, 0 ) ) };
            auto L_item_name { Gtk::manage( new Gtk::Label( code, Gtk::Align::START ) ) };
            L_item_name->set_margin_end( 15 ); // this makes it look better
            L_item_name->set_ellipsize( Pango::EllipsizeMode::END );
            L_item_name->set_hexpand( true );

            Bx_item->append( *L_item_name );
            m_LB->append( *Bx_item );
        }

        bool
        update_LB()
        {
            m_F_internal++;

            remove_all_children_from_LBx( m_LB );

            if( m_items.empty() )
            {
                m_F_internal--;
                return false;
            }

            for( auto& item : m_items )
                add_item_to_LB( item.code );

            m_LB->select_row( * m_LB->get_row_at_index( 0 ) );
            m_TV_desc->get_buffer()->set_text( get_selected_desc() );

            m_F_internal--;

            return true;
        }

        bool
        handle_key( guint keyval, bool F_ctrl, bool F_shift ) override
        {
            if( !is_on_display() )
                return false;
            else if( F_shift )
            {
                if( keyval == GDK_KEY_ISO_Left_Tab )
                {
                    select_LB_item_prev( m_LB );
                    m_TV_desc->get_buffer()->set_text( get_selected_desc() );
                    return true;
                }
            }
            else if( !F_ctrl )
            {
                switch( keyval )
                {
                    case GDK_KEY_Return:
                        if( m_LB->get_selected_row() )
                            emit_completion();
                        else
                            return false;
                        // no break
                    case GDK_KEY_Escape:
                        popdown();
                        return true;
                    case GDK_KEY_Tab:
                    case GDK_KEY_Down:
                        select_LB_item_next( m_LB );
                        m_TV_desc->get_buffer()->set_text( get_selected_desc() );
                        return true;
                    case GDK_KEY_Up:
                        select_LB_item_prev( m_LB );
                        m_TV_desc->get_buffer()->set_text( get_selected_desc() );
                        return true;
                }
            }

            return false;
        }

        void
        emit_completion()
        {
            auto&& row { m_LB->get_selected_row() };
            if( row )
            {
                auto& item { m_items.at( row->get_index() ) };
                m_Sg_item_activated.emit( item.code, item.repl_len );
            }
        }
        String
        get_selected_desc()
        {
            auto&& row { m_LB->get_selected_row() };
            return( row ? m_items.at( row->get_index() ).description : "" );
        }

        Gtk::TextView*              m_TV_desc;

        VecElems                    m_items;
};

} // end of namespace LoG

#endif
