/***************************************************************************
    smb4kscanner.h  -  The network scan core class of Smb4K.
                             -------------------
    begin                : Sam Mai 31 2003
    copyright            : (C) 2003-2007 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                                                    *
 ***************************************************************************/

#ifndef SMB4KSCANNER_H
#define SMB4KSCANNER_H

#ifndef HAVE_CONFIG_H
#include <config.h>
#endif

// Qt includes
#include <qobject.h>
#include <qstringlist.h>
#include <qptrqueue.h>

// KDE includes
#include <kprocess.h>

// application specific includes
#include "smb4kdefs.h"

// forward declarations
class Smb4KScannerPrivate;
class Smb4KWorkgroupItem;
class Smb4KHostItem;
class Smb4KShareItem;


/**
 * This is the core class, that communicates with the network. All look-up
 * stuff is done here.
 *
 * @author Alexander Reinholdt <dustpuppy@mail.berlios.de>
 */

class Smb4KScanner : public QObject
{
  Q_OBJECT

  public:
    /**
     * The constructor.
     *
     * @param workgroups      A list of Smb4KWorkgroupItem items which will be filled by the scanner
     *                        with the list of available workgroups. If a NULL pointer is passed, a
     *                        private list will be created which cannot be accessed from outside.
     *
     * @param hosts           A list of Smb4KHostItem items which will be filled by the scanner.
     *                        with the list of available hosts. If a NULL pointer is passed, a
     *                        private list will be created which cannot be accessed from outside.
     *
     * @param parent          The parent of this class.
     *
     * @param name            The name of this class.
     */
    Smb4KScanner( QValueList<Smb4KWorkgroupItem *> *workgroups = 0,
                  QValueList<Smb4KHostItem *> *hosts = 0,
                  QObject *parent = 0,
                  const char *name = 0 );

    /**
     * The destructor.
     */
    ~Smb4KScanner();

    /**
     * Initiates a network scan.
     *
     * Please not that after having invoked this function, the list of workgroups
     * as well as the list of known hosts will be cleared and refilled. Thus, all
     * known hosts except the current workgroup master browsers will have been
     * vanished.
     */
    void rescan();

    /**
     * Aborts the network scan.
     */
    void abort();

    /**
     * Reads the options.
     */
    void readOptions();

    /**
     * Scan for the shares on a selected host.
     *
     * @param workgroup       The workgroup of the host you want to scan.
     *
     * @param host            The host you want to scan.
     *
     * @param ip              The IP address of the host.
     *
     * @param protocol        With this argument you can force a special protocol
     *                        the net command has to use. Normally, you do not have
     *                        to set here anything.
     */
    void getShares( const QString &workgroup,
                    const QString &host,
                    const QString &ip,
                    const QString &protocol = QString::null );

    /**
     * Scans for workgroup members.
     *
     * @param workgroup       The workgroup of the master browser that should be scanned.
     *
     * @param master          The name of the master browser.
     *
     * @param ip              The IP address of the master browser.
     */
    void getWorkgroupMembers( const QString &workgroup,
                              const QString &master,
                              const QString &ip );

    /**
     * Get more info about a share (i.e. server and OS string, etc.).
     *
     * @param workgroup       The workgroup of the host
     *
     * @param host            The host's name
     *
     * @param ip              The host's IP address
     */
    void getInfo( const QString &workgroup,
                  const QString &host,
                  const QString &ip );

    /**
     * Starts the search for a host that matches @p string. If the host is already
     * in the list of known hosts, this function immediately emits the searchResult()
     * signal with the Smb4KHostItem representing the host. If this is not the case,
     * a search process is started.
     *
     * @param string          The user supplied search string.
     */
    void search( const QString &string );

    /**
     * This function returns an Smb4KWorkgroupItem, if the the workgroup
     * exists in the list, or NULL, if it does not.
     *
     * @param workgroup       The name of the workgroup
     */
    Smb4KWorkgroupItem *getWorkgroup( const QString &workgroup );

    /**
     * This function reports if the scanner is running or not.
     *
     * @returns             TRUE if the scanner is running and FALSE otherwise.
     */
    bool isRunning() { return m_working; }

    /**
     * This function returns the specified host item, or NULL, if this host was not found.
     * The name of the host is mandatory. The workgroup may be empty, but should be given,
     * because this will speed up the search process.
     *
     * @param name          The name of the host
     *
     * @param workgroup     The workgroup of the host item
     *
     * @returns             A host item
     */
    Smb4KHostItem *getHost( const QString &name,
                            const QString &workgroup = QString::null );

    /**
     * This function inserts a @p host into the list of known servers. If it belongs to
     * a workgroup that was not known until now, a new Smb4KWorkgroupItem item is also
     * created and added to the list of known workgroups. @p host is then marked as
     * pseudo master browser. On success, the this function emits the hostAdded() and
     * hostListChanged() signals. If the host is already in the known, nothing is done.
     *
     * @param host          The host that should be inserted
     */
    void insertHost( Smb4KHostItem *host );

    /**
     * This function initializes the network scan It just executes the rescan() function,
     * so you can also use that instead.
     */
    void init();

  signals:
    /**
     * This signal emits the run state.
     *
     * @param state         The so-called run state. There are several defined
     *                      in the smb4kdefs.h header file.
     */
    void state( int state );

    /**
     * This signal is emitted, when the workgroup list has been updated.
     *
     * @param list          The list of workgroups in the network neighborhood.
     */
    void workgroups( const QValueList<Smb4KWorkgroupItem *> &list );

