/*
 * $Id$
 *
 *  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.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *  Jabber
 *  Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
 */

/*! \file
 * \ingroup xmpp
 */


#include "xode.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


static void _xode_put_expatattribs(xode current, const char **atts)
{
    int i = 0;
    if (atts == NULL) return;
    while (atts[i] != '\0')
    {
        xode_put_attrib(current, atts[i], atts[i+1]);
        i += 2;
    }
}

static void _xode_expat_startElement(void* userdata, const char* name, const char** atts)
{
    /* get the xmlnode pointed to by the userdata */
    xode *x = userdata;
    xode current = *x;

    if (current == NULL)
    {
        /* allocate a base node */
        current = xode_new(name);
        _xode_put_expatattribs(current, atts);
        *x = current;
    }
    else
    {
        *x = xode_insert_tag(current, name);
        _xode_put_expatattribs(*x, atts);
    }
}

static void _xode_expat_endElement(void* userdata, const char* name)
{
    xode *x = userdata;
    xode current = *x;

    current->complete = 1;
    current = xode_get_parent(current);

    /* if it's NULL we've hit the top folks, otherwise back up a level */
    if(current != NULL)
        *x = current;
}

static void _xode_expat_charData(void* userdata, const char* s, int len)
{
    xode *x = userdata;
    xode current = *x;

    xode_insert_cdata(current, s, len);
}


xode xode_from_str(char *str, int len)
{
    XML_Parser p;
    xode *x, node; /* pointer to an xmlnode */

    if(NULL == str)
        return NULL;

    if(len == -1)
        len = strlen(str);

    x = malloc(sizeof(void *));

    *x = NULL; /* pointer to NULL */
    p = XML_ParserCreate(NULL);
    XML_SetUserData(p, x);
    XML_SetElementHandler(p, _xode_expat_startElement, _xode_expat_endElement);
    XML_SetCharacterDataHandler(p, _xode_expat_charData);
    if(!XML_Parse(p, str, len, 1))
    {
        /*        jdebug(ZONE,"xmlnode_str_error: %s",(char *)XML_ErrorString(XML_GetErrorCode(p)));*/
        xode_free(*x);
        *x = NULL;
    }
    node = *x;
    free(x);
    XML_ParserFree(p);
    return node; /* return the xmlnode x points to */
}

xode xode_from_strx(char *str, int len, int *err, int *pos)
{
    XML_Parser p;
    xode *x, node; /* pointer to an xmlnode */

    if(NULL == str)
        return NULL;

    if(len == -1)
        len = strlen(str);

    x = malloc(sizeof(void *));

    *x = NULL; /* pointer to NULL */
    p = XML_ParserCreate(NULL);
    XML_SetUserData(p, x);
    XML_SetElementHandler(p, _xode_expat_startElement, _xode_expat_endElement);
    XML_SetCharacterDataHandler(p, _xode_expat_charData);
    XML_Parse(p, str, len, 0);
	if(err != NULL)
		*err = XML_GetErrorCode(p);
	if(pos != NULL)
		*pos = XML_GetCurrentByteIndex(p);		
    node = *x;
    free(x);
    XML_ParserFree(p);
    
	return node; /* return the xmlnode x points to */
}

xode xode_from_file(char *file)
{
    XML_Parser p;
    xode *x, node; /* pointer to an xmlnode */
    char buf[BUFSIZ];
    int done, fd, len;
    char _file[1000];

    if(NULL == file)
        return NULL;

    /* perform tilde expansion */
    if(*file == '~')
    {
        char *env = getenv("HOME");
        if(env != NULL)
            snprintf((char*)_file, 1000, "%s%s", env, file + 1);
        else
            snprintf((char*)_file, 1000, "%s", file);
    }
    else
    {
        snprintf((char*)_file, 1000, "%s", file);
    }

    fd = open((char*)&_file,O_RDONLY);
    if(fd < 0)
        return NULL;

    x = malloc(sizeof(void *));

    *x = NULL; /* pointer to NULL */
    p = XML_ParserCreate(NULL);
    XML_SetUserData(p, x);
    XML_SetElementHandler(p, _xode_expat_startElement, _xode_expat_endElement);
    XML_SetCharacterDataHandler(p, _xode_expat_charData);
    do{
        len = read(fd, buf, BUFSIZ);
        done = len < BUFSIZ;
        if(!XML_Parse(p, buf, len, done))
        {
            /*            jdebug(ZONE,"xmlnode_file_parseerror: %s",(char *)XML_ErrorString(XML_GetErrorCode(p)));*/
            xode_free(*x);
            *x = NULL;
            done = 1;
        }
    }while(!done);

    node = *x;
    XML_ParserFree(p);
    free(x);
    close(fd);
    return node; /* return the xmlnode x points to */
}

int xode_to_file(char *file, xode node)
{
    char *doc;
    int fd, i;
    char _file[1000];

    if(file == NULL || node == NULL)
        return -1;

    /* perform tilde expansion */
    if(*file == '~')
    {
        char *env = getenv("HOME");
        if(env != NULL)
            snprintf((char*)_file, 1000, "%s%s", env, file + 1);
        else
            snprintf((char*)_file, 1000, "%s", file);
    }
    else
    {
        snprintf((char*)_file, 1000, "%s", file);
    }

    fd = open((char*)&_file, O_CREAT | O_WRONLY | O_TRUNC, 0600);
    if(fd < 0)
        return -1;

    doc = xode_to_str(node);
    i = write(fd,doc,strlen(doc));
    if(i < 0)
        return -1;

    close(fd);
    return 1;
}