/* This file is part of the KDE project
   Copyright (C) 2004 Arend van Beelen jr. <arend@auton.nl>

   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., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

#include <unistd.h>

#include <dcopclient.h>
#include <kapplication.h>
#include <kaction.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kdesktopfile.h>
#include <kgenericfactory.h>
#include <kglobal.h>
#include <khtml_part.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kmimetype.h>
#include <kprocess.h>
#include <kprotocolmanager.h>
#include <kstandarddirs.h>
#include <kurifilter.h>

#include <kparts/mainwindow.h>
#include <kparts/partmanager.h>

#include <qpopupmenu.h>
#include <qtimer.h>
#include <qstyle.h>
#include <qwhatsthis.h>
#include "searchbar.h"

typedef KGenericFactory<SearchBarPlugin> SearchBarPluginFactory;
K_EXPORT_COMPONENT_FACTORY(libsearchbarplugin,
                           SearchBarPluginFactory("searchbarplugin"))


SearchBarPlugin::SearchBarPlugin(QObject *parent, const char *name,
                                 const QStringList &) :
  KParts::Plugin(parent, name),
  m_searchCombo(0),
  m_searchMode(UseSearchProvider),
  m_urlEnterLock(false)
{
	m_searchCombo = new SearchBarCombo(0L, "search combo");
	m_searchCombo->setDuplicatesEnabled(false);
	m_searchCombo->setMaxCount(5);
	m_searchCombo->setFixedWidth(180);

	m_popupMenu = new QPopupMenu(m_searchCombo, "search selection menu");
	m_popupMenu->insertItem(SmallIcon("find"), i18n("Find in This Page"), this, SLOT(useFindInThisPage()),  0, 0);
	m_popupMenu->insertSeparator();
	m_popupMenu->insertItem("", this, SLOT(useSearchProvider()),  0, 1);
	m_popupMenu->insertItem(SmallIcon("enhanced_browsing"), i18n("Select Search Engine..."),
	                        this, SLOT(selectSearchEngine()), 0, 2);

	m_searchComboAction = new KWidgetAction(m_searchCombo, i18n("Search Bar"), 0,
	                                                     0, 0, actionCollection(), "toolbar_search_bar");
	m_searchComboAction->setShortcutConfigurable(false);

	connect(m_searchCombo, SIGNAL(activated(const QString &)),
	                       SLOT(startSearch(const QString &)));
	connect(m_searchCombo, SIGNAL(iconClicked()), SLOT(showSelectionMenu()));

	QWhatsThis::add(m_searchCombo, i18n("Search Bar<p>"
	                                    "Enter a search term."));

	configurationChanged();

	KParts::MainWindow *mainWin = static_cast<KParts::MainWindow*>(parent);

	//Grab the part manager. Don't know of any other way, and neither does Tronical, so..
	KParts::PartManager *partMan = static_cast<KParts::PartManager*>(mainWin->child(0, "KParts::PartManager"));
	if (partMan)
	{
		connect(partMan, SIGNAL(activePartChanged(KParts::Part*)),
		                 SLOT  (partChanged      (KParts::Part*)));
		partChanged(partMan->activePart());
	}
}

SearchBarPlugin::~SearchBarPlugin()
{
	KConfig *config = kapp->config();
	config->setGroup("SearchBar");
	config->writeEntry("Mode", (int) m_searchMode);

	delete m_searchCombo;
	m_searchCombo = 0L;
}

void SearchBarPlugin::startSearch(const QString &search)
{
	if(m_urlEnterLock || search.isEmpty() || !m_part)
		return;

	if(m_searchMode == FindInThisPage)
	{
		m_part->findText(search, 0);
		m_part->findTextNext();
	}
	else if(m_searchMode == UseSearchProvider)
	{
		m_urlEnterLock = true;
		KURIFilterData data;
		data.setData(search);
		QStringList list;
		list << "kurisearchfilter" << "kuriikwsfilter";

		if(!KURIFilter::self()->filterURI(data, list))
		{
			KConfig config( "kuriikwsfilterrc", true, false );
			config.setGroup( "General" );
			char deli = config.readNumEntry( "KeywordDelimiter", ':' );
			data.setData( QString::fromLatin1( "google" ) + deli + search );
			KURIFilter::self()->filterURI( data, list );
		}
		emit m_part->browserExtension()->openURLRequest(data.uri());
	}

	if(m_searchCombo->text(0).isEmpty())
	{
		m_searchCombo->changeItem(m_searchIcon, search, 0);
	}
	else
	{
		if(m_searchCombo->findHistoryItem(search) == -1)
		{
			m_searchCombo->insertItem(m_searchIcon, search, 0);
		}
	}

	m_searchCombo->setCurrentText("");
	m_urlEnterLock = false;
}

void SearchBarPlugin::setIcon()
{
	QPixmap icon;
	KURIFilterData data;
	data.setData(QString("some keyword"));
	QStringList list;
	list << "kurisearchfilter" << "kuriikwsfilter";

	if(KURIFilter::self()->filterURI(data, list))
	{
		QString iconPath = locate("cache", KMimeType::favIconForURL(data.uri()) + ".png");
		if(iconPath.isEmpty())
		{
			icon = SmallIcon("unknown");
		}
		else
		{
			icon = QPixmap(iconPath);
		}
	}
	else
	{
		icon = SmallIcon("google");
	}
	m_popupMenu->changeItem(1, icon, m_providerName);

	m_searchIcon = (m_searchMode == FindInThisPage ? SmallIcon("find") : icon);

	m_searchCombo->setIcon(m_searchIcon);
}

void SearchBarPlugin::showSelectionMenu()
{
	m_popupMenu->popup(m_searchCombo->mapToGlobal(QPoint(0, m_searchCombo->height() + 1)), 0);
}

void SearchBarPlugin::useFindInThisPage()
{
	m_searchMode = FindInThisPage;
	setIcon();
}

void SearchBarPlugin::useSearchProvider()
{
	m_searchMode = UseSearchProvider;
	setIcon();
}

void SearchBarPlugin::selectSearchEngine()
{
	KProcess *process = new KProcess;

	*process << "kcmshell" << "ebrowsing";

	connect(process, SIGNAL(processExited(KProcess *)), SLOT(searchEngineSelected(KProcess *)));

	if(!process->start())
	{
		kdDebug(1202) << "Couldn't invoke kcmshell." << endl;
                delete process;
	}
}

void SearchBarPlugin::searchEngineSelected(KProcess *process)
{
	if(!process || process->exitStatus() == 0)
	{
		configurationChanged();
	}
        delete process;
}

void SearchBarPlugin::configurationChanged()
{
	KConfig *config = new KConfig("kuriikwsfilterrc");
	config->setGroup("General");
	QString engine = config->readEntry("DefaultSearchEngine", "google");
	delete config;
	if(engine.isEmpty())
	{
		m_providerName = "Google";
	}
	else
	{
		KDesktopFile file("searchproviders/" + engine + ".desktop", true, "services");
		m_providerName = file.readName();
	}

	config = kapp->config();
	config->setGroup("SearchBar");
	m_searchMode = (SearchModes) config->readNumEntry("Mode", (int) UseSearchProvider);

	setIcon();
}

void SearchBarPlugin::partChanged(KParts::Part *newPart)
{
	m_part = ::qt_cast<KHTMLPart*>(newPart);

	//Delay since when destroying tabs part 0 gets activated for a bit, before the proper part
	QTimer::singleShot(0, this, SLOT(updateComboVisibility()));
}

void SearchBarPlugin::updateComboVisibility()
{
	if (m_part.isNull() || !m_searchComboAction->isPlugged())
	{
		m_searchCombo->setPluginActive(false);
		m_searchCombo->hide();
	}
	else
	{
		m_searchCombo->setPluginActive(true);
		m_searchCombo->show();
	}
}

SearchBarCombo::SearchBarCombo(QWidget *parent, const char *name) :
  KHistoryCombo(parent, name),
  m_pluginActive(true)
{
	connect(this, SIGNAL(cleared()), SLOT(historyCleared()));
}

const QPixmap &SearchBarCombo::icon() const
{
	return m_icon;
}

void SearchBarCombo::setIcon(const QPixmap &icon)
{
	m_icon = icon;

	if(count() == 0)
	{
		insertItem(m_icon, 0);
	}
	else
	{
		for(int i = 0; i < count(); i++)
		{
			changeItem(m_icon, text(i), i);
		}
	}
}

int SearchBarCombo::findHistoryItem(const QString &searchText)
{
	for(int i = 0; i < count(); i++)
	{
		if(text(i) == searchText)
		{
			return i;
		}
	}

	return -1;
}

void SearchBarCombo::mousePressEvent(QMouseEvent *e)
{
	int x0 = QStyle::visualRect( style().querySubControlMetrics( QStyle::CC_ComboBox, this, QStyle::SC_ComboBoxEditField ), this ).x();

	if(e->x() > x0 + 2 && e->x() < lineEdit()->x())
	{
		emit iconClicked();

		e->accept();
	}
	else
	{
		KHistoryCombo::mousePressEvent(e);
	}
}

void SearchBarCombo::historyCleared()
{
	setIcon(m_icon);
}

void SearchBarCombo::setPluginActive(bool pluginActive)
{
	m_pluginActive = pluginActive;
}

void SearchBarCombo::show()
{
	if(m_pluginActive)
	{
		KHistoryCombo::show();
	}
}

#include "searchbar.moc"
