/*
 * SPDX-FileName:tileentry.hxx -- routines to handle a scenery tile
 * SPDX-FileCopyrightText: 1998 Curtis L. Olson  - http://www.flightgear.org/~curt
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#pragma once

#include <Main/globals.hxx>
#include <Main/fg_props.hxx>

#include <simgear/compiler.h>

#include <vector>
#include <string>

#include <simgear/bucket/newbucket.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/scene/util/OrthophotoManager.hxx>
#include <simgear/scene/util/SGReaderWriterOptions.hxx>

#include <osg/ref_ptr>
#include <osgDB/ReaderWriter>
#include <osg/Group>
#include <osg/LOD>

/**
 * A class to encapsulate everything we need to know about a scenery tile.
 */
class TileEntry {

public:
    // this tile's official location in the world
    SGBucket tile_bucket;
    std::string tileFileName;

protected:
    // pointer to ssg range selector for this tile
    osg::ref_ptr<osg::LOD> _node;

private:
    // Reference to DatabaseRequest object set and used by the
    // osgDB::DatabasePager.
    osg::ref_ptr<osg::Referenced> _databaseRequest;
    // Overlay image/orthophoto for this tile
    simgear::OrthophotoRef _orthophoto;

    /**
     * This value is used by the tile scheduler/loader to load tiles
     * in a useful sequence. The priority is set to reflect the tiles
     * distance from the center, so all tiles are loaded in an innermost
     * to outermost sequence.
     */
    float _priority;
    /** Flag indicating if tile belongs to current view. */
    bool _current_view;
    /** Time when tile expires. */
    double _time_expired;

    void _create_orthophoto();

public:

    // Constructor.
    TileEntry( const SGBucket& b );
    TileEntry( const TileEntry& t );

    // Destructor
    virtual ~TileEntry() = 0;

    // Update the ssg transform node for this tile so it can be
    // properly drawn relative to our (0,0,0) point
    void prep_ssg_node(float vis);

    /**
     * Return true if the tile entry is loaded, otherwise return false
     * indicating that the loading thread is still working on this.
     */
    inline bool is_loaded() const
    {
        return _node->getNumChildren() > 0;
    }

    /**
     * Return the "bucket" for this tile
     */
    inline const SGBucket& get_tile_bucket() const { return tile_bucket; }

    /**
     * Add terrain mesh and ground lighting to scene graph.
     */
    void addToSceneGraph( osg::Group *terrain_branch);

    /**
     * disconnect terrain mesh and ground lighting nodes from scene
     * graph for this tile.
     */
    void removeFromSceneGraph();

    /**
     * return the scenegraph node for the terrain
     */
    osg::LOD *getNode() const { return _node.get(); }

    inline double get_time_expired() const { return _time_expired; }
    inline void update_time_expired( double time_expired ) { if (_time_expired<time_expired) _time_expired = time_expired; }

    inline void set_priority(float priority) { _priority=priority; }
    inline float get_priority() const { return _priority; }
    inline void set_current_view(bool current_view) { _current_view = current_view; }
    inline bool is_current_view() const { return _current_view; }

    /**
     * Return false if the tile entry is still needed, otherwise return true
     * indicating that the tile is no longer in active use.
     */
    inline bool is_expired(double current_time) const { return (_current_view) ? false : (current_time > _time_expired); }

    // Get the ref_ptr to the DatabaseRequest object, in order to pass
    // this to the pager.
    osg::ref_ptr<osg::Referenced>& getDatabaseRequest()
    {
        return _databaseRequest;
    }

    enum Extension {
        STG, VPB
    };

    virtual TileEntry::Extension getExtension() = 0;
};

class STGTileEntry : public TileEntry
{
public:
    STGTileEntry(const SGBucket& b);
    ~STGTileEntry();
    inline TileEntry::Extension getExtension() { return TileEntry::Extension::STG; };
};

class VPBTileEntry : public TileEntry
{
public:
    VPBTileEntry(const SGBucket& b, osg::ref_ptr<simgear::SGReaderWriterOptions> options);
    ~VPBTileEntry();
    inline TileEntry::Extension getExtension() { return TileEntry::Extension::VPB; };
};
