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

    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/>.

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


#include "lifeograph.hpp"
#include "app_window.hpp"
#include "widget_entrylist.hpp"
#include "view_entry.hpp"


using namespace LIFEO;


// WIDGET ENTRY LIST ===============================================================================
WidgetEntryList::WidgetEntryList( BaseObjectType* cobject,
                                  const Glib::RefPtr<Gtk::Builder>& )
:   Gtk::TreeView( cobject )
{
    // CELL RENDERERS
    Gtk::CellRendererPixbuf* cellr_pb_icon = Gtk::manage( new Gtk::CellRendererPixbuf );
    Gtk::CellRendererText* cellr_text = Gtk::manage( new Gtk::CellRendererText );
    Gtk::TreeViewColumn* column = Gtk::manage( new Gtk::TreeViewColumn );

    Gtk::CellRendererPixbuf* cellr_pb_icon2 = Gtk::manage( new Gtk::CellRendererPixbuf );

    cellr_text->property_ellipsize() = Pango::ELLIPSIZE_END;
    if( Lifeograph::settings.small_lists )
        cellr_text->property_scale() = .90;
    cellr_text->set_fixed_height_from_font( 1 );

    column->pack_start( *cellr_pb_icon, false );
    column->pack_start( *cellr_text );
    column->pack_start( *cellr_pb_icon2, false );

    column->add_attribute( cellr_pb_icon->property_pixbuf(), ListData::colrec->icon );
    column->add_attribute( cellr_text->property_markup(), ListData::colrec->info );
    column->add_attribute( cellr_pb_icon2->property_pixbuf(), ListData::colrec->icon2 );

    column->set_cell_data_func( *cellr_pb_icon2,
                                sigc::mem_fun( this, &WidgetEntryList::cell_data_func_icon ) );

    // TODO we failed to accomplish fixed height mode with the second icon renderer
    //column->set_sizing( Gtk::TREE_VIEW_COLUMN_FIXED );

    m_treestore = Gtk::TreeStore::create( *ListData::colrec );

    if( Lifeograph::s_color_insensitive.empty() )
    {
        Lifeograph::s_color_insensitive = convert_gdkcolor_to_html(
                get_style_context()->get_color( Gtk::STATE_FLAG_INSENSITIVE ) );
    }

    append_column( *column );

    get_selection()->signal_changed().connect(
            sigc::mem_fun( this, &WidgetEntryList::handle_selection_changed ) );
}

void
WidgetEntryList::cell_data_func_icon( Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter )
{
    DiaryElement* elem( ( * iter )[ ListData::colrec->ptr ] );
    if( elem != NULL )
    {
        bool favored( elem->is_favored() );
        cell->set_property( "visible", favored );
        if( favored )
            cell->set_property( "pixbuf", Lifeograph::icons->favorite_16 );
    }
}

WidgetEntryList::~WidgetEntryList()
{
}

void
WidgetEntryList::clear()
{
    m_treestore->clear();
    Lifeograph::s_elem_dragged = NULL;
}

void
WidgetEntryList::present_element( const DiaryElement* element )
{
    Gtk::TreePath path( element->m_list_data->treepath );

    expand_to_path( path );

    get_selection()->unselect_all();
    get_selection()->select( path );

    Gtk::TreePath path_b, path_e;
    get_visible_range( path_b, path_e );

    if( is_treepath_less( path, path_b ) || is_treepath_more( path, path_e ) )
    {
        PRINT_DEBUG( "path is not visible" );
        scroll_to_row( path, 0.0 );   // does nothing if already visible
    }
}

void
WidgetEntryList::expand_element( const DiaryElement* element ) // this function does not do much
{
    expand_to_path( element->m_list_data->treepath );
}

void
WidgetEntryList::go_up( bool flag_entry_operation )
{
    DiaryElement* elem( AppWindow::p->panel_main->get_cur_elem() );

    if( elem == NULL )
        return;
    else
    if( elem->get_type() < DiaryElement::ET_DIARY ) // not list element
        return;

    Gtk::TreePath path( elem->m_list_data->treepath );

    do
    {
        if( ! path.prev() )
        {
            if( path.size() > 1 )
                path.up();
            else    // diary
            if( make_path_deeper_last( path ) )
                make_path_deeper_last( path ); // go still deeper if possible:
        }
        else
            make_path_deeper_last( path );

        elem = ( * m_treestore->get_iter( path ) )[ ListData::colrec->ptr ];
    }
    // repeat until an entry is found if that is what we are looking for
    // BEWARE: do not set this flag when there is no entry in the list
    while( flag_entry_operation && elem->get_type() != DiaryElement::ET_ENTRY );

    PRINT_DEBUG( "previous path: " + path.to_string() );

    Gtk::TreeRow row( * m_treestore->get_iter( path ) );
    DiaryElement* element( row[ ListData::colrec->ptr ] );
    element->show();
}

