/*
 *
 *  Kepas - KDE Easy Publish and Share
 *
 *  Copyright (C) 2008  Tom Patzig <tpatzig@suse.de>
 *
 *  This file is part of kepas.
 *
 *  kepas 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.
 *
 *  kepas 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 kepas; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
*/


#include <trayicon.h>
#include <KDebug>
#include <KApplication>
#include <QTcpServer>
using namespace KPF;

TrayIcon::TrayIcon(QApplication* application) : QDBusAbstractAdaptor(application)
//TrayIcon::TrayIcon() : QMainWindow()
{

// 	 QCoreApplication::instance()->setApplicationName("kifer");	 
//	 config = new KConfig("kiver");	

	 setParent(application);

	 tray = new QSystemTrayIcon(this);
	 tray->setIcon(KIcon("kepas"));
         tray->setToolTip(tr("Kepas - KDE Easy Publish and Share"));

	 mainmenu = new QMenu();
	 
	 buddyAction = mainmenu->addAction(KIcon("user-identity"),i18n("Buddies"));
	 connect(buddyAction, SIGNAL(triggered(bool)), this, SLOT(slotBuddyList(bool)));
	 mainmenu->addSeparator();
	
	 sendFileAction = mainmenu->addAction(KIcon("text-directory"),i18n("Send File"));
	 connect(sendFileAction, SIGNAL(triggered(bool)), this, SLOT(slotFileSelect(bool)));

         sendNoteAction = mainmenu->addAction(KIcon("knotes"), "Send KNote");
         connect(sendNoteAction, SIGNAL(triggered(bool)), this, SLOT(slotDefineNote(bool)));
 
	 clipMenu = mainmenu->addMenu(KIcon("klipper"),i18n("Send Clipboard"));
	 addClipEntries();

	 kpfMenu = mainmenu->addMenu(KIcon("network-server"), i18n("Public Server"));
	 
	 newServerAction = kpfMenu->addAction(KIcon("network-server"), i18n("New Server"));
         connect(newServerAction, SIGNAL(triggered(bool)), this, SLOT(slotServerWizard(bool)));

	 configAction = mainmenu->addAction(KIcon("configure"), i18n("Configure..."));
	 connect(configAction, SIGNAL(triggered(bool)), this, SLOT(showConfigurationInterface()));

	 configAction = mainmenu->addAction(KIcon("kepas"),i18n("About"));
	 connect(configAction, SIGNAL(triggered(bool)), this, SLOT(showAboutInfo()));

	 quitAction = mainmenu->addAction(KIcon("application-exit"),i18n("Quit"));
	 connect(quitAction, SIGNAL(triggered(bool)), this, SLOT(slotQuitApp(bool)));
	 
	 m_dialog = 0;
         m_dialogNotes = 0;
	 publicServerWiz = 0;
	 configDialog = 0;
	 webServerHash = new QHash<QString, WebServer*>;
	 webServerMenuHash = new QHash<QString, QMenu*>;
	 actionHash = new QHash<QString, QAction*>;

	 mainmenu->setDefaultAction(buddyAction);
	 
	 buddylist = new BuddyList(this);
	 avahiClient = new ServiceLocator(this);
//	 connect(avahiClient, SIGNAL(serviceRuns()), this, SLOT(serviceRunning()));

	 tray->setContextMenu(mainmenu);
	 tray->setVisible(true);
	 connect(tray,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(slotTrayActivated(QSystemTrayIcon::ActivationReason)));
	 config = new KConfig("kepasrc");
	 confGroup = new KConfigGroup(config,"General");
	 if (confGroup->exists()) {
		avahiClient->receiver->setTargetPath(confGroup->readEntry("Path",avahiClient->receiver->getTargetPath()));
		avahiClient->setUserName(confGroup->readEntry("Nick",avahiClient->getUserName()));
	 }
	 avahiClient->startService();
	
}