    /**
     * Emits the list of workgroup members.
     *
     * @param workgroup     The workgroup in which the members are located
     *
     * @param list          The list of workgroup members.
     */
    void members( const QString &workgroup, const QValueList<Smb4KHostItem *> &list );

    /**
     * Emits the list of shares.
     *
     * @param host          The host that carries the shares
     *
     * @param list          The list of shares
     */
    void shares( const QString &host, const QValueList<Smb4KShareItem *> &list );

    /**
     * This signal provides info about a certain host. It passes the server
     * and the OS string.
     */
    void info( Smb4KHostItem *host );

    /**
     * Is emitted, when the results of a network search are to be passed.
     */
    void searchResult( Smb4KHostItem *host );

    /**
     * This signal emits the host item for which an IP address has
     * been found.
     *
     * @param host          The host item with the new IP address
     */
    void ipAddress( Smb4KHostItem *host );

    /**
     * This signal is emitted when the list of hosts is changed.
     */
    void hostListChanged();

    /**
     * This signal is emitted if a request could not be processed
     * successfully.
     */
    void failed();

    /**
     * This signal is emitted when a host has been added to the list of known
     * hosts via the addHost() function.
     *
     * @param host          The Smb4KHostItem that represents the host that
     *                      was added.
     */
    void hostAdded( Smb4KHostItem *host );

  protected:
    /**
     * Starts the process.
     *
     * @param state         The state
     */
    void startProcess( int state );

    /**
     * Is called, when the main process ends.
     */
    void endProcess();

    /**
     * Processes the output of the network group scan.
     */
    void processWorkgroups();

    /**
     * Processes the list of workgroup members retrieved by
     * scanning the workgroup master browser.
     */
    void processWorkgroupMembers();

    /**
     * Processes the output of the host scan.
     */
    void processShares();

    /**
     * Processes the output of the scan for the OS and Server
     * string.
     */
    void processInfo();

    /**
     * Processes the output of a search request.
     */
    void processSearch();

    /**
     * Process the data from the IP range scan.
     */
    void processIPScan();

    /**
     * Reimplemented from QObject
     */
    void timerEvent( QTimerEvent *e );

  protected slots:
    /**
     * Is called, if something is received on stdout from the main process.
     *
     * @param proc          The process
     *
     * @param buf           The buffer
     *
     * @param len           The length of the buffer
     */
    void slotReceivedStdout( KProcess *proc,
                             char *buf,
                             int len );

    /**
     * Is called, when the KProcess exited.
     *
     * @param proc          The process that exited
     */
    void slotProcessExited( KProcess *proc );

    /**
     * Is called, if something is received on stderr from the main process.
     *
     * @param proc          The process
     *
     * @param buf           The buffer
     *
     * @param len           The length of the buffer
     */
    void slotReceivedStderr( KProcess *proc,
                             char *buf,
                             int len );

    /**
     * Is called when the scan for IP addresses produced output on stdout.
     *
     * @param proc          The process
     *
     * @param buf           The buffer
     *
     * @param len           The length of the buffer
     */
    void slotReceivedIPAddresses( KProcess *proc,
                                  char *buf,
                                  int len );

    /**
     * Is called, when the KProcess exited.
     *
     * @param proc          The process that exited
     */
    void slotIPAddressProcessExited( KProcess *proc );


  private:
    /**
     * Initiates the (re-)scan of the network to retrieve the initial
     * browse list.
     */
    void scanNetwork();

    /**
     * Scans the group master for the group members.
     */
    void scanForWorkgroupMembers( const QString &workgroup,
                                  const QString &master,
                                  const QString &ip );

    /**
     * Scans the chosen host for its shares. This is the private part
     * of @see Smb4KScanner::getShares().
     */
    void scanForShares( const QString &workgroup,
                        const QString &host,
                        const QString &ip,
                        const QString &protocol );

    /**
     * Scans a given host for its OS and Server string.
     */
    void scanForInfo( const QString &workgroup,
                      const QString &host,
                      const QString &ip );

    /**
     * Searches for a given host.
     */
    void searchForHost( const QString &host );

    /**
     * This function initializes the lookup of IP addresses.
     */
    void lookupIPAddresses();

    /**
     * This function takes an Smb4KWorkgroupItem and appends it to the list,
     * if the represented workgroup isn't already in it.
     */
    void appendWorkgroup( Smb4KWorkgroupItem *item );

    /**
     * Internal enumeration.
     */
    enum TODO{ Workgroups, QueryHost, IPScan, Hosts, Shares, Info, Search, Init, Idle };

    /**
     * The main KProcess object.
     */
    KProcess *m_proc;

    /**
     * The buffer for the main process.
     */
    QString m_buffer;

    /**
     * This queue stores the incoming requests until they are processed.
     */
    QPtrQueue<QString> m_queue;

    /**
     * Is set to true, if the scanner is running.
     */
    bool m_working;

    /**
     * The list of workgroups including the master browser and their
     * IP addresses.
     */
    QValueList<Smb4KWorkgroupItem *> *m_workgroups_list;

    /**
     * This list contains all hosts, that are found by the scanner and
     * that are currently active.
     */
    QValueList<Smb4KHostItem *> *m_hosts_list;

    /**
     * The internal state of the main process. Do not mix this up with
     * the state that's emitted to notify the application about changes.
     */
    int m_state;

    /**
     * This is the pointer to the private helper class.
     */
    Smb4KScannerPrivate *m_priv;

    /**
     * The timer id
     */
    int m_timer_id;
};
#endif
