/*
 * Copyright (C) 2007 JasperSoft http://www.jaspersoft.com
 * 
 * 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 WITHOUT ANY WARRANTY; and without 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, see http://www.gnu.org/licenses/gpl.txt 
 * or write to:
 * 
 * Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330,
 * Boston, MA  USA  02111-1307
 */

#include <stdio.h>
#include <libxml/xmlreader.h>


#include "unmarshaller.h"


int jasperserver_readNodeText(xmlNode *node, jasperserver_string_t *dest);
jasperserver_resource_descriptor_t *jasperserver_read_resource_descriptor(xmlNode *node);
jasperserver_resource_property_t *jasperserver_read_resource_property(xmlNode *node);
jasperserver_parameter_t *jasperserver_read_parameter(xmlNode *node);

jasperserver_operation_result_t *jasperserver_response_unmarshal(jasperserver_string_t *xml)
{
     xmlDoc *doc = NULL;
     xmlNode *operationResultNode = NULL;
     xmlNode *child_node = NULL;

     jasperserver_operation_result_t *operationResult = NULL;
     
     operationResult = jasperserver_operation_result_new();
     operationResult->returnCode = -1;
     
     /*
     * The document being in memory, it have no base per RFC 2396,
     * and the "noname.xml" argument will serve as its base.
     */
     doc = xmlReadMemory(JS_UTFSTR(xml), xml->buffer->use,"noname.xml", "UTF-8", 0);
     if (doc == NULL) {
         jasperserver_string_cset(operationResult->returnMessage, "Unable to process the operation result");
         return operationResult;    
     }
     
     /*Get the root element node */
     operationResultNode = xmlDocGetRootElement(doc);
     
     // jasperserver_string_set is NULL safe...
     jasperserver_string_set(operationResult->version, xmlGetProp(operationResultNode, BAD_CAST "version" ) );

     for (child_node = operationResultNode->children; child_node; child_node = child_node->next) {
        if (child_node->type == XML_ELEMENT_NODE) {
        
            //printf("node type: Element, name: %s\n", child_node->name);
            if (!xmlStrcmp(child_node->name, BAD_CAST "returnCode"))
            {
                  jasperserver_string_t *fieldValue = NULL;
                  fieldValue = jasperserver_string_new();
                  if (jasperserver_readNodeText(child_node, fieldValue))
                  {
                     operationResult->returnCode = atoi( JS_CSTR(fieldValue) );
                  }
                  jasperserver_string_free(fieldValue);                         
            }
            else if (!xmlStrcmp(child_node->name, BAD_CAST "message"))
            {
                  jasperserver_readNodeText(child_node, operationResult->returnMessage);
            }
            else if (!xmlStrcmp(child_node->name, BAD_CAST "resourceDescriptor"))
            {
                  jasperserver_resource_descriptor_t *res = NULL;
                  res = jasperserver_read_resource_descriptor(child_node);
                  if (res)
                  {
                      jasperserver_list_append((jasperserver_list_t **)(&operationResult->resources), (jasperserver_list_t *)res);    
                  }
            }
        }
     }
     
     xmlFreeDoc(doc);
     xmlCleanupParser();
     return operationResult;
}

/**
* This function read the test of a node. The text can be stored in a text node or in a CDATA node.
*  it assume the next node will contain the text, so situations like:
   <mytag> blank space  <[CDATA[  ...  return a blank text.     
   
   returns 1 if text was found
   returns 0 if no text was found
*/
int jasperserver_readNodeText(xmlNode *node, jasperserver_string_t *dest)
{
     xmlNode *child_node;
     child_node = node->children;
     
     if ( child_node && child_node->content)
     {
          jasperserver_string_set(dest, child_node->content);
          return 1;
     }
     return 0;     
}

