/*
!===============================================================================
!
! ildg_xml.c - simple XML parser for XML part in ILDG lime files
!
!-------------------------------------------------------------------------------
!
! Copyright (C) 2007 Hinnerk Stueben
!
! This file is part of BQCD -- Berlin Quantum ChromoDynamics program
!
! BQCD 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 3 of the License, or
! (at your option) any later version.
!
! BQCD 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 BQCD.  If not, see <http://www.gnu.org/licenses/>.
!
!-------------------------------------------------------------------------------
*/
# include <ctype.h>
# include <string.h>
# include <stdlib.h>
# include <assert.h>
# include "c_defs.h"
# include "c_util.h"
# include "ildg.h"
# include "ildg_xml.h"

/*---------------------------------------------------------------------------*/
int ildg_xml_get_token(int n, char *xml, char **token, int *len)
{
   /*
    * n       number of token (first is n = 1) (input)
    * xml     XML input
    * token   pointer to token in "xml" (output)
    * len     length of token (output)
    *
    * There are tow types of tokens:
    *
    *       - XML (key-) words, e.g. "<precision>", "</precision>"
    *
    *       - values (between keyword), e.g. "<key>value</key>"
    *
    *         values are returned in "token" and "len" without
    *         leading and trailing white space
    *
   */

    char *s = xml;
    char *last_char;
    char c;
    int ket = 0;
    int i = 0;

    while ((c = *s++) != '\0') {
        switch (c) {
	    case '<':
	        ket = 0;
		if (i == n) {
		    *len = s - *token - 1;
		    *len = last_char - *token;
		    return *len;
		} else {
		    i++;
                    *token = s - 1;
		}
		break;
	    case '>':
		if (i == n) {
		    *len = s - *token;
		    return *len;
		} else {
		    ket = 1;
                } 
		break;
	    default:
	        if (ket) {
	  	    if (isspace(c)) {
		        break;
                    } else {
		        i++;
                        *token = s - 1;
		        ket = 0;
                    }
	        }
		if (! isspace(c)) {
		    last_char = s; 
                }
                break;
	}
    }
    return -1;
}

/*---------------------------------------------------------------------------*/
int ildg_xml_get_value1(char *xml, char *key, char *value)
{
   /*
    * xml     XML input
    * key     keyword, eg "<precision>" (input)
    * value   array of char to which the value is copied (output)
   */

    int lkey = strlen(key);
    char *token;
    int len;
    int i;
    int found;

    i = 1;
    found = 0;
    while (ildg_xml_get_token(i, xml, &token, &len) > 0) {
        if (found) {
	    strncpy(value, token, len); 
            value[len] = '\0';
            return len;
        }
        i++;
	if (strncmp(token, key, lkey) == 0) found = 1;
    }
    return -1;
}

/*---------------------------------------------------------------------------*/
int ildg_xml_get_value(char *key, char *xml, char **value, int *len)
{
   /*
    * key     keyword, eg "<precision>" (input)
    * xml     XML input (input)
    * value   pointer to value in "xml" (output)
    * len     length of value (output)
   */

    int lkey = strlen(key);
    int i = 1;
    int found = 0;

    while (ildg_xml_get_token(i, xml, value, len) > 0) {
        if (found) return *len;
	if (strncmp(*value, key, lkey) == 0) found = 1;
        i++;
    }
    return -1;
}
    
/*---------------------------------------------------------------------------*/
void ildg_xml_check_value(char *xml, char *key, char *value)
{
   /*
    * xml     XML input
    * key     keyword, eg "<precision>" (input)
    * value   value of key to be checked (input)
   */

    char *val;
    int len;

    if (ildg_xml_get_value(key, xml, &val, &len) >= 0) {
        if (strncmp(val, value, len) != 0) {
	    val[len] = '\0';
	    die("%s: unknown value for %s", val, key);
        }
    } else {
        die("%s: key/value not found", key);
    }
}

/*---------------------------------------------------------------------------*/
void ildg_xml_get_int(char *xml, char *key, int *i)
{
   /*
    * xml     XML input
    * key     keyword, eg "<precision>" (input)
    * i       integer value of key (output)
   */

    char value[32];
    char *val;
    int len;
  
    if (ildg_xml_get_value(key, xml, &val, &len) >= 0) {
        assert(len < 32);
        strncpy(value, val, len);
        value[len] = '\0';
        *i = atoi(value);
        return;
    } else {
        die("%s: key/value not found", key);
    }
}

/*===========================================================================*/
