/* enterdirop.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2009-2021 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 "enterdirop.hh"
#include "listermode.h"
#include "worker.h"
#include "wpucontext.h"
#include "ownop.h"
#include "fileentry.hh"
#include "worker_locale.h"
#include "dnd.h"
#include "aguix/cyclebutton.h"
#include "aguix/button.h"
#include "aguix/stringgadget.h"
#include "aguix/request.h"
#include "aguix/acontainer.h"
#include "aguix/awindow.h"
#include "datei.h"
#include "nwc_path.hh"
#include "argclass.hh"

/* Bei normalen Aufruf: aktiven Eintrag benutzen
   Bei DND: Element (muesste aktives sein) in Ziel (muss erst erkannt werden) darstellen
   Wenn diese Op einen Pfad hat (also nicht leer), dann diesen darstellen (also unabhaengig
   vom Eintrag */

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

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

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

EnterDirOp::EnterDirOp() : FunctionProto()
{
    dir = (char*)_allocsafe(1);
    dir[0] = 0;
    enterdirmode = ENTERDIROP_ACTIVE;
    hasConfigure = true;
    m_category = FunctionProto::CAT_CURSOR;
}

EnterDirOp::~EnterDirOp()
{
    _freesafe( dir );
}

EnterDirOp *EnterDirOp::duplicate() const
{
    EnterDirOp *ta = new EnterDirOp();
    _freesafe( ta->dir );
    ta->dir = dupstring( dir );
    ta->enterdirmode = enterdirmode;
    return ta;
}

int EnterDirOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
    Lister *l1;
    ListerMode *lm1;

    if ( msg->mode == msg->AM_MODE_DNDACTION ) {
        l1 = msg->dndmsg->getDestLister();
        if ( l1 != NULL ) {
            lm1 = l1->getActiveMode();
            if ( lm1 != NULL ) {

                const FileEntry *fe = msg->dndmsg->getFE();
            
                if ( fe != NULL && fe->fullname != NULL ) {
                    std::list< RefCount< ArgClass > > args;

                    args.push_back( RefCount< ArgClass >( new StringArg( fe->fullname ) ) );
                    lm1->runCommand( "enter_dir", args );
                }
            }
        }
    } else {
        if ( enterdirmode == ENTERDIROP_SPECIAL ) {
            if ( strlen( dir ) > 0 ) {
                l1 = msg->getWorker()->getActiveLister();
                if ( l1 != NULL ) {
                    lm1 = l1->getActiveMode();
                    if ( lm1 != NULL ) {
                        std::string res_str;
                        if ( wpu->parse( dir, res_str, a_max( EXE_STRING_LEN - 1024, 256 ),
                                         false, WPUContext::PERSIST_NOTHING ) == WPUContext::PARSE_SUCCESS ) {
                            std::list< RefCount< ArgClass > > args;

                            args.push_back( RefCount< ArgClass >( new StringArg( res_str ) ) );
                            lm1->runCommand( "enter_dir", args );
                        }
                    }
                }
            }
        } else if ( enterdirmode == ENTERDIROP_REQUEST ) {
            char *buttonstr, *return_str;
            const char *textstr;
            int erg;

            Requester *req = new Requester( msg->getWorker()->getAGUIX() );
            textstr = catalog.getLocale( 290 );
            buttonstr = (char*)_allocsafe( strlen( catalog.getLocale( 11 ) ) + 1 +
                                           strlen( catalog.getLocale( 8 ) ) + 1 );
            sprintf( buttonstr, "%s|%s", catalog.getLocale( 11 ),
                     catalog.getLocale( 8 ) );
            erg = req->string_request( catalog.getLocale( 123 ), textstr, "", buttonstr, &return_str );
            _freesafe( buttonstr );
            if ( erg == 0 && strlen( return_str) > 0 ) {
                l1 = msg->getWorker()->getActiveLister();
                if ( l1 != NULL ) {
                    lm1 = l1->getActiveMode();
                    if ( lm1 != NULL ) {
                        //TODO show a choosebutton in the requester to enable env replacing?
                        std::string tstr1 = return_str;
                        if ( tstr1[0] == '$' ) {
                            char *tstr2 = NWC::Path::handlePathExt( tstr1.c_str() );
                            tstr1 = tstr2;
                            _freesafe( tstr2 );
                        }

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

                        args.push_back( RefCount< ArgClass >( new StringArg( tstr1 ) ) );
                        lm1->runCommand( "enter_dir", args );
                    }
                }
            }
            _freesafe( return_str );
            delete req;
        } else {
            l1 = msg->getWorker()->getActiveLister();
            if ( l1 != NULL ) {
                lm1 = l1->getActiveMode();

                if ( lm1 != NULL ) {
                    std::list< NM_specialsourceExt > extfilelist;
                    std::string entry_fullname;

                    lm1->getSelFiles( extfilelist, ListerMode::LM_GETFILES_ONLYACTIVE );
                    for ( auto &ss1 : extfilelist ) {
                        if ( ss1.entry() ) {
                            entry_fullname = ss1.entry()->fullname;
                        }
                    }

                    if ( ! entry_fullname.empty() ) {
                        std::list< RefCount< ArgClass > > args;

                        args.push_back( RefCount< ArgClass >( new StringArg( entry_fullname ) ) );

                        if ( enterdirmode == ENTERDIROP_ACTIVE ) {
                            lm1->runCommand( "enter_active" );
                        } else {
                            ListerMode *nonactivemode = msg->getWorker()->getOtherLister( msg->getWorker()->getActiveLister() )->getActiveMode();

                            if ( nonactivemode ) {
                                nonactivemode->runCommand( "enter_dir", args );
                            }
                        }
                    }
                }
            }
        }
    }
    return 0;
}

