/* view_command_log_bg.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2022-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 "view_command_log_bg.hh"
#include "listermode.h"
#include "worker_locale.h"
#include "worker.h"
#include "fileentry.hh"
#include "argclass.hh"
#include "nwc_path.hh"
#include "aguix/aguix.h"
#include "aguix/awindow.h"
#include "aguix/text.h"
#include "aguix/fieldlistview.h"
#include "aguix/button.h"
#include <algorithm>
#include <functional>
#include "aguix/textview.h"
#include "worker_time.hh"

ViewCommandLogBG::ViewCommandLogBG( Worker *worker, std::unique_ptr< std::list< FileCommandLog::Entry > > log ) :
    m_worker( worker ),
    m_log( std::move( log ) )
{
}

ViewCommandLogBG::~ViewCommandLogBG()
{
    delete m_win;
}

void ViewCommandLogBG::createWindow()
{
    AGUIX *aguix = Worker::getAGUIX();


    m_win = new AWindow( aguix,
                         10, 10,
                         500, 400,
                         catalog.getLocale( 1410 ),
                         AWindow::AWINDOW_DIALOG );
    m_win->create();

    AContainer *cont0 = m_win->setContainer( new AContainer( m_win, 1, 3 ), true );
    cont0->setMaxSpace( 5 );

    cont0->addWidget( new Text( aguix, 0, 0, catalog.getLocale( 1411 ) ),
                      0, 0, AContainer::CO_INCWNR );

    m_lv = cont0->addWidget( new FieldListView( aguix, 0, 0, 
                                                200, 200, 0 ),
                             0, 1, AContainer::CO_MIN );
    m_lv->setNrOfFields( 3 );
    m_lv->setShowHeader( true );
    m_lv->setFieldText( 0, catalog.getLocale( 1415 ) );
    m_lv->setFieldText( 1, catalog.getLocale( 1319 ) );
    m_lv->setFieldText( 2, catalog.getLocale( 1412 ) );
    m_lv->setHBarState( 2 );
    m_lv->setVBarState( 2 );
    m_lv->setAcceptFocus( true );
    m_lv->setDisplayFocus( true );
    m_lv->setGlobalFieldSpace( 5 );
    m_lv->setDefaultColorMode( FieldListView::PRECOLOR_ONLYACTIVE );

    AContainer *cont10 = cont0->add( new AContainer( m_win, 4, 1 ), 0, 2 );
    cont10->setBorderWidth( 0 );
    cont10->setMinSpace( 5 );
    cont10->setMaxSpace( -1 );
    
    m_gob = cont10->addWidget( new Button( aguix, 0, 0,
                                           catalog.getLocale( 1442 ),
                                           catalog.getLocale( 1413 ),
                                           0 ),
                               0, 0, AContainer::CO_FIX );
    m_clearb = cont10->addWidget( new Button( aguix, 0, 0,
                                              catalog.getLocale( 1414 ),
                                              0 ),
                                  1, 0, AContainer::CO_FIX );
    m_clipboard_b = cont10->addWidget( new Button( aguix, 0, 0,
                                                   catalog.getLocale( 1471 ),
                                                   catalog.getLocale( 1472 ),
                                                   0 ),
                                       2, 0, AContainer::CO_FIX );
    m_closeb = cont10->addWidget( new Button( aguix, 0, 0,
                                              catalog.getLocale( 633 ),
                                              0 ),
                                  3, 0, AContainer::CO_FIX );
   
    m_win->contMaximize( true );
    m_win->setDoTabCycling( true );

    time_t now = time( NULL );

    for ( auto &e : *m_log ) {
        int row = m_lv->addRow();

        m_lv->setText( row, 0, e.m_command );
        m_lv->setText( row, 1, e.m_description );
        m_lv->setText( row, 2, WorkerTime::convert_time_diff_to_string( now - e.m_time ) );
    }

    maximizeWin( aguix, m_win, m_lv, cont0 );
    m_win->show();

    m_lv->takeFocus();

    return;
}

void ViewCommandLogBG::maximizeWin( AGUIX *aguix,
                                    AWindow *win,
                                    FieldListView *lv,
                                    AContainer *cont )
{
    int old_w = lv->getWidth();
    int old_h = lv->getHeight();

    int new_w = lv->getMaximumWidth();
    int new_h = lv->getMaximumHeight();

    if ( new_w <= old_w &&
         new_h <= old_h ) {
        cont->rearrange();
    } else {
        int my_w = new_w + 10;
        int my_h = new_h + 10;

        if ( my_w < 400 ) my_w = 400;
        if ( my_h < 300 ) my_h = 300;

        int rx, ry, rw, rh;

        aguix->getLargestDimensionOfCurrentScreen( &rx, &ry,
                                                   &rw, &rh );

        int mw = rw * 80 / 100;
        int mh = rh * 80 / 100;

        if ( mw < my_w ) {
            my_w = mw;
        }
        if ( mh < my_h ) {
            my_h = mh;
        }

        if ( my_w < new_w ) {
            cont->setMinWidth( my_w, 0, 1 );
        } else {
            cont->setMinWidth( new_w, 0, 1 );
        }
        if ( my_h < new_h ) {
            cont->setMinHeight( my_h, 0, 1 );
        } else {
            cont->setMinHeight( new_h, 0, 1 );
        }
        m_win->contMaximize( true );
    }
}

AWindow *ViewCommandLogBG::getAWindow()
{
    return m_win;
}

void ViewCommandLogBG::handleAGUIXMessage( AGMessage &msg )
{
    int endmode = 0;
    AGUIX *aguix = Worker::getAGUIX();

    switch ( msg.type ) {
        case AG_CLOSEWINDOW:
            if ( msg.closewindow.window == m_win->getWindow() ) endmode = -1;
            break;
        case AG_BUTTONCLICKED:
            if ( msg.button.button == m_gob ) {
                if ( msg.button.state == 1 ) {
                    endmode = 1;
                } else if ( msg.button.state == 2 ) {
                    endmode = 2;
                }
            } else if ( msg.button.button == m_closeb ) {
                endmode = -1;
            } else if ( msg.button.button == m_clearb ) {
                endmode = -2;
            } else if ( msg.button.button == m_clipboard_b ) {
                if ( msg.button.state == 1 ) {
                    copyEntryToClipboard( m_lv->getActiveRow() );
                } else if ( msg.button.state == 2 ) {
                    copyAllToClipboard();
                }
            }
            break;
        case AG_KEYPRESSED:
            if ( msg.key.key == XK_Return ) {
                endmode = 1;
            } else if ( msg.key.key == XK_Escape ) {
                endmode = -1;
            }
            break;
        case AG_FIELDLV_DOUBLECLICK:
            if ( msg.fieldlv.lv == m_lv ) {
                // double click in lv, actual element is unimportant here
                endmode = 1;
            }
            break;
    }

    if ( endmode == 1 || endmode == 2 ) {
        int row = m_lv->getActiveRow();
        if ( m_lv->isValidRow( row ) == true ) {
            auto it = m_log->begin();
            std::advance( it, row );
            if ( it != m_log->end() ) {
                jumpToEntry( it->m_path );
            }
        }
    } else if ( endmode == -2 ) {
        m_worker->clearCommandLog();
    }

    if ( endmode != 0 && endmode != 2 ) {
        aguix->unregisterBGHandler( m_win );
    }
}

void ViewCommandLogBG::jumpToEntry( const std::string &path )
{
    Lister *l1;
    ListerMode *lm1;
    
    l1 = m_worker->getActiveLister();
    if ( l1 == NULL ) {
        return;
    }

    lm1 = l1->getActiveMode();

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

        args.push_back( RefCount< ArgClass >( new StringArg( path ) ) );
        lm1->runCommand( "show_entry", args );
    }
}

void ViewCommandLogBG::copyEntryToClipboard( int row )
{
    if ( ! m_lv->isValidRow( row ) ) return;

    auto it = m_log->begin();
    std::advance( it, row );
    if ( it == m_log->end() ) return;

    AGUIX *aguix = Worker::getAGUIX();
    aguix->copyToClipboard( convertEntryToClipboardString( *it ),
                            AGUIX::CLIPBOARD_BUFFER );
}

void ViewCommandLogBG::copyAllToClipboard()
{
    std::string res;

    if ( m_log->empty() ) return;

    for ( const auto &entry : *m_log ) {
        res += convertEntryToClipboardString( entry );
    }

    AGUIX *aguix = Worker::getAGUIX();
    aguix->copyToClipboard( res,
                            AGUIX::CLIPBOARD_BUFFER );
}

std::string ViewCommandLogBG::convertEntryToClipboardString( const FileCommandLog::Entry &entry ) const
{
    std::string res;

    res += "type:";
    res += entry.m_command;
    res += "\n";

    if ( ! entry.m_src.empty() ) {
        res += "source:";
        res += entry.m_src;
        res += "\n";
        res += "dest:";
        res += entry.m_path;
        res += "\n";
    } else {
        res += "path:";
        res += entry.m_path;
        res += "\n";
    }

    res += "description:";
    res += entry.m_description;
    res += "\n";

    return res;
}

