#include <qapplication.h>
#include <qmessagebox.h>
#include <qfiledialog.h>
#include <kaction.h>
#include <qpixmap.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kapp.h>
#include <ktmainwindow.h>
#include <qiconset.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( "KTMainWindow" ) )
    collection = static_cast<KTMainWindow*>(parent)->actionCollection();

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

  disconnectAction = new KAction( i18n("&Close Connection"),
			       "disconnect",
			       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 );
}

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 );
  }
}

void KRFBCanvas::openURL( const KURL &url )
{
  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 );
}

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

  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" );

  warning( "About to show auth dialog" );

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

void KRFBCanvas::error( const QString &msg )
{
  QMessageBox::warning( this, "Error", msg );

  closeConnection();
}

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

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

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

void KRFBCanvas::saveSnapshot()
{
  QString filename;

  if ( !loggedIn_ )
      return;

  // I'll replace this with KFD when it stops being unstable
  filename = QFileDialog::getOpenFileName( QString::null, "*.png", this );

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

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

  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() ) );
}

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();
}
