/* wconfig_filetype.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2006-2014 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_filetype.hh"
#include "wconfig.h"
#include "worker.h"
#include "wcfiletype.hh"
#include "worker_locale.h"
#include "aguix/stringgadget.h"
#include "aguix/button.h"
#include "aguix/fieldlistview.h"
#include "flattypelist.hh"
#include "simplelist.hh"

FiletypePanel::FiletypePanel( AWindow &basewin, WConfig &baseconfig ) : WConfigPanel( basewin, baseconfig )
{
  cutft = NULL;
  l1 = NULL;
  tempconfig = _baseconfig.duplicate();
  allowRemoveUnique = false;
}

FiletypePanel::~FiletypePanel()
{
  if ( cutft != NULL ) delete cutft;
  if ( l1 != NULL ) delete l1;
  delete tempconfig;
}

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

  AContainer *ac1 = setContainer( new AContainer( this, 1, 4 ), true );
  ac1->setMinSpace( 5 );
  ac1->setMaxSpace( 5 );
  
  addMultiLineText( catalog.getLocale( 683 ),
                    *ac1,
                    0, 0,
                    NULL, NULL );

  AContainer *ac1_0 = ac1->add( new AContainer( this, 3, 0 ), 0, 1 );
  ac1_0->setBorderWidth( 0 );
  ac1_0->setMinSpace( 5 );
  ac1_0->setMaxSpace( 5 );

  ac1_0->add( new Text( _aguix, 0, 0, catalog.getLocale( 793 ) ), 0, 0, AContainer::CO_FIX );
  m_filter_sg = (StringGadget*)ac1_0->add( new StringGadget( _aguix, 0, 0, 100, "", 1 ), 1, 0, AContainer::CO_INCW );
  m_filter_sg->connect( this );
  m_clear_filter_b = (Button*)ac1_0->add( new Button( _aguix, 0, 0, catalog.getLocale( 794 ), 0 ), 2, 0, AContainer::CO_FIX );
  m_clear_filter_b->connect( this );

  lv = (FieldListView*)ac1->add( new FieldListView( _aguix, 0, 0, 100, 150, 0 ), 0, 2, AContainer::CO_MIN );
  lv->setHBarState( 2 );
  lv->setVBarState( 2 );
  lv->setAcceptFocus( true );
  lv->setDisplayFocus( true );
  lv->setDefaultColorMode( FieldListView::PRECOLOR_NORMAL );

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

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

  newb = (Button*)ac1_1_1->add( new Button( _aguix, 0, 0, catalog.getLocale( 85 ), 0 ), 0, 0, AContainer::CO_INCW );
  newb->connect( this );
  newchildb = (Button*)ac1_1_1->add( new Button( _aguix, 0, 0, catalog.getLocale( 596 ), 0 ), 1, 0, AContainer::CO_INCW );
  newchildb->connect( this );
  dupb = (Button*)ac1_1_1->add( new Button( _aguix, 0, 0, catalog.getLocale( 86 ), 0 ), 2, 0, AContainer::CO_INCW );
  dupb->connect( this );

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

  editb = (Button*)ac1_1_2->add( new Button( _aguix, 0, 0, catalog.getLocale( 88 ), 0 ), 0, 0, AContainer::CO_INCW );
  editb->connect( this );
  delb = (Button*)ac1_1_2->add( new Button( _aguix, 0, 0, catalog.getLocale( 87 ), 0 ), 1, 0, AContainer::CO_INCW );
  delb->connect( this );

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

  cutb = (Button*)ac1_1_3->add( new Button( _aguix, 0, 0, catalog.getLocale( 598 ), 0 ), 0, 0, AContainer::CO_INCW );
  cutb->connect( this );
  pasteb = (Button*)ac1_1_3->add( new Button( _aguix, 0, 0, catalog.getLocale( 599 ), 0 ), 1, 0, AContainer::CO_INCW );
  pasteb->connect( this );
  pastechildb = (Button*)ac1_1_3->add( new Button( _aguix, 0, 0, catalog.getLocale( 600 ), 0 ), 2, 0, AContainer::CO_INCW );
  pastechildb->connect( this );

  tempconfig->getFiletypes()->sort( WCFiletype::sortfunction, 0 );
  l1 = new FlatTypeList( tempconfig->getFiletypes(), "" );

  l1->buildLV( lv, NULL );

  contMaximize( true );
  return 0;
}

int FiletypePanel::saveValues()
{
  _baseconfig.setFiletypes( tempconfig->getFiletypes() );
  return 0;
}

void FiletypePanel::run( Widget *elem, const AGMessage &msg )
{
  List *filetypes = tempconfig->getFiletypes();
  int row;
  std::string s1;
  WCFiletype *pft;

  if ( _need_recreate == true ) return;

  if ( msg.type == AG_BUTTONCLICKED ) {
    if ( msg.button.button == newb ) {
      WCFiletype *tf1 = new WCFiletype();
      if ( tempconfig->configureFiletype( tf1 ) == true ) {
	filetypes->addElement( tf1 );
	updateConf( filetypes, &l1, lv, tf1 );
      } else {
	delete tf1;
      }
    } else if ( msg.button.button == newchildb ) {
      row = lv->getActiveRow();
      if ( ( lv->isValidRow( row ) == true ) &&
	   ( row < l1->getNrOfEntries() ) ) {
        if ( l1->getEntry( row ).filetype != NULL ) {
	  WCFiletype *tf1 = l1->getEntry( row ).filetype;
	  if( tf1->getinternID() == NORMALTYPE ) {
	    WCFiletype *tf2 = new WCFiletype();
            tf2->setColorMode( WCFiletype::PARENTCOL );
	    if ( tempconfig->configureFiletype( tf2 ) == true ) {
	      tf1->addSubType( tf2 );
	      updateConf( filetypes, &l1, lv, tf2 );
	    } else {
	      delete tf2;
	    }
	  }
	}
      }
    } else if ( msg.button.button == dupb ) {
      row = lv->getActiveRow();
      if ( ( lv->isValidRow( row ) == true ) &&
	   ( row < l1->getNrOfEntries() ) ) {
	if ( l1->getEntry( row ).filetype != NULL ) {
	  WCFiletype *tf1 = l1->getEntry( row ).filetype;
	  WCFiletype *tf2 = tf1->duplicate();
	  tf2->setinternID( NORMALTYPE );
	  pft = l1->findParent( row );
	  if ( pft == NULL ) {
	    // no parent
	    filetypes->addElement( tf2 );
	  } else {
	    pft->addSubType( tf2 );
	  }
	  updateConf( filetypes, &l1, lv, tf2 );
	}
      }
    } else if ( msg.button.button == delb ) {
        std::list< std::pair< WCFiletype *, int > > selected;
        std::set< WCFiletype * > to_delete;
        int max_depth = 0;
        bool rem = true;
        bool ask = false;

        // get all selected and store corresponding depth
        for ( row = 0; row < lv->getElements(); row++ ) {
            if ( lv->getSelect( row ) ) {
                WCFiletype *tf1 = l1->getEntry( row ).filetype;
                int depth = l1->getEntry( row ).depth;

                if ( tf1 ) {
                    selected.push_back( std::make_pair( tf1, depth ) );
                    if ( depth > max_depth ) max_depth = depth;
                }
            }
        }

        // if none are selected, use the active one
        if ( selected.empty() ) {
            row = lv->getActiveRow();
            if ( lv->isValidRow( row ) ) {
                WCFiletype *tf1 = l1->getEntry( row ).filetype;
                int depth = l1->getEntry( row ).depth;

                if ( tf1 ) {
                    selected.push_back( std::make_pair( tf1, depth ) );
                    if ( depth > max_depth ) max_depth = depth;
                }
            }
        }

        // now check for each entry if any of its parent is already
        // inside the list to delete
        // start with top level entries, then go deeper
        for ( int depth = 0; depth <= max_depth; depth++ ) {
            for ( auto &p : selected ) {
                if ( p.second == depth ) {
                    WCFiletype *tft = p.first->getParentType();
                    bool found = false;
                    while ( tft != NULL ) {
                        if ( to_delete.count( tft ) != 0 ) {
                            found = true;
                            break;
                        }
                        tft = tft->getParentType();
                    }

                    if ( ! found ) {
                        if ( p.first->getSubTypeList() != NULL &&
                             p.first->getSubTypeList()->size() > 0 ) {
                            ask = true;
                        }

                        to_delete.insert( p.first );
                    }
                }
            }
        }

        if ( to_delete.size() > 1 ||
             ask ) {
            s1 = catalog.getLocale( 11 );
            s1 += "|";
            s1 += catalog.getLocale( 8 );
            int erg = request( catalog.getLocale( 123 ),
                               catalog.getLocale( 1037 ),
                               s1.c_str() );
            if ( erg != 0 ) rem = false;
        }

        if ( rem ) {
            for ( auto &tf1 : to_delete ) {
                if( ( tf1->getinternID() == NORMALTYPE ) ||
                    ( allowRemoveUnique == true ) ) {
                    pft = tf1->getParentType();
                    if ( pft == NULL ) {
                        // no parent
                        filetypes->removeElement( tf1 );
                    } else {
                        pft->removeSubType( tf1 );
                    }
                    delete tf1;
                }
            }

            updateConf( filetypes, &l1, lv, NULL );
        }
    } else if ( msg.button.button == cutb ) {
      row = lv->getActiveRow();
      if ( ( lv->isValidRow( row ) == true ) &&
	   ( row < l1->getNrOfEntries() ) ) {
	if ( l1->getEntry( row ).filetype != NULL ) {
	  WCFiletype *tf1 = l1->getEntry( row ).filetype;
	  if( ( tf1->getinternID() == NORMALTYPE ) ||
	      ( allowRemoveUnique == true ) ) {
	    pft = l1->findParent( row );
	    if ( pft == NULL ) {
	      // no parent
	      filetypes->removeElement( tf1 );
	    } else {
	      pft->removeSubType( tf1 );
	    }
	    tf1->setParentType( NULL );
	    if ( cutft != NULL ) {
	      delete cutft;
	    }
	    cutft = tf1;
	    
	    updateConf( filetypes, &l1, lv, NULL );
	  }
	}
      }
    } else if ( msg.button.button == pastechildb ) {
      if ( cutft != NULL ) {
	row = lv->getActiveRow();
	if ( ( lv->isValidRow( row ) == true ) &&
	     ( row < l1->getNrOfEntries() ) ) {
	  if ( l1->getEntry( row ).filetype != NULL ) {
	    WCFiletype *tf1 = l1->getEntry( row ).filetype;
	    if( tf1->getinternID() == NORMALTYPE ) {
	      tf1->addSubType( cutft );
	      updateConf( filetypes, &l1, lv, cutft );
	      cutft = NULL;
	    }
	  }
	}
      }
    } else if ( msg.button.button == pasteb ) {
      if ( cutft != NULL ) {
	filetypes->addElement( cutft );
	updateConf( filetypes, &l1, lv, cutft );
	cutft = NULL;
      }
    } else if ( msg.button.button == editb ) {
      row = lv->getActiveRow();
      if ( ( lv->isValidRow( row ) == true ) &&
	   ( row < l1->getNrOfEntries() ) ) {
	if ( l1->getEntry( row ).filetype != NULL ) {
	  WCFiletype *tf1 = l1->getEntry( row ).filetype;
	  if ( tempconfig->configureFiletype( tf1 ) == true ) {
	    updateConf( filetypes, &l1, lv, tf1 );
	  }
	}
      }
    } else if ( msg.button.button == m_clear_filter_b ) {
        row = lv->getActiveRow();

        if ( lv->isValidRow( row ) == true ) {
            updateConf( filetypes, &l1, lv, l1->getEntry( row ).filetype, "" );
        } else {
            updateConf( filetypes, &l1, lv, NULL, "" );
        }
    }
  } else if ( msg.type == AG_STRINGGADGET_CONTENTCHANGE ) {
      if ( msg.stringgadget.sg == m_filter_sg ) {
          row = lv->getActiveRow();
          
          if ( lv->isValidRow( row ) == true ) {
              updateConf( filetypes, &l1, lv, l1->getEntry( row ).filetype, m_filter_sg->getText() );
          } else {
              updateConf( filetypes, &l1, lv, NULL, m_filter_sg->getText() );
          }
      }
  }
}

void FiletypePanel::updateConf( List *filetypes,
				FlatTypeList **flatlist,
				FieldListView *tlv,
				WCFiletype *highlightft,
                                const std::string &filter )
{
  if ( filetypes == NULL ) return;
  if ( flatlist == NULL ) return;
  if ( *flatlist == NULL ) return;
  if ( tlv == NULL ) return;
  
  filetypes->sort( WCFiletype::sortfunction, 0 );
  delete *flatlist;
  *flatlist = new FlatTypeList( filetypes, filter );
  (*flatlist)->buildLV( tlv, highlightft );
  tlv->showActive();
  tlv->redraw();

  if ( filter != m_filter_sg->getText() ) {
      m_filter_sg->setText( filter.c_str() );
  }
}

void FiletypePanel::setAllowRemoveUnique( bool nv )
{
  allowRemoveUnique = nv;
}

WConfigPanel::panel_action_t FiletypePanel::setColors( List *colors )
{
  if ( colors != tempconfig->getColors() ) {
    tempconfig->setColors( colors );
  }

  return PANEL_NOACTION;
}

int FiletypePanel::addFiletypes( List *filetypes,
                                 WConfigPanelCallBack::add_action_t action )
{
  int erg = 0;

  if ( filetypes != NULL && action == WConfigPanelCallBack::DO_IMPORT ) {
    erg = tempconfig->addFiletypes( filetypes );
  }
  _need_recreate = true;
  return erg;
}

void FiletypePanel::executeInitialCommand( const WConfigInitialCommand &cmd )
{
    if ( cmd.type() == WConfigInitialCommand::OPEN_NEW_FILE_TYPE ) {
        List *filetypes = tempconfig->getFiletypes();
        WCFiletype *tf1 = new WCFiletype();

        tf1->setMagicMime( true );
        tf1->setMagicPattern( cmd.getUserData().c_str() );
        tf1->setUseMagic( true );

        if ( tempconfig->configureFiletype( tf1, 2 ) == true ) {
            filetypes->addElement( tf1 );
            updateConf( filetypes, &l1, lv, tf1 );
        } else {
            delete tf1;
        }
    } else if ( cmd.type() == WConfigInitialCommand::SELECT_FILE_TYPE ) {
        List *filetypes = tempconfig->getFiletypes();
        m_filter_sg->setText( cmd.getUserData().c_str() );
        updateConf( filetypes, &l1, lv, NULL, m_filter_sg->getText() );
    }
}
