/* pathjumpop.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2012-2022 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * This program 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 2 of the License, or
 * (at your option) any later version.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "pathjumpop.hh"
#include "listermode.h"
#include "pathjumpui.hh"
#include "nmspecialsourceext.hh"
#include "worker.h"
#include "worker_locale.h"
#include "fileentry.hh"
#include "argclass.hh"
#include "nwc_path.hh"
#include "virtualdirmode.hh"
#include "datei.h"
#include "aguix/awindow.h"
#include "aguix/text.h"
#include "aguix/button.h"
#include "aguix/cyclebutton.h"
#include "aguix/choosebutton.h"

const char *PathJumpOp::name = "PathJumpOp";

PathJumpOp::PathJumpOp() : FunctionProto()
{
    m_category = FunctionProto::CAT_CURSOR;
    hasConfigure = true;
}

PathJumpOp::~PathJumpOp()
{
}

PathJumpOp *PathJumpOp::duplicate() const
{
    PathJumpOp *ta = new PathJumpOp();
    ta->m_initial_tab = m_initial_tab;
    ta->m_display_mode = m_display_mode;
    ta->m_include_all_data = m_include_all_data;
    ta->m_hide_non_existing = m_hide_non_existing;
    ta->m_lock_on_current_dir = m_lock_on_current_dir;
    return ta;
}

bool PathJumpOp::isName(const char *str)
{
    if ( strcmp( str, name ) == 0 )
        return true;
    else
        return false;
}

const char *PathJumpOp::getName()
{
    return name;
}

int PathJumpOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
    Lister *l1;
    ListerMode *lm1;
    
    l1 = msg->getWorker()->getActiveLister();
    if ( l1 == NULL )
        return 1;

    msg->getWorker()->setWaitCursor();

    PathJumpUI ui( *Worker::getAGUIX(),
                   msg->getWorker()->getPathStore(),
                   *msg->getWorker() );

    lm1 = l1->getActiveMode();
    if ( lm1 ) {
        std::list< NM_specialsourceExt > sellist;
        lm1->getSelFiles( sellist, ListerMode::LM_GETFILES_ONLYACTIVE );
            
        std::string dirname, basename;

        dirname = lm1->getCurrentDirectory();

        if ( sellist.empty() == false ) {
            if ( (*sellist.begin()).entry() != NULL ) {
                basename = (*sellist.begin()).entry()->name;
                dirname = NWC::Path::dirname( sellist.begin()->entry()->fullname );
            }
        }
            
        ui.setCurrentDirname( dirname );
        ui.setCurrentBasename( basename );

        if ( m_lock_on_current_dir ) {
            ui.setStartLockDirectory( dirname );
        }
    }

    PathJumpUI::initial_tab_t show_tab = PathJumpUI::SHOW_BY_TIME;
    if ( m_initial_tab == SHOW_BY_FILTER ) {
        show_tab = PathJumpUI::SHOW_BY_FILTER;
    } else if ( m_initial_tab == SHOW_BY_PROGRAM ) {
        show_tab = PathJumpUI::SHOW_BY_PROGRAM;
    }

    switch ( m_display_mode ) {
        case SHOW_SUBDIRS:
            ui.setEntryFilterMode( PathJumpUI::SHOW_ONLY_SUBDIRS );
            break;
        case SHOW_DIRECT_SUBDIRS:
            ui.setEntryFilterMode( PathJumpUI::SHOW_ONLY_DIRECT_SUBDIRS );
            break;
        default:
            ui.setEntryFilterMode( PathJumpUI::SHOW_ALL );
            break;
    }
    ui.setShowAllData( m_include_all_data );
    ui.setHideNonExisting( m_hide_non_existing );
    
    int res = ui.mainLoop( show_tab );

    if ( res == 1 ) {
        bool stored = false;
        std::string sel_path = ui.getSelectedPath( stored );

        std::list< RefCount< ArgClass > > args;

        if ( lm1 ) {
            args.push_back( RefCount< ArgClass >( new StringArg( sel_path ) ) );
            args.push_back( RefCount< ArgClass >( new KeyValueArg( "pathDBStored",
                                                                   std::make_shared< BoolArg >( stored ) ) ) );
            lm1->runCommand( "enter_dir", args );

            // if ( highlight_entry.empty() == false ) {
            //     nm1->activateEntry( highlight_entry );
            // }
        }
    } else if ( res == 2 ) {
        std::unique_ptr< NWC::Dir > resdir = ui.getResultsAsDir();

        l1->switch2Mode( 0 );

        VirtualDirMode *vdm = dynamic_cast< VirtualDirMode* >( l1->getActiveMode() );
        if ( vdm != NULL ) {
            vdm->newTab();

            vdm->showDir( resdir );
        }
    }

    msg->getWorker()->unsetWaitCursor();
    return 0;
}

const char *PathJumpOp::getDescription()
{
    return catalog.getLocale( 1301 );
}

void PathJumpOp::setInitialTab( initial_tab_t v )
{
    m_initial_tab = v;
}

void PathJumpOp::setDisplayMode( display_mode_t v )
{
    m_display_mode = v;
}

void PathJumpOp::setIncludeAllData( bool v )
{
    m_include_all_data = v;
}

void PathJumpOp::setHideNonExisting( bool v )
{
    m_hide_non_existing = v;
}

void PathJumpOp::setLockOnCurrentDir( bool v )
{
    m_lock_on_current_dir = v;
}

bool
PathJumpOp::save( Datei *fh )
{
    if ( fh == NULL ) return false;
    switch ( m_initial_tab ) {
        case SHOW_BY_FILTER:
            fh->configPutPair( "initialtab", "showbyfilter" );
            break;
        case SHOW_BY_PROGRAM:
            fh->configPutPair( "initialtab", "showbyprogram" );
            break;
        default:
            // don't save default value to be backward compatible
            break;
    }
    switch ( m_display_mode ) {
        case SHOW_SUBDIRS:
            fh->configPutPair( "displaymode", "showsubdirs" );
            break;
        case SHOW_DIRECT_SUBDIRS:
            fh->configPutPair( "displaymode", "showdirectsubdirs" );
            break;
        default:
            // don't save default value to be backward compatible
            break;
    }

    if ( m_include_all_data ) {
        fh->configPutPairBool( "includeall", m_include_all_data );
    }

    if ( m_hide_non_existing ) {
        fh->configPutPairBool( "hidenonexisting", m_hide_non_existing );
    }

    if ( m_lock_on_current_dir ) {
        fh->configPutPairBool( "lockoncurrentdir", m_lock_on_current_dir );
    }

    return true;
}

int
PathJumpOp::configure()
{
    AGUIX *aguix = Worker::getAGUIX();
    AWindow *win;
    CycleButton *rcyb;
    AGMessage *msg;
    int endmode = -1;

    auto title = AGUIXUtils::formatStringToString( catalog.getLocale( 293 ),
                                                   getDescription() );
    win = new AWindow( aguix, 10, 10, 10, 10, title.c_str(), AWindow::AWINDOW_DIALOG );
    win->create();
    
    AContainer *ac1 = win->setContainer( new AContainer( win, 1, 6 ), true );
    ac1->setMinSpace( 5 );
    ac1->setMaxSpace( 5 );
    
    AContainer *ac1_1 = ac1->add( new AContainer( win, 2, 1 ), 0, 0 );
    ac1_1->setMinSpace( 5 );
    ac1_1->setMaxSpace( 5 );
    ac1_1->setBorderWidth( 0 );

    ac1_1->add( new Text( aguix, 0, 0, catalog.getLocale( 1224 ) ), 0, 0, AContainer::CO_FIX );
    rcyb = (CycleButton*)ac1_1->add( new CycleButton( aguix, 0, 0, 100, 0 ), 1, 0, AContainer::CO_INCWNR );
    rcyb->addOption( catalog.getLocale( 1225 ) );
    rcyb->addOption( catalog.getLocale( 1226 ) );
    rcyb->addOption( catalog.getLocale( 1327 ) );
    rcyb->resize( rcyb->getMaxSize(), rcyb->getHeight() );
    ac1_1->readLimits();
    switch ( m_initial_tab ) {
        case SHOW_BY_FILTER:
            rcyb->setOption( 1 );
            break;
        case SHOW_BY_PROGRAM:
            rcyb->setOption( 2 );
            break;
        default:
            rcyb->setOption( 0 );
            break;
    }
    
    AContainer *ac1_3 = ac1->add( new AContainer( win, 2, 1 ), 0, 1 );
    ac1_3->setMinSpace( 5 );
    ac1_3->setMaxSpace( 5 );
    ac1_3->setBorderWidth( 0 );

    ac1_3->add( new Text( aguix, 0, 0, catalog.getLocale( 1387 ) ), 0, 0, AContainer::CO_FIX );
    auto dmcyb = ac1_3->addWidget( new CycleButton( aguix, 0, 0, 100, 0 ), 1, 0, AContainer::CO_INCWNR );
    dmcyb->addOption( catalog.getLocale( 981 ) );
    dmcyb->addOption( catalog.getLocale( 982 ) );
    dmcyb->addOption( catalog.getLocale( 983 ) );
    dmcyb->resize( dmcyb->getMaxSize(), dmcyb->getHeight() );
    ac1_3->readLimits();
    switch ( m_display_mode ) {
        case SHOW_SUBDIRS:
            dmcyb->setOption( 1 );
            break;
        case SHOW_DIRECT_SUBDIRS:
            dmcyb->setOption( 2 );
            break;
        default:
            dmcyb->setOption( 0 );
            break;
    }

    auto iacb = ac1->addWidget( new ChooseButton( aguix, 0, 0, m_include_all_data,
                                                  catalog.getLocale( 1388 ), LABEL_LEFT, 0 ), 0, 2,
                                AContainer::CO_INCWNR );

    auto hidenonexisting_cb = ac1->addWidget( new ChooseButton( aguix, 0, 0, m_hide_non_existing,
                                                                catalog.getLocale( 1115 ), LABEL_LEFT, 0 ), 0, 3,
                                              AContainer::CO_INCWNR );

    auto lockoncurrentdir_cb = ac1->addWidget( new ChooseButton( aguix, 0, 0, m_lock_on_current_dir,
                                                                 catalog.getLocale( 1435 ), LABEL_LEFT, 0 ), 0, 4,
                                               AContainer::CO_INCWNR );

    AContainer *ac1_2 = ac1->add( new AContainer( win, 2, 1 ), 0, 5 );
    ac1_2->setMinSpace( 5 );
    ac1_2->setMaxSpace( -1 );
    ac1_2->setBorderWidth( 0 );
    Button *okb =(Button*)ac1_2->add( new Button( aguix,
                                                  0,
                                                  0,
                                                  catalog.getLocale( 11 ),
                                                  0 ), 0, 0, AContainer::CO_FIX );
    Button *cb = (Button*)ac1_2->add( new Button( aguix,
                                                  0,
                                                  0,
                                                  catalog.getLocale( 8 ),
                                                  0 ), 1, 0, AContainer::CO_FIX );
    
    win->setDoTabCycling( true );
    win->contMaximize( true );
    win->show();

    for ( ; endmode == -1; ) {
        msg = aguix->WaitMessage( win );
        if ( msg != NULL ) {
            switch ( msg->type ) {
                case AG_CLOSEWINDOW:
                    if ( msg->closewindow.window == win->getWindow() ) endmode = 1;
                    break;
                case AG_BUTTONCLICKED:
                    if ( msg->button.button == okb ) endmode = 0;
                    else if ( msg->button.button == cb ) endmode = 1;
                    break;
                case AG_KEYPRESSED:
                    if ( win->isParent( msg->key.window, false ) == true ) {
                        switch ( msg->key.key ) {
                            case XK_Escape:
                                endmode = 1;
                                break;
                        }
                    }
                    break;
            }
            aguix->ReplyMessage( msg );
        }
    }
    
    if ( endmode == 0 ) {
        // ok
        switch ( rcyb->getSelectedOption() ) {
            case 1:
                m_initial_tab = SHOW_BY_FILTER;
                break;
            case 2:
                m_initial_tab = SHOW_BY_PROGRAM;
                break;
            default:
                m_initial_tab = SHOW_BY_TIME;
                break;
        }
        switch ( dmcyb->getSelectedOption() ) {
            case 1:
                m_display_mode = SHOW_SUBDIRS;
                break;
            case 2:
                m_display_mode = SHOW_DIRECT_SUBDIRS;
                break;
            default:
                m_display_mode = SHOW_ALL;
                break;
        }
        m_include_all_data = iacb->getState();
        m_hide_non_existing = hidenonexisting_cb->getState();
        m_lock_on_current_dir = lockoncurrentdir_cb->getState();
    }
    
    delete win;
    
    return endmode;
}
