/*
 * Copyright Staffan Gimåker 2010.
 *
 * ---
 *
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 */

#ifndef PEEKABOT_CLIENT_TRI_MESH_PROXY_HH_INCLUDED
#define PEEKABOT_CLIENT_TRI_MESH_PROXY_HH_INCLUDED


#include "ScalableProxy.hh"
#include "VertexBasedProxy.hh"

#include <boost/scoped_ptr.hpp>
#include <boost/cstdint.hpp>
#include <cstddef>
#include <vector>


namespace peekabot
{
    namespace client
    {
        /**
         * \brief A "set" (since it's ordered, sequence is more correct
         * nomenclature) of three-tuples of zero-indexed vertex indices
         * describing triangles.
         *
         * For example, (0, 7, 8) describes the triangle formed by vertex
         * 0, 7 and 8. Primitives are specified in counterclockwise order.
         */
        class PEEKABOT_API IndexSet
        {
            friend class TriMeshProxyBase;

        public:
            IndexSet();

            IndexSet(const IndexSet &other);

            ~IndexSet();

            IndexSet &operator=(const IndexSet &other);

            /**
             * \brief Add a triangle.
             */
            void add_triangle(
                boost::uint32_t v1,
                boost::uint32_t v2,
                boost::uint32_t v3);

            /**
             * \brief Add a quadrangle.
             */
            void add_quad(
                boost::uint32_t v1,
                boost::uint32_t v2,
                boost::uint32_t v3,
                boost::uint32_t v4);

            /**
             * \brief Add a convex polygon.
             *
             * \pre inds.size() >= 3
             */
            void add_convex_polygon(
                const std::vector<boost::uint32_t> &inds);

            void clear();

            bool empty() const;

        private:
            class Impl;
            boost::scoped_ptr<Impl> m_impl;
        };


        /**
         * \brief Base class for TriMeshProxy.
         */
        class PEEKABOT_API TriMeshProxyBase : public ScalableProxyBase,
                                              public VertexBasedProxyBase
        {
        public:
            TriMeshProxyBase();

            TriMeshProxyBase(TriMeshProxyBase &p);

            DelayedDispatch set_indices(const IndexSet &indices);

            DelayedDispatch add_indices(const IndexSet &indices);
        };


        /**
         * \brief Proxy class used to add and manipulate used-specified
         * triangular meshes.
         */
        class PEEKABOT_API TriMeshProxy : public TriMeshProxyBase
        {
        public:
            TriMeshProxy();

            TriMeshProxy(TriMeshProxyBase &p);

            TriMeshProxy &operator=(const TriMeshProxy &p);

            TriMeshProxy &operator=(const TriMeshProxyBase &p);

            /**
             * \copydoc ScalableProxy::assign(const ObjectProxyBase&)
             */
            DelayedDispatch assign(const ObjectProxyBase &p);

            /**
             * \copydoc ObjectProxy::assign(PeekabotClient&,const std::string&)
             */
            DelayedDispatch assign(
                PeekabotClient &client,
                const std::string &path);

            /**
             * \copydoc
             * ObjectProxy::assign(const ObjectProxyBase&,const std::string&)
             */
            DelayedDispatch assign(
                const ObjectProxyBase &parent,
                const std::string &rel_path);

            /**
             * \brief Add a tri-mesh to the scene.
             *
             * Adds an empty tri-mesh to the scene at the given path and
             * assigns the proxy to point to it. If an object already exists at
             * the given path the outcome is governed by \a conflict_policy.
             *
             * \param path The path where the object will be added, including
             * the name of the object.
             * \param conflict_policy Determines how name conflicts are handled.
             */
            DelayedDispatch add(
                PeekabotClient &client,
                const std::string &path,
                NameConflictPolicy conflict_policy = AUTO_ENUMERATE_ON_CONFLICT);

            /**
             * \brief Add a tri-mesh to the scene.
             *
             * Adds an empty tri-mesh with the given name under the
             * object referred to by \a parent and assigns the proxy to point
             * to it. If an object already exists at the given path the outcome
             * is governed by \a conflict_policy.
             *
             * \param parent The parent under which the object will be added.
             * \param name The name to assign to the created object.
             * \param conflict_policy Determines how name conflicts are handled.
             */
            DelayedDispatch add(
                const ObjectProxyBase &parent,
                const std::string &name,
                NameConflictPolicy conflict_policy = AUTO_ENUMERATE_ON_CONFLICT);
        };
    }
}


#endif // PEEKABOT_CLIENT_TRI_MESH_PROXY_HH_INCLUDED
