/* changelabelop.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2008-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 "changelabelop.hh"
#include "listermode.h"
#include "worker.h"
#include "bookmarkdbproxy.hh"
#include "bookmarkdbentry.hh"
#include "nwc_path.hh"
#include "nmspecialsourceext.hh"
#include <algorithm>
#include "fileentry.hh"
#include "datei.h"
#include "worker_locale.h"
#include "aguix/choosebutton.h"
#include "aguix/fieldlistview.h"
#include "aguix/button.h"
#include "aguix/stringgadget.h"
#include "aguix/awindow.h"
#include "wconfig.h"

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

ChangeLabelOp::ChangeLabelOp() : FunctionProto(),
                                 m_label( "" ),
                                 m_ask_for_label( true )
{
    m_label = "marked";
    hasConfigure = true;
}

ChangeLabelOp::~ChangeLabelOp()
{
}

ChangeLabelOp* ChangeLabelOp::duplicate() const
{
    ChangeLabelOp *ta = new ChangeLabelOp();
    ta->setLabel( m_label );
    ta->setAskForLabel( m_ask_for_label );
    return ta;
}

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

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

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

    lm1 = l1->getActiveMode();
    if ( lm1 == NULL ) {
        return 1;
    }

    if ( m_ask_for_label == true ) {
        lm1->runCommand( "open_label_popup" );
    } else {
        BookmarkDBProxy &bookmarks = msg->getWorker()->getBookmarkDBInstance();
        //TODO read necessary?
        bookmarks.read();
        
        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 );
            }
        }

        if ( dirname.length() > 0 && basename.length() > 0 ) {
            std::string fullname = NWC::Path::join( dirname, basename );
            //TODO normalize fullname?

            std::unique_ptr<BookmarkDBEntry> entry = bookmarks.getEntry( fullname );
            if ( entry.get() != NULL ) {
                if ( entry->getCategory() == m_label ) {
                    bookmarks.delEntry( *entry );
                } else {
                    BookmarkDBEntry newentry( *entry );
                    newentry.setCategory( m_label );
                    bookmarks.updateEntry( *entry, newentry );
                }

            } else {
                BookmarkDBEntry newentry( m_label, fullname, "", true );
                bookmarks.addEntry( newentry );
            }
            bookmarks.write();

            lm1->updateOnBookmarkChange();
        }
    }

    return 0;
}

bool ChangeLabelOp::save( Datei *fh )
{
    if ( fh == NULL ) return false;
    fh->configPutPairBool( "askforlabel", m_ask_for_label );
    fh->configPutPairString( "label", m_label.c_str() );
    return true;
}

const char *ChangeLabelOp::getDescription()
{
    return catalog.getLocale( 1296 );
}

int ChangeLabelOp::configure()
{
    AGUIX *aguix = Worker::getAGUIX();
    Button *okb, *cancelb;
    AWindow *win;
    ChooseButton *ask_cb = NULL;
    StringGadget *label_sg;
    AGMessage *msg;
    int endmode = -1;
    char *tstr;
    
    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, 4 ), true );
    ac1->setMinSpace( 5 );
    ac1->setMaxSpace( 5 );
    
    ask_cb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, ( m_ask_for_label == true ) ? 1 : 0,
                                                        catalog.getLocale( 830 ), LABEL_RIGHT, 0 ),
                                      0, 0, AContainer::CO_INCWNR );
    
    ac1->add( new Text( aguix, 0, 0, catalog.getLocale( 829 ) ), 0, 1, AContainer::CO_INCW );

    AContainer *ac1_3 = ac1->add( new AContainer( win, 1, 2 ), 0, 2 );
    ac1_3->setMinSpace( 0 );
    ac1_3->setMaxSpace( 0 );
    ac1_3->setBorderWidth( 0 );
    FieldListView *lv = (FieldListView*)ac1_3->add( new FieldListView( aguix,
                                                                      0, 0,
                                                                      40, 40, 0 ),
                                                   0, 0, AContainer::CO_MIN );
    lv->setHBarState( 2 );
    lv->setVBarState( 2 );

    std::list<std::string> cats = Worker::getBookmarkDBInstance().getCats();
    const std::map<std::string, WConfig::ColorDef::label_colors_t> labels = wconfig->getColorDefs().getLabelColors();
    std::map<std::string, WConfig::ColorDef::label_colors_t>::const_iterator label_it;

    for ( label_it = labels.begin(); label_it != labels.end(); ++label_it ) {
        if ( std::find( cats.begin(), cats.end(),
                        label_it->first ) == cats.end() ) {
            cats.push_back( label_it->first );
        }
    }
    if ( std::find( cats.begin(), cats.end(),
                    m_label ) == cats.end() ) {
        cats.push_back( m_label );
    }
    for ( std::list<std::string>::iterator it1 = cats.begin();
          it1 != cats.end();
          ++it1 ) {
        int row = lv->addRow();
        lv->setText( row, 0, *it1 );
        lv->setPreColors( row, FieldListView::PRECOLOR_ONLYACTIVE );
    }
    lv->resize( lv->getWidth(), 6 * aguix->getCharHeight() );
    ac1_3->readLimits();

    label_sg = (StringGadget*)ac1_3->add( new StringGadget( aguix, 0, 0, 100, m_label.c_str(), 0 ),
                                          0, 1, AContainer::CO_INCW );
  
    AContainer *ac1_5 = ac1->add( new AContainer( win, 2, 1 ), 0, 3 );
    ac1_5->setMinSpace( 5 );
    ac1_5->setMaxSpace( -1 );
    ac1_5->setBorderWidth( 0 );
    okb = (Button*)ac1_5->add( new Button( aguix,
                                           0,
                                           0,
                                           catalog.getLocale( 11 ),
                                           0 ), 0, 0, AContainer::CO_FIX );
    cancelb = (Button*)ac1_5->add( new Button( aguix,
                                               0,
                                               0,
                                               catalog.getLocale( 8 ),
                                               0 ), 1, 0, AContainer::CO_FIX );
    win->contMaximize( true );
    
    win->setDoTabCycling( 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 == cancelb ) endmode = 1;
                    break;
                case AG_KEYPRESSED:
                    if ( win->isParent( msg->key.window, false ) == true ) {
                        switch ( msg->key.key ) {
                            case XK_Return:
                                if ( cancelb->getHasFocus() == true ) {
                                    endmode = 1;
                                } else {
                                    endmode=0;
                                }
                                break;
                            case XK_Escape:
                                endmode = 1;
                                break;
                        }
                    }
                    break;
                case AG_FIELDLV_ONESELECT:
                case AG_FIELDLV_MULTISELECT:
                    if ( msg->fieldlv.lv == lv ) {
                        int row = lv->getActiveRow();
                        if ( lv->isValidRow( row ) == true ) {
                            label_sg->setText( lv->getText( row, 0 ).c_str() );
                        }
                    }
                    break;
            }
            aguix->ReplyMessage( msg );
        }
    }
    
    if ( endmode == 0 ) {
        // ok
        if ( ask_cb != NULL ) m_ask_for_label = ask_cb->getState();
        setLabel( label_sg->getText() );
    }
    delete win;

    return endmode;
}

void ChangeLabelOp::setAskForLabel( bool nv )
{
    m_ask_for_label = nv;
}

void ChangeLabelOp::setLabel( const std::string &nv )
{
    m_label = nv;
}