const char *EnterDirOp::getDescription()
{
    return catalog.getLocale( 1259 );
}

int EnterDirOp::configure()
{
    AGUIX *aguix = Worker::getAGUIX();
    AWindow *win;
    CycleButton *rcyb;
    StringGadget *sg;
    AGMessage *msg;
    int endmode = -1;
    char *tstr;
    const int cincw = AContainer::ACONT_MINH +
        AContainer::ACONT_MINW +
        AContainer::ACONT_MAXH;
    const int cfix = AContainer::ACONT_MINH +
        AContainer::ACONT_MINW +
        AContainer::ACONT_MAXH +
        AContainer::ACONT_MAXW;
  
    tstr = (char*)_allocsafe( strlen( catalog.getLocale( 293 ) ) +
                              strlen( getDescription() ) + 1 );
    sprintf( tstr, catalog.getLocale( 293 ), getDescription() );
    win = new AWindow( aguix, 10, 10, 10, 10, tstr, AWindow::AWINDOW_DIALOG );
    win->create();
    _freesafe( tstr );

    AContainer *ac1 = win->setContainer( new AContainer( win, 1, 3 ), 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( 317 ) ), 0, 0, cfix );
    rcyb = (CycleButton*)ac1_1->add( new CycleButton( aguix, 0, 0, 100, 0 ), 1, 0, cincw );
    rcyb->addOption( catalog.getLocale( 318 ) );
    rcyb->addOption( catalog.getLocale( 319 ) );
    rcyb->addOption( catalog.getLocale( 320 ) );
    rcyb->addOption( catalog.getLocale( 321 ) );
    rcyb->resize( rcyb->getMaxSize(), rcyb->getHeight() );
    switch ( enterdirmode ) {
        case ENTERDIROP_ACTIVE2OTHER:
            rcyb->setOption( 1 );
            break;
        case ENTERDIROP_SPECIAL:
            rcyb->setOption( 2 );
            break;
        case ENTERDIROP_REQUEST:
            rcyb->setOption( 3 );
            break;
        default:
            rcyb->setOption( 0 );
            break;
    }
    ac1_1->readLimits();
  
    AContainer *ac1_2 = ac1->add( new AContainer( win, 4, 1 ), 0, 1 );
    ac1_2->setMinSpace( 0 );
    ac1_2->setMaxSpace( 0 );
    ac1_2->setBorderWidth( 0 );

    ac1_2->add( new Text( aguix, 0, 0, catalog.getLocale( 322 ) ), 0, 0, cfix );
    ac1_2->setMinWidth( 5, 1, 0 );
    ac1_2->setMaxWidth( 5, 1, 0 );
    sg = (StringGadget*)ac1_2->add( new StringGadget( aguix, 0, 0, 100, dir, 0 ), 2, 0, cincw );
    Button *sgb = (Button*)ac1_2->add( new Button( aguix,
                                                   0,
                                                   0,
                                                   "F",
                                                   0 ), 3, 0, cfix );
    sgb->resize( sgb->getWidth(), sg->getHeight() );
    ac1_2->readLimits();

    AContainer *ac1_3 = ac1->add( new AContainer( win, 2, 1 ), 0, 2 );
    ac1_3->setMinSpace( 5 );
    ac1_3->setMaxSpace( -1 );
    ac1_3->setBorderWidth( 0 );
    Button *okb =(Button*)ac1_3->add( new Button( aguix,
                                                  0,
                                                  0,
                                                  catalog.getLocale( 11 ),
                                                  0 ), 0, 0, cfix );
    Button *cb = (Button*)ac1_3->add( new Button( aguix,
                                                  0,
                                                  0,
                                                  catalog.getLocale( 8 ),
                                                  0 ), 1, 0, cfix );

    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;
                    else if ( msg->button.button == sgb ) {
                        OwnOp *o;
            
                        o = new OwnOp();
                        tstr = o->getFlag();
                        delete o;
                        if ( tstr != NULL ) {
                            sg->insertAtCursor( tstr );
                            _freesafe( tstr );
                        }
                    }
                    break;
                case AG_STRINGGADGET_DEACTIVATE:
                    rcyb->setOption( 2 );
                    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:
                enterdirmode = ENTERDIROP_ACTIVE2OTHER;
                break;
            case 2:
                enterdirmode = ENTERDIROP_SPECIAL;
                break;
            case 3:
                enterdirmode = ENTERDIROP_REQUEST;
                break;
            default:
                enterdirmode = ENTERDIROP_ACTIVE;
                break;
        }
        _freesafe( dir );
        dir = dupstring( sg->getText() );
    }
  
    delete win;

    return endmode;
}

bool EnterDirOp::save(Datei *fh)
{
    if ( fh == NULL ) return false;
    fh->configPutPairString( "dir", dir );
    switch ( enterdirmode ) {
        case ENTERDIROP_ACTIVE2OTHER:
            fh->configPutPair( "mode", "active2other" );
            break;
        case ENTERDIROP_SPECIAL:
            fh->configPutPair( "mode", "special" );
            break;
        case ENTERDIROP_REQUEST:
            fh->configPutPair( "mode", "request" );
            break;
        default:
            fh->configPutPair( "mode", "active" );
    }
    return true;
}

void EnterDirOp::setMode(enterdir_t nv)
{
    enterdirmode = nv;
}

void EnterDirOp::setDir(const char* ndir)
{
    if ( dir != NULL ) _freesafe( dir );
    dir = dupstring( ndir );
}
