/***************************************************************************
    smb4kipaddressscanner  -  This class scans for IP addresses. It
    belongs to the core classes of Smb4K.
                             -------------------
    begin                : Di Apr 22 2008
    copyright            : (C) 2008 by Alexander Reinholdt
    email                : dustpuppy@users.berlios.de
 ***************************************************************************/

/***************************************************************************
 *   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; if not, write to the                         *
 *   Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,   *
 *   MA  02111-1307 USA                                                    *
 ***************************************************************************/

// KDE includes
#include <kglobal.h>
#include <kdebug.h>
#include <kshell.h>

// application specific includes
#include <smb4kipaddressscanner.h>
#include <smb4kglobal.h>
#include <smb4khost.h>
#include <smb4ksambaoptionshandler.h>
#include <smb4khost.h>
#include <smb4kworkgroup.h>
#include <smb4kcoremessage.h>

using namespace Smb4KGlobal;

class Smb4KIPAddressScannerPrivate
{
  public:
    /**
     * The Smb4KIPAddressScanner instance
     */
    Smb4KIPAddressScanner instance;
};


K_GLOBAL_STATIC( Smb4KIPAddressScannerPrivate, m_priv );


Smb4KIPAddressScanner::Smb4KIPAddressScanner() : QObject()
{
  m_auto_scan = false;
  m_timer_id = -1;
  m_process_error = (QProcess::ProcessError)(-1);
  m_working = false;

  m_proc = new KProcess( this );

  connect( m_proc, SIGNAL( readyReadStandardOutput() ),
           this,   SLOT( slotReceivedIPAddresses() ) );

  connect( m_proc, SIGNAL( finished( int, QProcess::ExitStatus ) ),
           this,   SLOT( slotProcessFinished( int, QProcess::ExitStatus ) ) );

  connect( m_proc, SIGNAL( error( QProcess::ProcessError ) ),
           this,   SLOT( slotProcessError( QProcess::ProcessError ) ) );
}


Smb4KIPAddressScanner::~Smb4KIPAddressScanner()
{
}


Smb4KIPAddressScanner *Smb4KIPAddressScanner::self()
{
  return &m_priv->instance;
}


void Smb4KIPAddressScanner::triggerScan()
{
  if ( m_auto_scan )
  {
    return;
  }

  if ( m_working )
  {
    // We will start a timer (if necessary), that is
    // used to check if the scan process ended and then
    // starts the lookup process.
    if ( m_timer_id == -1 )
    {
      m_timer_id = startTimer( timerInterval() );
    }
    else
    {
      // Do nothing
    }
  }
  else
  {
    // Immediately start the lookup process.
    lookupIPAddresses();
  }
}


void Smb4KIPAddressScanner::setAutoScan( int interval )
{
  if ( interval != 0 )
  {
    if ( m_timer_id != -1 )
    {
      killTimer( m_timer_id );

      m_timer_id = -1;
    }
    else
    {
      // Do nothing
    }

    m_timer_id = startTimer( interval );
  }
  else
  {
    killTimer( m_timer_id );

    m_timer_id = -1;
  }
}


void Smb4KIPAddressScanner::getIPAddress( Smb4KHost *host )
{
  if ( host )
  {
    // Lookup the host in the global host list and emit the
    // IP address, if the host is present the ipChecked()
    // function returns true.
    Smb4KHost *knownHost = findHost( host->name(), host->workgroup() );

    if ( knownHost )
    {
      if ( knownHost->ipChecked() )
      {
        // Copy the IP address and emit the ipAddress() signal.
        host->setIP( knownHost->ip() );
        emit ipAddress( host );
      }
      else
      {
        // Do nothing. This will be done by the scanner
        // automatically.
      }
    }
    else
    {
      m_queue.append( *host );
    }
  }
  else
  {
    // Do nothing
  }

  triggerScan();
}


void Smb4KIPAddressScanner::timerEvent( QTimerEvent */*e*/ )
{
  if ( !m_working )
  {
    if ( !m_auto_scan )
    {
      // Kill the timer, because it served its purpose.
      killTimer( m_timer_id );
      m_timer_id = -1;
    }
    else
    {
      // Do nothing
    }

    lookupIPAddresses();
  }
  else
  {
    // Do nothing
  }
}


