
#include "khtml_ext.h"
#include "khtmlview.h"
#include "khtml_pagecache.h"
#include "rendering/render_form.h"
#include "dom/html_form.h"
#include <qapplication.h>
#include <qclipboard.h>
#include <qpopupmenu.h>
#include <qlineedit.h>
#include <qmetaobject.h>

#include <kdebug.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <kio/job.h>
#include <ktoolbarbutton.h>
#include <ktoolbar.h>
#include <ktempfile.h>
#include <ksavefile.h>

#include <dom/dom_element.h>
#include <misc/htmltags.h>

KHTMLPartBrowserExtension::KHTMLPartBrowserExtension( KHTMLPart *parent, const char *name )
: KParts::BrowserExtension( parent, name )
{
    m_part = parent;
    setURLDropHandlingEnabled( true );

    enableAction( "cut", false );
    enableAction( "copy", false );
    enableAction( "paste", false );

    m_connectedToClipboard = false;
}

int KHTMLPartBrowserExtension::xOffset()
{
    return m_part->view()->contentsX();
}

int KHTMLPartBrowserExtension::yOffset()
{
  return m_part->view()->contentsY();
}

void KHTMLPartBrowserExtension::saveState( QDataStream &stream )
{
  kdDebug( 6050 ) << "saveState!" << endl;
  m_part->saveState( stream );
}

void KHTMLPartBrowserExtension::restoreState( QDataStream &stream )
{
  kdDebug( 6050 ) << "restoreState!" << endl;
  m_part->restoreState( stream );
}

void KHTMLPartBrowserExtension::editableWidgetFocused( QWidget *widget )
{
    m_editableFormWidget = widget;
    updateEditActions();

    if ( !m_connectedToClipboard && m_editableFormWidget )
    {
        connect( QApplication::clipboard(), SIGNAL( dataChanged() ),
                 this, SLOT( updateEditActions() ) );

        if ( m_editableFormWidget->inherits( "QLineEdit" ) )
            connect( m_editableFormWidget, SIGNAL( textChanged( const QString & ) ),
                     this, SLOT( updateEditActions() ) );
        else if ( m_editableFormWidget->inherits( "QMultiLineEdit" ) )
            connect( m_editableFormWidget, SIGNAL( textChanged() ),
                     this, SLOT( updateEditActions() ) );

        m_connectedToClipboard = true;
    }
}

void KHTMLPartBrowserExtension::editableWidgetBlurred( QWidget *widget )
{
    QWidget *oldWidget = m_editableFormWidget;

    m_editableFormWidget = widget;
    enableAction( "cut", false );
    enableAction( "paste", false );
    m_part->emitSelectionChanged();

    if ( m_connectedToClipboard )
    {
        disconnect( QApplication::clipboard(), SIGNAL( dataChanged() ),
                    this, SLOT( updateEditActions() ) );

        if ( oldWidget )
        {
            if ( oldWidget->inherits( "QLineEdit" ) )
                disconnect( oldWidget, SIGNAL( textChanged( const QString & ) ),
                            this, SLOT( updateEditActions() ) );
            else if ( oldWidget->inherits( "QMultiLineEdit" ) )
                disconnect( oldWidget, SIGNAL( textChanged() ),
                            this, SLOT( updateEditActions() ) );
        }

        m_connectedToClipboard = false;
    }
}

void KHTMLPartBrowserExtension::setExtensionProxy( KParts::BrowserExtension *proxy )
{
    if ( m_extensionProxy )
        disconnect( m_extensionProxy, SIGNAL( enableAction( const char *, bool ) ),
                    this, SLOT( extensionProxyActionEnabled( const char *, bool ) ) );

    m_extensionProxy = proxy;

    if ( m_extensionProxy )
    {
        connect( m_extensionProxy, SIGNAL( enableAction( const char *, bool ) ),
                 this, SLOT( extensionProxyActionEnabled( const char *, bool ) ) );

        enableAction( "cut", m_extensionProxy->isActionEnabled( "cut" ) );
        enableAction( "copy", m_extensionProxy->isActionEnabled( "copy" ) );
        enableAction( "paste", m_extensionProxy->isActionEnabled( "paste" ) );
    }
    else
    {
        updateEditActions();
        enableAction( "copy", false ); // ### re-check this
    }
}

