#include "view.h"

#include "formatter.h"
#include "history.h"

#include <dom/html_document.h>
#include <dom/html_misc.h>
#include <tdeaction.h>
#include <tdeactioncollection.h>
#include <tdeapplication.h>
#include <kdebug.h>
#include <tdehtml_settings.h>
#include <tdehtmlview.h>
#include <tdelocale.h>
#include <tdepopupmenu.h>
#include <kstandarddirs.h>

#include <tqfileinfo.h>
#include <tqclipboard.h>

using namespace KHC;

View::View( TQWidget *parentWidget, const char *widgetName,
                  TQObject *parent, const char *name, TDEHTMLPart::GUIProfile prof, TDEActionCollection *col )
    : TDEHTMLPart( parentWidget, widgetName, parent, name, prof ), mState( Docu ), mActionCollection(col)
{
    setJScriptEnabled(false);
    setJavaEnabled(false);
    setPluginsEnabled(false);

    mFormatter = new Formatter;
    if ( !mFormatter->readTemplates() ) {
      kdDebug() << "Unable to read Formatter templates." << endl;
    }

    m_zoomStepping = 10;

    connect( this, TQT_SIGNAL( setWindowCaption( const TQString & ) ),
             this, TQT_SLOT( setTitle( const TQString & ) ) );
    connect( this, TQT_SIGNAL( popupMenu( const TQString &, const TQPoint& ) ),
             this, TQT_SLOT( showMenu( const TQString &, const TQPoint& ) ) );
             
    TQString css = langLookup("common/tde-default.css");
    if (!css.isEmpty())
    {
       TQFile css_file(css);
       if (css_file.open(IO_ReadOnly))
       {
          TQTextStream s(&css_file);
          TQString stylesheet = s.read();
          preloadStyleSheet("help:/common/tde-default.css", stylesheet);
       }
    }

    view()->installEventFilter( this );
}

View::~View()
{
  delete mFormatter;
}

void View::copySelectedText()
{
  kapp->clipboard()->setText( selectedText() );
}

bool View::openURL( const KURL &url )
{
    if ( url.protocol().lower() == "about" )
    {
        showAboutPage();
        return true;
    }
    mState = Docu;
    return TDEHTMLPart::openURL( url );
}

void View::saveState( TQDataStream &stream )
{
    stream << mState;
    if ( mState == Docu )
        TDEHTMLPart::saveState( stream );
}

void View::restoreState( TQDataStream &stream )
{
    stream >> mState;
    if ( mState == Docu )
        TDEHTMLPart::restoreState( stream );
    else if ( mState == About )
        showAboutPage();
}

void View::showAboutPage()
{
    TQString file = locate( "data", "khelpcenter/intro.html.in" );
    if ( file.isEmpty() )
        return;

    TQFile f( file );

    if ( !f.open( IO_ReadOnly ) )
    return;

    mState = About;

    emit started( 0 );

    TQTextStream t( &f );

    TQString res = t.read();

    res = res.arg( i18n("Conquer your Desktop!") )
          .arg( langLookup( "khelpcenter/konq.css" ) )
          .arg( langLookup( "khelpcenter/pointers.png" ) )
          .arg( langLookup( "khelpcenter/khelpcenter.png" ) )
          .arg( i18n("Help Center") )
          .arg( langLookup( "khelpcenter/lines.png" ) )
          .arg( i18n( "Welcome to the Trinity Desktop Environment" ) )
          .arg( i18n( "The TDE team welcomes you to user-friendly UNIX-like computing" ) )
          .arg( i18n( "The Trinity Desktop Environment (TDE) is a graphical desktop\n"
                      "environment for UNIX-like workstations. The\n"
                      "Trinity Desktop Environment combines ease of use, contemporary functionality, and\n"
                      "professional graphical design along with the technical advantages of\n"
                      "UNIX-like operating systems." ) )
          .arg( i18n( "What is the Trinity Desktop Environment?" ) )
          .arg( i18n( "Contacting the TDE Project Members" ) )
          .arg( i18n( "Supporting the TDE Project" ) )
          .arg( i18n( "Useful links" ) )
          .arg( i18n( "Getting the most out of TDE" ) )
          .arg( i18n( "General Documentation" ) )
          .arg( i18n( "A Quick Start Guide to the Desktop" ) )
          .arg( i18n( "TDE Users' guide" ) )
          .arg( i18n( "Frequently Asked Questions" ) )
          .arg( i18n( "Basic Applications" ) )
          .arg( i18n( "The Kicker Desktop Panel" ) )
          .arg( i18n( "The Trinity Control Center" ) )
          .arg( i18n( "The Konqueror File manager and Web Browser" ) )
          .arg( langLookup( "khelpcenter/tdelogo2.png" ) );
    begin( KURL( "about:khelpcenter" ) );
    write( res );
    end();
    emit completed();
}

TQString View::langLookup( const TQString &fname )
{
    TQStringList search;

    // assemble the local search paths
    const TQStringList localDoc = TDEGlobal::dirs()->resourceDirs("html");

    // look up the different languages
    for (int id=localDoc.count()-1; id >= 0; --id)
    {
        TQStringList langs = TDEGlobal::locale()->languageList();
        langs.append( "en" );
        langs.remove( "C" );
        TQStringList::ConstIterator lang;
        for (lang = langs.begin(); lang != langs.end(); ++lang)
            search.append(TQString("%1%2/%3").arg(localDoc[id]).arg(*lang).arg(fname));
    }

    // try to locate the file
    TQStringList::Iterator it;
    for (it = search.begin(); it != search.end(); ++it)
    {
        TQFileInfo info(*it);
        if (info.exists() && info.isFile() && info.isReadable())
            return *it;

        // Fall back to the index.docbook for this language if we couldn't find its
        // specific docbook file. If we are not looking up docbook (images,
        // css etc) then look in other languages first.
        if ( ( *it ).endsWith( "docbook" ) )
        {
            TQString file = (*it).left((*it).findRev('/')) + "/index.docbook";
            info.setFile(file);
            if (info.exists() && info.isFile() && info.isReadable())
            {
                return *it;
            }
        }
    }

    return TQString::null;
}