void
WidgetEntryList::go_down( bool flag_entry_operation )
{
    DiaryElement* elem( AppWindow::p->panel_main->get_cur_elem() );

    if( elem == nullptr )
        return;
    else
    if( elem->get_type() < DiaryElement::ET_DIARY ) // not list element
        return;

    Gtk::TreePath path( elem->m_list_data->treepath );

    do
    {
        if( ! m_treestore->get_iter( path )->children().empty() )
            path.down();
        else
        if( ! move_path_next( path ) )
        {
            while( path.size() > 1 )
            {
                path.up();
                if( move_path_next( path ) )
                    break;
            }
        }

        elem = ( * m_treestore->get_iter( path ) )[ ListData::colrec->ptr ];
    }
    // repeat until an entry is found if that is what we are looking for
    // BEWARE: do not set this flag when there is no entry in the list
    while( flag_entry_operation && elem->get_type() != DiaryElement::ET_ENTRY );

    PRINT_DEBUG( "next path: " + path.to_string() );

    Gtk::TreeRow row( * m_treestore->get_iter( path ) );
    DiaryElement *listitem = row[ ListData::colrec->ptr ];
    listitem->show();
}

void
WidgetEntryList::handle_sorting_criteria_changed( SortingCriteria sc, int sd )
{
    switch( sc )
    {
        default: // future-proofing
        case SC_DATE:
            m_treestore->set_default_sort_func(
                    sigc::mem_fun( this, &WidgetEntryList::sort_by_date ) );
            break;
        case SC_SIZE_C:
            m_treestore->set_default_sort_func(
                    sigc::mem_fun( this, &WidgetEntryList::sort_by_size ) );
            break;
        case SC_CHANGE:
            m_treestore->set_default_sort_func(
                    sigc::mem_fun( this, &WidgetEntryList::sort_by_change ) );
            break;
    }
}

void
WidgetEntryList::reset_sorting_criteria()
{
    switch( Diary::d->get_sorting_criteria() )
    {
        default:
        case SC_DATE:
            m_treestore->set_default_sort_func(
                    sigc::mem_fun( this, &WidgetEntryList::sort_by_date ) );
            break;
        case SC_SIZE_C:
            m_treestore->set_default_sort_func(
                    sigc::mem_fun( this, &WidgetEntryList::sort_by_size ) );
            break;
        case SC_CHANGE:
            m_treestore->set_default_sort_func(
                    sigc::mem_fun( this, &WidgetEntryList::sort_by_change ) );
            break;
    }
}

// not used now but may be used in the future
Gtk::TreePath
WidgetEntryList::find_element( const DiaryElement* element ) const
{
    Gtk::TreeIter iter_diary( m_treestore->children().begin() );
    if( element == ( *iter_diary )[ ListData::colrec->ptr ] )
        return m_treestore->get_path( iter_diary );

    for( Gtk::TreeIter iter = ( *iter_diary )->children().begin();
         iter != ( *iter_diary )->children().end();
         ++iter )
    {
        const DiaryElement *list_elem( ( *iter )[ ListData::colrec->ptr ] );
        if( element->get_id() == list_elem->get_id() )
        {
            return m_treestore->get_path( iter );
        }
        else
        {
            if( element->get_type() == DiaryElement::ET_ENTRY &&
                list_elem->get_type() != DiaryElement::ET_ENTRY )
                if( element->get_date() > list_elem->get_date() )
                    for( Gtk::TreeIter itr2 = ( *iter )->children().begin();
                         itr2 != ( *iter )->children().end();
                         ++itr2 )
                    {
                        if( element == ( *itr2 )[ ListData::colrec->ptr ] )
                            return m_treestore->get_path( itr2 );
                    }
        }
    }

    return m_treestore->get_path( m_treestore->children().begin() );
}

