/* osgEarth
 * Copyright 2025 Pelican Mapping
 * MIT License
 */

#ifndef OSGEARTHUTIL_MEASURETOOL_H
#define OSGEARTHUTIL_MEASURETOOL_H 1

#include <osgEarth/Common>
#include <osgEarth/MapNode>
#include <osgEarth/MapNodeObserver>
#include <osgEarth/FeatureNode>
#include <osgEarth/Style>
#include <osg/Group>
#include <osgGA/GUIEventHandler>
#include <osgViewer/View>

namespace osgEarth { namespace Contrib
{
    using namespace osgEarth;

    struct OSGEARTH_EXPORT MeasureToolHandler : public osgGA::GUIEventHandler, public MapNodeObserver
    {
    public:

        class MeasureToolEventHandler : public osg::Referenced
        {
        public:
            virtual void onDistanceChanged(MeasureToolHandler* sender, double distance) {}
            virtual ~MeasureToolEventHandler() { }
        };

        typedef std::list< osg::ref_ptr< MeasureToolEventHandler > > MeasureToolEventHandlerList;


        MeasureToolHandler( MapNode* mapNode );        
        virtual ~MeasureToolHandler();

        bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa );        

        bool getLocationAt(osgViewer::View* view, double x, double y, double &lon, double &lat);
        
        void clear();

        void addEventHandler(MeasureToolEventHandler* handler );

        void setMouseButton(int mouseButton);
        int getMouseButton() const;

        GeoInterpolation getGeoInterpolation() const;
        void setGeoInterpolation( GeoInterpolation geoInterpolation );

        void setIsPath( bool path );
        bool getIsPath() const;

        /** Sets the style of the measurement line (to something other than the default) */
        void setLineStyle( const Style& style );
        const Style* getLineStyle() const { return _feature->style(); }

        void setIntersectionMask( osg::Node::NodeMask intersectionMask ) { _intersectionMask = intersectionMask; }
        osg::Node::NodeMask getIntersectionMask() const { return _intersectionMask;}
        
        osgEarth::Feature* getFeature() const { return _feature.get(); }

    public: // MapNodeObserver

        virtual void setMapNode( MapNode* mapNode );
        virtual MapNode* getMapNode() { return _mapNode.get(); }

    protected:
        GeoInterpolation _geoInterpolation;
        void fireDistanceChanged();
        bool _lastPointTemporary;
        bool _gotFirstLocation;
        bool _finished;
        bool _mouseDown;
        float _mouseDownX, _mouseDownY;
        int _mouseButton;
        osg::ref_ptr< osg::Group > _root;

        osg::ref_ptr< osgEarth::FeatureNode > _featureNode;
        osg::ref_ptr< osgEarth::Feature >  _feature;

        osg::ref_ptr< osgEarth::FeatureNode > _extentFeatureNode;
        osg::ref_ptr< osgEarth::Feature >       _extentFeature;

        MeasureToolEventHandlerList _eventHandlers;
        bool _isPath;        
        osg::observer_ptr< MapNode > _mapNode;
        osg::Node::NodeMask _intersectionMask;

        void rebuild();
    };
} }

#endif
