/*
 NAME
	cxmltree-test.m - test program for CXMLTree class
 VERSION
	$Id$
 CHANGELOG
	$Log$
 NOTE
 	This program is based on the `gjobread.c' distributed with
	libxml2 package.
 */

#include <coconut/cxmltree.h>
#include <coconut/fbasic.h>
#include <stdio.h>
#include <stdlib.h>

@interface CPerson : CObject
{
	const xmlChar *	name ;
	const xmlChar *	email ;
	xmlChar *	company ;
	xmlChar *	organisation ;
	xmlChar *	smail ;
	xmlChar *	webPage ;
	xmlChar *	phone ;
}

- init ;
- (void) setName: (const utf8_char *) str ;
- (void) setEmail: (const utf8_char *) str ;
- (void) print ;

@end

@implementation CPerson

- init
{
	name = email = NULL ;
	company = organisation = smail = webPage = phone = NULL ;
	return [super init] ;
}

- (void) setName: (const utf8_char *) str 
{	
	xmlFree((void *) name) ;
	name = xmlStrdup(str) ;
}

- (void) setEmail: (const utf8_char *) str
{
	xmlFree((void *) email) ;
	email = xmlStrdup(str) ;
}

- (void) print
{
	printf("----- Person\n") ;
	if(name)		printf("name:		%s\n", name) ;
	if(email)		printf("email:		%s\n", email) ;
	if(company)		printf("company:	%s\n", company) ;
	if(organisation)	printf("organisation:	%s\n", organisation) ;
	if(smail)		printf("smail:		%s\n", smail) ;
	if(webPage)		printf("webPage:	%s\n", webPage) ;
	if(phone)		printf("phone:		%s\n", phone) ;
	printf("----- end of Person\n") ;
}

@end

@interface CJob : CObject
{
	const xmlChar *	projectID ;
	const xmlChar *	application ;
	const xmlChar *	category ;
	CPerson *	contact ;
	int		nbDevelopers ;
	CPerson *	developers[100] ;
}

- init ;
- (void) setProjectID: (const utf8_char *) pid ;
- (void) setApplication: (const utf8_char *) str ;
- (void) setCategory: (const utf8_char *) str ;
- (void) setContact: (CPerson *) str ;
- (void) print ;

@end

@implementation CJob

- init
{
	projectID = NULL ;
	category = application = NULL ;
	contact = nil ;
	nbDevelopers = 0 ;
	return [super init] ;
}

- (void) setProjectID: (const utf8_char *) pid 
{
	xmlFree((void *) projectID) ;
	projectID = xmlStrdup(pid) ;
}

- (void) setApplication: (const utf8_char *) str
{
	xmlFree((void *) application) ;
	application = xmlStrdup(str) ;
}

- (void) setCategory: (const utf8_char *) str
{
	xmlFree((void *) category) ;
	category = xmlStrdup(str) ;
}

- (void) setContact: (CPerson *) str
{
	contact = str ;
}

- (void) print
{
	int i, n ;

	printf("====== Job\n") ;
	if(projectID)
		printf("projectID:\t%s\n", (char *) projectID) ;
	if(application)
		printf("application:\t%s\n", application) ;
	if(category)
		printf("category:\t%s\n", category) ;
	if(contact)
		[contact print] ;
	printf("%d developers\n", n = nbDevelopers) ;
	for(i=0 ; i<n ; i++)
		[developers[i] print] ;
	printf("====== \n") ;
}

@end

typedef struct gjob {
	int	nbJobs ;
	CJob *	jobs[500] ;
} gJob, * gJobPtr ;

void print_node(id <PXMLNode> node, const char * msg)
{
	if(!node){
		printf("ERROR %s\n", msg) ;
	}
}

CPerson * parsePerson(CXMLTree * tree)
{
	CPerson *		ret ;
	id <PXMLNode>		node ;
	id <PConstStr>		text ;

	ret = [[CPerson alloc] init] ;
	if(![tree skipToChild]){
		printf("ERROR: can not skip to child.\n") ;
		return nil ;
	}
	printf("skip to child.\n") ;
	do {
		node = [tree currentNode] ;
		if([node compareTagName: "Person"] == 0){
			text = [node getChildText] ;
			if(text){
				[ret setName: [text ptr]] ;
				[text release] ;
			} else {
				printf("ERROR: can not get person.\n");
			}
		}
		if([node compareTagName: "Email"] == 0){
			text = [node getChildText] ;
			if(text){
				[ret setEmail: [text ptr]] ;
				[text release] ;
			} else {
				printf("ERROR: can not get email.\n");
			}
		}
	} while([tree skipNext]) ;

	if(![tree moveToParent]){
		printf("ERROR: can not move to parent.\n") ;
		return nil ;
	}

	return ret ;
}