bool
select_true( const Glib::RefPtr< Gtk::TreeModel >& model,
             const Gtk::TreePath& path, bool path_currently_selected )
{
    return true;
}

bool
select_false( const Glib::RefPtr< Gtk::TreeModel >& model,
              const Gtk::TreePath& path, bool path_currently_selected )
{
    return false;
}

bool
WidgetEntryList::on_button_press_event( GdkEventButton* event )
{
    Lifeograph::s_flag_dragging = false;

    Gtk::TreePath path;
    if( get_path_at_pos( ( int ) event->x, ( int ) event->y, path ) )
    {
        Gtk::TreeRow row = * m_treestore->get_iter( path );

        if( get_selection()->is_selected( path ) && get_selection()->count_selected_rows() > 1 &&
            !( event->state & ( Gdk::CONTROL_MASK | Gdk::SHIFT_MASK ) ) )
        {
            Lifeograph::s_elem_dragged = &m_multiple_entries;
            get_selection()->set_select_function( sigc::ptr_fun( &select_false ) );
        }
        else
        {
            Lifeograph::s_elem_dragged = row[ ListData::colrec->ptr ];
            get_selection()->set_select_function( sigc::ptr_fun( &select_true ) );
        }
    }
    else
        Lifeograph::s_elem_dragged = NULL;

    return Gtk::TreeView::on_button_press_event( event );
}

bool
WidgetEntryList::on_button_release_event( GdkEventButton* event )
{
    get_selection()->set_select_function( sigc::ptr_fun( &select_true ) );

    if( ! Lifeograph::s_flag_dragging /*&& event->button != 1*/ )
    {
        if( Lifeograph::s_elem_dragged &&
            !( event->state & ( Gdk::CONTROL_MASK | Gdk::SHIFT_MASK ) ) )
        {
            if( Lifeograph::s_elem_dragged->get_type() == DiaryElement::ET_MULTIPLE_ENTRIES )
            {
                get_selection()->unselect_all();

                Gtk::TreePath path;
                if( get_path_at_pos( ( int ) event->x, ( int ) event->y, path ) )
                {
                    get_selection()->select( path );
                    Gtk::TreeRow row = * m_treestore->get_iter( path );
                    DiaryElement *element = row[ ListData::colrec->ptr ];
                    element->show();
                }
            }
            else
                Lifeograph::s_elem_dragged->show();
        }

        Lifeograph::s_elem_dragged = NULL;
    }

    return Gtk::TreeView::on_button_release_event( event );
}

bool
WidgetEntryList::on_key_press_event( GdkEventKey* event )
{
    if( event->state == 0 )
    {
        switch( event->keyval )
        {
            case GDK_KEY_Home:
                Diary::d->show();
                return true;
            case GDK_KEY_End:
                return true;
            case GDK_KEY_Up:
                go_up( false );
                return true;
            case GDK_KEY_Down:
                go_down( false );
                return true;
        }
    }
    return Gtk::TreeView::on_key_press_event( event );
}

void
WidgetEntryList::on_drag_begin( const Glib::RefPtr< Gdk::DragContext >& context )
{
    if( Lifeograph::s_elem_dragged )
    {
        Lifeograph::s_flag_dragging = true;
        get_selection()->set_select_function( sigc::ptr_fun( &select_true ) );

        //Gtk::TreeView::on_drag_begin( context );
        context->set_icon( Lifeograph::s_elem_dragged->get_icon32(), 0, 0 );
    }
}

void
WidgetEntryList::on_drag_end( const Glib::RefPtr< Gdk::DragContext >& context )
{
    PRINT_DEBUG( "WidgetEntryList::on_drag_end()" );
    Gtk::TreeView::on_drag_end( context );
    restore_selection();
    Lifeograph::s_elem_dragged = NULL;
}

