/* 
 *  Copyright (C) 1999 Bernd Gehrmann
 *                     bernd@physik.hu-berlin.de
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the "Artistic License" which comes with this Kit. 
 *
 * 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
 * Artistic License for more details.
 *
 * You should have received a copy of the Artistic License with 
 * this Kit, in the file named "Artistic".  If not, I'll be glad
 * to provide one.
 */


#include <qlineedit.h>
#include <qcheckbox.h>
#include <qpushbutton.h>
#include <qlistbox.h>
#include <qlayout.h>
#include <qsizepolicy.h>
#include <qgroupbox.h>

#include <kbuttonbox.h>
#include <kapp.h>
#include <kprocess.h>
#include <klocale.h>

#include "toplevel.h"


class ResultView : public QListBox
{
public:
    ResultView(QWidget *parent, const char *name=0)
        : QListBox(parent, name) {}
protected:
    virtual QSize minimumSizeHint() const
        { return QSize(0, fontMetrics().lineSpacing()*8); }
    virtual QSize sizeHint() const
        { return QSize(0, fontMetrics().lineSpacing()*8); }
    virtual QSizePolicy sizePolicy () const  
        { return QSizePolicy(QSizePolicy::MinimumExpanding,
                             QSizePolicy::MinimumExpanding); }
};


TopLevel::TopLevel() {
  setCaption(i18n("Search Files"));

  QWidget *mainwidget = new QWidget( this );
  layout = new QVBoxLayout(mainwidget, 10, 4);

  QGridLayout *grid = new QGridLayout(3, 4, 4);
  layout->addLayout(grid, 2);
  grid->setColStretch(0, 0);
  grid->setColStretch(1, 10);
  grid->setColStretch(2, 0);
  grid->addColSpacing(2, 10);

  layout->addSpacing(20);
  dirlabel = new QLabel(i18n("Where:"), mainwidget);
  grid->addWidget(dirlabel, 0, 0);

  diredit = new QLineEdit(mainwidget);
  diredit->setFocus();
  grid->addWidget(diredit, 0, 1);

  subdirsbox = new QCheckBox(i18n("Search in subdirectories"), mainwidget);
  subdirsbox->setChecked(true);
  grid->addWidget(subdirsbox, 1, 1);

  mountedbox = new QCheckBox(i18n("Descend into mounted file systems"), mainwidget);
  grid->addWidget(mountedbox, 2, 1);

  KButtonBox *buttonbox = new KButtonBox(mainwidget, KButtonBox::Vertical);
  searchbutton = buttonbox->addButton(i18n("&Search"));
  searchbutton->setDefault(true);
  connect( searchbutton, SIGNAL(clicked()), SLOT(slotSearch()) );

  cancelbutton = buttonbox->addButton(i18n("Cancel"));
  connect( cancelbutton, SIGNAL(clicked()), SLOT(slotCancel()) );
  cancelbutton->setEnabled(false);
  buttonbox->layout();
  grid->addMultiCellWidget(buttonbox, 0, 2, 3, 3);

  groupbox = new QGroupBox(mainwidget);

  criteria.append(new Criterion(groupbox));

  layout->addWidget(groupbox, 2);

  KButtonBox *morelessbox = new KButtonBox(mainwidget, KButtonBox::Horizontal);
  morelessbox->addStretch();
  morebutton = morelessbox->addButton(i18n("More criteria"));
  lessbutton = morelessbox->addButton(i18n("Fewer criteria"));
  lessbutton->setEnabled(false);
  morelessbox->addStretch();
  connect(morebutton, SIGNAL(clicked()), SLOT(slotMore()));
  connect(lessbutton, SIGNAL(clicked()), SLOT(slotLess()));
  morelessbox->layout();
  layout->addWidget(morelessbox, 2);

  foundlabel = new QLabel(i18n("Found:"), mainwidget);
  layout->addWidget(foundlabel, 2);

  resultbox = new ResultView(mainwidget);
  layout->addWidget(resultbox, 15);

  childproc = 0;

  setCentralWidget( mainwidget );
  grouplayout = 0;
  updateLayout();
}


TopLevel::~TopLevel() {
  delete childproc;
}


void TopLevel::updateLayout() {
  lessbutton->setEnabled(criteria.count() != 1);

  delete grouplayout;
  grouplayout = new QVBoxLayout(groupbox, 15, 4);

  QListIterator<Criterion> it(criteria);
  for (; it.current(); ++it) {
    grouplayout->addWidget(it.current(), 5);
  }
  grouplayout->activate();
  layout->activate();
}


void TopLevel::slotMore() {
  Criterion *crit = new Criterion(groupbox);
  crit->show();
  criteria.append(crit);
  updateLayout();
}


void TopLevel::slotLess() {
  Criterion *crit = criteria.last();
  delete crit;
  criteria.removeRef(crit);
  updateLayout();
}


void TopLevel::processOutput() {
  int pos;
  while ( (pos = buf.find('\n')) != -1) {
    QString item = buf.left(pos);
    if (!item.isEmpty()) {
      resultbox->insertItem(item);
    }
    buf = buf.right(buf.length()-pos-1);
  }
    
  foundlabel->setText(i18n("Found %1 matches").arg(resultbox->count()));
}


void TopLevel::slotSearch() {
  searchbutton->setEnabled(false);
  cancelbutton->setEnabled(true);

  QString cmd = "find ";
  cmd += diredit->text();
  cmd += " ";
  if (!subdirsbox->isChecked()) {
    cmd += "-maxdepth 1 ";
  }
  if (!mountedbox->isChecked()) {
    cmd += "-mount ";
  }

  QListIterator<Criterion> it(criteria);
  for (; it.current(); ++it) {
    cmd += it.current()->findString();
    cmd += " ";
  }
  qDebug( "Findstring: %s", cmd.ascii() );
#if 1
  childproc = new KShellProcess();
  *childproc << cmd;

  connect( childproc, SIGNAL(processExited(KProcess *)),
	   SLOT(childExited()) );
  connect( childproc, SIGNAL(receivedStdout(KProcess *, char *, int)),
	   SLOT(receivedOutput(KProcess *, char *, int)) );
  childproc->start(KProcess::NotifyOnExit, KProcess::Stdout);
    
#endif
}


void TopLevel::finish() {
  searchbutton->setEnabled(true);
  cancelbutton->setEnabled(false);

  buf += '\n';
  processOutput();
  delete childproc;
  childproc = 0;
}


void TopLevel::slotCancel() {
  finish();
}


void TopLevel::childExited() {
  int status = childproc->exitStatus();
    
  finish();

  QString msg = (
	   (status == 1)? i18n("No matches found")
	   : (status == 2)? i18n("Syntax error in pattern")
	   : i18n("Ready") );
  qDebug( msg );
}


void TopLevel::receivedOutput(KProcess*, char *buffer, int buflen) {
  buf += QString::fromLatin1( buffer, buflen+1 );
  processOutput();
}
