/*
 * Copyright (C) 1999-2017 Hartmut Seichter
 *
 * 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 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 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.
 */
#ifndef PW_SCENE_NODE_HPP
#define PW_SCENE_NODE_HPP

#include <pw/core/globals.hpp>
#include <pw/scene/component.hpp>
#include <pw/scene/transform.hpp>


namespace pw {

/**
 * @brief nodes represent the structure for the scene graph
 *
 * Unlike earlier designs the scenegraph here is not a DAG
 * but uses multiple references to components like Unity. This makes the
 * design of the scenegraph and traversal much more straight-forward.
 */
class node {
public:

	friend class component;

	typedef shared_ptr<node> ref;
	typedef std::vector<ref> ref_array;

	typedef node *ptr;
	typedef std::vector<ptr> ptr_array;

    //! standard c'tor
	node();

    //! copy c'tor
    node(const node& node);

	//! d'tor
	~node();

    //! cloning interface
	ref clone(const unsigned short& copymode) const;

	std::string name() const;	//!< get name
	void set_name(const std::string &name); //!< set name

	//! return parent of this node
	inline ptr parent() const { return _path.back(); }

	//! add a child node
	void add_child(ref child_node);

	//! remove a child
	void remove_child(ref child_node);

    //! get the list of children
    inline const ref_array& children() const { return _children; }

    //! get number of children
    inline size_t child_count() const { return children().size(); }

    //! check if this node is a leaf node
    inline bool is_leaf() const { return children().empty(); }

	//! check if this is the root node
	inline bool is_root() const { return _path.empty(); }

	//! list of components
	const component::array& components() const;

	//! add a node component
	void add_component(component new_component);

	template<typename T>
	void add_component_() {
		_components.push_back(T(*this));
	}

	//! remove a node component
	void remove_component(component c);

	//! paths to root
	const ptr_array& path() const;

	void traversal();

	// not sure about this
	const class transform& transform() const { return _transform; }
	class transform& transform() { return _transform; }

protected:

	ref_array _children; //!< list of children
	ptr_array _path; //!< path to root

	class transform _transform;

	component::array _components; //<! components

    std::string _name;

	// change mask
	// layer mask
};

}

#endif