bool
WidgetEntryList::on_drag_motion( const Glib::RefPtr< Gdk::DragContext >& context,
                                 int x, int y, guint time )
{
    m_flag_text_drop = false;
    if( context->list_targets()[ 0 ] == "GTK_TEXT_BUFFER_CONTENTS" )
        m_flag_text_drop = true;
    else if( ! Lifeograph::s_flag_dragging )
        return false;
    else if( ! Lifeograph::s_elem_dragged )
        return false;

    bool retval( false );
    Gdk::DragAction action{ m_flag_text_drop ? Gdk::ACTION_COPY : Gdk::ACTION_MOVE };
    Gtk::TreePath path;
    DiaryElement* element{ nullptr };

    // AUTOSCROLL
    Gdk::Rectangle rect;
    get_visible_rect( rect );
    int new_y = rect.get_y();
    if( y < ( rect.get_height() * 0.15 ) )
    {
        if( new_y > 0 )
        {
            new_y -= 5;
            if( new_y < 0 )
                new_y = 0;
            scroll_to_point( -1, new_y );
        }
    }
    else
    if( y > ( rect.get_height() * 0.85 ) )
    {
        if( get_vadjustment()->get_value() < get_vadjustment()->get_upper() )
        {
            new_y += 5;
            scroll_to_point( -1, new_y );
        }
    }

    // EVALUATE THE HOVERED ELEMENT
    if( get_path_at_pos( x, y, path ) )
    {
        Gtk::TreeRow row = * m_treestore->get_iter( path );
        element = row[ ListData::colrec->ptr ];
        if( m_flag_text_drop && element != nullptr )
        {
            if( element->get_type() == DiaryElement::ET_ENTRY )
                retval = true;
        }
        else if( element != nullptr && element != Lifeograph::s_elem_dragged )
        {
            switch( Lifeograph::s_elem_dragged->get_type() )
            {
                case DiaryElement::ET_ENTRY:
                    if( element->get_type() != DiaryElement::ET_DIARY )
                        retval = true;
                    break;
                case DiaryElement::ET_MULTIPLE_ENTRIES:
                    if( element->get_type() == DiaryElement::ET_CHAPTER ||
                        element->get_type() == DiaryElement::ET_TOPIC ||
                        element->get_type() == DiaryElement::ET_GROUP )
                        retval = true;
                    break;
                case DiaryElement::ET_CHAPTER:
                    // chapters can only be dropped onto temporal entries
                    if( element->get_type() == DiaryElement::ET_ENTRY &&
                        element->get_date().is_ordinal() == false &&
                        element->get_date().get_pure() !=
                                Lifeograph::s_elem_dragged->get_date().get_pure() )
                        retval = true;
                    break;
                case DiaryElement::ET_TOPIC:
                    // topics can only be dropped onto other topics
                    if( element->get_type() == DiaryElement::ET_TOPIC )
                        retval = true;
                    break;
                case DiaryElement::ET_GROUP:
                    // groups can only be dropped onto other groups
                    if( element->get_type() == DiaryElement::ET_GROUP )
                        retval = true;
                    break;
                case DiaryElement::ET_TAG:
                case DiaryElement::ET_UNTAGGED:
                    if( element->get_type() == DiaryElement::ET_ENTRY )
                    {
                        retval = true;
                        action = Gdk::ACTION_COPY;
                    }
                    break;
                default: // the rest is not accepted
                    break;
            }
        }
    }

    if( retval )
    {
        m_elem_drop_target = element;
        context->drag_status( action, time );
        restore_selection();
        get_selection()->select( path );
    }
    else
        restore_selection();

    //return Gtk::TreeView::on_drag_motion( context, x, y, time );
    return retval;
}