TrayIcon::~TrayIcon()
{
	qDebug() << "bye bye";
	if (m_dialog)
		delete m_dialog;
        if (m_dialogNotes)
                delete m_dialogNotes;

	delete buddylist;
	delete avahiClient;
	qDeleteAll (webServerHash->begin(),webServerHash->end());
	delete webServerHash;
	kDebug() << "webServerHash completly deleted";

	qDeleteAll (actionHash->begin(),actionHash->end());
	delete actionHash;
	kDebug() << "actionHash completly deleted";

	qDeleteAll (webServerMenuHash->begin(),webServerMenuHash->end());
	delete webServerMenuHash;
	kDebug() << "webServerMenuHash completly deleted";

	delete mainmenu;
	delete confGroup;
	delete config;
	delete tray;
	delete dbus;
}

void TrayIcon::slotBuddyList(bool set)
{
	 avahiClient->browse();
	 connect(avahiClient, SIGNAL(addBuddy(QMap<QString, QByteArray>)),buddylist,SLOT(addService(QMap<QString,QByteArray>)));
	 connect(avahiClient, SIGNAL(delBuddy(QString)),buddylist,SLOT(delService(QString)));
	
	 avahiClient->httpBrowse();
	 connect(avahiClient, SIGNAL(httpFound(QString,QString)),buddylist,SLOT(addHttpService(QString,QString)));
	 connect(avahiClient, SIGNAL(httpRemoved(QString)),buddylist,SLOT(delHttpService(QString)));
	 
	 buddylist->initDefaultBuddyList(avahiClient->getUserName());
}


void TrayIcon::slotServerWizard(bool set)
{
	publicServerWiz = new ServerWizard((QWidget*)mainmenu);
	connect(publicServerWiz,SIGNAL(dying(ServerWizard*)),SLOT(slotWizardDying(ServerWizard*)));
	publicServerWiz->show();
}

void TrayIcon::slotWizardDying(ServerWizard * wiz)
{
	kDebug() << "wizard finished";
	kDebug() << "ROOOT: " << wiz->root();

	QString dir = wiz->root();
	QString leer = "";
    	dir.replace(0,7,leer);
    if (QDialog::Accepted == wiz->result())
    {
	QTcpServer test;
	bool portFree = test.listen(QHostAddress::Any,wiz->listenPort());
	if (!portFree) {
		KMessageBox::error(mainmenu,i18n("Failed to bind port %1",(QString::number(wiz->listenPort()))));	
		return;
	}
	test.close();

	webSrv = new WebServer(
			 dir,
			 wiz->listenPort(),
			 wiz->bandwidthLimit(),
			 wiz->connectionLimit(),
			 Config::DefaultFollowSymlinks,
			 wiz->serverName()
	);

	newServerMenu = kpfMenu->addMenu(KIcon("user-online"), QString("%1:%2").arg(wiz->serverName()).arg(wiz->listenPort()));
	connect(newServerMenu,SIGNAL(triggered(QAction*)),this,SLOT(slotServerMenuTriggered(QAction*)));
	
	monitorAction = newServerMenu->addAction(KIcon("utilities-system-monitor"), i18n("Monitor"));
	pauseAction = newServerMenu->addAction(KIcon("media-playback-pause"), i18n("Pause"));
	removeAction = newServerMenu->addAction(KIcon("dialog-close"), i18n("Remove"));
	restartAction = newServerMenu->addAction(KIcon("view-refresh"), i18n("Restart"));
	prefAction = newServerMenu->addAction(KIcon("preferences-system-network"), i18n("Preferences"));
	
	actionHash->insertMulti(QString(wiz->serverName() + ":" + QString::number(wiz->listenPort())),monitorAction);
	actionHash->insertMulti(QString(wiz->serverName() + ":" + QString::number(wiz->listenPort())),pauseAction);
	actionHash->insertMulti(QString(wiz->serverName() + ":" + QString::number(wiz->listenPort())),removeAction);
	actionHash->insertMulti(QString(wiz->serverName() + ":" + QString::number(wiz->listenPort())),restartAction);
	actionHash->insertMulti(QString(wiz->serverName() + ":" + QString::number(wiz->listenPort())),prefAction);

	webServerHash->insert(QString(wiz->serverName() + ":" + QString::number(wiz->listenPort())),webSrv);
	webServerMenuHash->insert(QString(wiz->serverName() + ":" + QString::number(wiz->listenPort())),newServerMenu);
    }
    delete publicServerWiz;
    publicServerWiz = 0;
}

