/*
 *                 WARNING!
 * 
 * this file is `xml_c' and is preprocessed by m4 to produce `xml_m4.c'
 * 
 * It must be a valid m4 file, and must produce a valid C file.
 * 
 */

#include <stdio.h>

DECL_BEFORE

#include "array.h"

static TT_CONST ttbyte * dump_file_name;

static FILE * dump_file;

static ttbyte open_dump_file(void) {
    if ((dump_file = fopen(dump_file_name, "w"))) {
	fprintf(dump_file, "%s",
		"<?xml version=\"1.0\"?>\n"
		"<TT:dump xmlns:TT=\"http://twin.sourceforge.net/libTT/xml/\">\n"
		);
	return TRUE;
    }
    return FALSE;
}

static void close_dump_file(void) {
    fprintf(dump_file, "%s", "</TT:dump>\n");
    fclose(dump_file);
}

TT_INLINE void dump_object(ttobject o) {
    ttopaque i, last;
    ttopaque id;
    TT_CONST ttbyte *name;
    ttbyte buf[64];
    ttarg data;
    ttopaque type;
    
    if ((id = OBJ2ID(o))) {
	fprintf(dump_file, "  <TT:%s>\n", name = TTClassNameOf((tt_obj)id));
	sprintf(buf, "%s_field_last", name);
	last = (ttopaque)TTGet_ttfield(buf);
	
	i = (ttopaque)TTGet_ttfield("ttobj_field_first");
	for (; i < last; i++) {
	    /*
	     * evil trick here:
	     * TTGet_ttfield() actually returns an integer,
	     * and we try all values for that integer from
	     * ttfield "ttobj_field_first" to "<objtype>_field_last"
	     */
	    if ((name = TTGetName_ttfield((tt_obj)i)) &&
		TTGetField_ttobj((tt_obj)id, (tt_obj)i, &data) &&
		data.value != (ttany)0) {

		type = data.type;
		
		/* if it's an array of bytes (i.e. a string) then print as a string */
		if (TTFromType_ttclass(type) == TTClass_ttbyte && TTIsArrayType_ttclass(type))
		    fprintf(dump_file, "    <TT:%s value=\"%.*s\"/>\n", name, (int)data.size, (ttbyte *)(ttopaque)data.value);
		else
		    fprintf(dump_file, "    <TT:%s value=\"0x%lX\"/>\n", name, (unsigned long)data.value);
	    }
	}
	fprintf(dump_file, "  </TT:%s>\n", TTClassNameOf((tt_obj)id));
    }
}

static void dump_all(void) {
    ttbyte n;
    ttopaque i;
    ttobj o;

    if (open_dump_file()) {
	for (n = order_first; n < order_last; n++) {
	    for (i = 0; i < IdTop[n]; i++) {
		if ((o = IdList[n][i]) && IS(ttobject,o) &&
		    !(((ttobject)o)->oflags && ttobject_oflags_static)) {
		    
		    dump_object((ttobject)o);
		}
	    }
	}
	close_dump_file();
    }
}

/*
 * We need to write down only overloaded methods (actually none).
 */

static ttbyte HWDEF(Sync)(void) {
    return 1;
}
static ttbyte HWDEF(Flush)(void) {
    return 1;
}
static ttbyte HWDEF(TimidFlush)(void) {
    return 1;
}
static ttbyte HWDEF(MainLoopOnce)(ttbyte wait) {
    TTExitMainLoop();
    return 1;
}
static void HWDEF(DeleteCallback)(ttcallback o) {
}
static void HWDEF(Close)(void) {
    dump_all();
}
static int HWDEF(ConnectionFd)(void) {
  return -1;
}
static ttuint HWDEF(GetErrno)(void) {
  return 0;
}
static ttuint HWDEF(GetErrnoDetail)(void) {
  return 0;
}
static TT_CONST ttbyte *HWDEF(StrError)(ttuint E) {
    return "";
}
static TT_CONST ttbyte *HWDEF(StrErrorDetail)(ttuint E, ttuint S) {
    return "";
}


#ifdef THIS_MODULE
ttclasses InitModule(tthw *HW)
#else
ttclasses _TT_xml_InitHW(tthw *HW)
#endif
{
    ttbyte *arg = TTD.HWOptions;
    
    /*
     * (*HW) must be set even if initialization fails,
     * to report error messages.
     */
    *HW = &xml_TTClasses.HW;

    dump_file_name = "libTT.xml";
    if (arg && (arg = strstr("file=", arg))) {
	dump_file_name = arg + 5;
	if ((arg = strchr(dump_file_name, ',')))
	    *arg = '\0';
    }

    return &xml_TTClasses;
}

DECL_AFTER