void Smb4KIPAddressScanner::lookupIPAddresses()
{
  m_working = true;

  QString command = QString();

  // First process the buffered entries in the queue.
  if ( !m_queue.isEmpty() )
  {
    for ( int i = 0; i < m_queue.size(); ++i )
    {
      command.append( "nmblookup" );
      command.append( Smb4KSambaOptionsHandler::self()->nmblookupOptions() );
      command.append( Smb4KSambaOptionsHandler::self()->winsServer().isEmpty() ? "" : " -R -U "
                      +KShell::quoteArg( Smb4KSambaOptionsHandler::self()->winsServer() ) );
      command.append( " -- "+KShell::quoteArg( m_queue.at( i ).name() )+" | grep '<00>'" );
      command.append( " ; " );
    }
  }
  else
  {
    for ( int i = 0; i < hostsList()->size(); ++i )
    {
      if ( !hostsList()->at( i )->ipChecked() )
      {
        command.append( "nmblookup" );
        command.append( Smb4KSambaOptionsHandler::self()->nmblookupOptions() );
        command.append( Smb4KSambaOptionsHandler::self()->winsServer().isEmpty() ? "" : " -R -U "
                        +KShell::quoteArg( Smb4KSambaOptionsHandler::self()->winsServer() ) );
        command.append( " -- "+KShell::quoteArg( Smb4KGlobal::hostsList()->at( i )->name() )+" | grep '<00>'" );
        command.append( " ; " );

        continue;
      }
      else
      {
        continue;
      }
    }
  }

  command.truncate( command.length() - 3 );

  if ( !command.isEmpty() )
  {
    m_proc->setShellCommand( command );
    m_proc->setOutputChannelMode( KProcess::SeparateChannels );
    m_proc->start();
  }
  else
  {
    m_working = false;
  }
}


/////////////////////////////////////////////////////////////////////////////
// SLOT IMPLEMENTATIONS
/////////////////////////////////////////////////////////////////////////////

void Smb4KIPAddressScanner::slotReceivedIPAddresses()
{
  QString buffer = QString::fromLocal8Bit( m_proc->readAllStandardOutput(), -1 );

  if ( !buffer.trimmed().isEmpty() )
  {
    QString host_ip   = buffer.trimmed().section( " ", 0, 0 ).trimmed();
    QString host_name = buffer.trimmed().section( " ", 1, 1 ).section( "<00>", 0, 0 ).trimmed();

    if ( !host_name.isEmpty() && !host_ip.isEmpty() )
    {
      if ( !m_queue.isEmpty() )
      {
        Smb4KHost host;

        for ( int i = 0; i < m_queue.size(); ++i )
        {
          if ( QString::compare( m_queue.at( i ).name(), host_name, Qt::CaseInsensitive ) == 0 )
          {
            // Take the host from the list. Never remove or delete it here!
            host = m_queue.takeAt( i );

            break;
          }
          else
          {
            continue;
          }
        }

        host.setIP( host_ip );

        emit ipAddress( &host );
      }
      else
      {
        Smb4KHost *host = findHost( host_name );

        if ( host )
        {
          host->setIP( host_ip );

          if ( host->isMasterBrowser() )
          {
            Smb4KWorkgroup *workgroup = findWorkgroup( host->workgroup() );

            if ( workgroup )
            {
              workgroup->setMasterBrowserIP( host_ip );
            }
            else
            {
              // Do nothing
            }
          }
          else
          {
            // Do nothing
          }

          emit ipAddress( host );
        }
        else
        {
          // Do nothing
        }
      }
    }
    else
    {
      // Do nothing
    }
  }
  else
  {
    // Do nothing
  }
}


void Smb4KIPAddressScanner::slotProcessFinished( int /*exitCode*/, QProcess::ExitStatus exitStatus )
{
  if ( exitStatus == QProcess::NormalExit )
  {
    m_proc->clearProgram();
  }
  else
  {
    if ( m_process_error != -1 )
    {
      Smb4KCoreMessage::processError( ERROR_PROCESS_ERROR, m_process_error );
    }
    else
    {
      Smb4KCoreMessage::processError( ERROR_PROCESS_EXIT, m_process_error );
    }
  }

  m_process_error = (QProcess::ProcessError)(-1);
  m_working = false;
}


void Smb4KIPAddressScanner::slotProcessError( QProcess::ProcessError errorCode )
{
  m_process_error = errorCode;
}

#include <smb4kipaddressscanner.moc>
