/***************************************************************************
                          kdehandlers.cpp  -  KDE specific marshallers
                             -------------------
    begin                : Sun Sep 28 2003
    copyright            : (C) 2003 by Richard Dale
    email                : Richard_Dale@tipitina.demon.co.uk
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <qtruby.h>
#include <smokeruby.h>

#include <dcopclient.h>
#include <dcopobject.h>
#include <dcopref.h>
#include <tqptrlist.h>
#include <ktrader.h>
#include <kservicegroup.h>
#include <kservice.h>
#include <tdesycocatype.h>
#include <tdemainwindow.h>
#include <tdefile.h>
#include <tdefileview.h>
#include <kurl.h>
#include <tdecmdlineargs.h>
#include <tdeaction.h>
#include <kdockwidget.h>
#include <tdefiletreebranch.h>
#include <tdefiletreeviewitem.h>
#include <tdehtml_part.h>
#include <tdeparts/plugin.h>
#include <kuserprofile.h>
#include <tdeaboutdata.h>
#include <karchive.h>
#include <tdeconfigskeleton.h>
#include <kplugininfo.h>
#include <kmountpoint.h>
#include <tdeio/jobclasses.h>
#include <dom/dom_node.h>
#include <dom/dom_element.h>
#include <dom/dom_string.h>
#include <dom/html_element.h>

#define HAVE_STRLCAT_PROTO 1
#define HAVE_STRLCPY_PROTO 1
#include "config.h"

#ifndef HAVE_RUBY_1_9
#define RARRAY_LEN(x) (RARRAY(x)->len)
#define RSTRING_LEN(x) (RSTRING(x)->len)
#define rb_str_catf_1 rb_str_catf
#endif

extern "C" {
extern VALUE set_obj_info(const char * className, smokeruby_object * o);
};

extern bool isDerivedFromByName(Smoke *smoke, const char *className, const char *baseClassName);

extern "C" {
/*
 * Given an approximate classname and a kde instance, try to improve the resolution of the name
 * by using the various KDE rtti mechanisms
 */
const char *
kde_resolve_classname(Smoke * smoke, int classId, void * ptr)
{
	if (isDerivedFromByName(smoke, smoke->classes[classId].className, "KArchiveEntry")) {
		KArchiveEntry * entry = (KArchiveEntry *) smoke->cast(ptr, classId, smoke->idClass("KArchiveEntry"));
		if (entry->isDirectory()) {
			return "KDE::ArchiveDirectory";
		} else {
			return "KDE::ArchiveFile";
		}
	} else if (strcmp(smoke->classes[classId].className, "DOM::Node") == 0) {
		DOM::Node * node = (DOM::Node *) smoke->cast(ptr, classId, smoke->idClass("DOM::Node"));
		switch (node->nodeType()) {
		case DOM::Node::ELEMENT_NODE:
			if (((DOM::Element*)node)->isHTMLElement()) {
				return "DOM::HTMLElement";
			} else {
				return "DOM::Element";
			}
		case DOM::Node::ATTRIBUTE_NODE:
			return "DOM::Attr";
		case DOM::Node::TEXT_NODE:
			return "DOM::Text";
		case DOM::Node::CDATA_SECTION_NODE:
			return "DOM::CDATASection";
		case DOM::Node::ENTITY_REFERENCE_NODE:
			return "DOM::EntityReference";
		case DOM::Node::ENTITY_NODE:
			return "DOM::Entity";
		case DOM::Node::PROCESSING_INSTRUCTION_NODE:
			return "DOM::ProcessingInstruction";
		case DOM::Node::COMMENT_NODE:
			return "DOM::Comment";
		case DOM::Node::DOCUMENT_NODE:
			return "DOM::Document";
		case DOM::Node::DOCUMENT_TYPE_NODE:
			return "DOM::DocumentType";
		case DOM::Node::DOCUMENT_FRAGMENT_NODE:
			return "DOM::DocumentFragment";
		case DOM::Node::NOTATION_NODE:
			return "DOM::Notation";
		}
	}

	return smoke->binding->className(classId);
}

};

void marshall_TQCStringList(Marshall *m) {
    switch(m->action()) {
      case Marshall::FromVALUE:
	{
	    VALUE list = *(m->var());
	    if (TYPE(list) != T_ARRAY) {
		m->item().s_voidp = 0;
		break;
	    }

	    int count = RARRAY_LEN(list);
	    QCStringList *stringlist = new QCStringList;

	    for(long i = 0; i < count; i++) {
		VALUE item = rb_ary_entry(list, i);
		if(TYPE(item) != T_STRING) {
		    stringlist->append(TQCString());
		    continue;
		}
		stringlist->append(TQCString(StringValuePtr(item), RSTRING_LEN(item) + 1));
	    }

	    m->item().s_voidp = stringlist;
	    m->next();

	    if(m->cleanup()) {
		rb_ary_clear(list);
		for(QCStringList::Iterator it = stringlist->begin(); it != stringlist->end(); ++it)
		    rb_ary_push(list, rb_str_new2(static_cast<const char *>(*it)));
		delete stringlist;
	    }
	    break;
      }
      case Marshall::ToVALUE:
	{
	    QCStringList *stringlist = static_cast<QCStringList *>(m->item().s_voidp);
	    if(!stringlist) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();
	    for(QCStringList::Iterator it = stringlist->begin(); it != stringlist->end(); ++it) {
		VALUE rv = rb_str_new2(static_cast<const char *>((*it)));
		rb_ary_push(av, rv);
	    }

	    if(m->cleanup())
		delete stringlist;

	    *(m->var()) = av;
	}
	break;
      default:
	m->unsupported();
	break;
    }
}