void TrayIcon::slotTrayActivated(QSystemTrayIcon::ActivationReason reason)
{
        kDebug() << "Tray Activated Reason " << reason;
	disconnect(clipMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotSendClipEntry(QAction*)));
	if (reason == 1) {
		clipMenu->clear();
		addClipEntries();
		qDebug() << "update clipList";
	} else if (reason == 3)
                if (!buddylist->isVisible()) 
		    slotBuddyList(true);
                else 
                    buddylist->close();

 	connect(clipMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotSendClipEntry(QAction*)));
}

void TrayIcon::addClipEntries()
{
	dbus = new QDBusConnection("dbus");
	QDBusConnection dbusconn = dbus->connectToBus(QDBusConnection::SessionBus, "dbus");
	QString service = "org.kde.klipper";
	QString path = "/klipper";
	QString method = "getClipboardHistoryMenu";
	QString service2 = "org.kde.klipper.klipper";

	QDBusInterface* interface = new QDBusInterface(service,path,service2,dbusconn);
	QDBusReply<QStringList> reply = interface->call(method);
	
//	qDebug() << "klipper reply: " << reply.value();
	QStringList clipList = reply.value();

	for (int i=0; i < clipList.size(); i++){
		if (clipList.at(i).size() >= 30) {
			QString cut = clipList.at(i);
			cut.truncate(30);
			
			clipAction = clipMenu->addAction(cut + " ...");
	         } else
			clipAction = clipMenu->addAction(clipList.at(i));
		
		clipAction->setToolTip(clipList.at(i));
	}
}

void TrayIcon::slotSendClipEntry(QAction* action)
{
	//The triggered signal gets emitted two times for the QMenu, so we have to disconnect after the first signal
 	disconnect(clipMenu, SIGNAL(triggered(QAction*)), this, SLOT(slotSendClipEntry(QAction*)));
	QString entry = action->toolTip();
        SendKlipperEntry(entry);
}

void TrayIcon::slotSendNote()
{
        QString noteEntry = noteEdit.textEdit->toPlainText();
        delete m_dialogNotes;
        m_dialogNotes = 0;
        SendKNote (noteEntry);
}

void TrayIcon::slotShowToolTip(QAction* action)
{
	qDebug() << "tooltip: " << action->toolTip();
}

void TrayIcon::slotFileSelect(bool)
{
	qDebug() << "slotFileSelect";
	
	QString fileName = KFileDialog::getOpenFileName(KUrl("./"),"*",mainmenu, tr("Select File"));
	if (!fileName.isEmpty()) {
             SendFile(fileName);
	}
}

void TrayIcon::slotDefineNote(bool /*val*/)
{
        if (m_dialogNotes == 0) {
            kDebug() << "Creating Note editor";
            m_dialogNotes = new KDialog;
            m_dialogNotes->setCaption( i18n("Send KNote") );
            noteEdit.setupUi(m_dialogNotes->mainWidget());
            m_dialogNotes->setButtons( KDialog::None );
            connect(noteEdit.sendButton,SIGNAL(clicked()),this,SLOT(slotSendNote()));
            connect(noteEdit.cancelButton,SIGNAL(clicked()),m_dialogNotes,SLOT(close()));
        }
        m_dialogNotes->show();
}


void TrayIcon::showConfigurationInterface()
{
   QString target = confGroup->readEntry("Path",avahiClient->receiver->getTargetPath());
   QString nick = confGroup->readEntry("Nick",avahiClient->getUserName());

   if (m_dialog == 0) {
        m_dialog = new KDialog;
        m_dialog->setCaption( i18n("Configure Kepas") );
        ui.setupUi(m_dialog->mainWidget());
        m_dialog->setButtons( KDialog::Ok | KDialog::Cancel | KDialog::Apply );
        connect( m_dialog, SIGNAL(applyClicked()), this, SLOT(configAccepted()) );
        connect( m_dialog, SIGNAL(okClicked()), this, SLOT(configAccepted()) );
	connect( ui.saveToButton,SIGNAL(clicked()),this,SLOT(slotSelectDir()));
    }
    ui.pictureButton->setIcon(KIcon("user-identity"));
    ui.nameLineEdit->setText(nick);
    ui.saveToLineEdit->setText(target);
 
    
    m_dialog->show();
}

