/* -*- c++ -*-
 *
 * submit.cpp
 *
 * Copyright (C) 2003 Petter Stokke <ummo@hellokitty.com>
 *
 * 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., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include <kdebug.h>
#include <kconfig.h>
#include <klocale.h>
#include <kapplication.h>
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kmessagebox.h>
#include <qregexp.h>
#include "donkeyprotocol.h"
#include "hostmanager.h"
#include "version.h"
#include "submit.h"
#include "submit.moc"


#define MESSAGEBOX_TITLE "KMLDonkey URL error"


SubmitCallback::SubmitCallback(const QString& url, Submitter* submitter)
    : m_url(url)
{
    m_submitter = submitter;
}

void SubmitCallback::callback(const QString& cmd, const QString& res)
{
    kdDebug() << "Callback cmd: " << cmd << endl;
    kdDebug() << "Callback result: " << res << endl;
    if (res.lower() != "done" && !res.contains("parsing http url", false) && !res.startsWith("Added link :")) {
	/*
	if (res.contains("force_download")) {
	    if (KMessageBox::warningYesNo(0, i18n("Failed to submit URL %1\n\nForce download?")
		.arg(m_url)) == KMessageBox::Yes) {
		    m_submitter->submitURL(m_url, true);
		}
	}
	else
	*/
	KMessageBox::detailedError(0, i18n("Failed to submit URL:\n\n%1").arg(m_url), res);
    }
    m_submitter->callbackDone();
}


Submitter::Submitter(QCString host, bool recursive, QObject* parent, char* name) : QObject(parent,name)
{
    isRecursive = recursive;
    done = auth = callbackCount = 0;
    dict.setAutoDelete(true);
    callbacks.setAutoDelete(true);

    hostManager = new HostManager(this, 0, true);
    donkey = new DonkeyProtocol(true, this);
    connect(donkey, SIGNAL(signalDisconnected(int)), this, SLOT(donkeyDisconnected(int)));
    connect(donkey, SIGNAL(signalConnected()), this, SLOT(donkeyAuthenticating()));
    connect(donkey, SIGNAL(updatedConnectedServers()), this, SLOT(donkeyConnected()));
    donkey->setPassword(uname, pwd);
    if (!host.isNull() && hostManager->validHostName(host))
        donkey->setHost( hostManager->hostProperties(host) );
    else
        donkey->setHost( hostManager->defaultHost() );
    donkey->connectToCore();
}

void Submitter::donkeyDisconnected(int err)
{
    kdDebug() << "Donkey disconnected: " << err << endl;
    switch (err) {
    case ProtocolInterface::ConnectionRefusedError:
	KMessageBox::error(0, i18n("Connection to the core was refused. "
                                   "Are you sure it is running?"));
	break;
    case ProtocolInterface::HostNotFoundError: {
        HostInterface* host = hostManager->defaultHost();
	KMessageBox::error(0, host ? i18n("Host '%1' not found!").arg(host->address()) : i18n("No Host defined!"));
    } break;
    case ProtocolInterface::CommunicationError:
	KMessageBox::error(0, i18n("Disconnected due to a communication error."));
	break;
    case ProtocolInterface::IncompatibleProtocolError:
	KMessageBox::error(0, i18n("Your mldonkey core uses an obsolete communications protocol. "
				   "Please upgrade it to a more recent version!"));
	break;
    case ProtocolInterface::NoError:
        break;
    default:
	if (!auth || err == DonkeyProtocol::AuthenticationError)
	    KMessageBox::error(0, i18n("Authentication error. Incorrect name or password."));
        else
            KMessageBox::error(0, i18n("Unknown error!"));
	break;
    }
    emit quit();
}

void Submitter::donkeyAuthenticating()
{
    donkey->updateConnectedServers();
    kdDebug() << "Authenticating..." << endl;
}

void Submitter::donkeyConnected()
{
    kdDebug() << "Donkey authenticated." << endl;
    auth = 1;
    sendURLs();
}