#if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2
#  define BREAKPOINT { __asm__ __volatile__ ("int $03"); }
#else
#  define BREAKPOINT { fprintf(stderr, "hit ctrl-c\n"); int b = 0; while (b == 0) { ; } }
#endif

void marshall_TDECmdLineOptions(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
			VALUE optionslist = *(m->var());
			if (optionslist == Qnil
			|| TYPE(optionslist) != T_ARRAY
			|| RARRAY_LEN(optionslist) == 0 )
			{
					m->item().s_voidp = 0;
					break;
			}

			// Allocate 'length + 1' entries, to include an all NULLs last entry
			TDECmdLineOptions *cmdLineOptions = (TDECmdLineOptions *) calloc(	RARRAY_LEN(optionslist) + 1,
																			sizeof(struct TDECmdLineOptions) );

			VALUE options;
			long i;
			for(i = 0; i < RARRAY_LEN(optionslist); i++) {
				options = rb_ary_entry(optionslist, i);
				VALUE temp = rb_ary_entry(options, 0);
				cmdLineOptions[i].name = StringValuePtr(temp);
				temp = rb_ary_entry(options, 1);
				cmdLineOptions[i].description = StringValuePtr(temp);
				temp = rb_ary_entry(options, 2);
				cmdLineOptions[i].def = StringValuePtr(temp);
			}
			cmdLineOptions[i].name = 0;
			cmdLineOptions[i].description = 0;
			cmdLineOptions[i].def = 0;


			m->item().s_voidp = cmdLineOptions;
			m->next();
         /*
			if(m->cleanup()) {
			rb_ary_clear(optionslist);
			for(i = 0; cmdLineOptions[i].name; i++)
				options = rb_ary_new();
				rb_ary_push(options, rb_str_new2(cmdLineOptions[i].name));
				rb_ary_push(options, rb_str_new2(cmdLineOptions[i].description));
				rb_ary_push(options, rb_str_new2(cmdLineOptions[i].def));
				rb_ary_push(optionslist, options);
			}
         */
		}
		break;
	case Marshall::ToVALUE:
		{
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_WIdList(Marshall *m) {
    switch(m->action()) {
      case Marshall::FromVALUE:
	{
	    VALUE list = *(m->var());
	    if (TYPE(list) != T_ARRAY) {
		m->item().s_voidp = 0;
		break;
	    }
	    int count = RARRAY_LEN(list);
	    TQValueList<WId> *valuelist = new TQValueList<WId>;
	    long i;
	    for(i = 0; i < count; i++) {
		VALUE item = rb_ary_entry(list, i);
		if(TYPE(item) != T_FIXNUM && TYPE(item) != T_BIGNUM) {
		    valuelist->append(0);
		    continue;
		}
		valuelist->append(NUM2LONG(item));
	    }

	    m->item().s_voidp = valuelist;
	    m->next();

		if (!m->type().isConst()) {
			rb_ary_clear(list);
			for(TQValueListIterator<WId> it = valuelist->begin();
				it != valuelist->end();
				++it)
				rb_ary_push(list, LONG2NUM((int)*it));
		}

		if (m->cleanup()) {
			delete valuelist;
	    }
	}
	break;
      case Marshall::ToVALUE:
	{
	    TQValueList<WId> *valuelist = (TQValueList<WId>*)m->item().s_voidp;
	    if(!valuelist) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    for(TQValueListIterator<WId> it = valuelist->begin();
		it != valuelist->end();
		++it)
		rb_ary_push(av, LONG2NUM(*it));

	    *(m->var()) = av;

	    if(m->cleanup())
		delete valuelist;
	}
	break;
      default:
	m->unsupported();
	break;
    }
}

void marshall_KMimeTypeList(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
		}
		break;
	case Marshall::ToVALUE:
		{
	    KMimeType::List *offerList = (KMimeType::List*)m->item().s_voidp;
	    if(!offerList) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    for(KMimeType::List::Iterator it = offerList->begin();
		it != offerList->end();
		++it) {
        KMimeType * item  = new KMimeType (*(KMimeType*)((KMimeType::Ptr)(*it)).data());

		VALUE obj = getPointerObject(item);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = m->smoke()->idClass("KMimeType");
		    o->ptr = item;
		    o->allocated = true;
		    obj = set_obj_info("KDE::MimeType", o);
		}
		rb_ary_push(av, obj);
            }

	    *(m->var()) = av;

		if(m->cleanup())
		delete offerList;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_KMimeTypePtr(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
		}
		break;
	case Marshall::ToVALUE:
		{
	    KMimeType::Ptr ptr(*(KMimeType::Ptr*)m->item().s_voidp);
	    if(ptr == 0) {
		*(m->var()) = Qnil;
		break;
	    }
	    KMimeType * mimeType = new KMimeType(*(KMimeType*)ptr);

		VALUE obj = getPointerObject(mimeType);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = m->smoke()->idClass("KMimeType");
		    o->ptr = mimeType;
		    o->allocated = true;
		    obj = set_obj_info("KDE::MimeType", o);
		}

	    *(m->var()) = obj;

		if(m->cleanup())
		;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_KServicePtr(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
		}
		break;
	case Marshall::ToVALUE:
		{
		TDESharedPtr<KService> *ptr = new TDESharedPtr<KService>(*(TDESharedPtr<KService>*)m->item().s_voidp);
	    if(ptr == 0) {
		*(m->var()) = Qnil;
		break;
	    }
	    KService * service = ptr->data();

		VALUE obj = getPointerObject(service);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = m->smoke()->idClass("KService");
		    o->ptr = service;
		    o->allocated = true;
		    obj = set_obj_info("KDE::Service", o);
		}

	    *(m->var()) = obj;

		if(m->cleanup())
		;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_KServiceList(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
		}
		break;
	case Marshall::ToVALUE:
		{
	    KService::List *offerList = (KService::List*)m->item().s_voidp;
	    if(!offerList) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    for(KService::List::Iterator it = offerList->begin();
		it != offerList->end();
		++it) {
		TDESharedPtr<KService> *ptr = new TDESharedPtr<KService>(*it);
		KService * currentOffer = ptr->data();

		VALUE obj = getPointerObject(currentOffer);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = m->smoke()->idClass("KService");
		    o->ptr = currentOffer;
		    o->allocated = false;
		    obj = set_obj_info("KDE::Service", o);
		}
		rb_ary_push(av, obj);
            }

	    *(m->var()) = av;

		if(m->cleanup())
		delete offerList;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_KServiceGroupPtr(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
		}
		break;
	case Marshall::ToVALUE:
		{
	    KServiceGroup::Ptr ptr(*(KServiceGroup::Ptr*)m->item().s_voidp);
	    if(ptr == 0) {
		*(m->var()) = Qnil;
		break;
	    }
	    KServiceGroup * serviceGroup = new KServiceGroup(*(KServiceGroup*)ptr);

		VALUE obj = getPointerObject(serviceGroup);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = m->smoke()->idClass("KServiceGroup");
		    o->ptr = serviceGroup;
		    o->allocated = true;
		    obj = set_obj_info("KDE::ServiceGroup", o);
		}

	    *(m->var()) = obj;

		if(m->cleanup())
		;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_KServiceTypeList(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
		}
		break;
	case Marshall::ToVALUE:
		{
	    KServiceType::List *offerList = (KServiceType::List*)m->item().s_voidp;
	    if(!offerList) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    for(KServiceType::List::Iterator it = offerList->begin();
		it != offerList->end();
		++it) {
		KServiceType * currentOffer = new KServiceType(*((KServiceType*)*it));

		VALUE obj = getPointerObject(currentOffer);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = m->smoke()->idClass("KServiceType");
		    o->ptr = currentOffer;
		    o->allocated = true;
		    obj = set_obj_info("KDE::ServiceType", o);
		}
		rb_ary_push(av, obj);
            }

	    *(m->var()) = av;

		if(m->cleanup())
		delete offerList;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_KServiceGroupList(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
		}
		break;
	case Marshall::ToVALUE:
		{
	    KServiceGroup::List *offerList = (KServiceGroup::List*)m->item().s_voidp;
	    if(!offerList) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    for(KServiceGroup::List::ConstIterator it = offerList->begin();
		it != offerList->end();
		++it) {
		KSycocaEntry *p = (*it);
		VALUE obj = Qnil;
		if (p->isType(KST_KService)) {
			KService *s = static_cast<KService *>(p);
			obj = getPointerObject(s);
			if(obj == Qnil) {
		    	smokeruby_object  * o = ALLOC(smokeruby_object);
		    	o->smoke = m->smoke();
		    	o->classId = m->smoke()->idClass("KService");
		    	o->ptr = s;
		    	o->allocated = true;
		    	obj = set_obj_info("KDE::Service", o);
			}
		} else if (p->isType(KST_KServiceGroup)) {
			KServiceGroup *g = static_cast<KServiceGroup *>(p);
			obj = getPointerObject(g);
			if(obj == Qnil) {
		    	smokeruby_object  * o = ALLOC(smokeruby_object);
		    	o->smoke = m->smoke();
		    	o->classId = m->smoke()->idClass("KServiceGroup");
		    	o->ptr = g;
		    	o->allocated = true;
		    	obj = set_obj_info("KDE::ServiceGroup", o);
			}
		}

		rb_ary_push(av, obj);
        }

	    *(m->var()) = av;

		if(m->cleanup())
		delete offerList;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_KMountPointList(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
		}
		break;
	case Marshall::ToVALUE:
		{
	    KMountPoint::List *list = (KMountPoint::List*)m->item().s_voidp;
	    if(!list) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    for(KMountPoint::List::Iterator it = list->begin();
		it != list->end();
		++it) {
		KMountPoint * item = new KMountPoint(*((KMountPoint*)*it));

		VALUE obj = getPointerObject(item);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = m->smoke()->idClass("KMountPoint");
		    o->ptr = item;
		    o->allocated = true;
		    obj = set_obj_info("KDE::MountPoint", o);
		}
		rb_ary_push(av, obj);
            }

	    *(m->var()) = av;

		if(m->cleanup())
		delete list;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_KPluginInfoList(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
	    }
		break;
	case Marshall::ToVALUE:
		{
	    KPluginInfo::List *valuelist = (KPluginInfo::List*)m->item().s_voidp;
	    if(!valuelist) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    int ix = m->smoke()->idClass("KPluginInfo");
	    const char * className = m->smoke()->binding->className(ix);

	    for(KPluginInfo::List::Iterator it = valuelist->begin();
		it != valuelist->end();
		++it) {
		void *p = (*it);

		if(m->item().s_voidp == 0) {
		    *(m->var()) = Qnil;
		    break;
		}

		VALUE obj = getPointerObject(p);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = o->smoke->idClass("KPluginInfo");
		    o->ptr = p;
		    o->allocated = false;
		    obj = set_obj_info(className, o);
		}
		rb_ary_push(av, obj);
            }

	    if(m->cleanup())
		delete valuelist;
	    else
	        *(m->var()) = av;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_TDEActionPtrList(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
	    }
		break;
	case Marshall::ToVALUE:
		{
		TDEActionPtrList *valuelist = (TDEActionPtrList*)m->item().s_voidp;
		if (!valuelist) {
			*(m->var()) = Qnil;
			break;
	    }

	    VALUE av = rb_ary_new();

	    int ix = m->smoke()->idClass("TDEAction");
	    const char * className = m->smoke()->binding->className(ix);

		for (	TDEActionPtrList::Iterator it = valuelist->begin();
				it != valuelist->end();
				++it )
		{
			void *p = (*it);

			if (m->item().s_voidp == 0) {
		    	*(m->var()) = Qnil;
		    	break;
			}

			VALUE obj = getPointerObject(p);
			if (obj == Qnil) {
				smokeruby_object  * o = ALLOC(smokeruby_object);
				o->smoke = m->smoke();
				o->classId = o->smoke->idClass("TDEAction");
				o->ptr = p;
				o->allocated = false;
				obj = set_obj_info(className, o);
			}
			rb_ary_push(av, obj);
		}

		if (m->cleanup())
			delete valuelist;
		else
			*(m->var()) = av;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_TDETraderOfferList(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
		}
		break;
	case Marshall::ToVALUE:
		{
	    TDETrader::OfferList *offerList = (TDETrader::OfferList*)m->item().s_voidp;
	    if(!offerList) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    for(TDETrader::OfferList::Iterator it = offerList->begin();
		it != offerList->end();
		++it) {
		TDESharedPtr<KService> *ptr = new TDESharedPtr<KService>(*it);
		KService * currentOffer = ptr->data();

		VALUE obj = getPointerObject(currentOffer);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = m->smoke()->idClass("KService");
		    o->ptr = currentOffer;
		    o->allocated = false;
		    obj = set_obj_info("KDE::Service", o);
		}
		rb_ary_push(av, obj);
            }

	    *(m->var()) = av;

		if(m->cleanup())
		delete offerList;
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_KURLList(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
		{
			VALUE list = *(m->var());
			if (TYPE(list) != T_ARRAY) {
				m->item().s_voidp = 0;
				break;
			}
			int count = RARRAY_LEN(list);
			KURL::List *kurllist = new KURL::List;
			long i;
			for(i = 0; i < count; i++) {
				VALUE item = rb_ary_entry(list, i);
                // TODO do type checking!
				smokeruby_object *o = value_obj_info(item);
				if(!o || !o->ptr)
					continue;
				void *ptr = o->ptr;
				ptr = o->smoke->cast(
					ptr,				// pointer
					o->classId,				// from
					o->smoke->idClass("KURL")	        // to
					);
				kurllist->append((KURL&)*(KURL*)ptr);
			}

			m->item().s_voidp = kurllist;
			m->next();

			rb_ary_clear(list);
	    	int ix = m->smoke()->idClass("KURL");
	    	const char * className = m->smoke()->binding->className(ix);
			for (	KURL::List::Iterator it = kurllist->begin();
					it != kurllist->end();
					++it )
			{
				void *p = new KURL(*it);
				VALUE obj = getPointerObject(p);
				if(obj == Qnil) {
					smokeruby_object  * o = ALLOC(smokeruby_object);
					o->smoke = m->smoke();
					o->classId = ix;
					o->ptr = p;
					o->allocated = true;
					obj = set_obj_info(className, o);
				}
				rb_ary_push(list, obj);
			}

			if(m->cleanup()) {
				delete kurllist;
			}
	    }
		break;
	case Marshall::ToVALUE:
		{
	    KURL::List *kurllist = (KURL::List*)m->item().s_voidp;
	    if(!kurllist) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    int ix = m->smoke()->idClass("KURL");
	    const char * className = m->smoke()->binding->className(ix);

	    for(KURL::List::Iterator it = kurllist->begin();
		it != kurllist->end();
		++it) {
		void *p = new KURL(*it);

		VALUE obj = getPointerObject(p);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = ix;
		    o->ptr = p;
		    o->allocated = true;
		    obj = set_obj_info(className, o);
		}
		rb_ary_push(av, obj);
            }

	    *(m->var()) = av;

	    if(m->cleanup()) {
			delete kurllist;
		}
		}
		break;
	default:
		m->unsupported();
		break;
	}
}

void marshall_UDSEntryList(Marshall *m) {
	switch(m->action()) {
	case Marshall::FromVALUE:
	{
		VALUE list = *(m->var());
		if (TYPE(list) != T_ARRAY) {
			m->item().s_voidp = 0;
			break;
		}

		TDEIO::UDSEntryList *cpplist = new TDEIO::UDSEntryList;

		for(long i = 0; i < RARRAY_LEN(list); i++) {
			VALUE item = rb_ary_entry(list, i);
			TDEIO::UDSEntry *cppsublist = new TDEIO::UDSEntry;

			for (int j = 0; j < RARRAY_LEN(item); j++) {
				VALUE subitem = rb_ary_entry(item, j);
				smokeruby_object *o = value_obj_info(subitem);
				if(!o || !o->ptr)
					continue;
				void *ptr = o->ptr;
				ptr = o->smoke->cast(ptr, o->classId, o->smoke->idClass("TDEIO::UDSAtom"));
				cppsublist->append(*(TDEIO::UDSAtom*)ptr);
			}

			cpplist->append(*cppsublist);
		}

		m->item().s_voidp = cpplist;
		m->next();
	}
	break;
	case Marshall::ToVALUE:
	{
	  	TDEIO::UDSEntryList *valuelist = (TDEIO::UDSEntryList*)m->item().s_voidp;
		if (!valuelist) {
			*(m->var()) = Qnil;
			break;
		}

		VALUE av = rb_ary_new();

		int ix = m->smoke()->idClass("TDEIO::UDSAtom");

		for (	TDEIO::UDSEntryList::Iterator it = valuelist->begin();
				it != valuelist->end();
				++it )
		{
			TDEIO::UDSEntry * udsentry = &(*it);
			VALUE subav = rb_ary_new();

			for (	TDEIO::UDSEntry::Iterator it = udsentry->begin();
					it != udsentry->end();
					++it )
			{
				void * p = &(*it);
				VALUE obj = getPointerObject(p);
				if(obj == Qnil) {
					smokeruby_object  * o = ALLOC(smokeruby_object);
					o->smoke = m->smoke();
					o->classId = ix;
					o->ptr = p;
					o->allocated = false;
					obj = set_obj_info("TDEIO::UDSAtom", o);
				}

				rb_ary_push(subav, obj);
			}

			rb_ary_push(av, subav);
		}

		*(m->var()) = av;
	}
	break;
	default:
		m->unsupported();
		break;
	}
}


// Some time saving magic from Alex Kellett here..
template <class Item, class ItemList, const char *ItemSTR >
void marshall_ItemList(Marshall *m) {
    switch(m->action()) {
      case Marshall::FromVALUE:
	{
	    VALUE list = *(m->var());
	    if (TYPE(list) != T_ARRAY) {
		m->item().s_voidp = 0;
		break;
	    }
	    int count = RARRAY_LEN(list);
	    ItemList *cpplist = new ItemList;
	    long i;
	    for(i = 0; i < count; i++) {
		VALUE item = rb_ary_entry(list, i);
                // TODO do type checking!
		smokeruby_object *o = value_obj_info(item);
		if(!o || !o->ptr)
                    continue;
		void *ptr = o->ptr;
		ptr = o->smoke->cast(
		    ptr,				// pointer
		    o->classId,				// from
		    o->smoke->idClass(ItemSTR)	        // to
		);
		cpplist->append((Item*)ptr);
	    }

	    m->item().s_voidp = cpplist;
	    m->next();

	    if(m->cleanup()) {
		rb_ary_clear(list);
		for( Item * it = cpplist->first();
		    it != 0;
		    it = cpplist->next()) {
		    VALUE obj = getPointerObject((void*)it);
		    rb_ary_push(list, obj);
		}
		delete cpplist;
	    }
	}
	break;
      case Marshall::ToVALUE:
	{
	    ItemList *valuelist = (ItemList*)m->item().s_voidp;
	    if(!valuelist) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    int ix = m->smoke()->idClass(ItemSTR);
	    const char * className = m->smoke()->binding->className(ix);

	    for(Item * it = valuelist->first();
		it != 0;
		it = valuelist->next()) {
		void *p = it;

		if(m->item().s_voidp == 0) {
		    *(m->var()) = Qnil;
		    break;
		}

		VALUE obj = getPointerObject(p);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = o->smoke->idClass(ItemSTR);
		    o->ptr = p;
		    o->allocated = false;
		    obj = set_obj_info(className, o);
		}
		rb_ary_push(av, obj);
            }

	    if(m->cleanup())
		delete valuelist;
	    else
	        *(m->var()) = av;
	}
	break;
      default:
	m->unsupported();
	break;
    }
}