void KHTMLPartBrowserExtension::cut()
{
    if ( m_extensionProxy )
    {
        callExtensionProxyMethod( "cut()" );
        return;
    }

    ASSERT( m_editableFormWidget );
    if ( !m_editableFormWidget )
        return; // shouldn't happen

    if ( m_editableFormWidget->inherits( "QLineEdit" ) )
        static_cast<QLineEdit *>( &(*m_editableFormWidget) )->cut();
    else if ( m_editableFormWidget->inherits( "QMultiLineEdit" ) )
        static_cast<QMultiLineEdit *>( &(*m_editableFormWidget) )->cut();
}

void KHTMLPartBrowserExtension::copy()
{
    if ( m_extensionProxy )
    {
        callExtensionProxyMethod( "copy()" );
        return;
    }

    kdDebug( 6050 ) << "************! KHTMLPartBrowserExtension::copy()" << endl;
    if ( !m_editableFormWidget )
    {
        // get selected text and paste to the clipboard
        QString text = m_part->selectedText();
        QClipboard *cb = QApplication::clipboard();
        cb->setText(text);
    }
    else
    {
        if ( m_editableFormWidget->inherits( "QLineEdit" ) )
            static_cast<QLineEdit *>( &(*m_editableFormWidget) )->copy();
        else if ( m_editableFormWidget->inherits( "QMultiLineEdit" ) )
            static_cast<QMultiLineEdit *>( &(*m_editableFormWidget) )->copy();
    }
}

void KHTMLPartBrowserExtension::paste()
{
    if ( m_extensionProxy )
    {
        callExtensionProxyMethod( "paste()" );
        return;
    }

    ASSERT( m_editableFormWidget );
    if ( !m_editableFormWidget )
        return; // shouldn't happen

    if ( m_editableFormWidget->inherits( "QLineEdit" ) )
        static_cast<QLineEdit *>( &(*m_editableFormWidget) )->paste();
    else if ( m_editableFormWidget->inherits( "QMultiLineEdit" ) )
        static_cast<QMultiLineEdit *>( &(*m_editableFormWidget) )->paste();
}

void KHTMLPartBrowserExtension::callExtensionProxyMethod( const char *method )
{
    if ( !m_extensionProxy )
        return;

    QMetaData *metaData = m_extensionProxy->metaObject()->slot( method );
    if ( !metaData )
        return;

    KParts::BrowserExtension *ext = static_cast<KParts::BrowserExtension *>( m_extensionProxy );
    (ext->*(metaData->ptr))();
}

void KHTMLPartBrowserExtension::updateEditActions()
{
    if ( !m_editableFormWidget )
    {
        enableAction( "cut", false );
        enableAction( "paste", false );
        return;
    }

    // ### duplicated from KonqMainWindow::slotClipboardDataChanged
    QMimeSource *data = QApplication::clipboard()->data();
    enableAction( "paste", data->provides( "text/plain" ) );

    bool hasSelection = false;

    if ( m_editableFormWidget->inherits( "QLineEdit" ) )
        hasSelection = static_cast<QLineEdit *>( &(*m_editableFormWidget) )->hasMarkedText();
    else if ( m_editableFormWidget->inherits( "khtml::TextAreaWidget" ) )
        hasSelection = static_cast<khtml::TextAreaWidget *>( &(*m_editableFormWidget) )->hasMarkedText();

    enableAction( "copy", hasSelection );
    enableAction( "cut", hasSelection );
}

void KHTMLPartBrowserExtension::extensionProxyActionEnabled( const char *action, bool enable )
{
    // only forward enableAction calls for actions we actually do foward
    if ( strcmp( action, "cut" ) == 0 ||
         strcmp( action, "copy" ) == 0 ||
         strcmp( action, "paste" ) == 0 )
        enableAction( action, enable );
}

void KHTMLPartBrowserExtension::reparseConfiguration()
{
  m_part->reparseConfiguration();
}

void KHTMLPartBrowserExtension::print()
{
  m_part->view()->print();
}

