/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Module configuration.
 *//*
 * LEGAL:   COPYRIGHT (C) 2008 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#define SKY_CONF_CC 1
#include <fstream>
#include "base/module.hh"
#include "base/conf.hh"
#include "base/conf_template_macros.hh"
#include "base/stream.hh"
using namespace base;
#include "gfx/module.hh"
#include "gfx/rgba.hh"
#include "gfx/rgba_funcs.hh"
using namespace gfx;
#include "world/module.hh"
#include "world/conf.hh"
using namespace world;
#include "sky/module.hh"
#include "sky/defs.hh"
#include "sky/conf.hh"
#include "sky/weather.hh"

namespace sky {

////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////  Conf  ///////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

namespace global { Conf gConf; }

/*****************************************************************************
 * ctor/dtor.
 *****************************************************************************/
Conf::Conf( void )
:   mValid(false),
    // cmd-line args 
    mSkyEnabled(true),
    mUseOssim(false),  // WORLD_CONF isn't available to SKY_CONF
    // (none)
    // .conf file
    mSkyColor(sky::defs::DEFAULT_SKY_COLOR),
    mSkyFogDensity(sky::defs::DEFAULT_SKY_FOG_DENSITY),  // fpx
    mSkyDomeSliceCount(sky::defs::DEFAULT_SKY_DOME_SLICE_COUNT),
    mEnableMoon(true),
    mStarCount(sky::defs::DEFAULT_STAR_COUNT),
    mCloudsEnabled(true),
    mCloudConfFlat(),
    mCloudConfSphere(),
    mWeatherRainChance(0),
    mWeatherSnowChance(0)
{
}

/*****************************************************************************
 * Initialize/read configuration.
 *****************************************************************************/
void
Conf::Init( const base::InitArgs& initArgs, const string& confTxtFilename )
{
    CONF_TEMPLATE_Init_ParseCmdline_ReadConfTxt;
}

/*****************************************************************************
 * Parse cmdline args.
 *****************************************************************************/
void
Conf::ParseCmdlineArgs( int argc, char** argv )
{
    // Parse cmd-line args.
    for ( int i = 1; i < argc; ++i )
    {
        if ( STREQ( argv[i], "-ossim" ) )
        {
            mUseOssim = true;

            // Clouds don't look right in some places in OSSIM.
            SKY_CONF.mCloudsEnabled = false;
            CLOG << "Disabled clouds." << std::endl;
        }
        else if ( STRSTR( argv[i], "-no-cloud" ) )  // or -no-clouds
        {
            SKY_CONF.mCloudsEnabled = false;
            CLOG << "Disabled clouds." << std::endl;
        }
        else if ( STREQ( argv[i], "-fast" )
               or STREQ( argv[i], "-no-sky" ) )
        {
            SKY_CONF.mSkyEnabled = false;
            CLOG << "Disabled sky." << std::endl;
        }
        else if ( STREQ( argv[i], "-no-weather" ) )
        {
            GET_WEATHER().Enable( false );
            CLOG << "Disabled weather." << std::endl;
        }
        else if ( STREQ( argv[i], "-weather" ) )
        {
            GET_WEATHER().Enable( true );
            GET_WEATHER().SetWeather( Weather::eWeather_DEFAULT );
            CLOG << "Enabled weather (default)." << std::endl;
        }
        else if ( STRSTR( argv[i], "-rain" ) )  // or -weather-rain
        {
            GET_WEATHER().Enable( true );
            GET_WEATHER().SetWeather( Weather::eWeather_RAIN );
            CLOG << "Setting weather to rain." << std::endl;
        }
        else if ( STRSTR( argv[i], "-snow" ) )  // or -weather-snow
        {
            GET_WEATHER().Enable( true );
            GET_WEATHER().SetWeather( Weather::eWeather_SNOW );
            CLOG << "Setting weather to snow." << std::endl;
        }
    }
}

void
Conf::ParseCmdlineArgs2( int argc, char** argv )
{
    // NOP
}

/*****************************************************************************
 * Read from .conf file.
 *****************************************************************************/
void
Conf::ReadConfTxt( const string& confTxtFilename )
{
    CONF_TEMPLATE_ReadConfTxt;
}

void
Conf::ModuleConfTxt::ProcessField( string& field, std::ifstream& conf )
{
    bool error = false;

    if ( field == "SkyColor" )
    {
        fp r, g, b, a;
        conf >> r;
        conf >> g;
        conf >> b;
        conf >> a;
        SKY_CONF.mSkyColor.Set( r, g, b, a );
    }
    else if ( field == "SkyFogDensity" )
    {
        conf >> SKY_CONF.mSkyFogDensity;
    }
    else if ( field == "SkyDomeSlices" )
    {
        conf >> SKY_CONF.mSkyDomeSliceCount;
    }
    else if ( field == "EnableMoon" )
    {
        conf >> SKY_CONF.mEnableMoon;
    }
    else if ( (field == "FlatStars" and not SKY_CONF.mUseOssim)
           or (field == "SphereStars" and SKY_CONF.mUseOssim) )
    {
        conf >> SKY_CONF.mStarCount;
    }
    else if ( field == "WeatherRainChance" )
    {
        conf >> SKY_CONF.mWeatherRainChance;
    }
    else if ( field == "WeatherSnowChance" )
    {
        conf >> SKY_CONF.mWeatherSnowChance;
    }
    else
    {
        // Need to match prefix with correlating member.
        if ( field.find( "Flat" ) != string::npos )
            ProcessField( field, conf, SKY_CONF.mCloudConfFlat );
        else if ( field.find( "Sphere" ) != string::npos )
            ProcessField( field, conf, SKY_CONF.mCloudConfSphere );
    }
    
    // Errors?
    if ( error )
    {
        CERROR << "ERROR[conf]: parameter for " << field << " is invalid." << std::endl;
        EXIT( 1 );
    }
}

void
Conf::ModuleConfTxt::ProcessField( string& field, std::ifstream& conf, CloudConf& cloudConf )
{
    if ( field == "FlatClouds" or field == "SphereClouds" )
    {
        conf >> cloudConf.mCloudCount;
    }
    else if ( field == "FlatCloudMinAlt" or field == "SphereCloudMinAlt" )
    {
        fp f; conf >> f; cloudConf.mCloudMinAlt = Meter(f);
    }
    else if ( field == "FlatCloudMaxAlt" or field == "SphereCloudMaxAlt" )
    {
        fp f; conf >> f; cloudConf.mCloudMaxAlt = Meter(f);
    }
    else if ( field == "FlatCloudMinWidth" or field == "SphereCloudMinWidth" )
    {
        fp f; conf >> f; cloudConf.mCloudMinWidth = Meter(f);
    }
    else if ( field == "FlatCloudMaxWidth" or field == "SphereCloudMaxWidth" )
    {
        fp f; conf >> f; cloudConf.mCloudMaxWidth = Meter(f);
    }
}

/*****************************************************************************
 * Print Conf configuration.
 *****************************************************************************/
std::ostream& operator<<( std::ostream& strm, const Conf& conf )
{
    std::ios::fmtflags savedFlags = strm.flags();

    strm << "conf [sky]:"                                                        << std::endl
         << "SkyColor                    = " << conf.mSkyColor                ;//<< std::endl
    strm.flags(savedFlags);

    return strm;
}

} // namespace sky