#define DEF_LIST_MARSHALLER(ListIdent,ItemList,Item) namespace { char ListIdent##STR[] = #Item; };  \
        Marshall::HandlerFn marshall_##ListIdent = marshall_ItemList<Item,ItemList,ListIdent##STR>;

DEF_LIST_MARSHALLER( KFileItemList, TQPtrList<KFileItem>, KFileItem )
DEF_LIST_MARSHALLER( TDEMainWindowList, TQPtrList<TDEMainWindow>, TDEMainWindow )
DEF_LIST_MARSHALLER( TDEActionList, TQPtrList<TDEAction>, TDEAction )
DEF_LIST_MARSHALLER( DCOPObjectList, TQPtrList<DCOPObject>, DCOPObject )
DEF_LIST_MARSHALLER( KDockWidgetList, TQPtrList<KDockWidget>, KDockWidget )
DEF_LIST_MARSHALLER( KFileTreeBranch, TQPtrList<KFileTreeBranch>, KFileTreeBranch )
DEF_LIST_MARSHALLER( KFileTreeViewItem, TQPtrList<KFileTreeViewItem>, KFileTreeViewItem )
DEF_LIST_MARSHALLER( KPartList, TQPtrList<KParts::Part>, KParts::Part )
DEF_LIST_MARSHALLER( KPartPluginList, TQPtrList<KParts::Plugin>, KParts::Plugin )
DEF_LIST_MARSHALLER( KPartReadOnlyPartList, TQPtrList<KParts::ReadOnlyPart>, KParts::ReadOnlyPart )
DEF_LIST_MARSHALLER( KServiceTypeProfileList, TQPtrList<KServiceTypeProfile>, KServiceTypeProfile )

