/*****************************************************************************
 * $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) 2007 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#define WORLD_CONF_CC 1
#include <fstream>
#include "base/module.hh"
#include "base/conf.hh"
#include "base/conf_template_macros.hh"
#include "base/misc.hh"
#include "base/stream.hh"
using namespace base;
#include "math/module.hh"
#include "math/funcs.hh"
using namespace math;
#include "gfx/module.hh"
#include "gfx/rgba.hh"
using namespace gfx;
#include "control/module.hh"
using namespace control;
#include "world/module.hh"
#include "world/conf.hh"

namespace world {

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

namespace global { Conf gConf; }

/*****************************************************************************
 * ctor/dtor.
 *****************************************************************************/
Conf::Conf( void )
:   mValid(false),
    // cmd-line args
    mFlatWorld(true),
    mEnableOsgOptimizer(true),
    // .conf file
    // World:
    mObjectScale(1.0f),
    mObjectScale3(1.0f,1.0f,1.0f),
    mWorldAltitudeMin(0.0f),
    mWorldAltitudeMax(0.0f),
    // Terrain model of flat world:
    mFlatModelFile(""),
    mFlatModelRotationList(),
    mFlatModelScale(1.0f),
    mFlatModelOffset(0,0,0),
    mFlatModelNW(Degree(0),Degree(0),Meter(0)),
    mFlatModelSE(Degree(0),Degree(0),Meter(0)),
    mFlatModelMeterOffset(Meter(0),Meter(0),Meter(0)),
    mFlatModelMeterSimRatio(1.0f),
    mFlatModelMeterLowAlt(100.0f),
    mFlatModelMeterAltMin(0.0f),
    mFlatModelMeterAltMax(10000.0f)
{
    // NOP
}

/*****************************************************************************
 * 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 )
{
    for ( int i = 1; i < argc; ++i )
    {
        if ( STRSTR( argv[i], "-flat" ) )  // -flat-world
        {
            mFlatWorld = true;
            CmdargDone( i );
            CLOG << "Enabled flat world." << std::endl;
        }
#if COMPILE_OSSIM
        else if ( STRSTR( argv[i], "-spher" ) )  // -sphere or -sphere-world or -spherical
        {
            mFlatWorld = false;
            CLOG << "Enabled spherical world." << std::endl;
            CmdargDone( i );
        }
#endif
        else if ( STREQ( argv[i], "-no-osg-opt" ) )
        {
            mEnableOsgOptimizer = false;
            CmdargDone( i );
            CLOG << "Disabled OSG optimizer." << 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;

    //---------------------  flat/sphere world  --------------------------------
    if ( field == "FlatObjectScale" and WORLD_CONF.mFlatWorld )
    {
        conf >> WORLD_CONF.mObjectScale;
#if DEBUG
        // If ObjectScale != 1.0 then distorted shadows will appear
        // when the chase-view is nearly at same altitude as its target.
        // The cause of this problem is unknown.
        if ( WORLD_CONF.mObjectScale != 1.0f )
        {
            CERROR << "ObjectScale != 1.0 causes distorted shadows." << std::endl;
            EXIT( 1 );
        }
#endif
        WORLD_CONF.mObjectScale3[XX] = \
        WORLD_CONF.mObjectScale3[YY] = \
        WORLD_CONF.mObjectScale3[ZZ] = WORLD_CONF.mObjectScale;
    }
    else if ( field == "SphereObjectScale" and not WORLD_CONF.mFlatWorld )
    {
        conf >> WORLD_CONF.mObjectScale;
#if DEBUG
        // If ObjectScale != 1.0 then distorted shadows will appear
        // when the chase-view is nearly at same altitude as its target.
        // The cause of this problem is unknown.
        if ( WORLD_CONF.mObjectScale != 1.0f )
        {
            CERROR << "ObjectScale != 1.0 causes distorted shadows." << std::endl;
            EXIT( 1 );
        }
#endif
        WORLD_CONF.mObjectScale3[XX] = \
        WORLD_CONF.mObjectScale3[YY] = \
        WORLD_CONF.mObjectScale3[ZZ] = WORLD_CONF.mObjectScale;
    }
    else if ( field == "WorldAltitudeMin" )  // min
    {
        fp f;
        conf >> f; WORLD_CONF.mWorldAltitudeMin = Meter( f );
    }
    else if ( field == "WorldAltitudeMax" )  // max
    {
        fp f;
        conf >> f; WORLD_CONF.mWorldAltitudeMax = Meter( f );
    }
    //--------------------  terrain model of flat world  -----------------------
    else if ( field == "FlatModelFile" )
    {
        conf >> WORLD_CONF.mFlatModelFile;
    }
    else if ( field == "FlatModelRotationList" )
    {
        WORLD_CONF.mFlatModelRotationList.Parse( conf );
    }
    else if ( field == "FlatModelScale" )
    {
        conf >> WORLD_CONF.mFlatModelScale;
    }
    else if ( field == "FlatModelOffset" )
    {
        conf >> WORLD_CONF.mFlatModelOffset[XX];
        conf >> WORLD_CONF.mFlatModelOffset[YY];
        conf >> WORLD_CONF.mFlatModelOffset[ZZ];
    }
    else if ( field == "FlatModelMeterSimRatio" )
    {
        conf >> WORLD_CONF.mFlatModelMeterSimRatio;
    }
    else if ( field == "FlatModelNW" )
    {
        fp f;
        conf >> f; WORLD_CONF.mFlatModelNW.mLat = Degree(f);  // SphereVertex
        conf >> f; WORLD_CONF.mFlatModelNW.mLon = Degree(f);
        conf >> f; WORLD_CONF.mFlatModelNW.mAlt = Meter(f);
    }
    else if ( field == "FlatModelSE" )
    {
        fp f;
        conf >> f; WORLD_CONF.mFlatModelSE.mLat = Degree(f);  // SphereVertex
        conf >> f; WORLD_CONF.mFlatModelSE.mLon = Degree(f);
        conf >> f; WORLD_CONF.mFlatModelSE.mAlt = Meter(f);
    }
    else if ( field == "FlatModelMeterOffset" )
    {
        fp f;
        conf >> f; WORLD_CONF.mFlatModelMeterOffset[XX] = Meter(f);
        conf >> f; WORLD_CONF.mFlatModelMeterOffset[YY] = Meter(f);
        conf >> f; WORLD_CONF.mFlatModelMeterOffset[ZZ] = Meter(f);
    }
    else if ( field == "FlatWorldMeterLowAlt" )
    {
        fp f; conf >> f; WORLD_CONF.mFlatModelMeterLowAlt = Meter(f);
    }
    else if ( field == "FlatModelMeterAltMin" )
    {
        fp f; conf >> f; WORLD_CONF.mFlatModelMeterAltMin = Meter(f);
    }
    else if ( field == "FlatModelMeterAltMax" )
    {
        fp f; conf >> f; WORLD_CONF.mFlatModelMeterAltMax = Meter(f);
    }

    // Errors?
    if ( error )
    {
        CERROR << "ERROR[conf]: parameter for " << field << " is invalid." << std::endl;
        EXIT( 1 );
    }
}

/*****************************************************************************
 * Print Conf configuration.
 *****************************************************************************/
std::ostream& operator<<( std::ostream& strm, const Conf& conf )
{
    return strm;
}

} // namespace world
