/*
 *                         OpenSplice DDS
 *
 *   This software and documentation are Copyright 2006 to TO_YEAR PrismTech
 *   Limited, its affiliated companies and licensors. All rights reserved.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

#include "vortex_os.h"

#include "cf_element.h"
#include "cf_node.h"
#include "cf_attribute.h"
#include "cf__nodeList.h"

struct getNodeArg {
    const c_char *name;
    cf_node      node;
};

C_STRUCT(cf_element) {
    C_EXTENDS(cf_node);
    cf_nodeList attributes;
    cf_nodeList children;
};

/**************************************************************
 * Private functions
 **************************************************************/

static unsigned int
attributesToIterator(
    c_object o,
    c_iter *c)
{
    *c = c_iterInsert(*c, o);
    return 1;
}

static unsigned int
childsToIterator(
    c_object o,
    c_iter *c)
{
    *c = c_iterInsert(*c, o);
    return 1;
}

static unsigned int
getNode(
    c_object o,
    struct getNodeArg *arg)
{
    unsigned int result;
    c_long cmp;

    assert(arg != NULL);
    cmp = strcmp(cf_nodeGetName(cf_node(o)), arg->name);
    if (cmp == 0) {
        arg->node = cf_node(o);
        result = 0; /* stop the walk */
    } else {
        result = 1;
    }

    return result;
}

/**************************************************************
 * constructor/destructor
 **************************************************************/
cf_element
cf_elementNew (
    const c_char *tagName)
{
    cf_element el;

    assert(tagName != NULL);

    el = cf_element(os_malloc((os_uint32)C_SIZEOF(cf_element)));
    cf_elementInit(el, tagName);

    return el;
}

void
cf_elementInit (
    cf_element element,
    const c_char *tagName)
{
    assert(element != NULL);
    assert(tagName != NULL);

    cf_nodeInit(cf_node(element), CF_ELEMENT, tagName);

    element->attributes = cf_nodeListNew();
    element->children = cf_nodeListNew();
}

void
cf_elementFree (
    cf_element element)
{
    assert(element != NULL);

    cf_nodeFree(cf_node(element));
}

void
cf_elementDeinit (
    cf_element element)
{
    assert(element != NULL);
    
    if (element->attributes != NULL) {
        cf_nodeListClear(element->attributes);
        cf_nodeListFree(element->attributes);
        element->attributes = NULL;
    }
    if (element->children != NULL) {
        cf_nodeListClear(element->children);
        cf_nodeListFree(element->children);
        element->children = NULL;
    }

    cf_nodeDeinit(cf_node(element));
}
/**************************************************************
 * Protected functions
 **************************************************************/

/**************************************************************
 * Public functions
 **************************************************************/
cf_attribute
cf_elementAddAttribute (
    cf_element element,
    cf_attribute attribute)
{
    cf_attribute attr;

    assert(element != NULL);
    assert(attribute != NULL);

    attr = cf_attribute(cf_nodeListInsert(element->attributes, 
                                          cf_node(attribute)));

    return attr;
}

cf_node
cf_elementAddChild(
    cf_element element,
    cf_node child)
{
    cf_node ch;

    assert(element != NULL);
    assert(child != NULL);

    ch = cf_node(cf_nodeListInsert(element->children, 
                                   cf_node(child)));

    return ch;
}

c_iter
cf_elementGetAttributes(
    cf_element element)
{
    c_iter i = NULL;

    assert(element != NULL);

    cf_nodeListWalk(element->attributes, attributesToIterator, &i);

    return i;
}

c_iter
cf_elementGetChilds(
    cf_element element)
{
    c_iter i = NULL;

    assert(element != NULL);

    cf_nodeListWalk(element->children, childsToIterator, &i);

    return i;
}

cf_attribute
cf_elementAttribute(
    cf_element element,
    const c_char *attributeName)
{
    struct getNodeArg arg;

    assert(element != NULL);
    assert(attributeName != NULL);

    arg.name = attributeName;
    arg.node = NULL;
    cf_nodeListWalk(element->attributes, getNode, &arg);

    return cf_attribute(arg.node);
}

cf_node
cf_elementChild(
    cf_element element,
    const c_char *childName)
{
    struct getNodeArg arg;

    assert(element != NULL);
    assert(childName != NULL);

    arg.name = childName;
    arg.node = NULL;
    cf_nodeListWalk(element->children, getNode, &arg);

    return arg.node;
}