template <class Item, class ItemList, class ItemListIterator, const char *ItemSTR >
void marshall_ValueItemList(Marshall *m) {
    switch(m->action()) {
      case Marshall::FromVALUE:
	{
	    VALUE list = *(m->var());
	    if (TYPE(list) != T_ARRAY) {
		m->item().s_voidp = 0;
		break;
	    }
	    int count = RARRAY_LEN(list);
	    ItemList *cpplist = new ItemList;
	    long i;
	    for(i = 0; i < count; i++) {
		VALUE item = rb_ary_entry(list, i);
                // TODO do type checking!
		smokeruby_object *o = value_obj_info(item);
		if(!o || !o->ptr)
                    continue;
		void *ptr = o->ptr;
		ptr = o->smoke->cast(
		    ptr,				// pointer
		    o->classId,				// from
		    o->smoke->idClass(ItemSTR)	        // to
		);
		cpplist->append(*(Item*)ptr);
	    }

	    m->item().s_voidp = cpplist;
	    m->next();

	    if(m->cleanup()) {
		rb_ary_clear(list);
		for(ItemListIterator it = cpplist->begin();
		    it != cpplist->end();
		    ++it) {
		    VALUE obj = getPointerObject((void*)&(*it));
		    rb_ary_push(list, obj);
		}
		delete cpplist;
	    }
	}
	break;
      case Marshall::ToVALUE:
	{
	    ItemList *valuelist = (ItemList*)m->item().s_voidp;
	    if(!valuelist) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE av = rb_ary_new();

	    int ix = m->smoke()->idClass(ItemSTR);
	    const char * className = m->smoke()->binding->className(ix);

	    for(ItemListIterator it = valuelist->begin();
		it != valuelist->end();
		++it) {
		void *p = &(*it);

		if(m->item().s_voidp == 0) {
		    *(m->var()) = Qnil;
		    break;
		}

		VALUE obj = getPointerObject(p);
		if(obj == Qnil) {
		    smokeruby_object  * o = ALLOC(smokeruby_object);
		    o->smoke = m->smoke();
		    o->classId = o->smoke->idClass(ItemSTR);
		    o->ptr = p;
		    o->allocated = false;
		    obj = set_obj_info(className, o);
		}
		rb_ary_push(av, obj);
            }

	    if(m->cleanup())
		delete valuelist;
	    else
	        *(m->var()) = av;
	}
	break;
      default:
	m->unsupported();
	break;
    }
}

