#include "testlibrss.h"

#include <tqdatetime.h>
#include <tqfile.h>

#include <tdeaboutdata.h>
#include <tdecmdlineargs.h>
#include <tdeapplication.h>
#include <kdebug.h>
#include <krfcdate.h>

#include "image.h"
#include "enclosure.h"

#include <cstdlib>

using namespace RSS;


TestRetriever::TestRetriever()
	: m_errorCode(0)
{
}

TestRetriever::~TestRetriever()
{
}

void TestRetriever::retrieveData(const KURL &url)
{
	// Test files are local paths
	TQFile file(url.path());
	if (file.open(IO_ReadOnly))
	{
		TQStringList lines;
		TQTextStream stream(&file);

		while (!stream.atEnd())
		{
			lines += stream.readLine();
		}
		file.close();

		TQCString content = lines.join("\n").local8Bit();
		TQByteArray data;
		data.duplicate(content, content.length());
		emit dataRetrieved(data, true);
	}
	else
	{
		kdError() << "Failed to retrieveData: " << file.errorString() << endl;
		m_errorCode = file.status();
		emit dataRetrieved(TQByteArray{}, false);
	}
}

static const TDECmdLineOptions options[] =
{
  { "+url", I18N_NOOP("URL of feed"), 0 },
  TDECmdLineLastOption
};

template<typename ActualType, typename ExpectedType>
static void assertEquals(const ActualType& actual, const ExpectedType& expected)
{
	if (actual != expected)
	{
		kdError() << "Assertion failed: actual == expected\n"
			<< "   actual: " << actual << "\n"
			<< " expected: " << expected << endl;
		tdeApp->exit(1);
	}
}

static void checkRSS091(const Document& document)
{
	assertEquals(document.title(), "WriteTheWeb");
	assertEquals(document.link().url(), "http://writetheweb.com");
	assertEquals(document.description(), "News for web users that write back");
	assertEquals(document.language(), Language::en_us);
	assertEquals(document.copyright(), "Copyright 2000, WriteTheWeb team.");
	assertEquals(document.managingEditor(), "editor@writetheweb.com");
	assertEquals(document.webMaster(), "webmaster@writetheweb.com");

	const Image* image = document.image();
	if (!image)
	{
		kdError() << "Expected an <image> element to be found" << endl;
		tdeApp->exit(1);
	}

	assertEquals(image->title(), "WriteTheWeb");
	assertEquals(image->url().url(), "http://writetheweb.com/images/mynetscape88.gif");
	assertEquals(image->link().url(), "http://writetheweb.com");
	assertEquals(image->description(), "News for web users that write back");
	assertEquals(image->width(), 88);
	assertEquals(image->height(), 31);

	assertEquals(document.articles().count(), 6);

	Article article = document.articles().first();
	assertEquals(article.title(), "Giving the world a pluggable Gnutella");
	assertEquals(article.link().url(), "http://writetheweb.com/read.php?item=24");
	assertEquals(article.description(), "WorldOS is a framework on which to build programs that work like Freenet or Gnutella -allowing distributed applications using peer-to-peer routing.");
}

static void checkWFW(const Document& document)
{
	assertEquals(document.link().url(), "http://wellformedweb.org/news/");
	assertEquals(document.description(), "Exploring the limits of XML and HTTP");

	assertEquals(document.articles().count(), 5);

	Article article = document.articles().front();
	assertEquals(article.title(), "Should you use Content Negotiation in your Web Services?");
	assertEquals(article.commentsLink().url(), "http://bitworking.org/news/comments/WebServicesAndContentNegotiation");
}

static void checkDC(const Document& document)
{
	// librss will use dc:date if it is provided, otherwise it will use pubDate
	assertEquals(document.link().url(), "https://www.theguardian.com/us");

	TQDateTime expectedTime;
	time_t time = KRFCDate::parseDateISO8601("2025-03-13T07:28:39Z");
	expectedTime.setTime_t(time);
	assertEquals(document.pubDate(), expectedTime);

	assertEquals(document.articles().count(), 1);

	Article article = document.articles().first();
	time = KRFCDate::parseDateISO8601("2025-03-13T05:22:00Z");
	expectedTime.setTime_t(time);
	assertEquals(article.pubDate(), expectedTime);

	assertEquals(article.author(), "Hugo Lowell in Washington");
}

