/* This file is part of the KDE project
   Copyright (C) 2002-2003 Tim Jansen <tim@tjansen.de>
   Copyright (C) 2003-2004 Nadeem Hasan <nhasan@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; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include <tqregexp.h>
#include <tqtimer.h>

#include <kcombobox.h>
#include <kdebug.h>
#include <klineedit.h>
#include <tdelistview.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kpushbutton.h>

#include "hostpreferences.h"
#include "maindialogwidget.h"

static const TQString DEFAULT_SCOPE = "default";

class UrlListViewItem : public TDEListViewItem
{
  public:
    UrlListViewItem( TQListView *v, const TQString &url, const TQString &host,
        const TQString &protocol, const TQString &type, const TQString &userid,
        const TQString &fullname, const TQString &desc,
        const TQString &serviceid )
      : TDEListViewItem( v, host, i18n( "unknown" ), host, protocol ),
        m_url( url ), m_serviceid( serviceid )
    {
      if ( !type.isNull() )
      {
        //User connects to somebody else's desktop, used for krfb
        if ( type.lower() == "shared" )
          setText( 1, i18n( "Shared Desktop" ) );
        //User connects to desktop that exists only on the network
        else if ( type.lower() == "private" )
          setText( 1, i18n( "Standalone Desktop" ) );
      }
      if ( !desc.isNull() )
        setText( 0, desc );
      if ( ( !userid.isEmpty() ) && ( !fullname.isEmpty() ) )
        setText( 0, TQString( "%1 (%2)" ).arg( fullname ).arg( userid ) );
      else if ( !userid.isNull() )
        setText( 0, userid );
      else if ( !fullname.isNull() )
        setText( 0, fullname );
   }

  TQString url()
  {
    return m_url;
  }
  const TQString& serviceid() const
  {
    return m_serviceid;
  }

  protected:
    TQString m_url;
    TQString m_serviceid;
};

MainDialogWidget::MainDialogWidget( TQWidget *parent, const char *name )
    : MainDialogBase( parent, name ),
      m_scanning( false )
{
  HostPreferences *hp = HostPreferences::instance();
  TQStringList list;

  list  = hp->serverCompletions();
  m_serverInput->completionObject()->setItems( list );
  list = hp->serverHistory();
  m_serverInput->setHistoryItems( list );

  m_searchInput->setTrapReturnKey( true );

  connect( m_browsingView,
      TQ_SIGNAL( selectionChanged( TQListViewItem * ) ),
      TQ_SLOT( itemSelected( TQListViewItem * ) ) );
  connect( m_browsingView,
      TQ_SIGNAL( doubleClicked( TQListViewItem *, const TQPoint &, int ) ),
      TQ_SLOT( itemDoubleClicked( TQListViewItem * ) ) );
  connect( m_scopeCombo,
      TQ_SIGNAL( activated( const TQString & ) ),
      TQ_SLOT( scopeSelected( const TQString & ) ) );
  connect( m_serverInput,
      TQ_SIGNAL( returnPressed( const TQString & ) ),
      TQ_SLOT( rescan() ) );

  bool showBrowse = hp->showBrowsingPanel();
  enableBrowsingArea( showBrowse );

  m_locator_dnssd = new DNSSD::ServiceBrowser(TQStringList::split(',',"_rfb._tcp,_rdp._tcp"),0,DNSSD::ServiceBrowser::AutoResolve);
  connect(m_locator_dnssd,TQ_SIGNAL(serviceAdded(DNSSD::RemoteService::Ptr)),
	  TQ_SLOT(addedService(DNSSD::RemoteService::Ptr)));
  connect(m_locator_dnssd,TQ_SIGNAL(serviceRemoved(DNSSD::RemoteService::Ptr)),
	  TQ_SLOT(removedService(DNSSD::RemoteService::Ptr)));
  m_locator_dnssd->startBrowse();

  adjustSize();
}

MainDialogWidget::~MainDialogWidget()
{
  delete m_locator_dnssd;
}

void MainDialogWidget::save()
{
  HostPreferences *hp = HostPreferences::instance();
  TQStringList list;

  m_serverInput->addToHistory( m_serverInput->currentText() );
  list = m_serverInput->completionObject()->items();
  hp->setServerCompletions( list );
  list = m_serverInput->historyItems();
  hp->setServerHistory( list );

  hp->setShowBrowsingPanel( m_browsingPanel->isVisible() );
}

void MainDialogWidget::setRemoteHost( const TQString &host )
{
  m_serverInput->setEditText( host );
}

TQString MainDialogWidget::remoteHost()
{
  return m_serverInput->currentText();
}

void MainDialogWidget::hostChanged( const TQString &text )
{
  emit hostValid(text.contains(TQRegExp(":[0-9]+$")) ||
                 text.contains(TQRegExp("^vnc:/.+")) ||
                 text.contains(TQRegExp("^rdp:/.+")));
}

void MainDialogWidget::toggleBrowsingArea()
{
    enableBrowsingArea(!m_browsingPanel->isVisible());
}

void MainDialogWidget::enableBrowsingArea( bool enable )
{
  int hOffset = 0;
  if (enable)
  {
    m_browsingPanel->show();
    m_browsingPanel->setMaximumSize(1000, 1000);
    m_browsingPanel->setEnabled(true);
    m_browseButton->setText(m_browseButton->text().replace(">>", "<<"));
  }
  else
  {
    hOffset = m_browsingPanel->height();
    m_browsingPanel->hide();
    m_browsingPanel->setMaximumSize(0, 0);
    m_browsingPanel->setEnabled(false);
    m_browseButton->setText(m_browseButton->text().replace("<<", ">>"));
    int h = minimumSize().height()-hOffset;
    setMinimumSize(minimumSize().width(), (h > 0) ? h : 0);
    resize(width(), height()-hOffset);

    TQTimer::singleShot( 0, parentWidget(), TQ_SLOT( adjustSize() ) );
  }

  if (enable)
    rescan();
}

void MainDialogWidget::itemSelected( TQListViewItem *item )
{
  UrlListViewItem *u = ( UrlListViewItem* ) item;
  TQRegExp rx( "^service:remotedesktop\\.kde:([^;]*)" );
  if ( rx.search( u->url() ) < 0 ) 
    m_serverInput->setCurrentText( u->url());
    else m_serverInput->setCurrentText( rx.cap( 1 ) );
}

void MainDialogWidget::itemDoubleClicked( TQListViewItem *item )
{
  itemSelected( item );
  emit accept();
}

void MainDialogWidget::scopeSelected( const TQString &scope )
{
  TQString s = scope;
  if ( s == i18n( "default" ) )
    s = DEFAULT_SCOPE;

  if ( m_scope == s )
    return;
  m_scope = s;
  rescan();
}

void MainDialogWidget::rescan()
{
  TQStringList scopeList;

  if ( m_scanning )
    return;
  m_scanning = true;
  m_rescanButton->setEnabled( false );
  m_scopeCombo->setEnabled( false );
  if ( !ensureLocatorOpen() )
    return;

  m_browsingView->clear();

  TQString filter;
  if ( !m_searchInput->text().stripWhiteSpace().isEmpty() ) {
    TQString ef = KServiceLocator::escapeFilter(
					       m_searchInput->text().stripWhiteSpace() );
    filter = "(|(|(description=*"+ef+"*)(username=*"+ef+"*))(fullname=*"+ef+"*))";
  }

  if ( !m_locator->findServices( "service:remotedesktop.kde",
				 filter, m_scope ) ) {
    kdWarning() << "Failure in findServices()" << endl;
    errorScanning();
    return;
  }
}

bool MainDialogWidget::ensureLocatorOpen()
{
  if ( m_locator )
    return true;

  m_locator = new KServiceLocator();

  if ( !m_locator->available() ) {
#ifdef HAVE_SLP
    KMessageBox::error( 0,
        i18n( "Browsing the network is not possible. You probably "
              "did not install SLP support correctly." ),
        i18n( "Browsing Not Possible" ), false );
#endif
    return false;
  }

  connect( m_locator, TQ_SIGNAL( foundService( TQString,int ) ),
                      TQ_SLOT( foundService( TQString,int ) ) );
  connect( m_locator, TQ_SIGNAL( lastServiceSignal( bool ) ),
                      TQ_SLOT( lastSignalServices( bool ) ) );
  connect( m_locator, TQ_SIGNAL( foundScopes( TQStringList ) ),
                      TQ_SLOT( foundScopes( TQStringList ) ) );
   return true;
}

void MainDialogWidget::errorScanning()
{
  KMessageBox::error( 0,
      i18n( "An error occurred while scanning the network." ),
      i18n( "Error While Scanning" ), false );
  finishScanning();
}

void MainDialogWidget::finishScanning()
{
  m_rescanButton->setEnabled( true );
  m_scopeCombo->setEnabled( true );
  m_scanning = false;
}

void MainDialogWidget::foundService( TQString url, int )
{
  TQRegExp rx(  "^service:remotedesktop\\.kde:(\\w+)://([^;]+);(.*)$" );

  if ( rx.search( url ) < 0 )
  {
    rx = TQRegExp(  "^service:remotedesktop\\.kde:(\\w+)://(.*)$" );
    if ( rx.search( url ) < 0 )
      return;
  }

  TQMap<TQString,TQString> map;
  KServiceLocator::parseAttributeList( rx.cap( 3 ), map );

  new UrlListViewItem( m_browsingView, url, rx.cap( 2 ), rx.cap( 1 ),
      KServiceLocator::decodeAttributeValue( map[ "type" ] ),
      KServiceLocator::decodeAttributeValue( map[ "username" ] ),
      KServiceLocator::decodeAttributeValue( map[ "fullname" ] ),
      KServiceLocator::decodeAttributeValue( map[ "description" ] ),
      KServiceLocator::decodeAttributeValue( map[ "serviceid" ] ) );
}

void MainDialogWidget::addedService( DNSSD::RemoteService::Ptr service )
{
TQString type = service->type().mid(1,3);
if (type == "rfb") type = "vnc";
TQString url = type+"://"+service->hostName()+":"+TQString::number(service->port());
new UrlListViewItem( m_browsingView, url, service->serviceName(),
     type.upper(),service->textData()["type"],
     service->textData()["u"],service->textData()["fullname"],
     service->textData()["description"],service->serviceName()+service->domain());
}

void MainDialogWidget::removedService( DNSSD::RemoteService::Ptr service )
{
  TQListViewItemIterator it( m_browsingView );
  while ( it.current() ) {
    if ( ((UrlListViewItem*)it.current())->serviceid() == service->serviceName()+service->domain() )
      delete it.current();
      else ++it;
  }
}


void MainDialogWidget::lastSignalServices( bool success )
{
  if ( !success )
  {
    errorScanning();
    return;
  }

  if ( !m_locator->findScopes() )
  {
    kdWarning() << "Failure in findScopes()" << endl;
    errorScanning();
  }
}

void MainDialogWidget::foundScopes( TQStringList scopeList )
{
  int di = scopeList.findIndex( DEFAULT_SCOPE );
  if ( di >= 0 )
    scopeList[ di ] = i18n( "default" );

  int ct = scopeList.findIndex( m_scopeCombo->currentText() );
  m_scopeCombo->clear();
  m_scopeCombo->insertStringList( scopeList );
  if ( ct >= 0 )
    m_scopeCombo->setCurrentItem( ct );
  finishScanning();
}

#include "maindialogwidget.moc"
