#include <qapplication.h>
#include <qclipboard.h>
#undef Unsorted // X11 headers
#include <kfiledialog.h>
#include <kaction.h>
#include <qpixmap.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kapp.h>
#include <kmainwindow.h>
#include <knotifyclient.h>
#include <qiconset.h>
#include <kconfig.h>
#include <kmessagebox.h>

#include "kvncauthdlg.h"
#include "kvncconnectdlg.h"
#include "krfbconnection.h"
#include "krfbcanvas.h"
#include "krfboptions.h"
#include "krfbbuffer.h"
#include "krfbcanvas.moc"

KRFBCanvas::KRFBCanvas( QWidget *parent, const char *name )
  : QScrollView( parent, name )
{
  connection_ = new KRFBConnection();
  loggedIn_ = false;
  connect( connection_, SIGNAL( statusChanged( const QString & ) ),
           this, SIGNAL( statusChanged( const QString & ) ) );

  viewport()->setFocusPolicy( QWidget::StrongFocus );
  viewport()->setFocus();

  // get our action collection
  KActionCollection *collection = 0;
  if ( parent && parent->inherits( "KMainWindow" ) )
    collection = static_cast<KMainWindow*>(parent)->actionCollection();

  connectAction = new KAction( i18n("&Open Connection..."),
			       "connect_creating",
			       0,
			       this, SLOT( openConnection() ),
			       collection,
             "open_connection" );

  disconnectAction = new KAction( i18n("&Close Connection"),
			       "connect_no",
			       0,
			       this, SLOT( closeConnection() ),
			       collection,
             "close_connection" );
  disconnectAction->setEnabled( false );

  saveSnapshotAction = new KAction( i18n("&Save Snapshot As..."),
				    "filesave",
				    0,
				    this, SLOT( saveSnapshot() ),
				    collection,
            "save_snapshot" );
  saveSnapshotAction->setEnabled( false );

  recentAction = new KRecentFilesAction( i18n("&Recent Connections"),
					 "connect_established",
					 0,
					 this, SLOT( openURL( const KURL & ) ),
					 collection,
           "recent_connections");

  static QString group = I18N_NOOP( "Recent Connections" );
  KConfigGroupSaver saveGroup( kapp->config(), group );
  recentAction->loadEntries( kapp->config() );
}

KRFBCanvas::~KRFBCanvas()
{
}

void KRFBCanvas::openConnection()
{
  KVNCConnectDlg dlg( connection_, this, "connect dialog" );
  int result = dlg.exec();

  if ( result ) {
    connect( connection_, SIGNAL( error( const QString & ) ),
	     this, SLOT( error( const QString & ) ) );
    connect( connection_, SIGNAL( passwordRequired( KRFBConnection * ) ),
	     this, SLOT( passwordRequired( KRFBConnection * ) ) );
    connect( connection_, SIGNAL( loggedIn() ),
	     this, SLOT( loggedIn() ) );

    QCString host = dlg.hostname().latin1();
    connection_-> connectTo( host, dlg.display() );

    disconnectAction->setEnabled( true );
    connectAction->setEnabled( false );
    recentAction->setEnabled( false );
  }
}

void KRFBCanvas::openURL( const KURL &url )
{
  if ( loggedIn_ ) {
      qWarning( "openURL invoked when logged in\n" );
      return;
  }

  connect( connection_, SIGNAL( error( const QString & ) ),
	   this, SLOT( error( const QString & ) ) );
  connect( connection_, SIGNAL( passwordRequired( KRFBConnection * ) ),
	   this, SLOT( passwordRequired( KRFBConnection * ) ) );
  connect( connection_, SIGNAL( loggedIn() ),
	   this, SLOT( loggedIn() ) );

  QCString host = url.host().latin1();
  int display = url.port();
  if ( url.hasPass() )
    connection_->setPassword( url.pass().latin1() );

  connection_->connectTo( host, display );

  disconnectAction->setEnabled( true );
  connectAction->setEnabled( false );
  recentAction->setEnabled( false );
}

void KRFBCanvas::closeConnection()
{
  disconnectAction->setEnabled( false );
  connectAction->setEnabled( true );
  saveSnapshotAction->setEnabled( false );
  recentAction->setEnabled( true );

  static QString msg = i18n( "Disconnected" );
  emit statusChanged( msg );

  loggedIn_ = false;
  connection_->disconnect();
  connection_ = new KRFBConnection();

  connect( connection_, SIGNAL( statusChanged( const QString & ) ),
           this, SIGNAL( statusChanged( const QString & ) ) );

  viewport()->setMouseTracking( false );
  viewport()->setBackgroundMode( PaletteDark );
  setBackgroundMode( PaletteDark );
  update();
}