#define DEF_VALUELIST_MARSHALLER(ListIdent,ItemList,Item,Itr) namespace { char ListIdent##STR[] = #Item; };  \
        Marshall::HandlerFn marshall_##ListIdent = marshall_ValueItemList<Item,ItemList,Itr,ListIdent##STR>;

DEF_VALUELIST_MARSHALLER( ChoicesList, TQValueList<TDEConfigSkeleton::ItemEnum::Choice>, TDEConfigSkeleton::ItemEnum::Choice, TQValueList<TDEConfigSkeleton::ItemEnum::Choice>::Iterator )
DEF_VALUELIST_MARSHALLER( TDEAboutPersonList, TQValueList<TDEAboutPerson>, TDEAboutPerson, TQValueList<TDEAboutPerson>::Iterator )
DEF_VALUELIST_MARSHALLER( TDEAboutTranslatorList, TQValueList<TDEAboutTranslator>, TDEAboutTranslator, TQValueList<TDEAboutTranslator>::Iterator )
DEF_VALUELIST_MARSHALLER( KIOCopyInfoList, TQValueList<TDEIO::CopyInfo>, TDEIO::CopyInfo, TQValueList<TDEIO::CopyInfo>::Iterator )
DEF_VALUELIST_MARSHALLER( KServiceOfferList, TQValueList<KServiceOffer>, KServiceOffer, TQValueList<KServiceOffer>::Iterator )
DEF_VALUELIST_MARSHALLER( UDSEntry, TQValueList<TDEIO::UDSAtom>, TDEIO::UDSAtom, TQValueList<TDEIO::UDSAtom>::Iterator )

