/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
 * Copyright 2008-2010 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * 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 OSGEARTHFEATURES_FEATURE_SOURCE_H
#define OSGEARTHFEATURES_FEATURE_SOURCE_H 1

#include <osgEarthFeatures/Common>
#include <osgEarthFeatures/Feature>
#include <osgEarthFeatures/Annotation>
#include <osgEarthSymbology/Geometry>
#include <osgEarthSymbology/Query>
#include <osgEarthFeatures/Filter>
#include <osgEarthSymbology/Style>
#include <osgEarth/Profile>
#include <osgEarth/GeoData>
#include <osgDB/ReaderWriter>
#include <OpenThreads/Mutex>
#include <list>

namespace osgEarth { namespace Features
{   
    using namespace osgEarth;

    /**
     * A cursor that lets you iterate over a collection of features returned 
     * from a feature query performed on a FeatureStore.
     */
    class OSGEARTHFEATURES_EXPORT FeatureCursor : public osg::Referenced
    {
    public:
        virtual bool hasMore() const =0;
        virtual Feature* nextFeature() =0;
    };

    /**
     * A simple cursor implementation that returns features from an in-memory
     * feature list.
     */
    class OSGEARTHFEATURES_EXPORT FeatureListCursor : public FeatureCursor
    {
    public:
        FeatureListCursor( const FeatureList& input );
        virtual bool hasMore() const;
        virtual Feature* nextFeature();
    protected:
        FeatureList _features;
        FeatureList::iterator _iter;
    };

    /**
     * A simple cursor that returns each Geometry wrapped in a feature.
     */
    class OSGEARTHFEATURES_EXPORT GeometryFeatureCursor : public FeatureCursor
    {
    public:
        GeometryFeatureCursor( Symbology::Geometry* geom );
        GeometryFeatureCursor( Symbology::Geometry* geom, const FeatureProfile* fp, const FeatureFilterList& filters );
        virtual bool hasMore() const;
        virtual Feature* nextFeature();
    protected:
        osg::ref_ptr<Symbology::Geometry> _geom;
        osg::ref_ptr<const FeatureProfile> _featureProfile;
        const FeatureFilterList _filters;
        osg::ref_ptr<Feature> _lastFeature;
    };

    /**
     * Configuration options for creating a FeatureSource.
     */
    class OSGEARTHFEATURES_EXPORT FeatureSourceOptions : public DriverConfigOptions
    {
    public: // properties

        FeatureFilterList& filters() { return _filters; }
        const FeatureFilterList& filters() const { return _filters; }

    public:
        FeatureSourceOptions( const ConfigOptions& options =ConfigOptions() );
        virtual Config getConfig() const;

    protected:
        virtual void mergeConfig( const Config& conf ) {
            DriverConfigOptions::mergeConfig( conf );
            fromConfig( conf );
        }

    private:
        void fromConfig( const Config& conf );

        FeatureFilterList _filters;
    };

    /**
     * A FeatureSource is a pluggable object that generates Features, and 
     * optionally, styling information to go along with them.
     */
    class OSGEARTHFEATURES_EXPORT FeatureSource : public virtual Revisioned<osg::Object> // public virtual osg::Object
    {
    public:      
        /**
         * Constructs a new feature source with the provided read/write options.
         */
        FeatureSource( const ConfigOptions& options =ConfigOptions() );

        /**
         * Gets a reference to the metadata that describes features that you can
         * get from this FeatureSource. A valid feature profile indiciates that the
         * feature source successfully initialized.
         */
        const FeatureProfile* getFeatureProfile() const;

        /**
         * Gets the options that were passed into this object's CTOR.
         */
        const FeatureSourceOptions& getFeatureSourceOptions() const { return _options; }

        /**
         * Creates a cursor that iterates over all the features corresponding to the
         * specified query.
         *
         * Caller takes ownership of the returned object.
         */
        virtual FeatureCursor* createFeatureCursor( const Symbology::Query& query ) =0;


    public: // Styling

        /**
         * Returns true if this source creates features with embedded style information.
         * By default, this is false (features are not expected to carry their own
         * style definitions).
         */
        virtual bool hasEmbeddedStyles() const {
            return false; }

    public:

        /**
         * Accesses the list of feature filters that will transform features
         * before they are returned in a feature cursor.
         */
        const FeatureFilterList& getFilters() const;

    public: 

        // META_Object specialization:
        virtual osg::Object* cloneType() const { return 0; } // cloneType() not appropriate
        virtual osg::Object* clone(const osg::CopyOp&) const { return 0; } // clone() not appropriate
        virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const FeatureSource*>(obj)!=NULL; }
        virtual const char* className() const { return "FeatureSource"; }
        virtual const char* libraryName() const { return "osgEarthFeatures"; }


		/**
		 * Initialize the FeatureSource.  The profile should be computed and set here using setProfile()
		 */
		virtual void initialize( const std::string& referenceURI ) =0;

    protected:

        /**
         * Creates and returns a metadata structure describing the features in a named
         * feature class. This method is called by the public function getFeatureProfile()
         * in this same object to create the metadata structure.
         */
        virtual const FeatureProfile* createFeatureProfile() =0;

        /**
         * DTOR is protected to prevent this object from being allocated on the stack.
         */
        virtual ~FeatureSource() { }

    private:
        const FeatureSourceOptions _options;

        osg::ref_ptr<const FeatureProfile> _featureProfile;
        OpenThreads::Mutex _createMutex;

        friend class Map;
        friend class FeatureSourceFactory;
    };

    //--------------------------------------------------------------------

    class OSGEARTHFEATURES_EXPORT FeatureSourceDriver : public osgDB::ReaderWriter
    {
    public:
        virtual const FeatureSourceOptions& getFeatureSourceOptions( const osgDB::ReaderWriter::Options* rwopt ) const;
    };

    //--------------------------------------------------------------------

    /**
     * Factory class that will instantiate a FeatureSource corresponding to a driver name.
     */
    class OSGEARTHFEATURES_EXPORT FeatureSourceFactory
    {
	public:
        static FeatureSource* create( const FeatureSourceOptions& options );
    };

} } // namespace osgEarth::Features

#endif // OSGEARTHFEATURES_FEATURE_SOURCE_H

