#include "worker_requests.hh"
#include "aguix/util.h"
#include "aguix/awindow.h"
#include "aguix/acontainerbb.h"
#include "aguix/button.h"

WorkerRequests::WorkerRequests( AGUIX *aguix, AWindow *twin ) :
    m_aguix( aguix ),
    m_twin( twin )
{
}

static void highlight_path_component_button( std::vector< Button * > path_component_buttons,
                                             ssize_t old_pos,
                                             size_t new_pos )
{
    if ( old_pos >= 0 && old_pos < (ssize_t)path_component_buttons.size() ) {
        path_component_buttons.at( old_pos )->setFG( 0, "button-fg" );
        path_component_buttons.at( old_pos )->setBG( 0, "button-bg" );
    }

    if ( new_pos >= 0 && new_pos < path_component_buttons.size() ) {
        path_component_buttons.at( new_pos )->setFG( 0, "button-special1-fg" );
        path_component_buttons.at( new_pos )->setBG( 0, "button-special1-bg" );
    }
}

WorkerRequests::request_path_component_result WorkerRequests::request_path_component( const std::string &title,
                                                                                      const std::string &text,
                                                                                      const std::string &path,
                                                                                      const std::vector< std::string > &buttons )
{
    std::vector< std::string > components;

    if ( ! m_aguix ) return { -1 };

    AGUIXUtils::split_string( components, path, '/' );

    if ( components.empty() ) return { -1 };
    if ( buttons.empty() ) return { -1 };

    if ( components[0].empty() ) {
        // set explicit slash for absolute paths
        components[0] = "/";
    }

    std::vector< Button * > result_buttons;
    std::vector< Button * > path_component_buttons;
  
    AWindow win = AWindow( m_aguix, 10, 10, 10, 10, title, AWindow::AWINDOW_DIALOG );
    win.create();
    if ( m_twin != NULL ) {
        win.setTransientForAWindow( m_twin );
    } else {
        win.setTransientForAWindow( m_aguix->getTransientWindow() );
    }

    AContainer *ac1 = win.setContainer( new AContainer( &win, 1, 3 ), true );
    ac1->setMinSpace( 0 );
    ac1->setMaxSpace( 0 );
    ac1->setBorderWidth( 5 );

    AContainerBB *ac1_texts = dynamic_cast<AContainerBB*>( ac1->add( new AContainerBB( &win, 1, 1 ), 0, 0 ) );
    ac1_texts->setBorderWidth( 5 );
    win.addMultiLineText( text, *ac1_texts, 0, 0, NULL, NULL );

    AContainer *ac1_path_components = ac1->add( new AContainerBB( &win,
                                                                  components.size() > 1 ? components.size() : 3,
                                                                  1 ),
                                                0, 1 );
    if ( components.size() == 1 ) {
        path_component_buttons.push_back( ac1_path_components->addWidget( new Button( m_aguix, 0, 0, components[0].c_str(), 0 ),
                                                                          1, 0, AContainer::CO_FIX ) );
        ac1_path_components->setMinSpace( 0 );
        ac1_path_components->setMaxSpace( 0 );
    } else {
        for ( size_t i = 0; i < components.size(); i++ ) {
            path_component_buttons.push_back( ac1_path_components->addWidget( new Button( m_aguix, 0, 0,
                                                                                          components[i].empty() ? "/" : components[i].c_str(),
                                                                                          0 ),
                                                                              i, 0, AContainer::CO_FIX ) );
        }
        ac1_path_components->setMinSpace( 5 );
        ac1_path_components->setMaxSpace( -1 );
    }

    AContainer *ac1_result_buttons = NULL;

    if ( buttons.size() == 1 ) {
        ac1_result_buttons = ac1->add( new AContainer( &win, 3, 1 ), 0, 2 );
        ac1_result_buttons->setMinSpace( 0 );
        ac1_result_buttons->setMaxSpace( 0 );

        result_buttons.push_back( ac1_result_buttons->addWidget( new Button( m_aguix, 0, 0, buttons[0].c_str(), 0 ),
                                                                 1, 0, AContainer::CO_FIX ) );
    } else {
        ac1_result_buttons = ac1->add( new AContainer( &win, buttons.size(), 1 ), 0, 2 );
        ac1_result_buttons->setMinSpace( 5 );
        ac1_result_buttons->setMaxSpace( -1 );

        for ( size_t i = 0; i < buttons.size(); i++ ) {
            result_buttons.push_back( ac1_result_buttons->addWidget( new Button( m_aguix, 0, 0, buttons[i].c_str(), 0 ),
                                                                     i, 0, AContainer::CO_FIX ) );
        }
    }
    ac1_result_buttons->setBorderWidth( 0 );

    for ( auto &b : result_buttons ) {
        b->setAcceptFocus( true );
    }

    size_t selected_path_component = path_component_buttons.size() - 1;
    highlight_path_component_button( path_component_buttons, -1, selected_path_component );
 
    win.useStippleBackground();
    win.setDoTabCycling( true );
    win.contMaximize( true );
    win.centerScreen();
    win.show();

    int endmode = -1;

    for ( ; endmode == -1; ) {
        AGMessage *msg = m_aguix->WaitMessage( &win );
        if ( ! msg ) continue;

        switch(msg->type) {
            case AG_CLOSEWINDOW:
                if ( msg->closewindow.window == win.getWindow() ) {
                    endmode = result_buttons.size() - 1;
                }
                break;
            case AG_BUTTONCLICKED:
                for ( size_t i = 0; i < result_buttons.size(); i++ ) {
                    if ( msg->button.button == result_buttons[i] ) {
                        endmode = i;
                        break;
                    }
                }
                for ( size_t i = 0; i < path_component_buttons.size(); i++ ) {
                    if ( msg->button.button == path_component_buttons[i] ) {
                        selected_path_component = i;
                        endmode = 0;
                        break;
                    }
                }
                break;
            case AG_KEYPRESSED:
                if ( win.isParent( msg->key.window, false ) == true ) {
                    // key release only accept when not first key we get
                    // means a key is pressed when we started and if we use this
                    // key it could confuse the user
                    switch(msg->key.key) {
                        case XK_KP_Enter:
                        case XK_Return:
                            for ( size_t i = 0; i < result_buttons.size(); i++ ) {
                                if ( result_buttons[i]->getHasFocus() == true ) {
                                    endmode = i;
                                    break;
                                }
                            }
                            // no button has focus so handle as button 0
                            endmode = 0;
                            break;
                        case XK_Escape:
                            endmode = result_buttons.size() - 1;
                            break;
                        case XK_F1:
                            endmode = 0;
                            break;
                        case XK_F2:
                            endmode = 1;
                            if ( (size_t)endmode >= result_buttons.size() ) endmode = -1;
                            break;
                        case XK_F3:
                            endmode = 2;
                            if ( (size_t)endmode >= result_buttons.size() ) endmode = -1;
                            break;
                        case XK_F4:
                            endmode = 3;
                            if ( (size_t)endmode >= result_buttons.size() ) endmode = -1;
                            break;
                        case XK_F5:
                            endmode = 4;
                            if ( (size_t)endmode >= result_buttons.size() ) endmode = -1;
                            break;
                        case XK_F6:
                            endmode = 5;
                            if ( (size_t)endmode >= result_buttons.size() ) endmode = -1;
                            break;
                        case XK_F7:
                            endmode = 6;
                            if ( (size_t)endmode >= result_buttons.size() ) endmode = -1;
                            break;
                        case XK_F8:
                            endmode = 7;
                            if ( (size_t)endmode >= result_buttons.size() ) endmode = -1;
                            break;
                        case XK_F9:
                            endmode = 8;
                            if ( (size_t)endmode >= result_buttons.size() ) endmode = -1;
                            break;
                        case XK_F10:
                            endmode = 9;
                            if ( (size_t)endmode >= result_buttons.size() ) endmode = -1;
                            break;
                        case XK_Left:
                            if ( selected_path_component > 0 ) {
                                highlight_path_component_button( path_component_buttons, selected_path_component, selected_path_component - 1 );
                                selected_path_component--;
                            }
                            break;
                        case XK_Right:
                            if ( selected_path_component + 1 < path_component_buttons.size() ) {
                                highlight_path_component_button( path_component_buttons, selected_path_component, selected_path_component + 1 );
                                selected_path_component++;
                            }
                            break;
                    }
                }
                break;
        }
        m_aguix->ReplyMessage(msg);
    }

    std::string result;

    for ( size_t i = 0; i <= selected_path_component; i++ ) {
        if ( i > 0 && result != "/" ) {
            // add slashes but skip if the first path component was
            // already a slash
            result += "/";
        }
        result += components[i];
    }

    return { endmode, result };
}