void TrayIcon::configAccepted()
{
	confGroup->writeEntry("Path",ui.saveToLineEdit->text());
	confGroup->writeEntry("Nick",ui.nameLineEdit->text());

	avahiClient->receiver->setTargetPath(ui.saveToLineEdit->text());
	avahiClient->setUserName(ui.nameLineEdit->text());
	bool OK = avahiClient->restartPublish();
        OK ? qDebug() << "Service restarted and published succesfull " : qDebug() << "Service not published";
}

void TrayIcon::slotSelectDir()
{

	QString dirname = KFileDialog::getExistingDirectory(KUrl("./"),mainmenu, tr("Select Target Directory"));
	if (!dirname.isEmpty())
		ui.saveToLineEdit->setText(dirname);
}

void TrayIcon::serviceRunning()
{
	KMessageBox::information(mainmenu, "Service already running!");
	slotQuitApp(true);
}

void TrayIcon::slotQuitApp(bool set)
{
	kapp->quit();
}

void TrayIcon::showAboutInfo()
{
	KAboutData aboutData("kepas", 0, ki18n("Kepas"), "0.9",
		           ki18n("KDE Easy Publish and Share"), KAboutData::License_GPL_V2);
	aboutData.addAuthor(ki18n("Tom Patzig"), KLocalizedString(), "tpatzig@suse.de", "http://www.kde.org/");
	QByteArray tmp;
	tmp.append("rik@kde.org");
	aboutData.addCredit(ki18n("Rik Hemsley"),ki18n("Common Codebase of KPF KDE3"),tmp);

	KAboutApplicationDialog about(&aboutData, mainmenu);
//	about.setIcon( KIcon( "network-folder" ) );
	about.exec();
}

void TrayIcon::slotMonitorAction(QAction* ac)
{
	kDebug() << "slotMonitorAction" ;
	QMenu* men = (QMenu*)ac->parentWidget();
	QString serverName = men->title();
	kDebug() << "ServerName: "<< serverName ;
	kDebug() << "Server: "<< men->title() ;

	WebServer* srv = webServerHash->value(serverName);		
	kDebug() << srv->serverName();

	monitorWindow = new ActiveMonitorWindow(srv);
	connect(monitorWindow,SIGNAL(dying(ActiveMonitorWindow*)),this,SLOT(slotMonitorDying(ActiveMonitorWindow*)));
	monitorWindow->show();
	monitorWindow->raise();
}

void TrayIcon::slotMonitorDying(ActiveMonitorWindow* monitor)
{
        kDebug() << "Closing Monitor";
	monitor->deleteLater();
    	monitor = 0;
}

void TrayIcon::slotRemoveServerAction(QAction* ac)
{
	kDebug() << "slotRemoveAction" ;
	QMenu* men = (QMenu*)ac->parentWidget();
	disconnect(men,0,0,0);
	QString serverName = men->title();


//	kpfMenu->removeAction(men);	
	kDebug() << "ServerName: "<< serverName ;

	WebServer* srv = webServerHash->value(serverName);		
	WebServerManager::instance()->disableServer(srv->root());
	webServerHash->remove(serverName);
	delete srv;
	kDebug() << "WebServerdeleted";	

	QList<QAction*> tmpList = actionHash->values(serverName);

	qDeleteAll(tmpList.begin(),tmpList.end());
	actionHash->remove(serverName);

	kDebug() << "Actions deleted ";
	men->clear();

	webServerMenuHash->remove(serverName);
	men->deleteLater();

}

