/*
 * Copyright (c) 2001, 2002, 2003, 2004, 2005  Netli, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $Id: ncnf_constr.c,v 1.1 2005/05/26 12:08:19 vlm Exp $
 */
/*
 * Implementation of construction, cloning and destruction.
 */
#include "headers.h"
#include "ncnf_int.h"

/*
 * Basic constructor for the configuration object.
 * Takes optional type and name/value, and inserts their copies into
 * the newly created structure.
 */
struct ncnf_obj_s *
_ncnf_obj_new(void *mr, enum obj_class obj_class, const bstr_t type, const bstr_t value, int config_line) {
	struct ncnf_obj_s *nobj;

	nobj = calloc(1, sizeof(struct ncnf_obj_s));
	if(nobj == NULL)
		return NULL;

	/*
	 * Initializing basic header data.
	 */

	nobj->obj_class = obj_class;
	if(type) nobj->type = bstr_ref(type);
	if(value) nobj->value = bstr_ref(value);
	nobj->config_line = config_line;
	nobj->mr = mr;

	return nobj;
}


/*
 * Kill everything alive within the configuration object structure.
 */
void
_ncnf_obj_destroy(struct ncnf_obj_s *obj) {

	assert(obj->obj_class != NOBJ_INVALID);

	/*
	 * Clear the common object header.
	 */

	bstr_free(obj->type);
	bstr_free(obj->value);

	/*
	 * Class-dependent destruction.
 	 */

	switch(obj->obj_class) {
	case NOBJ_ROOT:
	case NOBJ_COMPLEX:
		{
			enum collections_e c;
			for(c = 0; c < MAX_COLLECTIONS; c++)
				_ncnf_coll_clear(obj->mr,
					&obj->m_collection[c], 1);
		}
		break;
	case NOBJ_REFERENCE:
		assert(obj->m_ref_type);
		assert(obj->m_ref_value);

		bstr_free(obj->m_ref_type);
		bstr_free(obj->m_ref_value);

		obj->m_ref_type = 0;
		obj->m_ref_value = NULL;

		bstr_free(obj->m_new_ref_type);
		obj->m_new_ref_type = NULL;
		bstr_free(obj->m_new_ref_value);
		obj->m_new_ref_value = NULL;
		break;
	case NOBJ_ITERATOR:
		/* Do not destroy contained objects */
		_ncnf_coll_clear(obj->mr, &obj->m_iterator_collection, 0);
		break;
	case NOBJ_LAZY_NOTIF:
	case NOBJ_ATTRIBUTE:
	case NOBJ_INSERTION:
		/* Do nothing */
		break;
	case NOBJ_INVALID:	/* Mostly for switch()/enum integration */
		/* Do nothing */
		break;
	}


	obj->obj_class = NOBJ_INVALID;	/* Post invalidity */
	free(obj);
}


/*
 * Insert an object into an object.
 */
int
_ncnf_attach_obj(struct ncnf_obj_s *to, struct ncnf_obj_s *what, int relaxed_ns) {
	collection_t *coll;


	switch(to->obj_class) {
	case NOBJ_ROOT:
	case NOBJ_COMPLEX:

		coll = NULL;

		switch(what->obj_class) {
		case NOBJ_COMPLEX:
		case NOBJ_REFERENCE:
			coll = &to->m_collection[COLLECTION_OBJECTS];
			goto insert;
		case NOBJ_ATTRIBUTE:
			coll = &to->m_collection[COLLECTION_ATTRIBUTES];
			goto insert;
		case NOBJ_INSERTION:
			coll = &to->m_collection[COLLECTION_INSERTS];
			goto insert;
		case NOBJ_LAZY_NOTIF:
			coll = &to->m_collection[COLLECTION_LAZY_NOTIF];
			goto insert;
	insert:
			what->parent = to;
			return _ncnf_coll_insert(to->mr, coll, what,
				(relaxed_ns ? MERGE_NOFLAGS : MERGE_DUPCHECK)
				| MERGE_EMPTYSRC);
		case NOBJ_ROOT:
			{
				enum collections_e c;
				for(c = 0; c < MAX_COLLECTIONS; c++) {
					if(_ncnf_coll_join(to->mr,
						&to->m_collection[c],
						&what->m_collection[c],
						to,
						(relaxed_ns ? MERGE_NOFLAGS : MERGE_DUPCHECK)
						| MERGE_EMPTYSRC
					)) {
						_ncnf_obj_destroy(what);
						return -1;
					}
				}
			}
			return 0;
		case NOBJ_ITERATOR:
		case NOBJ_INVALID:
			/* Never happens */
			assert(0);
		}

		/* Fall through */
	default:
		/* Cant attach object to the non-complex class */
		errno = EINVAL;
		return -1;
	}


}

/*
 * Create a full copy of the given object.
 */
struct ncnf_obj_s *
_ncnf_obj_clone(void *mr, struct ncnf_obj_s *root) {
	struct ncnf_obj_s *obj;
	enum collections_e c;

	/*
	 * Create wireframe of the new object.
	 */
	obj = _ncnf_obj_new(mr, root->obj_class,
		root->type, root->value, root->config_line);
	if(obj == NULL)
		return NULL;

	switch(obj->obj_class) {
	case NOBJ_ROOT:
	case NOBJ_COMPLEX:
		for(c = 0; c < MAX_COLLECTIONS; c++) {
			collection_t *coll = &root->m_collection[c];
			int i;

			for(i = 0; i < coll->entries; i++) {
				struct ncnf_obj_s *clone;

				clone = _ncnf_obj_clone(mr,
						coll->entry[i].object);
				if(clone == NULL) {
					_ncnf_obj_destroy(obj);
					return NULL;
				}

				if(_ncnf_coll_insert(mr, &obj->m_collection[c],
						clone,
						/* Cloning does not have
						 * to do DUPCHECK */
						MERGE_NOFLAGS)
				) {
					_ncnf_obj_destroy(clone);
					_ncnf_obj_destroy(obj);
					return NULL;
				} else {
					clone->parent = obj;
				}
			}
		}
		break;
	case NOBJ_ATTRIBUTE:
		obj->m_attr_flags = root->m_attr_flags;
		break;
	case NOBJ_REFERENCE:
		obj->m_ref_type = bstr_ref(root->m_ref_type);
		obj->m_ref_value = bstr_ref(root->m_ref_value);
		obj->m_ref_flags = root->m_ref_flags;
		obj->m_direct_reference = root->m_direct_reference;
		break;
	case NOBJ_INSERTION:
	default:
		/* Do nothing */
		break;
	}

	/* Object copied. */
	return obj;
}




syntax highlighted by Code2HTML, v. 0.9.1