 /*
 *  This file is part of the Trinity Help Center
 *
 *  Copyright (C) 1999 Matthias Elter (me@kde.org)
 *                2001 Stephan Kulow (coolo@kde.org)
 *
 *  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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "mainwindow.h"

#include "history.h"
#include "view.h"
#include "searchengine.h"
#include "fontdialog.h"
#include "prefs.h"

#include <tdeapplication.h>
#include <tdeconfig.h>
#include <dcopclient.h>
#include <kiconloader.h>
#include <kmimemagic.h>
#include <krun.h>
#include <tdeaboutdata.h>
#include <kdebug.h>
#include <tdehtmlview.h>
#include <tdehtml_settings.h>
#include <tdeaction.h>
#include <kstatusbar.h>
#include <tdestdaccel.h>
#include <kdialogbase.h>

#include <tqsplitter.h>
#include <tqtextedit.h>
#include <tqlayout.h>

#include <stdlib.h>
#include <assert.h>

using namespace KHC;

class LogDialog : public KDialogBase
{
  public:
    LogDialog( TQWidget *parent = 0 )
      : KDialogBase( Plain, i18n("Search Error Log"), Ok, Ok, parent, 0,
                     false )
    {
      TQFrame *topFrame = plainPage();

      TQBoxLayout *topLayout = new TQVBoxLayout( topFrame );

      mTextView = new TQTextEdit( topFrame );
      mTextView->setTextFormat( LogText );
      topLayout->addWidget( mTextView );

      resize( configDialogSize( "logdialog" ) );
    }

    ~LogDialog()
    {
      saveDialogSize( "logdialog" );
    }

    void setLog( const TQString &log )
    {
      mTextView->setText( log );
    }

  private:
    TQTextEdit *mTextView;
};


MainWindow::MainWindow()
    : TDEMainWindow(0, "MainWindow"), DCOPObject( "KHelpCenterIface" ),
      mLogDialog( 0 )
{
    mSplitter = new TQSplitter( this );

    mDoc = new View( mSplitter, 0, this, 0, TDEHTMLPart::DefaultGUI, actionCollection() );
    connect( mDoc, TQ_SIGNAL( setWindowCaption( const TQString & ) ),
             TQ_SLOT( setCaption( const TQString & ) ) );
    connect( mDoc, TQ_SIGNAL( setStatusBarText( const TQString & ) ),
             TQ_SLOT( statusBarMessage( const TQString & ) ) );
    connect( mDoc, TQ_SIGNAL( onURL( const TQString & ) ),
             TQ_SLOT( statusBarMessage( const TQString & ) ) );
    connect( mDoc, TQ_SIGNAL( started( TDEIO::Job * ) ),
             TQ_SLOT( slotStarted( TDEIO::Job * ) ) );
    connect( mDoc, TQ_SIGNAL( completed() ),
             TQ_SLOT( documentCompleted() ) );
    connect( mDoc, TQ_SIGNAL( searchResultCacheAvailable() ),
             TQ_SLOT( enableLastSearchAction() ) );

    connect( mDoc, TQ_SIGNAL( selectionChanged() ),
             TQ_SLOT( enableCopyTextAction() ) );

    statusBar()->insertItem(i18n("Preparing Index"), 0, 1);
    statusBar()->setItemAlignment(0, AlignLeft | AlignVCenter);

    connect( mDoc->browserExtension(),
             TQ_SIGNAL( openURLRequest( const KURL &,
                                     const KParts::URLArgs & ) ),
             TQ_SLOT( slotOpenURLRequest( const KURL &,
                                       const KParts::URLArgs & ) ) );

    mNavigator = new Navigator( mDoc, mSplitter, "nav" );
    connect( mNavigator, TQ_SIGNAL( itemSelected( const TQString & ) ),
             TQ_SLOT( viewUrl( const TQString & ) ) );
    connect( mNavigator, TQ_SIGNAL( glossSelected( const GlossaryEntry & ) ),
             TQ_SLOT( slotGlossSelected( const GlossaryEntry & ) ) );

    mSplitter->moveToFirst(mNavigator);
    mSplitter->setResizeMode(mNavigator, TQSplitter::KeepSize);
    setCentralWidget( mSplitter );
    TQValueList<int> sizes;
    sizes << 220 << 580;
    mSplitter->setSizes(sizes);
    setGeometry(366, 0, 800, 600);

    TDEConfig *cfg = tdeApp->config();
    {
      TDEConfigGroupSaver groupSaver( cfg, "General" );
      if ( cfg->readBoolEntry( "UseKonqSettings", true ) ) {
        TDEConfig konqCfg( "konquerorrc" );
        const_cast<TDEHTMLSettings *>( mDoc->settings() )->init( &konqCfg );
      }
      const int zoomFactor = cfg->readNumEntry( "Font zoom factor", 100 );
      mDoc->setZoomFactor( zoomFactor );
    }

    setupActions();

    actionCollection()->addDocCollection( mDoc->actionCollection() );

    setupGUI(ToolBar | Keys | StatusBar | Create);
    setAutoSaveSettings();

    History::self().installMenuBarHook( this );

    connect( &History::self(), TQ_SIGNAL( goInternalUrl( const KURL & ) ),
             mNavigator, TQ_SLOT( openInternalUrl( const KURL & ) ) );
    connect( &History::self(), TQ_SIGNAL( goUrl( const KURL & ) ),
             mNavigator, TQ_SLOT( selectItem( const KURL & ) ) );

    statusBarMessage(i18n("Ready"));
    enableCopyTextAction();

    readConfig();
}

MainWindow::~MainWindow()
{
    writeConfig();
}

void MainWindow::enableCopyTextAction()
{
    mCopyText->setEnabled( mDoc->hasSelection() );
}

void MainWindow::saveProperties( TDEConfig *config )
{
    kdDebug()<<"void MainWindow::saveProperties( TDEConfig *config )" << endl;
    config->writePathEntry( "URL" , mDoc->baseURL().url() );
}

void MainWindow::readProperties( TDEConfig *config )
{
    kdDebug()<<"void MainWindow::readProperties( TDEConfig *config )" << endl;
    mDoc->slotReload( KURL( config->readPathEntry( "URL" ) ) );
}

void MainWindow::readConfig()
{
    TDEConfig *config = TDEGlobal::config();
    config->setGroup( "MainWindowState" );
    TQValueList<int> sizes = config->readIntListEntry( "Splitter" );
    if ( sizes.count() == 2 ) {
        mSplitter->setSizes( sizes );
    }

    mNavigator->readConfig();
}

void MainWindow::writeConfig()
{
    TDEConfig *config = TDEGlobal::config();
    config->setGroup( "MainWindowState" );
    config->writeEntry( "Splitter", mSplitter->sizes() );

    mNavigator->writeConfig();

    Prefs::writeConfig();
}

void MainWindow::setupActions()
{
    KStdAction::quit( this, TQ_SLOT( close() ), actionCollection() );
    KStdAction::print( this, TQ_SLOT( print() ), actionCollection(),
                       "printFrame" );

    TDEAction *prevPage  = new TDEAction( i18n( "Previous Page" ), CTRL+Key_PageUp, mDoc, TQ_SLOT( prevPage() ),
                         actionCollection(), "prevPage" );
    prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) );

    TDEAction *nextPage  = new TDEAction( i18n( "Next Page" ), CTRL + Key_PageDown, mDoc, TQ_SLOT( nextPage() ),
                         actionCollection(), "nextPage" );
    nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) );

    TDEAction *home = KStdAction::home( this, TQ_SLOT( slotShowHome() ), actionCollection() );
    home->setText(i18n("Table of &Contents"));
    home->setToolTip(i18n("Table of contents"));
    home->setWhatsThis(i18n("Go back to the table of contents"));

    mCopyText = KStdAction::copy( this, TQ_SLOT(slotCopySelectedText()), actionCollection(), "copy_text");

    mLastSearchAction = new TDEAction( i18n("&Last Search Result"), 0, this,
                                     TQ_SLOT( slotLastSearch() ),
                                     actionCollection(), "lastsearch" );
    mLastSearchAction->setEnabled( false );

    new TDEAction( i18n("Build Search Index..."), 0, mNavigator,
      TQ_SLOT( showIndexDialog() ), actionCollection(), "build_index" );
    KStdAction::keyBindings( guiFactory(), TQ_SLOT( configureShortcuts() ),
      actionCollection() );

    TDEConfig *cfg = TDEGlobal::config();
    cfg->setGroup( "Debug" );
    if ( cfg->readBoolEntry( "SearchErrorLog", false ) ) {
      new TDEAction( i18n("Show Search Error Log"), 0, this,
                   TQ_SLOT( showSearchStderr() ), actionCollection(),
                   "show_search_stderr" );
    }

    History::self().setupActions( actionCollection() );

    new TDEAction( i18n( "Configure Fonts..." ), TDEShortcut(), this, TQ_SLOT( slotConfigureFonts() ), actionCollection(), "configure_fonts" );
    new TDEAction( i18n( "Increase Font Sizes" ), "zoom-in", TDEShortcut(), this, TQ_SLOT( slotIncFontSizes() ), actionCollection(), "incFontSizes" );
    new TDEAction( i18n( "Decrease Font Sizes" ), "zoom-out", TDEShortcut(), this, TQ_SLOT( slotDecFontSizes() ), actionCollection(), "decFontSizes" );
}

void MainWindow::slotCopySelectedText()
{
  mDoc->copySelectedText();
}

void MainWindow::print()
{
    mDoc->view()->print();
}

void MainWindow::slotStarted(TDEIO::Job *job)
{
    if (job)
       connect(job, TQ_SIGNAL(infoMessage( TDEIO::Job *, const TQString &)),
               TQ_SLOT(slotInfoMessage(TDEIO::Job *, const TQString &)));

    History::self().updateActions();
}

void MainWindow::goInternalUrl( const KURL &url )
{
  mDoc->closeURL();
  slotOpenURLRequest( url, KParts::URLArgs() );
}

void MainWindow::slotOpenURLRequest( const KURL &url,
                                     const KParts::URLArgs &args )
{
  kdDebug( 1400 ) << "MainWindow::slotOpenURLRequest(): " << url.url() << endl;

  mNavigator->selectItem( url );
  viewUrl( url, args );
}

void MainWindow::viewUrl( const TQString &url )
{
  viewUrl( KURL( url ) );
}

void MainWindow::viewUrl( const KURL &url, const KParts::URLArgs &args )
{
    stop();

    TQString proto = url.protocol().lower();

    if ( proto == "khelpcenter" ) {
      History::self().createEntry();
      mNavigator->openInternalUrl( url );
      return;
    }

    bool own = false;

    if ( proto == "help" || proto == "glossentry" || proto == "about" ||
         proto == "man" || proto == "info" || proto == "cgi" ||
         proto == "ghelp" )
        own = true;
    else if ( url.isLocalFile() ) {
        KMimeMagicResult *res = KMimeMagic::self()->findFileType( url.path() );
        if ( res->isValid() && res->accuracy() > 40
             && res->mimeType() == "text/html" )
            own = true;
    }

    if ( !own ) {
        new KRun( url );
        return;
    }

    History::self().createEntry();

    mDoc->browserExtension()->setURLArgs( args );

    if ( proto == TQString::fromLatin1("glossentry") ) {
        TQString decodedEntryId = KURL::decode_string( url.encodedPathAndQuery() );
        slotGlossSelected( mNavigator->glossEntry( decodedEntryId ) );
        mNavigator->slotSelectGlossEntry( decodedEntryId );
    } else {
        mDoc->openURL( url );
    }
}

void MainWindow::documentCompleted()
{
    kdDebug() << "MainWindow::documentCompleted" << endl;

    History::self().updateCurrentEntry( mDoc );
    History::self().updateActions();
}

void MainWindow::slotInfoMessage(TDEIO::Job *, const TQString &m)
{
    statusBarMessage(m);
}

void MainWindow::statusBarMessage(const TQString &m)
{
    statusBar()->changeItem(m, 0);
}

void MainWindow::openUrl( const TQString &url )
{
    openUrl( KURL( url ) );
}

void MainWindow::openUrl( const TQString &url, const TQCString& startup_id )
{
    TDEStartupInfo::setNewStartupId( this, startup_id );
    openUrl( KURL( url ) );
}

void MainWindow::openUrl( const KURL &url )
{
    if ( url.isEmpty() ) slotShowHome();
    else {
      mNavigator->selectItem( url );
      viewUrl( url );
    }
}

void MainWindow::slotGlossSelected(const GlossaryEntry &entry)
{
    kdDebug() << "MainWindow::slotGlossSelected()" << endl;

    stop();
    History::self().createEntry();
    mDoc->begin( KURL( "help:/khelpcenter/glossary" ) );
    mDoc->write( Glossary::entryToHtml( entry ) );
    mDoc->end();
}

void MainWindow::stop()
{
    kdDebug() << "MainWindow::stop()" << endl;

    mDoc->closeURL();
    History::self().updateCurrentEntry( mDoc );
}

void MainWindow::showHome()
{
    slotShowHome();
}

void MainWindow::slotShowHome()
{
    viewUrl( mNavigator->homeURL() );
    mNavigator->clearSelection();
}

void MainWindow::lastSearch()
{
    slotLastSearch();
}

void MainWindow::slotLastSearch()
{
    mDoc->lastSearch();
}

void MainWindow::enableLastSearchAction()
{
    mLastSearchAction->setEnabled( true );
}

void MainWindow::showSearchStderr()
{
  TQString log = mNavigator->searchEngine()->errorLog();

  if ( !mLogDialog ) {
    mLogDialog = new LogDialog( this );
  }

  mLogDialog->setLog( log );
  mLogDialog->show();
  mLogDialog->raise();
}

void MainWindow::slotIncFontSizes()
{
  mDoc->slotIncFontSizes();
  updateZoomActions();
}

void MainWindow::slotDecFontSizes()
{
  mDoc->slotDecFontSizes();
  updateZoomActions();
}

void MainWindow::updateZoomActions()
{
  actionCollection()->action( "incFontSizes" )->setEnabled( mDoc->zoomFactor() + mDoc->zoomStepping() <= 300 );
  actionCollection()->action( "decFontSizes" )->setEnabled( mDoc->zoomFactor() - mDoc->zoomStepping() >= 20 );

  TDEConfig *cfg = tdeApp->config();
  {
    TDEConfigGroupSaver groupSaver( cfg, "General" );
    cfg->writeEntry( "Font zoom factor", mDoc->zoomFactor() );
    cfg->sync();
  }
}

void MainWindow::slotConfigureFonts()
{
  FontDialog dlg( this );
  if ( dlg.exec() == TQDialog::Accepted )
    mDoc->slotReload();
}

#include "mainwindow.moc"