template <class Key, class Value, class ItemMapIterator, const char *KeySTR, const char *ValueSTR >
void marshall_Map(Marshall *m) {
    switch(m->action()) {
      case Marshall::FromVALUE:
	{
	    VALUE hash = *(m->var());
	    if (TYPE(hash) != T_HASH) {
		m->item().s_voidp = 0;
		break;
	    }

		TQMap<Key,Value> * map = new TQMap<Key,Value>;

		// Convert the ruby hash to an array of key/value arrays
		VALUE temp = rb_funcall(hash, rb_intern("to_a"), 0);

		for (long i = 0; i < RARRAY_LEN(temp); i++) {
			VALUE key = rb_ary_entry(rb_ary_entry(temp, i), 0);
			VALUE value = rb_ary_entry(rb_ary_entry(temp, i), 1);

			smokeruby_object *o = value_obj_info(key);
			if( !o || !o->ptr)
                   continue;
			void * key_ptr = o->ptr;
			key_ptr = o->smoke->cast(key_ptr, o->classId, o->smoke->idClass(KeySTR));

			o = value_obj_info(value);
			if( !o || !o->ptr)
                   continue;
			void * val_ptr = o->ptr;
			val_ptr = o->smoke->cast(val_ptr, o->classId, o->smoke->idClass(ValueSTR));

			(*map)[(Key)*(Key*)key_ptr] = (Value)*(Value*)val_ptr;
		}

		m->item().s_voidp = map;
		m->next();

	    if(m->cleanup())
		delete map;
	}
	break;
      case Marshall::ToVALUE:
	{
	    TQMap<Key,Value> *map = (TQMap<Key,Value>*)m->item().s_voidp;
	    if(!map) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE hv = rb_hash_new();

		int key_ix = m->smoke()->idClass(KeySTR);
	    const char * key_className = m->smoke()->binding->className(key_ix);

		int val_ix = m->smoke()->idClass(ValueSTR);
	    const char * val_className = m->smoke()->binding->className(val_ix);

		ItemMapIterator it;
		for (it = map->begin(); it != map->end(); ++it) {
			void *key_p = new Key(it.key());
			VALUE key_obj = getPointerObject(key_p);
			smokeruby_object  * o;

			if (key_obj == Qnil) {
				o = ALLOC(smokeruby_object);
				o->classId = m->smoke()->idClass(KeySTR);
				o->smoke = m->smoke();
				o->ptr = key_p;
				o->allocated = true;
				key_obj = set_obj_info(key_className, o);
			}

			void *val_p = new Value(it.data());
			VALUE value_obj = getPointerObject(val_p);

			if (value_obj == Qnil) {
				o = ALLOC(smokeruby_object);
				o->classId = m->smoke()->idClass(ValueSTR);
				o->smoke = m->smoke();
				o->ptr = val_p;
				o->allocated = true;
				value_obj = set_obj_info(val_className, o);
			}

			rb_hash_aset(hv, key_obj, value_obj);
        }

		*(m->var()) = hv;
		m->next();

	    if(m->cleanup())
		delete map;
	}
	break;
      default:
	m->unsupported();
	break;
    }
}