class KHTMLPopupGUIClient::KHTMLPopupGUIClientPrivate
{
public:
  KHTMLPart *m_khtml;
  KURL m_url;
  KURL m_imageURL;
  KAction *m_paPrintFrame;
  KAction *m_paSaveLinkAs;
  KAction *m_paSaveImageAs;
  KAction *m_paCopyLinkLocation;
  KAction *m_paCopyImageLocation;
  KAction *m_paReloadFrame;
  KAction *m_paViewFrameSource;
};


KHTMLPopupGUIClient::KHTMLPopupGUIClient( KHTMLPart *khtml, const QString &doc, const KURL &url )
{
  d = new KHTMLPopupGUIClientPrivate;
  d->m_khtml = khtml;
  d->m_url = url;

  setInstance( khtml->instance() );

  actionCollection()->insert( khtml->actionCollection()->action( "selectAll" ) );
  actionCollection()->insert( khtml->actionCollection()->action( "viewDocumentSource" ) );

  // frameset? -> add "Reload Frame" etc.
  if ( khtml->parentPart() )
  {
    d->m_paReloadFrame = new KAction( i18n( "Reload Frame" ), 0, this, SLOT( slotReloadFrame() ),
                                      actionCollection(), "reloadframe" );
    d->m_paViewFrameSource = new KAction( i18n( "View Frame Source" ), 0, d->m_khtml, SLOT( slotViewDocumentSource() ),
                                          actionCollection(), "viewFrameSource" );
    // This one isn't in khtml_popupmenu.rc anymore, because Print isn't either,
    // and because print frame is already in the toolbar and the menu.
    // But leave this here, so that it's easy to readd it.
    d->m_paPrintFrame = new KAction( i18n( "Print Frame..." ), "fileprint", 0, d->m_khtml->browserExtension(), SLOT( print() ), actionCollection(), "printFrame" );
  }

  actionCollection()->insert( khtml->actionCollection()->action( "setEncoding" ) );

  if ( !url.isEmpty() )
  {
    d->m_paSaveLinkAs = new KAction( i18n( "&Save Link As..." ), 0, this, SLOT( slotSaveLinkAs() ),
                                     actionCollection(), "savelinkas" );
    d->m_paCopyLinkLocation = new KAction( i18n( "Copy Link Location" ), 0, this, SLOT( slotCopyLinkLocation() ),
                                           actionCollection(), "copylinklocation" );
  }

  DOM::Element e;
  e = khtml->nodeUnderMouse();

  if ( !e.isNull() && (e.elementId() == ID_IMG ||
                       (e.elementId() == ID_INPUT && !static_cast<DOM::HTMLInputElement>(e).src().isEmpty())))
  {
    d->m_imageURL = KURL( d->m_khtml->url(), e.getAttribute( "src" ).string() );
    d->m_paSaveImageAs = new KAction( i18n( "Save Image As..." ), 0, this, SLOT( slotSaveImageAs() ),
                                      actionCollection(), "saveimageas" );
    d->m_paCopyImageLocation = new KAction( i18n( "Copy Image Location" ), 0, this, SLOT( slotCopyImageLocation() ),
                                            actionCollection(), "copyimagelocation" );
  }

  setXML( doc );
  setDOMDocument( QDomDocument(), true ); // ### HACK

  QDomElement menu = domDocument().documentElement().namedItem( "Menu" ).toElement();

  if ( actionCollection()->count() > 0 )
    menu.insertBefore( domDocument().createElement( "separator" ), menu.firstChild() );
}

KHTMLPopupGUIClient::~KHTMLPopupGUIClient()
{
  delete d;
}

void KHTMLPopupGUIClient::slotSaveLinkAs()
{
  saveURL( d->m_khtml->widget(), i18n( "Save Link As" ), d->m_url );
}

void KHTMLPopupGUIClient::slotSaveImageAs()
{
  saveURL( d->m_khtml->widget(), i18n( "Save Image As" ), d->m_imageURL );
}

void KHTMLPopupGUIClient::slotCopyLinkLocation()
{
  QApplication::clipboard()->setText( d->m_url.url() );
}

void KHTMLPopupGUIClient::slotCopyImageLocation()
{
  QApplication::clipboard()->setText( d->m_imageURL.url() );
}