CJob * parseJob(CXMLTree * tree)
{
	CJob *			ret ;
	CPerson *		person ;
	id <PXMLNode> 		node ;
	id <PConstStr>		text ;
	id <PConstStr> 		prop ;

	ret = [[CJob alloc] init] ;
	if(ret == NULL){
		printf("ERROR: out of memory.\n");
		exit(1) ;
	}
	print_node([tree skipToChild], "skip to child") ;
	printf("skip to child ...\n") ;
	do {
		node = [tree currentNode] ;
		if([node compareTagName: "Project"] == 0){
			prop = [node getAttrValueByName: "ID"] ;
			if(prop){
				printf("ID node has \"%s\" property.\n", 
				  [prop ptr]) ;
				[ret setProjectID: [prop ptr]] ;
				[prop release] ;
			}
		}
		if([node compareTagName: "Application"] == 0){
			text = [node getChildText] ;
			if(text){
				printf("Application node has \"%s\" text.\n",
				  [text ptr]) ;
				[ret setApplication: [text ptr]] ;
				[text release] ;
			} else {
				printf("ERROR: no application text\n") ;
			}
		}
		if([node compareTagName: "Category"] == 0){
			text = [node getChildText] ;
			if(text){
				printf("Category node has \"%s\" text.\n",
				  [text ptr]) ;
				[ret setCategory: [text ptr]] ;
				[text release] ;
			} else {
				printf("ERROR: no category text\n") ;
			}
		}
		if([node compareTagName: "Contact"] == 0){
			person = parsePerson(tree) ;
			if(person){
				[ret setContact: person] ;
			} else {
				printf("ERROR: no person given.\n") ;
			}
		}
	} while([tree skipNext]) ;
	print_node([tree moveToParent], "move to parent") ;
	return ret ;
}

gJobPtr parseGjobFile(const char * filename)
{
	id <PXMLTree>	tree ;
	id <PXMLNode>	node ;
	const char *	prefix ;
	const char *	name ;
	CJob *		curjob ;
	gJobPtr		ret ;

	  tree = [[CXMLTree alloc] init] ;
	    if([tree loadFile: filename validate: FALSE] != 0)
		printf("ERROR: can not load the file\n") ;

	    /* printf("dump all:\n") ;
	       [tree dumpAll: stdout] ; */

	    prefix = [[tree currentNode] searchNameSpacePrefixByHref: 
	      "http://www.gnome.org/some-location"] ;
	    if(prefix){
	    	printf("the namespace prefix is \"%s\"\n", prefix) ;
	    } else {
	    	printf("ERROR: no prefix is found.\n") ;
	    }

	    node = [tree currentNode] ;
	    if(strcmp(name = [node tagName], "Helping") == 0){
	    	printf("the current node name is \"%s\"\n", name) ;
	    } else {
	    	printf("ERROR: document of the wrong type\n") ;
	    }

	    ret = (gJobPtr) malloc(sizeof(gJob)) ;
	    if(ret == NULL){
	    	printf("ERROR: out of memory\n") ;
	    }
	    memset(ret, 0, sizeof(gJob)) ;

	    printf("now, walk the tree.\n") ;
	    print_node([tree skipToChild], "skip to child.\n") ;

	    /* printf("print current subtree.\n") ;
	       [tree dumpCurrentNode: stdout] ; */

	    node = [tree currentNode] ;
	    if([node compareTagName: "Jobs"] == 0){
	    	printf("node \"Jobs\" was found.\n") ;
	    } else {
	    	printf("ERROR: target \"Jobs\" not is not found.\n") ;
		printf(" the current name is \"%s\".\n", [node tagName]) ;
	    }

	    print_node([tree skipToChild], "skip to child") ;
	    do {
	        node = [tree currentNode] ;
		if([node compareTagName: "Job"] == 0){
			printf("the Job node was found.\n") ;
			curjob = parseJob(tree) ;
			if(curjob)
				ret->jobs[ret->nbJobs++] = curjob ;
			if(ret->nbJobs >= 500)
				break ;
		}
	    } while([tree skipNext]) ;

	  [tree release] ;
	return ret ;
}

void handleGjob(gJobPtr jobp)
{	
	int i, n ;
	printf("%d Jobs registered.\n", n = jobp->nbJobs) ;
	for(i=0 ; i<n ; i++)
		[(jobp->jobs[i]) print] ;
}

int main()
{
	gJobPtr	jobp ;

	printf("*** test program for CXMLTree class\n") ;
	jobp = parseGjobFile("./cxmltree-test.xml") ;
	if(jobp)
		handleGjob(jobp) ;
	else
		printf("ERROR: parsing error.\n") ;
	printf("bye.\n") ;
	return 0 ;
}