void TrayIcon::slotPauseServerAction(QAction* ac)
{
	kDebug() << "slotPauseAction" ;
	QMenu* men = (QMenu*)ac->parentWidget();
	QString serverName = men->title();
	
	WebServer* srv = webServerHash->value(serverName);		
	srv->pause(!srv->paused());
	kDebug() << "Server is paused: " << srv->paused();

	if (srv->paused()) {
		men->setIcon(KIcon("user-offline"));
		pauseAction->setIcon(KIcon("media-playback-start"));
		pauseAction->setText("Start");
	} else {
		men->setIcon(KIcon("user-online"));
		pauseAction->setIcon(KIcon("media-playback-pause"));
		pauseAction->setText("Pause");
	}

	kDebug() << "ServerName: "<< serverName ;
}

void TrayIcon::slotRestartServerAction(QAction* ac)
{
	kDebug() << "slotRestartAction" ;
	QMenu* men = (QMenu*)ac->parentWidget();
	QString serverName = men->title();
	
	WebServer* srv = webServerHash->value(serverName);		
	srv->restart();
	kDebug() << "ServerName: "<< serverName ;
}

void TrayIcon::slotPrefsServerAction(QAction* ac)
{
	kDebug() << "slotPrefsAction" ;
	QMenu* men = (QMenu*)ac->parentWidget();
	QString serverName = men->title();
	
	WebServer* srv = webServerHash->value(serverName);		
	if (!configDialog) {
		configDialog = new SingleServerConfigDialog(srv, 0);
		connect(configDialog,SIGNAL(dying(SingleServerConfigDialog *)),SLOT(slotConfigDialogDying(SingleServerConfigDialog *)));
	}
	configDialog->show();
	kDebug() << "ServerName: "<< serverName ;
}

void TrayIcon::slotConfigDialogDying(SingleServerConfigDialog* dialog)
{
	dialog->delayedDestruct();
    	dialog = 0;
	configDialog = 0;
}

void TrayIcon::slotServerMenuTriggered(QAction* act)
{
	QHash<QString,QMenu*>::iterator foo;
	foo = webServerMenuHash->begin();
	for(foo = webServerMenuHash->begin(); foo != webServerMenuHash->end();foo++) {
		QMenu* tmp = foo.value();
		disconnect(tmp,SIGNAL(triggered(QAction*)),this,SLOT(slotServerMenuTriggered(QAction*)));
	}

	if (act->text() == "Monitor")
		slotMonitorAction(act);
	else if (act->text() == "Pause" || act->text() == "Start")
		slotPauseServerAction(act);	
	else if (act->text() == "Remove")
		slotRemoveServerAction(act);	
	else if (act->text() == "Restart")
		slotRestartServerAction(act);	
	else if (act->text() == "Preferences")	
		slotPrefsServerAction(act);

	for(foo = webServerMenuHash->begin(); foo != webServerMenuHash->end();foo++) {
		QMenu* tmp = foo.value();
		connect(tmp,SIGNAL(triggered(QAction*)),this,SLOT(slotServerMenuTriggered(QAction*)));
	}

}

// ------------------------------Public DBus Methods ----------------------------------------------/////
void TrayIcon::SendKNote(QString text)
{
 	avahiClient->browse();
	connect(avahiClient, SIGNAL(addBuddy(QMap<QString, QByteArray>)),buddylist,SLOT(addService(QMap<QString,QByteArray>)));
	connect(avahiClient, SIGNAL(delBuddy(QString)),buddylist,SLOT(delService(QString)));
       
	buddylist->initSendNoteBuddyList(text,avahiClient->getUserName());
}

void TrayIcon::SendKlipperEntry(QString text)
{
	avahiClient->browse();
	connect(avahiClient, SIGNAL(addBuddy(QMap<QString, QByteArray>)),buddylist,SLOT(addService(QMap<QString,QByteArray>)));
	connect(avahiClient, SIGNAL(delBuddy(QString)),buddylist,SLOT(delService(QString)));
	buddylist->initSendClipBuddyList(text,avahiClient->getUserName());
}

void TrayIcon::SendFile(QString filename)
{
        avahiClient->browse();
        connect(avahiClient, SIGNAL(addBuddy(QMap<QString, QByteArray>)),buddylist,SLOT(addService(QMap<QString,QByteArray>)));
        connect(avahiClient, SIGNAL(delBuddy(QString)),buddylist,SLOT(delService(QString)));
        buddylist->initSendFileBuddyList(filename,avahiClient->getUserName());
}
