/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
* Copyright 2016 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*/
#ifndef OSGEARTH_ANNOTATION_TRACK_NODE_H
#define OSGEARTH_ANNOTATION_TRACK_NODE_H 1

#include <osgEarthAnnotation/GeoPositionNode>
#include <osgEarthSymbology/Style>
#include <osgEarth/Containers>
#include <osg/Image>
#include <osgText/String>

namespace osgEarth
{ 
    class MapNode;
}
    
namespace osgEarth { namespace Annotation
{	
    using namespace osgEarth;
    using namespace osgEarth::Symbology;

    /**
     * Defines for a labeling field associated with a TrackNode. A TrackNode
     * can have zero or more "fields", each being a text label rendered 
     * along with the node's icon.
     */
    struct /*no-export*/ TrackNodeField
    {
        /**
         * Constructs a new field definition.
         * @param symbol  Text symbol describing the field's appearance and placement
         * @param dynamic Whether the text label will be dynamic; i.e. whether the user
         *                intends to update it at runtime. Setting this to "false" for a
         *                static label yields better performance in a multithreaded app.
         */
        TrackNodeField( const TextSymbol* symbol, bool dynamic =true )
            : _symbol(symbol), _dynamic(dynamic) { }

        /** other constructors (internal) */
        TrackNodeField()
            : _dynamic(true) { }

        TrackNodeField( const TrackNodeField& rhs ) 
            : _symbol(rhs._symbol.get()), _dynamic(rhs._dynamic) { }

        osg::ref_ptr<const TextSymbol> _symbol;
        bool                           _dynamic;
    };

    /**
     * Schema that maps field names to field definitions.
     */
    typedef fast_map<std::string, TrackNodeField> TrackNodeFieldSchema;

    /** 
     * TrackNode is a movable, single-point entity represented by an icon,
     * optional placeable text labels, and optional localized geometry.
     *
     * NOTE. TrackNode does not automatically support terrain clamping. This is
     * because its intention is for use as a trackable entity marker, and 
     * presumably the entity itself will be responsible for its own absolute
     * positioning (and clamping, if applicable).
     */
    class OSGEARTHANNO_EXPORT TrackNode : public GeoPositionNode
    {
    public:
        META_AnnotationNode(osgEarthAnnotation, TrackNode);

        /**
         * Constructs a new track node
         * @param mapNode     Map node under which this track will live
         * @param position    Initial position
         * @param image       Icon image to use
         * @param fieldSchema Schema for track label fields
         */
        TrackNode(
            MapNode*                    mapNode,
            const GeoPoint&             position,
            osg::Image*                 image,
            const TrackNodeFieldSchema& fieldSchema );

        /**
         * Constructs a new track node
         * @param mapNode     Map node under which this track will live
         * @param position    Initial position
         * @param style       Style containing an IconSymbol for the image
         * @param fieldSchema Schema for track label fields
         */
        TrackNode(
            MapNode*                    mapNode,
            const GeoPoint&             position,
            const Style&                style,
            const TrackNodeFieldSchema& fieldSchema );

        /** 
         * Sets the value of one of the field labels.
         * @param name  Field name as identified in the field schema.
         * @param value Value to which to set the field label.
         */
        void setFieldValue( const std::string& name, const std::string& value ) { setFieldValue(name, osgText::String(value)); }
        void setFieldValue( const std::string& name, const osgText::String& value );

        /**
         * Adds an arbitrary drawable to this track node. Useful for adding
         * user-defined graphics.
         * @param name     Name of the drawable (for later retrieval). The namespace
         *                 should not conflict with that of the field schema.
         * @param drawable Drawable to add.
         */
        void addDrawable( const std::string& name, osg::Drawable* drawable );

        /**
         * Gets a drawable (as previously added with addDrawable). 
         * Note: Make sure that if you are modifying a drawable, mark it with a 
         * DYNAMIC data variance so it will be thread-safe.
         */
        osg::Drawable* getDrawable( const std::string& name ) const;

    public:

        virtual void setPriority(float value);

    protected:

        virtual ~TrackNode() { }

        Style             _style;
        class osg::Geode* _geode;

        typedef fast_map<std::string, osg::Drawable*> NamedDrawables;
        NamedDrawables _namedDrawables;

        void init( const TrackNodeFieldSchema& schema );

    protected: // AnnotationNode override
        
        virtual bool supportsRenderBinDetails() const { return false; }

    private:
        // required by META_Node, but this object is not cloneable
        TrackNode() { }
        TrackNode(const TrackNode& rhs, const osg::CopyOp& op =osg::CopyOp::DEEP_COPY_ALL) { }

        void updateLayoutData();

    };

} } // namespace osgEarth::Annotation

#endif //OSGEARTH_ANNOTATION_TRACK_NODE_H