void KHTMLPopupGUIClient::slotReloadFrame()
{
  KParts::URLArgs args( d->m_khtml->browserExtension()->urlArgs() );
  args.reload = true;
  // reload document
  d->m_khtml->closeURL();
  d->m_khtml->browserExtension()->setURLArgs( args );
  d->m_khtml->openURL( d->m_khtml->url() );
}

void KHTMLPopupGUIClient::saveURL( QWidget *parent, const QString &caption, const KURL &url, const QString &filter, long cacheId )
{
  KFileDialog *dlg = new KFileDialog( QString::null, filter, parent, "filedia", true );

  dlg->setKeepLocation( true );

  dlg->setCaption( caption );

  if (!url.fileName().isEmpty())
    dlg->setSelection( url.fileName() );
  else
    dlg->setSelection( QString::fromLatin1("index.html") );

  if ( dlg->exec() )
  {
    KURL destURL( dlg->selectedURL() );
    if ( !destURL.isMalformed() )
    {
      bool saved = false;
      if (KHTMLPageCache::self()->isValid(cacheId))
      {
        if (destURL.isLocalFile())
        {
          KSaveFile destFile(destURL.path());
          if (destFile.status() == 0)
          {
            KHTMLPageCache::self()->saveData(cacheId, destFile.dataStream());
            saved = true;
          }
        }
        else
        {
          // save to temp file, then move to final destination.
          KTempFile destFile;
          if (destFile.status() == 0)
          {
            KHTMLPageCache::self()->saveData(cacheId, destFile.dataStream());
            destFile.close();
            KURL url2 = KURL();
            url2.setPath(destFile.name());
            KIO::move(url2, destURL);
            saved = true;
          }
        }
      }
      if(!saved)
      {
        /*KIO::Job *job = */ KIO::copy( url, destURL );
        // TODO connect job result, to display errors
      }
    }
  }

  delete dlg;
}

KHTMLPartBrowserHostExtension::KHTMLPartBrowserHostExtension( KHTMLPart *part )
: KParts::BrowserHostExtension( part )
{
  m_part = part;
}

KHTMLPartBrowserHostExtension::~KHTMLPartBrowserHostExtension()
{
}

QStringList KHTMLPartBrowserHostExtension::frameNames() const
{
  return m_part->frameNames();
}

const QList<KParts::ReadOnlyPart> KHTMLPartBrowserHostExtension::frames() const
{
  return m_part->frames();
}

bool KHTMLPartBrowserHostExtension::openURLInFrame( const KURL &url, const KParts::URLArgs &urlArgs )
{
  return m_part->openURLInFrame( url, urlArgs );
}

KHTMLFontSizeAction::KHTMLFontSizeAction( KHTMLPart *part, bool direction, const QString &text, const QString &icon, const QObject *receiver, const char *slot, QObject *parent, const char *name )
    : KAction( text, icon, 0, receiver, slot, parent, name )
{
    m_direction = direction;
    m_part = part;

    m_popup = new QPopupMenu;
    m_popup->insertItem( i18n( "Default font size" ) );

    int m = m_direction ? 1 : -1;

    for ( int i = 1; i < 5; ++i )
    {
        int num = i * m;
        QString numStr = QString::number( num );
        if ( num > 0 ) numStr.prepend( '+' );

        m_popup->insertItem( i18n( "Font Size %1" ).arg( numStr ) );
    }

    connect( m_popup, SIGNAL( activated( int ) ), this, SLOT( slotActivated( int ) ) );
}

KHTMLFontSizeAction::~KHTMLFontSizeAction()
{
    delete m_popup;
}

int KHTMLFontSizeAction::plug( QWidget *w, int index )
{
    int containerId = KAction::plug( w, index );
    if ( containerId == -1 || !w->inherits( "KToolBar" ) )
        return containerId;

    KToolBarButton *button = static_cast<KToolBar *>( w )->getButton( menuId( containerId ) );
    if ( !button )
        return containerId;

    button->setDelayedPopup( m_popup );
    return containerId;
}

void KHTMLFontSizeAction::slotActivated( int id )
{
    int idx = m_popup->indexOf( id );

    if ( idx == 0 )
        m_part->setFontBaseInternal( 0, true );
    else
        m_part->setFontBaseInternal( idx * ( m_direction ? 1 : -1 ), false );
}

using namespace KParts;
#include "khtml_ext.moc"

