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

    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_APP_WINDOW_HEADER
#define LIFEOGRAPH_APP_WINDOW_HEADER

#define LIFEOGRAPH_DEVELOPMENT_VERSION


#include <gtkmm.h>

#include "lifeograph.hpp"
#include "helpers.hpp"
#include "ui_login.hpp"
#include "ui_entry.hpp"
#include "ui_diary.hpp"
#include "ui_extra.hpp"
#include "dialogs/dialog_popupnote.hpp"


namespace LoG
{

using FuncEntriesGetter = std::function< EntrySelection() >;


class AppWindow : public Gtk::ApplicationWindow
{
    public:
        enum InfoResponse { RESP_OK = 10, RESP_UNDO_REMOVE_DIARY = 20 };

                                    AppWindow( BaseObjectType*,
                                               const Glib::RefPtr<Gtk::Builder>& );
                                    ~AppWindow();
        static AppWindow*           p;

        void                        refresh_title();
        void                        set_title( const Ustring& title )
        { m_L_title->set_text( title ); }
        void                        set_subtitle( const Ustring& subt )
        {
            if( subt.empty() )
                m_L_subtitle->hide();
            else
            {
                m_L_subtitle->show();
                m_L_subtitle->set_text( subt );  // TODO: 3.2: use markup
            }
        }

        void                        enter_selection_mode()
        { m_Hb_main->add_css_class( "selection-mode" ); }
        void                        exit_selection_mode()
        { m_Hb_main->remove_css_class( "selection-mode" ); }

        void                        confirm_dismiss_element( const Ustring&,
                                                             const FuncVoid&,
                                                             Gtk::Widget* = nullptr );

        void                        login();
        bool                        check_finish_diary_session( bool = true );
        void                        finish_diary_session();

        void                        handle_login();
        void                        handle_edit_enabled();
        void                        handle_logout();

        void                        handle_undo();
        void                        handle_redo();

        static void                 show_about();

        void                        show_info( const Ustring&,
                                               const Ustring& = "",
                                               const FuncVoid& = [](){} );
        void                        close_info();

        static void                 open_uri_os( Diary*, const String& );

        bool                        write_lock();

        void                        focus_next_panel();
        void                        refresh_panels();
        void                        fix_paned_positions_if_needed();

        void                        init_textview_theme_classes();
        void                        add_textview_theme_class( Theme* );
        void                        remove_textview_theme_class( Theme* );
        void                        update_textview_theme_class( Theme* );
        void                        clear_textview_theme_classes();

        void                        refresh_theme_in_TVDs( const Theme* );

        // METHODS INVOLVING MULTIPLE PANELS AT ONCE
        void                        show_elem( DiaryElement* );
        void                        show_elem( const D::DEID& );
        void                        show_entry( Entry* );
        void                        handle_dismiss_entry( Entry* );

        static void                 set_entries_getter( const FuncEntriesGetter p2func )
        { p2get_entries = std::move( p2func ); }
        static EntrySelection       get_entries_per_context()
        {
            if( p2get_entries )
                return p2get_entries();
            else
                return {};
        }

        void                        print();

        void                        go_to_prev( bool = false );
        void                        go_to_next( bool = false );

        // CONTEXTUAL HELP
        static void                 set_help_topic( Widget*, const String& );
        void                        show_contextual_help( Widget* = nullptr );
        void                        show_contextual_help_topic( const String& );
        void                        setup_contextual_help_for_Po( Gtk::Popover* );

        void                        open_webpage_contribute();

        // POPUP NOTES (AKA STICKY NOTES)
        DialogPopupNote*            get_popup_dlg( const D::DEIDF& );
        void                        open_popup_dlg( DiaryElemTag* );
        void                        remove_popup_dlg( const D::DEIDF& );
        bool                        get_popup_notes_visible() const;
        void                        hide_all_popup_notes();
        void                        toggle_popup_notes_visible();
        void                        update_popup_note_editabilities();
        void                        update_popup_note_editability( const D::DEIDF& );
        void                        unpopup_active_entry();

        void                        do_for_each_popup_dlg(
                                        const std::function< void( DialogPopupNote* ) >& process )
        { for( auto kv_dlg : m_popup_notes ) process( kv_dlg.second ); }

        void                        add_entry_to_be_refreshed( D::DEIDF, EditorType );
        void                        remove_entry_to_be_refreshed( D::DEID );
        bool                        handle_entry_need_for_refresh( D::DEID, EditorType );

        // AUTO LOGOUT FUNCTIONALITY
        bool                        handle_idle();
        void                        freeze_auto_close();
        void                        unfreeze_auto_close();
        void                        update_auto_logout_count_down();
        // void                        disable_auto_logout_for_the_session();
        // void                        reenable_auto_logout_for_the_session();
        bool                        is_auto_close_in_use()
        { return( m_auto_close_freeze_level == 0 ); }
        void                        handle_auto_logout_toggled();
        void                        update_toggle_auto_close_gui( bool = false );

        bool                        on_event( const Glib::RefPtr< const Gdk::Event >& );

        // UI FUNCTIONALITY
        UILogin*                    UI_login{ nullptr };
        UIDiary*                    UI_diary{ nullptr };
        UIEntry*                    UI_entry{ nullptr };
        UIExtra*                    UI_extra{ nullptr };

        static int                  parallel_thread_count;

        // PRINTING
        Glib::RefPtr< Gtk::PageSetup >
                                    m_r2page_setup;
        Glib::RefPtr< Gtk::PrintSettings >
                                    m_r2print_settings;


    protected:
        bool                        on_close_request() override
        { return( !Lifeograph::p->quit() ); }

        Diary*                      get_user_manual();

        void                        load_file_based_scripts()
        {
            PyBindings::load_script_files( Lifeograph::s_py_path );
            PyBindings::load_script_files( Lifeograph::SHAREDIR + "/py" );
        }
        void                        reload_file_based_scripts()
        {
            PyBindings::remove_file_based_scripts();
            load_file_based_scripts();
        }

        // WIDGETS
        Gtk::Box*                   m_Bx_main;
        Gtk::HeaderBar*             m_Hb_main;
        Gtk::Label*                 m_L_title;
        Gtk::Label*                 m_L_subtitle;
        Gtk::Stack*                 m_St_main   { nullptr };
        Gtk::Revealer*              m_Rv_info;
        Gtk::Label*                 m_L_info;
        Gtk::Button*                m_B_info;

        Gtk::Paned*                 m_Pd_main   { nullptr };
        Gtk::Paned*                 m_Pd_extra  { nullptr };

        sigc::connection            m_connection_backup;

        int                         m_seconds_remaining{ LOGOUT_COUNTDOWN + 1 };
        sigc::connection            m_connection_timeout;
        int                         m_auto_close_freeze_level { 1 }; // reflects the result of all factors
        bool                        m_F_block_backup_on_idle  { false };
        FuncVoid                    m_info_resp_handler;

        static FuncEntriesGetter    p2get_entries;

        std::map< LoGID, EditorType >
                                    m_entries_to_be_refreshed;

        Diary*                      m_user_manual { nullptr };
        inline const static Glib::Quark
                                    CONT_HELP_KEY { Glib::Quark( "context-help" ) };

        std::map< const String, Glib::RefPtr< Gtk::CssProvider > > m_TV_css_providers;

        // list of open sticky dialogs:
        std::unordered_map< D::DEIDF, DialogPopupNote*, LoGIDHasher > m_popup_notes;

        // ACTIONS
        R2Action                    m_A_disable_auto_close;
        R2Action                    m_A_close_diary_wo_save;
};

} // end of namespace LoG

#endif