/**
* Returns a resource descriptor. It is responsability of the user free the resource using
jasperserver_resource_descriptor_free();
*/
jasperserver_resource_descriptor_t *jasperserver_read_resource_descriptor(xmlNode *resNode)
{
    jasperserver_resource_descriptor_t *res = NULL;
    res = jasperserver_resource_descriptor_new();
    xmlNode *child_node = NULL;
    
    // jasperserver_string_set is NULL safe...
    if (xmlHasProp(resNode, BAD_CAST "name" )) { jasperserver_string_set(res->name, xmlGetProp(resNode, BAD_CAST "name" ) ); }
    if (xmlHasProp(resNode, BAD_CAST "wsType" )) { jasperserver_string_set(res->wsType, xmlGetProp(resNode, BAD_CAST "wsType" ) ); }
    if (xmlHasProp(resNode, BAD_CAST "uriString" )) { jasperserver_string_set(res->uriString, xmlGetProp(resNode, BAD_CAST "uriString" ) ); }
    if (xmlHasProp(resNode, BAD_CAST "isNew" )) {
       res->isNew = (!xmlStrcmp(xmlGetProp(resNode, BAD_CAST "isNew" ), "true")) ? 1 : 0; 
    }


    for (child_node = resNode->children; child_node; child_node = child_node->next) {
        if (child_node->type == XML_ELEMENT_NODE) {
        
            //printf("node type: Element, name: %s\n", child_node->name);
            if (!xmlStrcmp(child_node->name, BAD_CAST "label"))
            {
                  jasperserver_readNodeText(child_node, res->label);
            }
            else if (!xmlStrcmp(child_node->name, BAD_CAST "description"))
            {
                  jasperserver_readNodeText(child_node, res->description);
            }
            else if (!xmlStrcmp(child_node->name, BAD_CAST "resourceProperty"))
            {
                  jasperserver_resource_property_t *resProperty = NULL;
                  resProperty = jasperserver_read_resource_property(child_node);
                  if (res)
                  {
                      jasperserver_list_append((jasperserver_list_t **)(&res->properties), (jasperserver_list_t *)resProperty);    
                  }
            }
            else if (!xmlStrcmp(child_node->name, BAD_CAST "resourceDescriptor"))
            {
                  jasperserver_resource_descriptor_t *resDescriptor = NULL;
                  resDescriptor = jasperserver_read_resource_descriptor(child_node);
                  if (resDescriptor)
                  {
                      jasperserver_list_append((jasperserver_list_t **)(&res->children), (jasperserver_list_t *)resDescriptor);    
                  }
            }
            else if (!xmlStrcmp(child_node->name, BAD_CAST "parameter"))
            {
                  jasperserver_parameter_t *parameter = NULL;
                  parameter = jasperserver_read_parameter(child_node);
                  if (res)
                  {
                      jasperserver_list_append((jasperserver_list_t **)(&res->parameters), (jasperserver_list_t *)parameter);    
                  }
            }
        }
     }
     
    return res;
}

/**
* Returns a resource descriptor. It is responsability of the user free the resource using
jasperserver_resource_descriptor_free();
*/
jasperserver_resource_property_t *jasperserver_read_resource_property(xmlNode *resNode)
{
    jasperserver_resource_property_t *property = NULL;
    property = jasperserver_resource_property_new();
    xmlNode *child_node = NULL;
    
    // jasperserver_string_set is NULL safe...
    if (xmlHasProp(resNode, BAD_CAST "name" )) { jasperserver_string_set(property->name, xmlGetProp(resNode, BAD_CAST "name" ) ); }
    

    for (child_node = resNode->children; child_node; child_node = child_node->next) {
        if (child_node->type == XML_ELEMENT_NODE) {
        
            if (!xmlStrcmp(child_node->name, BAD_CAST "value"))
            {
                  // Read the text or PCDATA inside this node...
                  jasperserver_readNodeText(child_node, property->value);
            }
            else if (!xmlStrcmp(child_node->name, BAD_CAST "resourceProperty"))
            {
                  jasperserver_resource_property_t *resProperty = NULL;
                  resProperty = jasperserver_read_resource_property(child_node);
                  if (resProperty)
                  {
                      jasperserver_list_append((jasperserver_list_t **)(&property->properties), (jasperserver_list_t *)resProperty);    
                  }
            }
        }
     }
     
    return property;
}

/**
* Returns a resource descriptor. It is responsability of the user free the resource using
jasperserver_resource_descriptor_free();
*/
jasperserver_parameter_t *jasperserver_read_parameter(xmlNode *resNode)
{
    jasperserver_parameter_t *parameter = NULL;
    parameter = jasperserver_parameter_new();
    
    // jasperserver_string_set is NULL safe...
    if (xmlHasProp(resNode, BAD_CAST "name" )) { jasperserver_string_set(parameter->name, xmlGetProp(resNode, BAD_CAST "name" ) ); }
    if (xmlHasProp(resNode, BAD_CAST "isListItem" )) {
       parameter->isListItem = (!xmlStrcmp(xmlGetProp(resNode, BAD_CAST "isListItem" ), "true")) ? 1 : 0; 
    }

    // Read the text or PCDATA inside the parameter...
    jasperserver_readNodeText(resNode, parameter->value);
     
    return parameter;
}
