/******************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Template Method to read human-editable text conf file via C++ stream.
 * @remarks ConfBin is a binary configuration file (actually it is barely readable).
 *          ConfTxt is text and human-editable.
 *//*
 * 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 BASE_CONF_TXT_CC 1
#include <fstream>
#include "base/module.hh"
#include "base/stream.hh"
#include "base/stream_funcs.hh"
#include "base/conf_txt.hh"

namespace base {

/*****************************************************************************
 * @return Filename of text conf file (for ConfTxt).
 *****************************************************************************/
string
GetConfTxtFilename( const string& programName )
{
    // The ConfTxt ctor will figure out the full pathname.
    return programName + string(".conf");
}

////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////  ConfTxt  ////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * ctor/dtor.
 * Actual code is at Read() instead of ctor because the virtual method
 * ProcessField() has to be called.
 *****************************************************************************/
ConfTxt::ConfTxt( void )
{
    // NOP
}

ConfTxt::~ConfTxt()
{
    // NOP
}

/*****************************************************************************
 * Read configuration and either parse or defer fields.
 *
 * --- MIGHT THROW AN EXCEPTION ---
 *
 * Read() allows the derivative of ProcessField(string& field, ifstream& conf)
 * to modify both passed args.
 *****************************************************************************/
void
ConfTxt::Read( const string& pathname )
{
    // Pathname uninitialized?
    if ( pathname.empty() )
        throw Exception();

    // Open file stream for input.
    std::ifstream config;
    config.open( pathname.c_str(), std::ios::in | std::ios::binary );
    if ( not config.good() or not config.is_open() )
    {
        throw Exception();
    }

    // Configure stream.

    // ***************
    // ** IMPORTANT **
    // ***************
    // C++ streams default to converting decimal numbers ONLY.
    // Change to allow converting hex numbers also.
    // Unfortunately this also enables octal numbers.
    config >> std::setbase(0);

    // Parse each line.
    while ( config.good() )
    {
        // At beginning of line.
        string field;
        config >> field;
        if ( UX( not config.good() or field.empty() ) )
        {
            break;
        }
        // Comment?
        else if ( UX( field[0] == '#' ) )
        {
            StreamToNextLine( config );
        }
        else
        {
            // Template Method.
            // Read() allows the derivative to modify both (non-const) args.
            ProcessField( field, config );
        }
    }

    config.close();
}

} // namespace base
