/* wconfig_button.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2006-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_button.hh"
#include "wconfig.h"
#include "worker.h"
#include "aguix/acontainerbb.h"
#include "aguix/button.h"
#include "aguix/solidbutton.h"
#include "aguix/cyclebutton.h"
#include "aguix/fieldlistview.h"
#include "wcbutton.hh"
#include "worker_locale.h"
#include "simplelist.hh"

ButtonPanel::ButtonPanel( AWindow &basewin, WConfig &baseconfig ) : WConfigPanel( basewin, baseconfig )
{
  banknr = 0;
  bbs = NULL;
  rows = _baseconfig.getRows();
  columns = _baseconfig.getColumns();

  banksize = rows * columns * 2;
  maxbank = _baseconfig.getButtons()->size() / banksize;

  extmode = false;
  m_mode = 0;
  selindex = -1;
}

ButtonPanel::~ButtonPanel()
{
  for ( int i = 0; i < (int)( rows * columns ); i++ ) {
    delete [] bbs[i];
  }
  delete [] bbs;
}

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

  int i;
  unsigned int i2;
  
  AContainer *ac1 = setContainer( new AContainer( this, 1, 6 ), true );
  ac1->setMinSpace( 5 );
  ac1->setMaxSpace( 5 );
  
  AContainerBB *ac1_1[2];
  AContainer *ac1_1_1[2];
  
  bbs = new Button**[rows*columns];
  for ( i = 0; i < (int)( rows * columns ); i++ ) {
    bbs[i] = new Button*[2];
  }
  for(int k=0;k<2;k++) {
    ac1_1[k] = static_cast<AContainerBB*>( ac1->add( new AContainerBB( this, 1, 2 ), 0, k ) );
    ac1_1[k]->setMinSpace( 5 );
    ac1_1[k]->setMaxSpace( 5 );
    ac1_1[k]->add( new Text( _aguix, 0, 0, catalog.getLocale( 51 + k ) ),
                   0, 0, AContainer::CO_INCWNR );
    ac1_1_1[k] = ac1_1[k]->add( new AContainer( this, columns, rows ), 0, 1 );
    ac1_1_1[k]->setMinSpace( 0 );
    ac1_1_1[k]->setMaxSpace( 0 );
    ac1_1_1[k]->setBorderWidth( 0 );
    for(i2=0;i2<rows;i2++) {
      for(unsigned int j=0;j<columns;j++) {
        bbs[i2*columns+j][k] = (Button*)ac1_1_1[k]->add( new Button( _aguix,
                                                                     0,
                                                                     0,
                                                                     20,
                                                                     "",
                                                                     2 * ( i2 * columns + j ) + k ),
                                                         j, i2, AContainer::CO_INCW );
        bbs[i2*columns+j][k]->connect( this );
      }
    }
  }

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

  ac1_2->add( new Text( _aguix, 0, 0, catalog.getLocale( 68 ) ), 0, 0, AContainer::CO_FIX );
  bnrt = (Text*)ac1_2->add( new Text( _aguix, 0, 0, "   " ), 1, 0, AContainer::CO_FIX );
  ac1_2->add( new Text( _aguix, 0, 0, "/" ), 2, 0, AContainer::CO_FIX );
  maxbankt = (Text*)ac1_2->add( new Text( _aguix, 0, 0, "   " ), 3, 0, AContainer::CO_FIX );

  nextbb = (Button*)ac1_2->add( new Button( _aguix, 0, 0,
                                            catalog.getLocale( 69 ), 0 ),
                                4, 0, AContainer::CO_INCW );
  nextbb->connect( this );
  prevbb = (Button*)ac1_2->add( new Button( _aguix, 0, 0,
                                            catalog.getLocale( 70 ), 0 ),
                                5, 0, AContainer::CO_INCW );
  prevbb->connect( this );
  newbb = (Button*)ac1_2->add( new Button( _aguix, 0, 0,
                                           catalog.getLocale( 71 ), 0 ),
                               6, 0, AContainer::CO_INCW );
  newbb->connect( this );
  delbb = (Button*)ac1_2->add( new Button( _aguix, 0, 0,
                                           catalog.getLocale( 72 ), 0 ),
                               7, 0, AContainer::CO_INCW );
  delbb->connect( this );
  swapnextb = (Button*)ac1_2->add( new Button( _aguix, 0, 0,
                                               catalog.getLocale( 571 ), 0 ),
                                   8, 0, AContainer::CO_INCW );
  swapnextb->connect( this );
  swapprevb = (Button*)ac1_2->add( new Button( _aguix, 0, 0,
                                               catalog.getLocale( 572 ), 0 ),
                                   9, 0, AContainer::CO_INCW );
  swapprevb->connect( this );
  sbsb = (SolidButton*)ac1->add( new SolidButton( _aguix,
                                                  0,
                                                  0,
                                                  10,
                                                  "",
                                                  "button-special1-fg", "button-special1-bg",
                                                  false ),
                                 0, 3, AContainer::CO_INCW );

  AContainer *ac1_3 = ac1->add( new AContainer( this, 2, 1 ), 0, 4 );
  ac1_3->setMinSpace( 5 );
  ac1_3->setMaxSpace( 5 );
  ac1_3->setBorderWidth( 0 );
  ac1_3->add( new Text( _aguix, 0, 0, catalog.getLocale( 227 ) ), 0, 0, AContainer::CO_FIX );
  cyb = new CycleButton( _aguix, 0, 0, 100, 0 );
  cyb->addOption( catalog.getLocale( 228 ) );
  cyb->addOption( catalog.getLocale( 229 ) );
  cyb->resize( cyb->getMaxSize(), cyb->getHeight() );

  ac1_3->add( cyb, 1, 0, AContainer::CO_INCW );
  if ( extmode == true ) cyb->setOption( 1 );
  else cyb->setOption( 0 );
  
  cyb->connect( this );
  
  AContainer *ac1_4 = ac1->add( new AContainer( this, 3, 1 ), 0, 5 );
  ac1_4->setMinSpace( 0 );
  ac1_4->setMaxSpace( 0 );
  ac1_4->setBorderWidth( 0 );
  copyb = (Button*)ac1_4->add( new Button( _aguix, 0, 0, catalog.getLocale( 48 ), 0 ),
                               0, 0, AContainer::CO_INCW );
  copyb->connect( this );
  swapb = (Button*)ac1_4->add( new Button( _aguix, 0,
                                                   0, catalog.getLocale( 49 ), 0 ),
                                       1, 0, AContainer::CO_INCW );
  swapb->connect( this );
  delb = (Button*)ac1_4->add( new Button( _aguix, 0,
                                                  0, catalog.getLocale( 50 ), 0 ),
                                      2, 0, AContainer::CO_INCW );
  delb->connect( this );
  contMaximize( true );
  updateBankStr();
  sbsb->setText( catalog.getLocale( 53 ) );
  showButtonBank();

  addKeyCallBack( this, AWindow::KEYCB_WHENVISIBLE );
  return 0;
}

int ButtonPanel::saveValues()
{
  return 0;
}

void ButtonPanel::showButtonBank()
{
  WCButton *b1;
  int id= _baseconfig.getButtons()->initEnum();
  if((banknr>=0)&&(banknr<(_baseconfig.getButtons()->size()/(banksize)))) {
    for(unsigned int i=0;i<rows;i++) {
      for(unsigned int j=0;j<columns;j++) {
        b1=(WCButton*)_baseconfig.getButtons()->getElementAt(id,banknr*banksize+i*columns*2+j*2);
        if((b1!=NULL)&&(b1->getCheck()==true)) {
          bbs[i*columns+j][0]->setText(0,b1->getText());
          bbs[i*columns+j][0]->setFG(0,b1->getFG());
          bbs[i*columns+j][0]->setBG(0,b1->getBG());
        } else {
          bbs[i*columns+j][0]->setText(0,"");
          bbs[i*columns+j][0]->setFG(0,1);
          bbs[i*columns+j][0]->setBG(0,0);
        }
        b1=(WCButton*)_baseconfig.getButtons()->getNextElement(id);
        if((b1!=NULL)&&(b1->getCheck()==true)) {
          bbs[i*columns+j][1]->setText(0,b1->getText());
          bbs[i*columns+j][1]->setFG(0,b1->getFG());
          bbs[i*columns+j][1]->setBG(0,b1->getBG());
        } else {
          bbs[i*columns+j][1]->setText(0,"");
          bbs[i*columns+j][1]->setFG(0,1);
          bbs[i*columns+j][1]->setBG(0,0);
        }
      }
    }
  }
  _baseconfig.getButtons()->closeEnum(id);
}

void ButtonPanel::run( Widget *elem, const AGMessage &msg )
{
  List *buttons = _baseconfig.getButtons();

  if ( _need_recreate == true ) return;

  if ( msg.type == AG_BUTTONCLICKED ) {
    if ( msg.button.button == nextbb ) {
      if ( ( banknr + 1 ) < maxbank ) {
        banknr++;
        showButtonBank();
        updateBankStr();
      }
    } else if ( msg.button.button == prevbb ) {
      if ( banknr > 0 ) {
        banknr--;
        showButtonBank();
        updateBankStr();
      }
    } else if ( msg.button.button == newbb ) {
      int s2 = ( banknr + 1 ) * banksize;
      for ( int i = 0; i < banksize; i++ ) {
        buttons->addElementAt( s2, new WCButton() );
      }
      maxbank++;
      banknr++;
      showButtonBank();
      updateBankStr();
    } else if ( msg.button.button == delbb ) {
      if ( maxbank > 1 ) {
        int s2 = banknr * banksize;
        WCButton *b1;

        for ( int i = 0; i < banksize; i++ ) {
          b1 = (WCButton*)buttons->getElementAt( s2 );
          delete b1;
          buttons->removeElementAt( s2 );
        }
        maxbank--;
        if ( banknr >= maxbank ) {
          banknr--;
        }
        updateBankStr();
        showButtonBank();
      }
    } else if ( msg.button.button == swapnextb ) {
      if ( ( banknr + 1 ) < maxbank ) {
        int delpos = ( banknr + 1 ) * banksize;
        int delta = ( - banksize );
        WCButton *b1;
        
        for ( int i = 0; i < banksize; i++ ) {
          b1 = (WCButton*)buttons->getElementAt( delpos + i );
          if ( b1 == NULL ) break;
          buttons->removeElementAt( delpos + i );
          buttons->addElementAt( delpos + i + delta, b1 );
        }
        banknr++;
        showButtonBank();
        updateBankStr();
      }
    } else if ( msg.button.button == swapprevb ) {
      if ( banknr > 0 ) {
        int delpos = banknr * banksize;
        int delta = ( - banksize );
        WCButton *b1;
        
        for ( int i = 0; i < banksize; i++ ) {
          b1 = (WCButton*)buttons->getElementAt( delpos + i );
          if ( b1 == NULL ) break;
          buttons->removeElementAt( delpos + i );
          buttons->addElementAt( delpos + i + delta, b1 );
        }
        banknr--;
        showButtonBank();
        updateBankStr();
      }
    } else if ( msg.button.button == copyb ) {
      if ( ( m_mode == 1 ) || ( m_mode == 2 ) ) {
        sbsb->setText( catalog.getLocale( 53 ) );
        setMode( 0 );
      } else {
        sbsb->setText( catalog.getLocale( 54 ) );
        setMode( 1 );
      }
    } else if ( msg.button.button == swapb ) {
      if ( ( m_mode == 3 ) || ( m_mode == 4 ) ) {
        sbsb->setText( catalog.getLocale( 53 ) );
        setMode( 0 );
      } else {
        sbsb->setText( catalog.getLocale( 56 ) );
        setMode( 3 );
      }
    } else if ( msg.button.button == delb ) {
      if ( m_mode == 5 ) {
        sbsb->setText( catalog.getLocale( 53 ) );
        setMode( 0 );
      } else {
        sbsb->setText( catalog.getLocale( 58 ) );
        setMode( 5 );
      }
    } else {
      int t1, t2, t3;
      
      t1 = msg.button.button->getData();
      if ( t1 >= 0 ) {
        t2 = t1 & 1;
        t3 = t1 / 2;
        if ( bbs[t3][t2] == msg.button.button ) {
          int s1 = t1 + banknr * banksize;
          WCButton *b1, *b2;
          switch ( m_mode ) {
            case 1:
              selindex = s1;
              sbsb->setText( catalog.getLocale( 55 ) );
              setMode( 2 );
              break;
            case 2:
              // copy selindex -> s1
              b1 = (WCButton*)buttons->getElementAt( selindex );
              b2 = b1->duplicate();
              // reset shortkey to avoid duplicates
              b2->setDoubleKeys( NULL );
              
              b1 = (WCButton*)buttons->exchangeElement( s1, b2 );
              if ( b1 != NULL ) delete b1;
              showButtonBank();
              if ( extmode == true ) {
                sbsb->setText( catalog.getLocale( 54 ) );
                setMode( 1 );
              } else {
                sbsb->setText( catalog.getLocale( 53 ) );
                setMode( 0 );
              }
              break;
            case 3:
              selindex = s1;
              sbsb->setText( catalog.getLocale( 57 ) );
              setMode( 4 );
              break;
            case 4:
              // swap s1 <-> selindex
              b1 = (WCButton*)buttons->getElementAt( selindex );
              b2 = (WCButton*)buttons->exchangeElement( s1, b1 );
              buttons->exchangeElement( selindex, b2 );
              showButtonBank();
              if ( extmode == true ) {
                sbsb->setText( catalog.getLocale( 56 ) );
                setMode( 3 );
              } else {
                sbsb->setText( catalog.getLocale( 53 ) );
                setMode( 0 );
              }
              break;
            case 5:
              // del s1
              b1 = new WCButton();
              b2 = (WCButton*)buttons->exchangeElement( s1, b1 );
              if ( b2 != NULL ) delete b2;
              showButtonBank();
              if ( extmode == false ) {
                sbsb->setText( catalog.getLocale( 53 ) );
                setMode( 0 );
              }
              break;
            default:
              // configure s1
              b1 = (WCButton*)buttons->getElementAt( s1 );
              if ( b1 != NULL ) {
                if ( _baseconfig.configureButtonIndex( s1 ) == true ) {
                  msg.button.button->setText( 0, b1->getText() );
                  msg.button.button->setFG( 0, b1->getFG() );
                  msg.button.button->setBG( 0, b1->getBG() );
                }
              }
          }
        }
      }
    }
  } else if ( msg.type == AG_CYCLEBUTTONCLICKED ) {
    if ( msg.cyclebutton.cyclebutton == cyb ) {
      if ( msg.cyclebutton.option == 1 ) extmode = true;
      else extmode = false;
    }
  } else if ( msg.type == AG_KEYPRESSED ) {
    if ( msg.key.key == XK_Escape ) {
      sbsb->setText( catalog.getLocale( 53 ) );
      setMode( 0 );
    }
  }
}

WConfigPanel::panel_action_t ButtonPanel::setColors( List *colors )
{
  if ( colors != _baseconfig.getColors() ) {
    _baseconfig.setColors( colors );
  }

  return PANEL_NOACTION;
}

WConfigPanel::panel_action_t ButtonPanel::setRows( int r )
{
  if ( r != (int)_baseconfig.getRows() ) {
    _baseconfig.setRows( r );
  }
  _need_recreate = true;
  return PANEL_RECREATE;
}

WConfigPanel::panel_action_t ButtonPanel::setColumns( int c )
{
  if ( c != (int)_baseconfig.getColumns() ) {
    _baseconfig.setColumns( c );
  }
  _need_recreate = true;
  return PANEL_RECREATE;
}

int ButtonPanel::addButtons( List *buttons,
                             WConfigPanelCallBack::add_action_t action )
{
  int erg = 0;

  if ( buttons != NULL && action == WConfigPanelCallBack::DO_IMPORT ) {
    erg = _baseconfig.addButtons( buttons );
  }
  _need_recreate = true;
  return erg;
}

int ButtonPanel::addHotkeys( List *hotkeys,
                             WConfigPanelCallBack::add_action_t action )
{
  int erg = 0;

  if ( hotkeys != NULL && action == WConfigPanelCallBack::CHECK_DOUBLEKEYS ) {
    erg = _baseconfig.fixDoubleKeys( _baseconfig.getButtons(), NULL, NULL, NULL, hotkeys );
  }
  _need_recreate = true;
  return erg;
}

void ButtonPanel::updateBankStr()
{
  char bankstr[ A_BYTESFORNUMBER( int ) ];

  sprintf( bankstr, "%2d", banknr + 1 );
  bnrt->setText( bankstr );
  sprintf( bankstr, "%2d", maxbank );
  maxbankt->setText( bankstr );
}

bool ButtonPanel::escapeInUse()
{
    // return current value and check if mode is still in use
    bool res = m_escape_active;

    if ( m_mode == 0 ) m_escape_active = false;

    return res;
}

void ButtonPanel::setMode( int m )
{
    if ( m != 0 ) m_escape_active = true;
    m_mode = m;
}