void KRFBCanvas::passwordRequired( KRFBConnection *con )
{
  KVNCAuthDialog auth( connection_, this, "login dialog" );

  qWarning( "About to show auth dialog" );

  if ( auth.exec() ) {
    QCString pass = auth.password().latin1();
    con->setPassword( pass );
  }
}

void KRFBCanvas::error( const QString &msg )
{
    emit statusChanged( msg );
    KMessageBox::error( this, msg );
}

void KRFBCanvas::connected()
{
  // Update status bar
  qWarning( "We've got a socket connection" );

  static QString msg = i18n( "Connected to remote host" );
  emit statusChanged( msg );
}

void KRFBCanvas::bell()
{
  KNotifyClient::beep();

  if ( connection_->options()->deIconify ) {
    topLevelWidget()->show();
  }
}

void KRFBCanvas::saveSnapshot()
{
  QString filename;

  if ( !loggedIn_ )
      return;

  filename = KFileDialog::getOpenFileName( QString::null, "*.png", this );

  if ( !filename.isNull() ) {
    connection_->buffer()->pixmap()->save( filename, "PNG" );

    static QString msg = i18n( "Snapshot saved" );
    emit statusChanged( msg );
  }
}

void KRFBCanvas::loggedIn()
{
  qWarning( "Ok, we're logged in" );

  //
  // Manage recent connections list
  //
  recentAction->addURL( connection_->url() );

  static QString group = I18N_NOOP( "Recent Connections" );
  KConfigGroupSaver saveGroup( kapp->config(), group );
  recentAction->saveEntries( kapp->config() );
  kapp->config()->sync();

  //
  // Update the status bar
  //
  static QString msg = i18n( "Logged in to remote host" );
  emit statusChanged( msg );

  //
  // Get ready for action
  //
  loggedIn_ = true;
  viewport()->setMouseTracking( true );
  viewport()->setBackgroundMode( NoBackground );
  setBackgroundMode( NoBackground );
  saveSnapshotAction->setEnabled( true );

  // Start using the buffer
  connect( connection_->buffer(), SIGNAL( sizeChanged( int, int ) ),
           this, SLOT( resizeContents(int,int) ) );
  connect( connection_->buffer(), SIGNAL( updated( int, int, int, int ) ),
           this, SLOT( viewportUpdate(int,int,int,int) ) );
  connect( connection_->buffer(), SIGNAL( bell() ),
           this, SLOT( bell() ) );
  connect( qApp->clipboard(), SIGNAL( dataChanged() ),
           this, SLOT( clipboardChanged() ) );
}

void KRFBCanvas::viewportPaintEvent( QPaintEvent *e )
{
  QRect r = e->rect();

  if ( loggedIn_ ) {
    bitBlt( viewport(), r.x(), r.y(),
	    connection_->buffer()->pixmap(),
	    r.x() + contentsX(), r.y() + contentsY(),
	    r.width(), r.height() );
  }
  else {
    QScrollView::viewportPaintEvent( e );
  }
}

void KRFBCanvas::viewportUpdate( int x, int y, int w, int h )
{
  updateContents( x, y, w, h );
}

void KRFBCanvas::contentsMousePressEvent( QMouseEvent *e )
{
  if ( loggedIn_ )
    connection_->buffer()->mouseEvent( e );
}

void KRFBCanvas::contentsMouseReleaseEvent( QMouseEvent *e )
{
  if ( loggedIn_ )
    connection_->buffer()->mouseEvent( e );
}

void KRFBCanvas::contentsMouseMoveEvent( QMouseEvent *e )
{
  if ( loggedIn_ )
    connection_->buffer()->mouseEvent( e );
}

void KRFBCanvas::keyPressEvent( QKeyEvent *e )
{
  if ( loggedIn_ )
    connection_->buffer()->keyPressEvent( e );
}

void KRFBCanvas::keyReleaseEvent( QKeyEvent *e )
{
  if ( loggedIn_ )
    connection_->buffer()->keyReleaseEvent( e );
}

void KRFBCanvas::refresh()
{
  if ( loggedIn_ )
    connection_->refresh();
}

void KRFBCanvas::clipboardChanged()
{
  if ( loggedIn_ ) {
      connection_->sendCutText( qApp->clipboard()->text() );
  }
}