#define DEF_MAP_MARSHALLER(MapIdent,Key,Value) namespace { char KeyIdent##STR[] = #Key; char ValueIdent##STR[] = #Value; };  \
        Marshall::HandlerFn marshall_##MapIdent = marshall_Map<Key, Value,TQMap<Key,Value>::Iterator,KeyIdent##STR, ValueIdent##STR>;

DEF_MAP_MARSHALLER( TQMapKEntryKeyKEntry, KEntryKey, KEntry )

void marshall_TQMapTQCStringDCOPRef(Marshall *m) {
    switch(m->action()) {
      case Marshall::FromVALUE:
	{
	    VALUE hash = *(m->var());
	    if (TYPE(hash) != T_HASH) {
		m->item().s_voidp = 0;
		break;
	    }

		TQMap<TQCString,DCOPRef> * map = new TQMap<TQCString,DCOPRef>;

		// Convert the ruby hash to an array of key/value arrays
		VALUE temp = rb_funcall(hash, rb_intern("to_a"), 0);

		for (long i = 0; i < RARRAY_LEN(temp); i++) {
			VALUE key = rb_ary_entry(rb_ary_entry(temp, i), 0);
			VALUE value = rb_ary_entry(rb_ary_entry(temp, i), 1);

			smokeruby_object *o = value_obj_info(value);
			if( !o || !o->ptr)
                   continue;
			void * ptr = o->ptr;
			ptr = o->smoke->cast(ptr, o->classId, o->smoke->idClass("DCOPRef"));

			(*map)[TQCString(StringValuePtr(key))] = (DCOPRef)*(DCOPRef*)ptr;
		}

		m->item().s_voidp = map;
		m->next();

	    if(m->cleanup())
		delete map;
	}
	break;
      case Marshall::ToVALUE:
	{
	    TQMap<TQCString,DCOPRef> *map = (TQMap<TQCString,DCOPRef>*)m->item().s_voidp;
	    if(!map) {
		*(m->var()) = Qnil;
		break;
	    }

	    VALUE hv = rb_hash_new();

		TQMap<TQCString,DCOPRef>::Iterator it;
		for (it = map->begin(); it != map->end(); ++it) {
			void *p = new DCOPRef(it.data());
			VALUE obj = getPointerObject(p);

			if (obj == Qnil) {
				smokeruby_object  * o = ALLOC(smokeruby_object);
				o->classId = m->smoke()->idClass("DCOPRef");
				o->smoke = m->smoke();
				o->ptr = p;
				o->allocated = true;
				obj = set_obj_info("KDE::DCOPRef", o);
			}

			rb_hash_aset(hv, rb_str_new2((const char *) it.key()), obj);
        }

		*(m->var()) = hv;
		m->next();

	    if(m->cleanup())
		delete map;
	}
	break;
      default:
	m->unsupported();
	break;
    }
}

