/***************************************************************************
 *   tdeio-locate: KDE I/O Slave for the locate command                      *
 *                                                                         *
 *   Copyright (C) 2005 by Tobi Vollebregt                                 *
 *   tobivollebregt@gmail.com                                              *
 *                                                                         *
 *   Thanks to Google's Summer Of Code Program!                            *
 *                                                                         *
 *   Copyright (C) 2004 by Armin Straub                                    *
 *   linux@arminstraub.de                                                  *
 *                                                                         *
 *   This program was initially written by Michael Schuerig.               *
 *   Although I have completely rewritten it, most ideas are adopted       *
 *   from his original work.                                               *
 *                                                                         *
 *   Copyright (C) 2002 by Michael Schuerig                                *
 *   michael@schuerig.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.                                   *
 ***************************************************************************/

/**
 * \mainpage KDE I/O Slave for the locate command
 *
 * \section intro_sec What is tdeio-locate?
 * tdeio-locate is a KDE I/O Slave for the locate command.
 * <p>This means that you can use tdeio-locate by simply typing in konquerors
 * address box. You can e.g. type "locate:index.html" to find all files that
 * contain "index.html" in their name.
 * <p>There's even more: You can use tdeio-locate in all TDE applications, that
 * accept URLs.
 * <p>To find out more about tdeio-locate and to look for new versions, you
 * should take a look at
 * <a href="http://arminstraub.de/browse.php?page=programs_kiolocate">
 * arminstraub.de</a>.
 *
 *
 * \todo Implement locater:help.
 *
 * \todo If a directory matches then don't add its childs.\ At least make
 * this configurable.
 *
 * \todo Use different icons for collapsed directories and make this
 * configurable.
 *
 * \todo After updating the settings show a success html message instead
 * of a blank page.
 *
 * \todo Check if locate's databases are outdated and warn about that.
 *
 * \todo Provide a means of updating the locate database (configurable
 * of course).
 */

#ifndef _tdeio_locate_H_
#define _tdeio_locate_H_

#include <tqcstring.h>
#include <tqstring.h>
#include <tqstringlist.h>
#include <tqdict.h>
#include <tqvaluelist.h>

#include <tdeio/global.h>
#include <tdeio/slavebase.h>

#include "locater.h"
#include "pattern.h"

class TQCString;

class KURL;


class LocateItem;
class LocateDirectory;

typedef TQValueList<LocateItem> LocateItems;
typedef TQDict<LocateDirectory> LocateDirectories;
typedef TQDictIterator<LocateDirectory> LocateDirectoriesIterator;

enum LocateCaseSensitivity { caseAuto, caseSensitive, caseInsensitive };
enum LocateCollapsedIcon { iconBlue, iconGreen, iconGrey, iconOrange, iconRed, iconViolet, iconYellow };


/**
 * Implementation of the tdeioslave for the locate protocol.
 *
 * Enables you to enter "locate:pattern" wherever an URL can be used
 * in KDE.
 */
class LocateProtocol : public TQObject, public TDEIO::SlaveBase
{
	TQ_OBJECT
  
 public:
	/**
	 * Constructor
	 */
	LocateProtocol(const TQCString &pool_socket, const TQCString &app_socket);

	virtual ~LocateProtocol();

	/**
	 * Returns the mimetype "inode/directory".
	 * @param url the url to work on
	 */
	virtual void mimetype(const KURL& url);

	/**
	 * Raises an error so that eyerone notes we are dealing with
	 * directories only.
	 * @param url the url to work on
	 */
	virtual void get(const KURL& url);

	/**
	 * Marks the url as a directory.
	 * @param url the url to work on
	 */
	virtual void stat(const KURL& url);

	/**
	 * Searches for the pattern specified in the url.
	 * Every file found is listed.
	 * @param url the url to work on
	 */
	virtual void listDir(const KURL& url);

	/**
	 * Actually report a hit.
	 * If subItems > 0 then this hit is a "directory subsearch".
	 * @param path the path of the hit
	 * @param subItems the number of hits beneath this one
	 * (or 0 for a regular hit)
	 */
	virtual void addHit(const TQString& path, int subItems = 0);