void Submitter::sendURLs()
{
    if (!auth) return;
    while (list.size()) {
	bool force = false;
	QString foo = list.first();
	if (foo.startsWith("FORCE ")) {
	    force = true;
	    foo = foo.right(foo.length() - 6);
	}
	SubmitCallback* callback = new SubmitCallback(foo, this);
	callbacks.append(callback);
	callbackCount++;
	kdDebug() << "Callback count incremented: " << callbackCount << endl;
	donkey->sendConsoleMessage(QString("dllink \"%1\"").arg(foo), callback);
	if (force) donkey->sendConsoleMessage("force_download");
	// donkey->submitURL(foo);
	kdDebug() << "Submitted URL: " << foo << endl;
	list.pop_front();
    }
    if (done && dict.isEmpty() && !callbackCount) donkey->disconnectFromCore();
}

void Submitter::callbackDone()
{
    callbackCount--;
    kdDebug() << "Callback count decremented: " << callbackCount << endl;
    if (done && dict.isEmpty() && !callbackCount) donkey->disconnectFromCore();
}

void Submitter::submitURL(const QString& url, bool force)
{
    if (url.lower().startsWith("ed2k://") || !isRecursive) {
	if (force)
	    list.append(QString("FORCE ") + url);
	else
	    list.append(url);
	sendURLs();
    } else {
	KIO::TransferJob *job = KIO::get(KURL( url ));
	connect(job, SIGNAL(result(KIO::Job*)), this, SLOT(jobResult(KIO::Job*)));
	connect(job, SIGNAL(data(KIO::Job*, const QByteArray&)), this, SLOT(jobData(KIO::Job*, const QByteArray&)));
	dict.insert(job->progressId(), new QString());
	kdDebug() << "Job " << job->progressId() << " fetching URL: " << url << endl;
    }
}

void Submitter::allDone()
{
    done = 1;
    sendURLs();
}

void Submitter::jobData(KIO::Job* job, const QByteArray& data)
{
    dict.find(job->progressId())->append(data);
}

void Submitter::jobResult(KIO::Job* job)
{
    if (job->error())
	KMessageBox::error(0, job->errorString());

    QString* data = dict.find(job->progressId());
    kdDebug() << "Job " << job->progressId() << " done." << endl;

    QRegExp rx("(ed2k://[|]file[|][^|]+[|]\\d+[|][0-9a-fA-F]+[|])");
    int pos = 0;

    while (pos >= 0) {
	pos = rx.search(*data, pos);
	if (pos > -1) {
	    QString url(rx.cap(1));
	    submitURL(url);
	    pos += rx.matchedLength();
	}
    }

    dict.remove(job->progressId());
    sendURLs();
}

static KCmdLineOptions options[] = {
    { "r", 0, 0 },
    { "read-html", I18N_NOOP("Load HTTP URLs and add ed2k links contained in the retrieved documents rather than submitting them as is."), 0 },
    { "h", 0, 0 },
    { "host <hostid>", I18N_NOOP("Specify which host to send the URLs to. <hostid> is the name of the host as defined in the KDE Control Center."), 0 },
    { "+url", I18N_NOOP("URL (or multiple URLs) to process."), 0 },
    { 0,0,0 }
};

int main(int argc, char **argv)
{
    KAboutData about("kmldonkey", I18N_NOOP("kmldonkey_submit"), KMLDONKEY_VERSION,
		     I18N_NOOP("Submit a URL to mldonkey"),
                     KAboutData::License_GPL_V2, I18N_NOOP("Copyright (C) 2003, 2004 The KMLDonkey Authors"),
		     I18N_NOOP("Part of the KMLDonkey package."),
		     "http://www.kmldonkey.org");
    about.addAuthor("Petter Stokke", 0, "ummo@hellokitty.com");
    about.setTranslator(I18N_NOOP("_: NAME OF TRANSLATORS\nYour names"), I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails"));
    KCmdLineArgs::init(argc, argv, &about);
    KCmdLineArgs::addCmdLineOptions(options);
    KApplication::addCmdLineOptions();
    KApplication app;
    KCmdLineArgs* args = KCmdLineArgs::parsedArgs();

    if (!args->count()) args->usage();

    Submitter sub(args->getOption("host"), args->isSet("read-html"), &app);
    app.connect(&sub, SIGNAL(quit()), SLOT(quit()));
    for (int i = 0; i < args->count(); i++)
	sub.submitURL(args->arg(i));
    sub.allDone();

    app.exec();
}
