
/* osgEarth
 * Copyright 2025 Pelican Mapping
 * MIT License
 */
#ifndef OSGEARTH_DRIVER_KML_COMMON
#define OSGEARTH_DRIVER_KML_COMMON 1

#include <osgEarth/Common>
#include <osgEarth/URI>
#include <osgEarth/SpatialReference>
#include <osgEarth/Style>
#include <osgEarth/StyleSheet>
#include <osgEarth/ResourceCache>
#include "KMLOptions"

#include "rapidxml.hpp"
#include "rapidxml_utils.hpp"
#include "rapidxml_ext.hpp"

using namespace rapidxml;
using namespace osgEarth::KML;

#define LC "[KML] "

#define for_one( NAME, FUNC, NODE, CX ) \
{ \
		xml_node<> *n = NODE->first_node(#NAME, 0, false); \
		if (n) {\
	        KML_##NAME instance; \
            instance. FUNC (n, CX); \
		}\
}


#define for_many( NAME, FUNC, NODE, CX ) \
{ \
   if (NODE) { \
       for (xml_node<>* n = NODE->first_node(#NAME, 0, false); n; n = n->next_sibling(#NAME, 0, false)) { \
	       KML_##NAME instance; \
		   instance. FUNC (n, CX); \
	   } \
   }\
}

#define for_features( FUNC, NODE, CX ) \
    for_many( Document,      FUNC, NODE, CX ); \
    for_many( Folder,        FUNC, NODE, CX ); \
    for_many( PhotoOverlay,  FUNC, NODE, CX ); \
    for_many( ScreenOverlay, FUNC, NODE, CX ); \
    for_many( GroundOverlay, FUNC, NODE, CX ); \
    for_many( NetworkLink,   FUNC, NODE, CX ); \
    for_many( Placemark,     FUNC, NODE, CX );

namespace osgEarth_kml
{
    using namespace osgEarth;

    struct KMLContext
    {
        const KMLOptions*                     _options;         // user options
        osg::ref_ptr<StyleSheet>              _sheet;           // entire style sheet
        Style                                 _activeStyle;     // currently active style
        std::stack<osg::ref_ptr<osg::Group> > _groupStack;      // resulting scene graph
        osg::ref_ptr<const SpatialReference>  _srs;             // map's spatial reference
        osg::ref_ptr<const osgDB::Options>    _dbOptions;       // I/O options (caching, etc)
        std::string                           _referrer;        // The referrer for loading things from relative paths.
    };

    struct KMLUtils
    {
        // parse KML's many variants on a URL link.
        static std::string parseLink( xml_node<>* node )
		{
			if (node)
			{
				xml_node<>* link = node->first_node("link", 0, false);
				if ( link )
				{
					std::string url = getValue(link, "href");
					if (url.empty())
					{
						url = getValue(link, "href");
					}
					if (url.empty())
					{
						url = link->value();
					}

					std::string httpQuery = getValue(link, "httpQuery");
					if (!httpQuery.empty())
					{
					    std::stringstream buf;
					    buf << url << "?" << httpQuery;
						url = buf.str();
					}
					return url;
				}
				else
				{
					link = node->first_node("url", 0, false);
                    if (link)
                    {
					    std::string url = getValue(link, "href");
					    if (url.empty())
					    {
    						url = link->value();
					    }
					    return url;
                    }
				}
			}
			return "";
        }
    };

} // namespace osgEarth_kml

#endif // OSGEARTH_DRIVER_KML_READER

