#include <qfile.h>
#include <qtextstream.h>

#include <kaboutdata.h>
#include <kapplication.h>
#include <kcmdlineargs.h>
#include <kdebug.h>
#include <klocale.h>

#include <khtml_part.h>
#include <khtmlview.h>
#include <kparts/browserextension.h>
#include <kparts/part.h>

#include "dom/dom_doc.h"
#include "dom/dom_element.h"
#include "dom/dom_string.h"

#include "xpath_query.h"
#include "xpath_expression.h"
#include "xpath_tests.h"

namespace XPath {

QTextStream log( stdout, IO_WriteOnly );

QTextStream &msg()
{
    return log;
}

void Tests::interactive( KHTMLPart *html )
{
    DOM::Document doc = html->document();
    DOM::Node el = doc.documentElement();

    printf("Entering interactive mode.\n"
	   "Use debug() to print to the console. Press C-d or C-c to exit.\n\n");

    char buffer[1000];
    FILE *in = fdopen(0, "r");
    
    while (1) {

	DOM::Node pn = el;
	QString s("");
	while ( !pn.isNull() ) {
	    s = QString("%1/%2").arg(pn.nodeName().string()).arg(s);
	    pn = pn.parentNode();
	}
	msg() << s << QString("\t\t%1").arg(el.index()) << endl;

	printf("XPath> ");
	if (!fgets(buffer, 999, in))
	    break;

	QString query( buffer );
	query = query.stripWhiteSpace();

	if ( query == "c" ) {
	    DOM::Node n = el.firstChild();
	    if ( !n.isNull() )
		el = n;
	}
	else if ( query == "n" ) {
	    DOM::Node n = el.nextSibling();
	    if ( !n.isNull() )
		el = n;
	}
	else if ( query == ".." ) {
	    DOM::Node n = el.parentNode();
	    if ( !n.isNull() )
		el = n;
	}
	else if ( (query == "l") || (query == "ls") ) {
	    DOM::Node n = el.firstChild();
	    while ( !n.isNull() ) {
		msg() << n.nodeName().string() << endl;
		n = n.nextSibling();
	    }
	}
	else if ( query == "." ) {
	}
	else {
	    XPath::Query xp;
	    XPath::Value *v = xp.select( query, el );
	    msg() << v->qstring() << endl;
	}
    }

    msg() << endl;
}

void Tests::test_ast( KHTMLPart *html )
{
    // XPathNode
    msg() << "XPathNode" << endl;
    XPath::XPathNode n;
    msg() << "\t" << n.qstring() << endl;

    // Axes
    msg() << endl << "Axes" << endl;
    XPath::Axis ax;
    for ( ushort i = 0 ; i < 16 ; i++ ) {
	ax = XPath::Axis( i );
	msg() << "\t" << ax.qstring() << endl;
    }

    // BinaryOps
    msg() << endl << "BinaryOps" << endl;
    XPath::BinaryOp bo;
    for ( ushort i = 0 ; i < 14 ; i++ ) {
	bo = XPath::BinaryOp( i );
	msg() << "\t" << bo.qstring() << endl;
    }

    // Functions
    msg() << endl << "Functions" << endl;
    XPath::FunctionCall f;
    for ( ushort i = 0 ; i < 28 ; i++ ) {
	f = XPath::FunctionCall( i );
	msg() << "\t" << f.qstring() << endl;
    }

    test_values( html );
}

void Tests::test_values( KHTMLPart * )
{
    msg() << endl << "Values" << endl;

    XPath::Value v;
    msg() << "\t" << v.qstring() << endl;

    XPath::Exception vx("oh my god, an error!");
    msg() << "\t" << vx.qstring() << endl;

    XPath::NodeSet vns;
    msg() << "\t" << vns.qstring() << endl;

    XPath::Boolean vb;
    msg() << "\t" << vb.qstring() << endl;

    XPath::Number vnu;
    msg() << "\t" << vnu.qstring() << endl;
    vnu = XPath::Number(12345UL);
    msg() << "\t" << vnu.qstring() << endl;
    vnu = XPath::Number(3.141);
    msg() << "\t" << vnu.qstring() << endl;

    XPath::String vs;
    msg() << "\t" << vs.qstring() << endl;
    vs = XPath::String( "testing a const char *" );
    msg() << "\t" << vs.qstring() << endl;
    vs = XPath::String( QString("testing a QString") );
    msg() << "\t" << vs.qstring() << endl;
}

}; // namespace XPath