void View::setTitle( const TQString &title )
{
    mTitle = title;
}

void View::beginSearchResult()
{
  mState = Search;

  begin();
  mSearchResult = "";
}

void View::writeSearchResult( const TQString &str )
{
  write( str );
  mSearchResult += str;
}

void View::endSearchResult()
{
  end();
  if ( !mSearchResult.isEmpty() ) emit searchResultCacheAvailable();
}

void View::beginInternal( const KURL &url )
{
  mInternalUrl = url;
  begin();
}

KURL View::internalUrl() const
{
  return mInternalUrl;
}

void View::lastSearch()
{
  if ( mSearchResult.isEmpty() ) return;
 
  mState = Search;
  
  begin();
  write( mSearchResult );
  end();
}

void View::slotIncFontSizes()
{
  setZoomFactor( zoomFactor() + m_zoomStepping );
}

void View::slotDecFontSizes()
{
  setZoomFactor( zoomFactor() - m_zoomStepping );
}

void View::showMenu( const TQString& url, const TQPoint& pos)
{
  TDEPopupMenu* pop = new TDEPopupMenu(view());
  if (url.isEmpty())
  {
    TDEAction *action;
    action = mActionCollection->action("go_home");
    if (action) action->plug(pop);

    pop->insertSeparator();

    action = mActionCollection->action("prevPage");
    if (action) action->plug(pop);
    action = mActionCollection->action("nextPage");
    if (action) action->plug(pop);

    pop->insertSeparator();

    History::self().m_backAction->plug(pop);
    History::self().m_forwardAction->plug(pop);
  }
  else
  {
    pop->insertItem(i18n("Copy Link Address"), this, TQT_SLOT(slotCopyLink()));
    mCopyURL = completeURL(url).url();
  }
	
  pop->exec(pos);
  delete pop;
}

void View::slotCopyLink()
{
  TQApplication::clipboard()->setText(mCopyURL);
}

bool View::prevPage(bool checkOnly)
{
  const DOM::HTMLCollection links = htmlDocument().links();

  // The first link on a page (top-left corner) would be the Prev link.
  const DOM::Node prevLinkNode = links.item( 0 );
  KURL prevURL = urlFromLinkNode( prevLinkNode );
  if (!prevURL.isValid())
    return false;

  if (!checkOnly)
    openURL( prevURL );
  return true;
}

bool View::nextPage(bool checkOnly)
{
  const DOM::HTMLCollection links = htmlDocument().links();

  KURL nextURL;

  // If we're on the first page, the "Next" link is the last link
  if ( baseURL().path().endsWith( "/index.html" ) )
    nextURL = urlFromLinkNode( links.item( links.length() - 1 ) );
  else
    nextURL = urlFromLinkNode( links.item( links.length() - 2 ) );

  if (!nextURL.isValid())
    return false;

  // If we get a mail link instead of a http URL, or the next link points
  // to an index.html page (a index.html page is always the first page
  // there can't be a Next link pointing to it!) there's probably nowhere
  // to go. Next link at all.
  if ( nextURL.protocol() == "mailto" ||
       nextURL.path().endsWith( "/index.html" ) )
    return false;

  if (!checkOnly)
    openURL( nextURL );
  return true;
}

bool View::eventFilter( TQObject *o, TQEvent *e )
{
  if ( e->type() != TQEvent::KeyPress ||
       htmlDocument().links().length() == 0 )
    return TDEHTMLPart::eventFilter( o, e );

  TQKeyEvent *ke = TQT_TQKEYEVENT( e );
  if ( ke->state() & TQt::ShiftButton && ke->key() == Key_Space ) {
    // If we're on the first page, it does not make sense to go back.
    if ( baseURL().path().endsWith( "/index.html" ) )
      return TDEHTMLPart::eventFilter( o, e );

    const TQScrollBar * const scrollBar = view()->verticalScrollBar();
    if ( scrollBar->value() == scrollBar->minValue() ) {
      if (prevPage())
         return true;
    }
  } else if ( ke->key() == Key_Space ) {
    const TQScrollBar * const scrollBar = view()->verticalScrollBar();
    if ( scrollBar->value() == scrollBar->maxValue() ) {
      if (nextPage())
        return true;
    }
  }
  return TDEHTMLPart::eventFilter( o, e );
}

KURL View::urlFromLinkNode( const DOM::Node &n ) const
{
  if ( n.isNull() || n.nodeType() != DOM::Node::ELEMENT_NODE )
    return KURL();

  DOM::Element elem = static_cast<DOM::Element>( n );

  KURL href ( elem.getAttribute( "href" ).string() );
  if ( !href.protocol().isNull() )
    return href;

  TQString path = baseURL().path();
  path.truncate( path.findRev( '/' ) + 1 );
  path += href.url();

  KURL url = baseURL();
  url.setRef( TQString::null );
  url.setEncodedPathAndQuery( path );

  return url;
}

void View::slotReload( const KURL &url )
{
  const_cast<TDEHTMLSettings *>( settings() )->init( kapp->config() );
  KParts::URLArgs args = browserExtension()->urlArgs();
  args.reload = true;
  browserExtension()->setURLArgs( args );
  if ( url.isEmpty() )
    openURL( baseURL() );
  else
    openURL( url );
}

#include "view.moc"