bool
WidgetEntryList::on_drag_drop( const Glib::RefPtr< Gdk::DragContext >& context,
                               int x, int y, guint time )
{
    bool retval( false );

    if( Lifeograph::s_flag_dragging )
    {
        if( Lifeograph::s_elem_dragged != NULL && m_elem_drop_target != NULL )
        {
            switch( Lifeograph::s_elem_dragged->get_type() )
            {
                case DiaryElement::ET_ENTRY:
                {
                    Entry* entry( dynamic_cast< Entry* >( Lifeograph::s_elem_dragged ) );
                    switch( m_elem_drop_target->get_type() )
                    {
                        case DiaryElement::ET_CHAPTER:
                        case DiaryElement::ET_TOPIC:
                        case DiaryElement::ET_GROUP:
                        {
                            Chapter* chapter( dynamic_cast< Chapter* >( m_elem_drop_target ) );
                            Diary::d->set_entry_date( entry, chapter->get_free_order() );
                            AppWindow::p->panel_main->refresh_title();
                            AppWindow::p->panel_diary->update_entry_list();
                            retval = true;
                            break;
                        }
                        case DiaryElement::ET_ENTRY:
                            Diary::d->set_entry_date( entry, m_elem_drop_target->get_date() );
                            AppWindow::p->panel_main->refresh_title();
                            AppWindow::p->panel_diary->update_entry_list();
                            retval = true;
                            break;
                        default:
                            break;
                    }
                    break;
                }
                case DiaryElement::ET_MULTIPLE_ENTRIES:
                    if( m_elem_drop_target->get_type() == DiaryElement::ET_CHAPTER ||
                        m_elem_drop_target->get_type() == DiaryElement::ET_TOPIC ||
                        m_elem_drop_target->get_type() == DiaryElement::ET_GROUP )
                    {
                        Chapter* chapter( dynamic_cast< Chapter* >( m_elem_drop_target ) );
                        sigc::slot< void, Entry* > s = sigc::bind(
                                 sigc::mem_fun( this, &WidgetEntryList::move_entry_to_chapter ),
                                 chapter );
                        AppWindow::p->panel_diary->do_for_each_selected_entry( s );

                        AppWindow::p->panel_main->refresh_title();
                        AppWindow::p->panel_diary->update_entry_list();
                    }
                    break;
                case DiaryElement::ET_CHAPTER:
                {
                    Chapter* chapter( dynamic_cast< Chapter* >( Lifeograph::s_elem_dragged ) );
                    Diary::d->get_current_chapter_ctg()->set_chapter_date(
                            chapter, m_elem_drop_target->get_date_t() );
                    AppWindow::p->panel_main->refresh_title();
                    AppWindow::p->panel_diary->update_entry_list();
                    retval = true;
                    break;
                }
                case DiaryElement::ET_GROUP:
                case DiaryElement::ET_TOPIC:
                {
                    Chapter* chapter( dynamic_cast< Chapter* >( Lifeograph::s_elem_dragged ) );
                    Diary::d->set_topic_order( chapter, m_elem_drop_target->get_date_t() );
                    AppWindow::p->panel_main->refresh_title();
                    AppWindow::p->panel_diary->update_entry_list();
                    retval = true;
                    break;
                }
                case DiaryElement::ET_TAG:
                case DiaryElement::ET_UNTAGGED:
                    if( m_elem_drop_target->get_type() == DiaryElement::ET_ENTRY )
                    {
                        Tag* tag( dynamic_cast< Tag* >( Lifeograph::s_elem_dragged ) );
                        Entry* entry( dynamic_cast< Entry* >( m_elem_drop_target ) );
                        if( entry->add_tag( tag ) ) // if does not already have the tag
                        {
                            if( AppWindow::p->panel_main->is_cur_elem( m_elem_drop_target ) )
                            {
                                AppWindow::p->m_entry_view->update_tag_widget();
                                AppWindow::p->m_entry_view->update_theme();
                            }

                            retval = true;
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    }
    else if( m_flag_text_drop && m_elem_drop_target )
    {
        if( AppWindow::p->panel_main->get_cur_elem()->get_type() == DiaryElement::ET_ENTRY &&
            m_elem_drop_target->get_type() == DiaryElement::ET_ENTRY )
        {
            PRINT_DEBUG( AppWindow::p->m_entry_view->get_buffer()->get_selected_text() );
            dynamic_cast< Entry* >( m_elem_drop_target )->append_text(
                    AppWindow::p->m_entry_view->get_buffer()->get_selected_text() );
            retval = true;
        }
    }

    context->drag_finish( retval, false, time );
    return retval;
}

void
WidgetEntryList::handle_selection_changed()
{
    if( Lifeograph::s_internaloperation || Lifeograph::s_flag_dragging )
        return;

    m_multiple_entries.m_entries.clear();

    Glib::RefPtr< Gtk::TreeSelection > sel( get_selection() );
    int num_sel( sel->count_selected_rows() );

    std::vector< Gtk::TreePath > selected_rows = sel->get_selected_rows();

    for( Gtk::TreePath& path : selected_rows )
    {
        Gtk::TreeRow row( * m_treestore->get_iter( path ) );
        DiaryElement* elem( row[ ListData::colrec->ptr ] );
        if( elem->get_type() != DiaryElement::ET_ENTRY )
        {
            if( num_sel > 1 )
            {
                Lifeograph::s_internaloperation++;
                sel->unselect( path );
                Lifeograph::s_internaloperation--;
            }
        }
        else
            m_multiple_entries.m_entries.push_back( dynamic_cast< Entry* >( elem ) );
    }
}

void
WidgetEntryList::restore_selection()
{
    get_selection()->unselect_all();

    for( Entry* entry : m_multiple_entries.m_entries )
        get_selection()->select( entry->m_list_data->treepath );

    // TODO also restore if last selection was another type of element than entry
}

void
WidgetEntryList::do_for_each_selected_entry( sigc::slot< void, Entry* >& slot )
{
    for( Entry* entry : m_multiple_entries.m_entries )
    {
        slot( entry );
    }
}

int
WidgetEntryList::sort_by_date( const Gtk::TreeModel::iterator& itr1,
                               const Gtk::TreeModel::iterator& itr2 )
{
    // SORT BY DATE (ONLY DESCENDINGLY FOR NOW)
    DiaryElement* item1 = ( *itr1 )[ ListData::colrec->ptr ];
    DiaryElement* item2 = ( *itr2 )[ ListData::colrec->ptr ];
    if( !( item1 && item2 ) )
        return 0;
    else
    if( item1->get_type() == DiaryElement::ET_DIARY )
    return -1;

    const int direction( ( item1->get_date().is_ordinal() != item2->get_date().is_ordinal() ) ?
            1 : ( Diary::d->get_sorting_dir() == SD_DESCENDING ? 1 : -1 ) );

    if( item1->get_date() > item2->get_date() )
        return -direction;
    else
    if( item1->get_date() < item2->get_date() )
        return direction;
    else
        return 0;
}

int
WidgetEntryList::sort_by_size( const Gtk::TreeModel::iterator& itr1,
                               const Gtk::TreeModel::iterator& itr2 )
{
    DiaryElement* item1 = ( *itr1 )[ ListData::colrec->ptr ];
    DiaryElement* item2 = ( *itr2 )[ ListData::colrec->ptr ];
    if( !( item1 && item2 ) )
        return 0;

    const int direction{ Diary::d->get_sorting_dir() == SD_DESCENDING ? 1 : -1 };

    // group ordinal entries together:
//    if( item1->get_date().is_ordinal() != item2->get_date().is_ordinal() )
//        return( item1->get_date().is_ordinal() ? -1 : 1 );

    if( item1->get_size() > item2->get_size() )
        return -direction;
    else
    if( item1->get_size() < item2->get_size() )
        return direction;
    else
        return 0;
}

int
WidgetEntryList::sort_by_change( const Gtk::TreeModel::iterator& itr1,
                                 const Gtk::TreeModel::iterator& itr2 )
{
    DiaryElement* item1 = ( *itr1 )[ ListData::colrec->ptr ];
    DiaryElement* item2 = ( *itr2 )[ ListData::colrec->ptr ];
    if( !( item1 && item2 ) )
        return 0;

    time_t date1( item1->get_type() == DiaryElement::ET_ENTRY ?
            dynamic_cast< Entry* >( item1 )->get_date_edited() : 0 );
    time_t date2( item2->get_type() == DiaryElement::ET_ENTRY ?
            dynamic_cast< Entry* >( item2 )->get_date_edited() : 0 );

    const int direction{ Diary::d->get_sorting_dir() == SD_DESCENDING ? 1 : -1 };

    if( date1 > date2 )
        return -direction;
    else
    if( date1 < date2 )
        return direction;
    else
        return 0;
}

inline bool
WidgetEntryList::move_path_next( Gtk::TreePath& path )
{
    if( unsigned( path.back() ) <
            ( m_treestore->get_iter( path )->parent()->children().size() - 1 ) )
    {
        path.next();
        return true;
    }
    else
        return false;
}

inline bool
WidgetEntryList::make_path_deeper_last( Gtk::TreePath& path )
{
    if( ! m_treestore->get_iter( path )->children().empty() )
    {
        path.push_back( m_treestore->get_iter( path )->children().size() - 1 );
        return true;
    }
    return false;
}

// HELPER FUNCTION
void
WidgetEntryList::move_entry_to_chapter( Entry* entry, Chapter* chapter )
{
    Diary::d->set_entry_date( entry, chapter->get_free_order() );
}

const Glib::RefPtr< Gdk::Pixbuf >&
WidgetEntryList::MultipleEntries::get_icon32() const
{
    return Lifeograph::icons->entry_32;
}
