/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   control 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 CONTROL_CONF_CC 1
#include <fstream>
#include "base/module.hh"
#include "base/misc.hh"
#include "base/conf.hh"
#include "base/conf_template_macros.hh"
#include "base/conf_txt.hh"
#include "base/stream.hh"
using namespace base;
#include "control/module.hh"
#include "control/conf.hh"
#include "control/joystick.hh"
#include "control/defs.hh"

namespace control {

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

namespace global { Conf gConf; }

/*****************************************************************************
 * ctor/dtor.
 *****************************************************************************/
Conf::Conf( void )
:   mValid(false),
    // cmd-line args
    mJoystickEnabled(false),
    mJoystickAxis3(false),
    mJoystickPrint(false),
    mJoystickConfFilename("joystick.conf")
{
}

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

    ReadJoystickConfTxt();  // specific to control module
}

// Read joystick configuration.
void
Conf::ReadJoystickConfTxt( void )
{
    try
    {
        ModuleConfTxt confTxt;
        // Handle if -jc cmd-line arg was passed (don't use data dir).
        // Allows the user to set configuration for a specific joystick.
        if ( mJoystickConfFilename == "joystick.conf" )
        {
            confTxt.Read( string(GetDataDir()) + string("joystick.conf") );
        }
        else
        {
            CLOG << "Using joystick conf " << mJoystickConfFilename << std::endl;
            confTxt.Read( mJoystickConfFilename );  // -jc was passed on cmdline
        }
    }
    catch (...)
    {
        CERROR << "ERROR: cannot read joystick.conf" << std::endl;
        EXIT( 1 );
    }
}

/*****************************************************************************
 * Parse cmdline args.
 *****************************************************************************/
void
Conf::ParseCmdlineArgs( int argc, char** argv )
{
// Too early to enable joystick.
#define JOYSTICK_ARG() {{ mJoystickEnabled = true; }}

    // Parse args.
    for ( int i = 1; i < argc; ++i )
    {
        // -- Other joystick args are parsed at control module. --

        // Any -j arg will enable joystick.
        if ( (argv[i][0] == '-')
         and (argv[i][1] == 'j') )
        {
            JOYSTICK_ARG();
            CmdargDone( i );
        }

        //......................................................................

        // Print joystick values (to help user to calibrate)?
        if ( STREQ( argv[i], "-jp" ) )
        {
            // -jp imples enabling joystick but higher-level code now
            // also parses -jp and shows joystick values in GUI (used to be cout).
            JOYSTICK_ARG();
            mJoystickPrint = true;
            CmdargDone( i );
        }
        else if ( STREQ( argv[i], "-jc" ) )
        {
            JOYSTICK_ARG();
            mJoystickConfFilename = Argstr( i+1, argc, argv );
            CmdargDone( i, 2 );
            i += 1;
        }
    }
}

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;

    control::Joystick& joystick = GET_CONTROL_JOYSTICK();

    // -----------------------  joystick.conf  -----------------------------------------
    if ( field == "PitchAxis" )
    {
        int i; conf >> i;
        joystick.MapAxis( control::Joystick::AxisMap::PITCH, i );
    }
    else if ( field == "RollAxis" )
    {
        int i; conf >> i;
        joystick.MapAxis( control::Joystick::AxisMap::ROLL, i );
    }
    else if ( field == "YawAxis" )
    {
        int i; conf >> i;
        joystick.MapAxis( control::Joystick::AxisMap::YAW, i );
    }
    else if ( field == "ThrottleAxis" )
    {
        int i; conf >> i;
        joystick.MapAxis( control::Joystick::AxisMap::THROTTLE, i );
    }
    else if ( field == "PitchRange" )
    {
        // Example:
        // PitchRange -0x7fff -1000 1000 0x7fff
        control::Joystick::Calibration calibration = joystick.GetCalibration();
        conf >> calibration.mPitchUp.mMax;  // max,min,min,max
        conf >> calibration.mPitchUp.mMin;
        conf >> calibration.mPitchDown.mMin;
        conf >> calibration.mPitchDown.mMax;
        joystick.SetCalibration( calibration );
    }
    else if ( field == "RollRange" )
    {
        control::Joystick::Calibration calibration = joystick.GetCalibration();
        conf >> calibration.mRollLeft.mMax;
        conf >> calibration.mRollLeft.mMin;
        conf >> calibration.mRollRight.mMin;
        conf >> calibration.mRollRight.mMax;
        joystick.SetCalibration( calibration );
    }
    else if ( field == "YawRange" )
    {
        control::Joystick::Calibration calibration = joystick.GetCalibration();
        conf >> calibration.mYawLeft.mMax;
        conf >> calibration.mYawLeft.mMin;
        conf >> calibration.mYawRight.mMin;
        conf >> calibration.mYawRight.mMax;
        joystick.SetCalibration( calibration );
    }
    else if ( field == "ThrottleRange" )
    {
        // Throttle is different as it has one range:
        // ThrottleRange  -0x7fff +0x7ffff
        control::Joystick::Calibration calibration = joystick.GetCalibration();
        conf >> calibration.mThrottle.mMin;
        conf >> calibration.mThrottle.mMax;
        joystick.SetCalibration( calibration );
    }
    else if ( field == "MapButton" )
    {
        uint buttonLogical;
        uint buttonReal;
        conf >> buttonLogical;
        conf >> buttonReal;
        joystick.MapButton( buttonLogical, buttonReal );
    }

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

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

} // namespace control