static void checkRDF(const Document& document)
{
	assertEquals(document.title(), "XML.com");
	assertEquals(document.link().url(), "http://xml.com/pub");

	assertEquals(document.articles().count(), 2);

	Article article = document.articles().first();

	assertEquals(article.title(), "Processing Inclusions with XSLT");
	assertEquals(article.link().url(), "http://xml.com/pub/2000/08/09/xslt/xslt.html");
	assertEquals(article.guid(), "http://xml.com/pub/2000/08/09/xslt/xslt.html");
	assertEquals(article.guidIsPermaLink(), false);
}

static void checkAtom10(const Document& document)
{
	assertEquals(document.title(), "dive into mark");
	assertEquals(document.description(), "A <em>lot</em> of effort went into making this effortless");
	kdWarning() << "Skipping check for Atom \"rights\" (Document::copyright) -- not implemented." << endl;
	// assertEquals(document.copyright(), "Copyright (c) 2003, Mark Pilgrim");
	assertEquals(document.language(), Language::en_us);

	// 2005-07-31T12:29:29Z
	// TQDateTime compTime;
	// time_t time = KRFCDate::parseDateISO8601("2005-07-31T12:29:29Z");
	// compTime.setTime_t(time);
	// assertEquals(document.pubDate(), compTime);
	kdWarning() << "Skipping check for Atom \"updated\" (Document::pubDate/lastBuildDate) -- not implemented." << endl;

	assertEquals(document.link().url(), "http://example.org/");

	assertEquals(document.articles().count(), 1);

	Article article = document.articles().first();

	assertEquals(article.title(), "Atom draft-07 snapshot");
	assertEquals(article.link().url(), "http://example.org/2005/04/02/atom");

	if (article.description().isNull())
	{
		kdError() << "Empty Atom article description." << endl;
		tdeApp->exit(1);
	}

	// Enclosure enclosure = article.enclosure();
	// assertEquals(enclosure.url(), "http://example.org/audio/ph34r_my_podcast.mp3");
	// assertEquals(enclosure.length(), 1337);
	// assertEquals(enclosure.type(), "audio/mpeg");
	kdWarning() << "Skipping check for Atom \"enclosure\" links -- not implemented." << endl;

	assertEquals(article.guid(), "tag:example.org,2003:3.2397");

	// 2005-07-31T12:29:29Z
	// Need a little workaround since librss converts the timestamp to local time.
	// NOTE: Atom provides both 'published' and 'updated'; librss uses 'updated'.
	TQDateTime articlePublishedDate;
	time_t publishedTime = KRFCDate::parseDateISO8601("2005-07-31T12:29:29Z");
	articlePublishedDate.setTime_t(publishedTime);
	assertEquals(article.pubDate(), articlePublishedDate);

	assertEquals(article.author(), "<a href=\"mailto:f8dy@example.com\">Mark Pilgrim</a>");
}

void Tester::test( const TQString &url )
{
	Loader *loader = Loader::create();
	connect( loader, TQ_SIGNAL( loadingComplete( Loader *, Document, Status ) ),
	         this, TQ_SLOT( slotLoadingComplete( Loader *, Document, Status ) ) );
	loader->loadFrom( url, new TestRetriever );
}

void Tester::slotLoadingComplete( Loader *loader, Document doc, Status status )
{
	if (status != Success)
	{
		kdError() << "Failed to load Document: ec=" << loader->errorCode() << " status=" << status << endl;
		exit(1);
	}

	switch (doc.version())
	{
		case RSS::v0_91:
		{
			checkRSS091(doc);
			break;
		}
		case RSS::v2_0:
		{
			if (doc.title() == "The Well-Formed Web")
			{
				checkWFW(doc);
				break;
			}
			else if (doc.title() == "The Guardian")
			{
				checkDC(doc);
				break;
			}
			else if (doc.title() == "XML.com")
			{
				checkRDF(doc);
				break;
			}
			kdError() << "Unknown RSS 2.0 document '" << doc.title() << "'" << endl;
			exit(1);
		}
		case RSS::vAtom_1_0:
		{
			checkAtom10(doc);
			break;
		}
		default:
		{
			break;
		}
	}

	exit(0);
}

int main( int argc, char **argv )
{
	TDEAboutData aboutData( "testlibrss", "testlibrss", "0.1" );
	TDECmdLineArgs::init( argc, argv, &aboutData );
	TDECmdLineArgs::addCmdLineOptions( options );
	TDEApplication app(false, false);

        TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
        if ( args->count() != 1 ) args->usage();

	Tester tester;
	tester.test( args->arg( 0 ) );

	return app.exec();
}

#include "testlibrss.moc"
