/* osgEarth
 * Copyright 2025 Pelican Mapping
 * MIT License
 */
#include "SilverLiningAPIWrapper"
#include <SilverLining.h>

#ifndef SILVERLINING_MAJOR_VERSION
#include <Version.h>
#endif

#define LC "[SilverLiningAPI] "

using namespace osgEarth::SilverLining;

#define SETGET_EXPLICIT(NS, SETTER, GETTER, TYPE) \
    void NS :: SETTER (TYPE value) { HANDLE-> SETTER (value); } \
    TYPE NS :: GETTER () const     { return HANDLE -> GETTER (); }

#define SETGET(NS, FUNC, TYPE) \
    SETGET_EXPLICIT(NS, Set##FUNC, Get##FUNC, TYPE)

//................................
#undef  HANDLE
#define HANDLE ((::SilverLining::Atmosphere*)_handle)

SETGET_EXPLICIT(Atmosphere, EnableLensFlare, GetLensFlareEnabled, bool);

void Atmosphere::SetSkyModel(SkyModel skyModel) { HANDLE->SetSkyModel(static_cast< ::SkyModel >(skyModel)); }
Atmosphere::SkyModel Atmosphere::GetSkyModel() const { return static_cast<SkyModel>(HANDLE->GetSkyModel()); }
AtmosphericConditions Atmosphere::GetConditions() const { return AtmosphericConditions((uintptr_t)HANDLE->GetConditions()); }
bool Atmosphere::GetFogEnabled() const { return HANDLE->GetFogEnabled(); }
void Atmosphere::GetFogSettings(float &density, osg::Vec3f &color) const {HANDLE->GetFogSettings(&density, &color.x(), &color.y(), &color.z());}
void Atmosphere::GetHorizonColor(float yawDeg, float pitchDeg, osg::Vec3f &color) const { HANDLE->GetHorizonColor(yawDeg, pitchDeg, &color.x(), &color.y(), &color.z());}
void Atmosphere::SetHaze(const osg::Vec3 &color, double depth, double density) { HANDLE->SetHaze(color.x(), color.y(), color.z(),depth, density);}
bool Atmosphere::GetEnvironmentMap(GLuint &environmentMapTex, int facesToRender, bool floatingPoint, void* cameraID, bool drawClouds, bool drawSunAndMoon, bool isGeocentric) const
{
    void* ptr;

#if ((SILVERLINING_MAJOR_VERSION >= 5) && (SILVERLINING_MINOR_VERSION >= 30))
    bool success = HANDLE->GetEnvironmentMap(ptr, facesToRender, floatingPoint, cameraID, drawClouds, drawSunAndMoon, isGeocentric);
#else
    bool success = HANDLE->GetEnvironmentMap(ptr, facesToRender, floatingPoint, cameraID, drawClouds, drawSunAndMoon);
#endif

    if (success)
       environmentMapTex = static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
    return success;
}

SETGET(Atmosphere, Gamma, double);
SETGET(Atmosphere, InfraRedMode, bool);

//................................
#undef  HANDLE
#define HANDLE ((::SilverLining::AtmosphericConditions*)_handle)

SETGET(AtmosphericConditions, Visibility, double);
SETGET(AtmosphericConditions, Turbidity, double);
SETGET(AtmosphericConditions, LightPollution, double);

void AtmosphericConditions::SetPrecipitation(int type, double rate) {
    HANDLE->SetPrecipitation((::CloudLayer::PrecipitationTypes)type, rate);
}

int AtmosphericConditions::AddCloudLayer(CloudLayer& layer) { return HANDLE->AddCloudLayer((::SilverLining::CloudLayer*)layer._handle); }
bool AtmosphericConditions::RemoveCloudLayer(int layerHandle) { return HANDLE->RemoveCloudLayer(layerHandle); }
void AtmosphericConditions::RemoveAllCloudLayers() { HANDLE->RemoveAllCloudLayers(); }

int AtmosphericConditions::SetWind(const WindVolume& windVolume)
{
    ::SilverLining::WindVolume slVolume;
    slVolume.SetMinAltitude(windVolume.GetMinAltitude());
    slVolume.SetMaxAltitude(windVolume.GetMaxAltitude());
    slVolume.SetWindSpeed(windVolume.GetWindSpeed());
    slVolume.SetDirection(windVolume.GetDirection());
    return HANDLE->SetWind(slVolume);
}
int AtmosphericConditions::SetWind(double metersPerSecond, double degreesFromNorth) { return SetWind(WindVolume(metersPerSecond, degreesFromNorth)); }
bool AtmosphericConditions::RemoveWindVolume(int layerHandle) { return HANDLE->RemoveWindVolume(layerHandle); }
void AtmosphericConditions::ClearWindVolumes() { HANDLE->ClearWindVolumes(); }
void AtmosphericConditions::SetPresetConditions(ConditionPresets preset, Atmosphere& atm) { HANDLE->SetPresetConditions(static_cast< ::SilverLining::AtmosphericConditions::ConditionPresets >(preset), *(::SilverLining::Atmosphere*)atm._handle); }
void AtmosphericConditions::EnableTimePassage(bool enabled, long relightFrequencyMS) { HANDLE->EnableTimePassage(enabled, relightFrequencyMS); }
void AtmosphericConditions::GetLocation(double &latitude, double &longitude, double &altitude) const { latitude = HANDLE->GetLocation().GetLatitude(); longitude = HANDLE->GetLocation().GetLongitude(); altitude = HANDLE->GetLocation().GetAltitude(); }
void AtmosphericConditions::SetFog(double density, const osg::Vec3 &color) { HANDLE->SetFog(density, color.x(), color.y(), color.z()); }

//................................
WindVolume::WindVolume() :
_minAltitude( 0.0 ),
_maxAltitude( 100000.0 ),
_windSpeed  ( 0.0 ),
_direction  ( 0.0 )
{
}
WindVolume::WindVolume(double windSpeed, double direction) :
_minAltitude( 0.0 ),
_maxAltitude( 100000.0 ),
_windSpeed  ( windSpeed ),
_direction  ( direction )
{
}
void WindVolume::SetMinAltitude(double metersMSL) { _minAltitude = metersMSL; }
double WindVolume::GetMinAltitude() const { return _minAltitude; }
void WindVolume::SetMaxAltitude(double metersMSL) { _maxAltitude = metersMSL; }
double WindVolume::GetMaxAltitude() const { return _maxAltitude; }
void WindVolume::SetWindSpeed(double metersPerSecond) { _windSpeed = metersPerSecond; }
double WindVolume::GetWindSpeed() const { return _windSpeed; }
void WindVolume::SetDirection(double degreesFromNorth) { _direction = degreesFromNorth; }
double WindVolume::GetDirection() const { return _direction; }

//................................
#undef  HANDLE
#define HANDLE ((::SilverLining::CloudLayer*)_handle)

SETGET(CloudLayer, Enabled, bool)
SETGET(CloudLayer, BaseWidth, double)
SETGET(CloudLayer, BaseLength, double)
SETGET(CloudLayer, BaseAltitude, double)
SETGET(CloudLayer, Thickness, double)
SETGET(CloudLayer, Density, double)
SETGET(CloudLayer, IsInfinite, bool)
SETGET(CloudLayer, CloudWrapping, bool)
SETGET(CloudLayer, FadeTowardEdges, bool)
SETGET(CloudLayer, Alpha, double)

void CloudLayer::SetLayerPosition(double e, double n) { HANDLE->SetLayerPosition(e, n); }
void CloudLayer::GetLayerPosition(double& e, double& n) const { HANDLE->GetLayerPosition(e, n); }

void CloudLayer::SetWind(double windEast, double windSouth) { HANDLE->SetWind(windEast, windSouth); }
void CloudLayer::GetWind(double& windEast, double& windSouth) const { HANDLE->GetWind(windEast, windSouth); }

void CloudLayer::SetCloudAnimationEffects(double a, bool b, int c, int d) { HANDLE->SetCloudAnimationEffects(a, b, c, d); }
void CloudLayer::GetCloudAnimationEffects(double& a, bool& b, int& c, int& d) { HANDLE->SetCloudAnimationEffects(a, b, c, d); }

void CloudLayer::SeedClouds(Atmosphere& a) { HANDLE->SeedClouds(*(::SilverLining::Atmosphere*)a._handle); }

CloudLayer CloudLayerFactory::Create(int kind, Atmosphere& a)
{
#ifdef OSGEARTH_SILVERLINING_USE_PRE_5_079_API
    return CloudLayer((uintptr_t)::SilverLining::CloudLayerFactory::Create((::CloudTypes)kind));
#else
    return CloudLayer((uintptr_t)::SilverLining::CloudLayerFactory::Create((::CloudTypes)kind, *(::SilverLining::Atmosphere*)a._handle));
#endif
}
