/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
* Copyright 2015 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_ANNO_LOCALIZED_NODE_H
#define OSGEARTH_ANNO_LOCALIZED_NODE_H 1

#include <osgEarthAnnotation/AnnotationNode>
#include <osgEarth/GeoData>
#include <osgEarth/Horizon>
#include <osg/MatrixTransform>

namespace osgEarth { namespace Annotation
{	
    using namespace osgEarth;

    /**
     * Base class for node that is localized at a specific geographic point.
     *
     * Don't use this class *directly*. If you are trying to add your own 
     * osg::Node as an Annotation, use the LocalizedGeometryNode instead.
     */
    class OSGEARTHANNO_EXPORT LocalizedNode : public PositionedAnnotationNode
    {
    public:
        META_AnnotationNodeAbstract(osgEarthAnnotation, LocalizedNode);

        /**
         * Constructs a new LocalizedNode.
         * @param mapSRS  Spatial reference for position info
         * @param pos     Initial position of the node (map coords)
         */
        LocalizedNode( 
            MapNode*          mapNode,
            const GeoPoint&   pos      =GeoPoint::INVALID );

        LocalizedNode(
            MapNode*          mapNode,
            const Config&     conf );


    public: // PositionedAnnotationNode

        /** Sets the node position */
        virtual bool setPosition( const GeoPoint& p );

        /** Gets the node position (in map coords) */
        virtual GeoPoint getPosition() const;


    public: // MapNodeObserver

        virtual void setMapNode( MapNode* mapNode );

    public:
        /**
         * Sets a "local offset" position - for an ECEF map, this is an offset in 
         * the local tangent plane of the node that is applied to the geometry.
         */
        void setLocalOffset( const osg::Vec3d& offset );

        /**
         * Gets the local tangent plane -space offset.
         */
        const osg::Vec3d& getLocalOffset() const;

        /**
         * Sets a local rotation - a rotation relative to the local tangent plane
         * of the geometry.
         */
        void setLocalRotation( const osg::Quat& rotation );

        /**
         * Gets the local tangent plane -space rotation.
         */
        const osg::Quat& getLocalRotation() const;

        /**
         * Local scale factor.
         */
        virtual void setScale( const osg::Vec3f& scale );
        const osg::Vec3f& getScale() const { return _scale; }

        /**
         * Enables or disable automatic horizon culling
         */
        void setHorizonCulling( bool value );
        bool getHorizonCulling() const;

    public: // AnnotationNode

        virtual Config getConfig() const;

    public: // osg::Node

        virtual osg::BoundingSphere computeBound() const;

    protected:

        /**
         * The matrix transform that controls this node's position
         */
        virtual osg::MatrixTransform* getTransform() =0;

	public:
        // refreshed the main transform with data from an asbolute point
        bool updateTransform(const GeoPoint& absPt, osg::Node* patch =0L);

    protected:
        bool                               _initComplete;
        GeoPoint                           _mapPosition;
        osg::Vec3f                         _scale;
        osg::Vec3d                         _localOffset;
        osg::Quat                          _localRotation;
        
        bool                               _horizonCullingRequested;
        osg::ref_ptr<HorizonCullCallback>  _horizonCuller;

        friend class Decoration;
        
        // re-clamped the vert mesh based on a new terrain tile coming in
        virtual void reclamp( const TileKey& key, osg::Node* tile, const Terrain* terrain );

        // checks for overlay requirements, and if needed, installs a decorator node above
        // the passed-in node to facilitate the clamping/draping. The proper usage pattern
        // is:  node = applyAltitudePolicy(node, style)
        osg::Node* applyAltitudePolicy( osg::Node* node, const Style& style );

        // hidden copy constructor
        LocalizedNode() { }
        LocalizedNode(const LocalizedNode& rhs, const osg::CopyOp& op=osg::CopyOp::DEEP_COPY_ALL) : PositionedAnnotationNode(rhs, op) { }
        virtual ~LocalizedNode() { }


    private:

        void init();
    };

} } // namespace osgEarth::Annotation

#endif // OSGEARTH_ANNO_LOCALIZED_NODE_H
