/* wconfig_directory_presets.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2019-2023 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 "wconfig_directory_presets.hh"
#include "wconfig.h"
#include "worker.h"
#include "worker_locale.h"
#include "aguix/fieldlistview.h"
#include "aguix/button.h"
#include "aguix/choosebutton.h"
#include "aguix/cyclebutton.h"
#include "aguix/acontainerbb.h"
#include "aguix/stringgadget.h"
#include "datei.h"
#include "nwc_path.hh"
#include "verzeichnis.hh"
#include <iostream>

DirectoryPresetsPanel::DirectoryPresetsPanel( AWindow &basewin, WConfig &baseconfig ) : WConfigPanel( basewin, baseconfig )
{
}

DirectoryPresetsPanel::~DirectoryPresetsPanel()
{
}

int DirectoryPresetsPanel::create()
{
    Panel::create();

    AContainer *ac1 = setContainer( new AContainer( this, 1, 5 ), true );
    ac1->setMinSpace( 5 );
    ac1->setMaxSpace( 5 );

    addMultiLineText( catalog.getLocale( 1335 ),
                      *ac1,
                      0, 0,
                      NULL, NULL );

    m_lv =(FieldListView*)ac1->add( new FieldListView( _aguix, 0, 0, 100, 100, 0 ), 0, 1, AContainer::CO_MIN );
    m_lv->setHBarState(2);
    m_lv->setVBarState(2);
    m_lv->setAcceptFocus( true );
    m_lv->setDisplayFocus( true );
    m_lv->connect( this );

    AContainer *ac1_1 = ac1->add( new AContainer( this, 2, 1 ), 0, 2 );
    ac1_1->setMinSpace( 0 );
    ac1_1->setMaxSpace( 0 );
    ac1_1->setBorderWidth( 0 );

    m_addb = (Button*)ac1_1->add( new Button( _aguix, 0, 0, catalog.getLocale( 181 ), 0 ),
                                  0, 0, AContainer::CO_INCW );
    m_addb->connect( this );

    m_delb = (Button*)ac1_1->add( new Button( _aguix, 0, 0, catalog.getLocale( 183 ), 0 ),
                                  1, 0, AContainer::CO_INCW );
    m_delb->connect( this );

    m_sort_cont = (AContainerBB*)ac1->add( new AContainerBB( this, 1, 4 ), 0, 3 );
    m_sort_cont->setMinSpace( 5 );
    m_sort_cont->setMaxSpace( 5 );
    m_sort_cont->setBorderWidth( 5 );

    m_sort_cont->add( new Text( _aguix, 0, 0, catalog.getLocale( 1336 ) ), 0, 0, AContainer::CO_INCWNR );

    AContainer *m_sort_cont_1 = m_sort_cont->add( new AContainer( this, 2, 1 ), 0, 1 );
    m_sort_cont_1->setMinSpace( 5 );
    m_sort_cont_1->setMaxSpace( 5 );
    m_sort_cont_1->setBorderWidth( 0 );
    m_sort_cont_1->add( new Text( _aguix, 0, 0, catalog.getLocale( 1338 ) ), 0, 0, AContainer::CO_FIXNR | AContainer::ACONT_CENTER );

    m_sort_cyb = m_sort_cont_1->addWidget( new CycleButton( _aguix, 0, 0, 100, 0 ), 1, 0, AContainer::CO_INCW );
    m_sort_cyb->addOption( catalog.getLocale( 160 ) );
    m_sort_cyb->addOption( catalog.getLocale( 161 ) );
    m_sort_cyb->addOption( catalog.getLocale( 162 ) );
    m_sort_cyb->addOption( catalog.getLocale( 163 ) );
    m_sort_cyb->addOption( catalog.getLocale( 164 ) );
    m_sort_cyb->addOption( catalog.getLocale( 432 ) );
    m_sort_cyb->addOption( catalog.getLocale( 433 ) );
    m_sort_cyb->addOption( catalog.getLocale( 552 ) );
    m_sort_cyb->addOption( catalog.getLocale( 553 ) );
    m_sort_cyb->addOption( catalog.getLocale( 907 ) );
    m_sort_cyb->addOption( catalog.getLocale( 1240 ) );
    m_sort_cyb->addOption( catalog.getLocale( 1534 ) );
    m_sort_cyb->resize( m_sort_cyb->getMaxSize(),
                        m_sort_cyb->getHeight() );
    m_sort_cyb->connect( this );

    m_reverse_sort_chb = m_sort_cont->addWidget( new ChooseButton( _aguix, 0, 0,
                                                             0,
                                                             catalog.getLocale( 165 ),
                                                             LABEL_LEFT, 0 ), 0, 2, AContainer::CO_INCWNR );
    m_reverse_sort_chb->connect( this );

    AContainer *m_sort_cont_2 = m_sort_cont->add( new AContainer( this, 2, 1 ), 0, 3 );
    m_sort_cont_2->setMinSpace( 5 );
    m_sort_cont_2->setMaxSpace( 5 );
    m_sort_cont_2->setBorderWidth( 0 );
    m_sort_cont_2->add( new Text( _aguix, 0, 0, catalog.getLocale( 353 ) ), 0, 0, AContainer::CO_FIXNR | AContainer::ACONT_CENTER );

    m_dirmode_cyb = m_sort_cont_2->addWidget( new CycleButton( _aguix, 0, 0, 100, 0 ), 1, 0, AContainer::CO_INCW );
    m_dirmode_cyb->addOption( catalog.getLocale( 354 ) );
    m_dirmode_cyb->addOption( catalog.getLocale( 355 ) );
    m_dirmode_cyb->addOption( catalog.getLocale( 356 ) );
    m_dirmode_cyb->resize( m_dirmode_cyb->getMaxSize(),
                           m_dirmode_cyb->getHeight() );
    m_dirmode_cyb->connect( this );

    m_filter_cont = (AContainerBB*)ac1->add( new AContainerBB( this, 1, 5 ), 0, 4 );
    m_filter_cont->setMinSpace( 5 );
    m_filter_cont->setMaxSpace( 5 );
    m_filter_cont->setBorderWidth( 5 );

    m_filter_cont->add( new Text( _aguix, 0, 0, catalog.getLocale( 1337 ) ), 0, 0, AContainer::CO_INCWNR );

    m_show_hidden_cb = m_filter_cont->addWidget( new ChooseButton( _aguix, 0, 0,
                                                                   0,
                                                                   catalog.getLocale( 357 ),
                                                                   LABEL_RIGHT, 0 ),
                                                 0, 1, AContainer::CO_INCWNR );
    m_show_hidden_cb->connect( this );

    m_filter_cont->add( new Text( _aguix, 0, 0,
                                  catalog.getLocale( 1220 ) ),
                        0, 2, AContainer::CO_INCWNR );

    m_filter_lv = m_filter_cont->addWidget( new FieldListView( _aguix,
                                                               0,
                                                               0,
                                                               100,
                                                               10 * _aguix->getCharHeight(),
                                                               0 ),
                                            0, 3, AContainer::CO_MIN );
    m_filter_lv->setHBarState( 2 );
    m_filter_lv->setVBarState( 2 );
    m_filter_lv->setNrOfFields( 3 );
    m_filter_lv->setFieldWidth( 1, 1 );
    m_filter_lv->setAcceptFocus( true );
    m_filter_lv->setDisplayFocus( true );

    AContainer *filter_cont_2 = m_filter_cont->add( new AContainer( this, 3, 1 ), 0, 4 );
    filter_cont_2->setMinSpace( 0 );
    filter_cont_2->setMaxSpace( 0 );
    filter_cont_2->setBorderWidth( 0 );

    m_newfilter_b = filter_cont_2->addWidget( new Button( _aguix, 0, 0,
                                                          catalog.getLocale( 167 ), 0 ), 0, 0, AContainer::CO_INCW );
    m_newfilter_b->connect( this );
    m_delfilter_b = filter_cont_2->addWidget( new Button( _aguix, 0, 0,
                                                          catalog.getLocale( 1339 ), 0 ), 1, 0, AContainer::CO_INCW );
    m_delfilter_b->connect( this );
    m_editfilter_b = filter_cont_2->addWidget( new Button( _aguix, 0, 0,
                                                           catalog.getLocale( 172 ), 0 ), 2, 0, AContainer::CO_INCW );
    m_editfilter_b->connect( this );

    contMaximize( true );

    m_presets = _baseconfig.getDirectoryPresets();

    for ( auto &e : m_presets ) {
        int row = m_lv->addRow();
        m_lv->setPreColors( row, FieldListView::PRECOLOR_ONLYACTIVE );
        m_lv->setText( row, 0, e.first.c_str() );

        if ( row == 0 ) {
            m_lv->setActiveRow( row );

            updateView( e.first );
        }
    }

    if ( m_lv->getElements() < 1 ) {
        updateView( "" );
    }

    m_lv->redraw();

    return 0;
}

int DirectoryPresetsPanel::saveValues()
{
    if ( m_lv == NULL ) return 1;
  
    std::list< std::string > l;

    int trow = 0;

    while ( m_lv->isValidRow( trow ) == true ) {
        l.push_back( m_lv->getText( trow, 0 ) );
        trow++;
    }

    _baseconfig.setDirectoryPresets( m_presets );

    return 0;
}

void DirectoryPresetsPanel::run( Widget *elem, const AGMessage &msg )
{
    if ( msg.type == AG_BUTTONCLICKED ) {
        if ( msg.button.button == m_addb ) {
            std::string buttonstr = catalog.getLocale( 11 );
            buttonstr += "|";
            buttonstr += catalog.getLocale( 8 );

            char *tstr = NULL;
            char *tstr2 = NULL;

            if ( string_request( catalog.getLocale( 123 ), catalog.getLocale( 1340 ), "", buttonstr.c_str(), &tstr ) == 0 ) {
                if ( strlen( tstr ) > 0 ) {
                    if ( tstr[0] == '/' ) {
                        tstr2 = NWC::Path::handlePath( tstr );

                        if ( m_presets.count( tstr2 ) == 0 ) {
                            int trow = m_lv->addRow();
                            m_lv->setPreColors( trow, FieldListView::PRECOLOR_ONLYACTIVE );
                            m_lv->setText( trow, 0, tstr2 );
                            m_lv->setActiveRow( trow );
                            m_lv->showActive();
                            m_lv->redraw();

                            m_presets[ tstr2 ] = {};

                            updateView( tstr2 );
                        }
                        _freesafe( tstr2 );
                    }
                }
                _freesafe( tstr );
            } else {
                _freesafe( tstr );
            }

            return;
        }
    }

    int row = m_lv->getActiveRow();
    if ( ! m_lv->isValidRow( row ) ) {
        return;
    }

    std::string path = m_lv->getText( row, 0 );
    if ( m_presets.count( path ) == 0 ) {
        return;
    }

    auto &e = m_presets.at( path );

    if ( msg.type == AG_BUTTONCLICKED ) {
        if ( msg.button.button == m_delb ) {
            m_presets.erase( path );
            m_lv->deleteRow( row );
            m_lv->redraw();

            if ( m_lv->isValidRow( row ) ) {
                m_lv->setActiveRow( row );
                updateView( m_lv->getText( row, 0 ) );
            } else if ( m_lv->isValidRow( row - 1 ) ) {
                m_lv->setActiveRow( row - 1 );
                updateView( m_lv->getText( row - 1, 0 ) );
            } else {
                updateView( "" );
            }
        } else if ( msg.button.button == m_newfilter_b ) {
            NM_Filter tfi;
            tfi.setCheck( NM_Filter::EXCLUDE );
          
            if ( configureFilter( tfi ) == 0 ) {
                int trow = m_filter_lv->addRow();
                setLVC4Filter( m_filter_lv, trow, tfi );
                m_filter_lv->setPreColors( trow, FieldListView::PRECOLOR_ONLYACTIVE );
                m_filter_lv->setActiveRow( trow );
                m_filter_lv->showActive();
                e.filters.push_back( tfi );
                m_filter_lv->redraw();
            }
        } else if ( msg.button.button == m_editfilter_b ) {
            int trow = m_filter_lv->getActiveRow();
            if ( m_filter_lv->isValidRow( trow ) ) {
                auto it = e.filters.begin();
                std::advance( it, trow );
                if ( configureFilter( *it ) == 0 ) {
                    setLVC4Filter( m_filter_lv, trow, *it );
                    m_filter_lv->redraw();
                }
            }
        } else if ( msg.button.button == m_delfilter_b ) {
            int trow = m_filter_lv->getActiveRow();
            if ( m_filter_lv->isValidRow( trow ) ) {
                int del_pos = trow;
                auto fil_it1 = e.filters.begin();

                while ( fil_it1 != e.filters.end() && del_pos > 0 ) {
                    fil_it1++;
                    del_pos--;
                }

                if ( fil_it1 != e.filters.end() ) {
                    e.filters.erase( fil_it1 );
                    m_filter_lv->deleteRow( trow );
                    m_filter_lv->redraw();
                }
            }
        }
    } else if ( msg.type == AG_CHOOSECLICKED ) {
        if ( msg.choose.button == m_reverse_sort_chb ) {
            if ( m_reverse_sort_chb->getState() ) {
                e.sortmode |= SORT_REVERSE;
            } else {
                e.sortmode &= ~SORT_REVERSE;
            }
        } else if ( msg.choose.button == m_show_hidden_cb ) {
            e.show_hidden = m_show_hidden_cb->getState() ? true : false;
        }
    } else if ( msg.type == AG_CYCLEBUTTONCLICKED ) {
        if ( msg.cyclebutton.cyclebutton == m_sort_cyb ) {
            switch ( msg.cyclebutton.option ) {
                case 1:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_SIZE;
                    break;
                case 2:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_ACCTIME;
                    break;
                case 3:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_MODTIME;
                    break;
                case 4:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_CHGTIME;
                    break;
                case 5:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_TYPE;
                    break;
                case 6:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_OWNER;
                    break;
                case 7:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_INODE;
                    break;
                case 8:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_NLINK;
                    break;
                case 9:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_PERMISSION;
                    break;
                case 10:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_EXTENSION;
                    break;
                case 11:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_CUSTOM_ATTRIBUTE;
                    break;
                default:
                    e.sortmode = ( e.sortmode & ~0xff ) | SORT_NAME;
                    break;
            }
        } else if ( msg.cyclebutton.cyclebutton == m_dirmode_cyb ) {
            switch ( msg.cyclebutton.option ) {
                case 1:
                    e.sortmode = ( e.sortmode & ~( SORT_DIRLAST | SORT_DIRMIXED ) ) | SORT_DIRLAST;
                    break;
                case 2:
                    e.sortmode = ( e.sortmode & ~( SORT_DIRLAST | SORT_DIRMIXED ) ) | SORT_DIRMIXED;
                    break;
                default:
                    e.sortmode = ( e.sortmode & ~( SORT_DIRLAST | SORT_DIRMIXED ) );
                    break;
            }
        }
    } else if ( msg.type == AG_FIELDLV_ONESELECT ||
                msg.type == AG_FIELDLV_MULTISELECT ) {
        updateView( path );
    }
}

void DirectoryPresetsPanel::updateView( const std::string &path )
{
    if ( m_presets.count( path ) == 0 ) {
        m_sort_cont->hide();
        m_filter_cont->hide();
        return;
    }

    m_sort_cont->show();
    m_filter_cont->show();

    auto &e = m_presets.at( path );

    if ( ( e.sortmode & 0xff ) == SORT_SIZE ) m_sort_cyb->setOption( 1 );
    else if ( ( e.sortmode & 0xff ) == SORT_ACCTIME ) m_sort_cyb->setOption( 2 );
    else if ( ( e.sortmode & 0xff ) == SORT_MODTIME ) m_sort_cyb->setOption( 3 );
    else if ( ( e.sortmode & 0xff ) == SORT_CHGTIME ) m_sort_cyb->setOption( 4 );
    else if ( ( e.sortmode & 0xff ) == SORT_TYPE ) m_sort_cyb->setOption( 5 );
    else if ( ( e.sortmode & 0xff ) == SORT_OWNER ) m_sort_cyb->setOption( 6 );
    else if ( ( e.sortmode & 0xff ) == SORT_INODE ) m_sort_cyb->setOption( 7 );
    else if ( ( e.sortmode & 0xff ) == SORT_NLINK ) m_sort_cyb->setOption( 8 );
    else if ( ( e.sortmode & 0xff ) == SORT_PERMISSION ) m_sort_cyb->setOption( 9 );
    else if ( ( e.sortmode & 0xff ) == SORT_EXTENSION ) m_sort_cyb->setOption( 10 );
    else if ( ( e.sortmode & 0xff ) == SORT_CUSTOM_ATTRIBUTE ) m_sort_cyb->setOption( 11 );
    else m_sort_cyb->setOption( 0 );

    m_reverse_sort_chb->setState( ( ( e.sortmode & SORT_REVERSE ) == SORT_REVERSE ) ? 1 : 0 );

    if ( ( e.sortmode & SORT_DIRLAST ) == SORT_DIRLAST ) m_dirmode_cyb->setOption( 1 );
    else if ( ( e.sortmode & SORT_DIRMIXED ) == SORT_DIRMIXED ) m_dirmode_cyb->setOption( 2 );
    else m_dirmode_cyb->setOption( 0 );

    m_show_hidden_cb->setState( e.show_hidden ? 1 : 0 );

    m_filter_lv->setSize( 0 );

    for ( auto &filter : e.filters ) {
        int trow = m_filter_lv->addRow();
        setLVC4Filter( m_filter_lv, trow, filter );
        m_filter_lv->setPreColors( trow, FieldListView::PRECOLOR_ONLYACTIVE );
    }

    m_filter_lv->redraw();
}

void DirectoryPresetsPanel::setLVC4Filter( FieldListView *filv, int row, NM_Filter &fi )
{
    if ( ! filv ) return;
    if ( ! filv->isValidRow( row ) ) return;

    const char *p = fi.getPattern();
  
    filv->setText( row, 0, ( p != NULL ) ? p : "" );
    if ( fi.getCheck() == 1 ) filv->setText( row, 2, catalog.getLocale( 170 ) );
    else if ( fi.getCheck() == 2 ) filv->setText( row, 2, catalog.getLocale( 171 ) );
    else filv->setText( row, 2, "" );
}

int DirectoryPresetsPanel::configureFilter( NM_Filter &fi )
{
    const char *tstr;

    AWindow *win = new AWindow( _aguix, 10, 10, 10, 10, catalog.getLocale( 172 ), AWindow::AWINDOW_DIALOG );
    win->create();

    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( 93 ) ), 0, 0, AContainer::CO_FIX );

    tstr = fi.getPattern();
    StringGadget *tsg = ac1_1->addWidget( new StringGadget( _aguix, 0, 0, 100,
                                                            ( tstr != NULL ) ? tstr : "", 0 ), 1, 0, AContainer::CO_INCW );

    CycleButton *cyb = ac1->addWidget( new CycleButton( _aguix, 0, 0, 100, 0 ), 0, 1, AContainer::CO_INCW );
    cyb->addOption( catalog.getLocale( 358 ) );
    cyb->addOption( catalog.getLocale( 170 ) );
    cyb->addOption( catalog.getLocale( 171 ) );

    if ( fi.getCheck() == 1 ) cyb->setOption( 1 );
    else if ( fi.getCheck() == 2 ) cyb->setOption( 2 );
    else cyb->setOption( 0 );

    cyb->resize( cyb->getMaxSize(), cyb->getHeight() );

    ac1->readLimits();

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

    tsg->takeFocus();

    AGMessage *msg;
    while ( ( msg = _aguix->GetMessage( NULL ) ) != NULL ) _aguix->ReplyMessage( msg );

    int ende = 0;
    while ( ende ==0 ) {
        msg = _aguix->WaitMessage( win );

        if ( ! msg ) continue;

        if ( msg->type == AG_CLOSEWINDOW ) {
            if ( msg->closewindow.window == win->getWindow() ) ende = -1;
        } else if ( msg->type == AG_BUTTONCLICKED ) {
            if ( msg->button.button == okb ) ende = 1;
            else if ( msg->button.button == cancelb ) ende = -1;
        }

        _aguix->ReplyMessage( msg );
    }

    if ( ende == 1 ) {
        switch ( cyb->getSelectedOption() ) {
            case 1:
                fi.setCheck( NM_Filter::INCLUDE );
                break;
            case 2:
                fi.setCheck( NM_Filter::EXCLUDE );
                break;
            default:
                fi.setCheck( NM_Filter::INACTIVE );
                break;
        }
        fi.setPattern( tsg->getText() );
    }
  
    delete win;

    return ( ende == 1 ) ? 0 : 1;
}