	const LocateRegExp& getRegExp() const;
	int getCollapseDirectoryThreshold() const;

 private slots:
	void processLocateOutput(const TQStringList& items);
	void locateFinished();
	void configFinished();
	void updateConfig();

 private:
	Locater m_locater;
	KURL m_url;

	TQString m_locatePattern;
	LocateRegExp m_locateRegExp;    // Equals m_locatePattern, but regexp.
	TQString m_locateDirectory;      // Includes a trailing slash.
	LocateRegExpList m_regExps;     // List of extra filtering regexps.

	LocateCaseSensitivity m_caseSensitivity; // For current search.
	bool m_useRegExp;

    // Options
	struct
	{
		LocateCaseSensitivity m_caseSensitivity; // Default case sensitivity.
		int m_collapseDirectoryThreshold; // Maximum number of hits in a directory
		                                  // before a directory search is created
		TQString m_collapsedDisplay;       // Format string used for collapsed directories.
		LocateCollapsedIcon m_collapsedIcon; // Icon used for collapsed directories.
		LocateRegExpList m_whiteList;     // Path must match at least one regexp in this list.
		LocateRegExpList m_blackList;     // Path may not match any regexp in this list.
	} m_config;

	bool m_configUpdated;  // Used in config methods to check if config was cancelled or okay'ed.
	TQString m_pendingPath; // Must be processed as soon as new output becomes available.

	LocateDirectory *m_baseDir; // The toplevel directory, e.g. "/usr/".
	LocateDirectory *m_curDir;  // The current directory (while locating).

	TDEIO::UDSEntryList m_entries; // Used to cache a lot of hits and list them all at once.

	TQString partToPattern(const TQString& part, bool forLocate);
	bool isMatching(const TQString& file);
	TQString pathToDisplay(const TQString& path, int subItems = 0);
	void addPreviousLocateOutput();
	void processPath(const TQString &path, const TQString &nextPath);

	bool isSearchRequest();
	bool isConfigRequest();
	bool isHelpRequest();

	void searchRequest();
	void configRequest();
	void helpRequest();

	bool isCaseSensitive(const TQString& text);

	/**
	 * Composes a locater:... url for the current search parameters
	 * bound to a given directory.
	 * @param directory the directory in which we should be searched
	 * @return the url that envokes the specified search
	 */
	TQString makeLocaterUrl(const TQString& dir);

	/**
	 * This function has to check whether we are accessed via the standard
	 * locater protocol. If this is not the case we have to redirect
	 * this access to an access via the locater protocol.
     * There are other ways, that I have tried to achieve this:
	 * - Use a search provider. This works perfectly for konqueror but
	 *   not for any other KDE application.
	 * - Really use redirection. But this turned out not to be a good
	 *   solution. Seemed not to work from OpenDialogs ...
	 * - So no we just internally redirect... Works, isn't it?
	 */
	void setUrl(const KURL& url);

    void outputHtml(const TQString& body);
};


/**
 * Internally used class to represent a hit as tdeio-locate will
 * report.
 *
 * This may either be a path as given by locate or a directory
 * search (if the number of subItems is set to a positive number).
 */
class LocateItem
{
 public:
	LocateItem();
	LocateItem(const TQString& path, int subItems);

 public:
	TQString m_path;
	int m_subItems;
};


/**
 * Internally used class to represent a directory while tdeio-locate
 * gathers data from locate.
 *
 * Each directory has a list of files found in just that directory
 * and a list of all subdirectories.
 */
class LocateDirectory
{
 public:
	LocateDirectory(LocateDirectory *parent, const TQString& path);

	LocateDirectory *addPath(const TQString& path);
	void prepareListing(const LocateProtocol* protocol, int skip);
	void listItems(LocateProtocol *protocol);
	void debugTrace(int level = 0);

 public:
	TQString m_path;                 // Including trailing slash.
	LocateDirectory *m_parent;
	LocateDirectories m_childs;
	LocateItems m_items;
	int m_itemsCount;
	int m_fullCount;

	LocateDirectory *getSubDirectory(const TQString& relPath);
	void addItem(const TQString& path);
	int countMatchingItems(const LocateProtocol *protocol, int skip);
};

#endif