TypeHandler KDE_handlers[] = {
    { "QCStringList", marshall_TQCStringList },
    { "TDECmdLineOptions*", marshall_TDECmdLineOptions },
    { "TDEActionPtrList", marshall_TDEActionList },
    { "TQPtrList<TDEAction>", marshall_TDEActionList },
    { "TQPtrList<TDEAction>&", marshall_TDEActionList },
    { "KMimeType::List", marshall_KMimeTypeList },
    { "KMimeType::Ptr", marshall_KMimeTypePtr },
    { "KService::Ptr", marshall_KServicePtr },
    { "KService::List", marshall_KServiceList },
    { "KServiceGroup::List", marshall_KServiceGroupList },
    { "KServiceGroup::Ptr", marshall_KServiceGroupPtr },
    { "KMountPoint::List", marshall_KMountPointList },
    { "KPluginInfo::List", marshall_KPluginInfoList },
    { "TQValueList<TDEConfigSkeleton::ItemEnum::Choice>", marshall_ChoicesList },
    { "TQValueList<TDEConfigSkeleton::ItemEnum::Choice>&", marshall_ChoicesList },
    { "KServiceType::List", marshall_KServiceTypeList },
    { "TDETrader::OfferList", marshall_TDETraderOfferList },
    { "KURL::List", marshall_KURLList },
    { "KURL::List&", marshall_KURLList },
    { "KFileItemList", marshall_KFileItemList },
    { "KFileItemList*", marshall_KFileItemList },
    { "TQPtrList<TDEMainWindow>*", marshall_TDEMainWindowList },
    { "TQPtrList<DCOPObject>", marshall_DCOPObjectList },
    { "TQPtrList<KDockWidget>&", marshall_KDockWidgetList },
    { "TQPtrList<KDockWidget>*", marshall_KDockWidgetList },
    { "KFileTreeBranchList&", marshall_KFileTreeBranch },
    { "KFileTreeViewItemList&", marshall_KFileTreeViewItem },
    { "TQPtrList<KParts::Part>*", marshall_KPartList },
    { "TQPtrList<KParts::Plugin>", marshall_KPartPluginList },
    { "TQPtrList<KParts::ReadOnlyPart>", marshall_KPartReadOnlyPartList },
    { "TQPtrList<KServiceTypeProfile>&", marshall_KServiceTypeProfileList },
    { "TQValueList<TDEAction*>", marshall_TDEActionPtrList },
    { "TDEActionPtrList", marshall_TDEActionPtrList },
    { "TQValueList<TDEAboutPerson>", marshall_TDEAboutPersonList },
    { "TQValueList<TDEAboutTranslator>", marshall_TDEAboutTranslatorList },
    { "TQValueList<TDEIO::CopyInfo>&", marshall_KIOCopyInfoList },
	{ "TDEIO::UDSEntry&", marshall_UDSEntry },
    { "TDEIO::UDSEntryList&", marshall_UDSEntryList },
    { "KServiceTypeProfile::OfferList", marshall_KServiceOfferList },
    { "KEntryMap", marshall_TQMapKEntryKeyKEntry },
    { "KEntryMap&", marshall_TQMapKEntryKeyKEntry },
    { "KEntryMap*", marshall_TQMapKEntryKeyKEntry },
    { "TQMap<TQCString,DCOPRef>", marshall_TQMapTQCStringDCOPRef },
    { "TQValueList<WId>&", marshall_WIdList },
    { "TQValueList<WId>", marshall_WIdList },
    { 0, 0 }
};
