/*
 * kxmlrpcclient.h - (c) 2003 Frerich Raabe <raabe@kde.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifndef KXMLRPCCLIENT_H
#define KXMLRPCCLIENT_H

#include <kurl.h>

#include <tqbuffer.h>
#include <tqdatastream.h>
#include <tqobject.h>
#include <tqvariant.h>
#include <tqvaluelist.h>

class TQDomDocument;
class TQDomElement;

namespace TDEIO
{
	class Job;
}

namespace KXMLRPC
{
	class Query;
	class QueryResult;
	class Server;

	class Query : public TQObject
	{
		TQ_OBJECT
  
		public:
			class Result
			{
				friend class Query;
				friend TQDataStream &operator>>( TQDataStream &s, Query::Result &r );
				public:
					Result() { }

					bool success() const { return m_success; }
					int errorCode() const { return m_errorCode; }
					TQString errorString() const { return m_errorString; }
					TQValueList<TQVariant> data() const { return m_data; }
					TQString server() const { return m_server; }
					TQString method() const { return m_method; }
					TQValueList<TQVariant> args() const { return m_args; }

				private:
					bool m_success;
					int m_errorCode;
					TQString m_errorString;
					TQValueList<TQVariant> m_data;
					TQString m_server;
					TQString m_method;
					TQValueList<TQVariant> m_args;
			};

			static Query *create( TQObject *parent = 0, const char *name = 0 );
			static TQString marshal( const TQVariant &v );
			static TQVariant demarshal( const TQDomElement &e );

		public slots:
			void call( const TQString &server, const TQString &method,
			           const TQValueList<TQVariant> &args = TQValueList<TQVariant>(),
			           const TQString &userAgent = "KDE-XMLRPC" );

		signals:
			void infoMessage( const TQString &msg );
			void finished( const KXMLRPC::Query::Result &result );

		private slots:
			void slotInfoMessage( TDEIO::Job *job, const TQString &msg );
			void slotData( TDEIO::Job *job, const TQByteArray &data );
			void slotResult( TDEIO::Job *job );

		private:
			bool isMessageResponse( const TQDomDocument &doc ) const;
			bool isFaultResponse( const TQDomDocument &doc ) const;

			Result parseMessageResponse( const TQDomDocument &doc ) const;
			Result parseFaultResponse( const TQDomDocument &doc ) const;

			TQString markupCall( const TQString &method,
			                    const TQValueList<TQVariant> &args ) const;

			Query( TQObject *parent = 0, const char *name = 0 );

			TQBuffer m_buffer;
			TQString m_server;
			TQString m_method;
			TQValueList<TQVariant> m_args;
	};

	class Server : public TQObject
	{
		TQ_OBJECT
  
		public:
			Server( const KURL &url = KURL(),
			        TQObject *parent = 0, const char *name = 0 );

			const KURL &url() const { return m_url; }
			void setUrl( const KURL &url );

			TQString userAgent() const { return m_userAgent; }
			void setUserAgent( const TQString &userAgent) { m_userAgent = userAgent; }

			template <typename T>
			void call( const TQString &method, const TQValueList<T> &arg,
			           TQObject *object, const char *slot );

			static TQValueList<TQVariant> toVariantList( const TQVariant &arg );
			static TQValueList<TQVariant> toVariantList( int arg );
			static TQValueList<TQVariant> toVariantList( bool arg );
			static TQValueList<TQVariant> toVariantList( double arg );
			static TQValueList<TQVariant> toVariantList( const TQString &arg );
			static TQValueList<TQVariant> toVariantList( const TQCString &arg );
			static TQValueList<TQVariant> toVariantList( const TQByteArray &arg );
			static TQValueList<TQVariant> toVariantList( const TQDateTime &arg );
			static TQValueList<TQVariant> toVariantList( const TQStringList &arg );

		signals:
			void infoMessage( const TQString &msg );

		public slots:
			void call( const TQString &method, const TQValueList<TQVariant> &args,
			           TQObject *object, const char *slot );
			void call( const TQString &method, const TQValueList<TQVariant> &args,
			           TQObject *object, const char *slot,
			           TQObject *infoObject, const char *infoSlot );

		private:
			KURL m_url;
			TQString m_userAgent;
	};

	inline TQDataStream &operator>>( TQDataStream &s, Query::Result &r )
	{
		return s >> r.m_errorCode >> r.m_errorString >> r.m_data
		         >> r.m_server >> r.m_method >> r.m_args;
	}
}

template <typename T>
void KXMLRPC::Server::call( const TQString &method, const TQValueList<T> &arg,
                            TQObject *object, const char *slot )
{
	TQValueList<TQVariant> args;

	typename TQValueList<T>::ConstIterator it = arg.begin();
	typename TQValueList<T>::ConstIterator end = arg.end();
	for ( ; it != end; ++it )
		args << TQVariant( *it );

	call( method, args, object, slot );
}

inline TQDataStream &operator<<( TQDataStream &s, const KXMLRPC::Query::Result &r )
{
	return s << r.errorCode() << r.errorString() << r.data()
	         << r.server() << r.method() << r.args();
}

#endif // KXMLRPCCLIENT_H
