//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project / PF
//
//File: fileparser.cpp
//
//Version: $Revision: 1.4 $
//
//State: $State: Exp $
//
//Date: $Date: 1999/03/02 14:48:49 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
//
//Author:
//      Timo Pärnänen
//
//Description:
//      See corresponding header file.
//
//Copyright:
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999.
//
//Licence:
//
//
//History: 

#include "fileparser.h"
#include "pf/error.h"
#include "pf/tools.h"
#include <string.h>
#include <sys/stat.h>

pfFileParser :: pfFileParser(const string &fileName_)
    : _fileName(fileName_),
      _fileStream(),
      _commentCharacter('\0'),
      _lineMap(),
      _currentValue(),
      _endLine(),
      _initDone(false)
{
    initMap();
    return;
}

pfFileParser :: ~pfFileParser(void)
{
    for (mapIteratorType i = _lineMap.begin(); i != _lineMap.end(); i++)
    {
        lineType *line = (*i).second;
        // Delete call list destructor which erases automatically
        // string objects
        delete line;
    }
    return;
}

//
//Function: parseFile
//
//Description:
//    Find variable and value tokens from file. Tokens are
//    store to map/list containers. Each line list is mapped
//    with variable as a key.
//

void pfFileParser :: parseFile(void)
{
    _fileStream.open(_fileName.c_str());
    if (_fileStream.fail() != 0)
    {
        debugString("pfFileParser: Could not open file", _fileName);
        THROW_RESOURCE_UNAVAILABILITY_UNSPECIFIED;
    }

    // Line length in a config file MAY NOT be greater
    // than MAX_LINE_LENGTH. Otherwise parser doesn't
    // work properly.
    //
    int MAX_LINE_LENGTH = 160;
    char line[MAX_LINE_LENGTH];
    const char *separator = " \t";

    while (_fileStream.getline(line, MAX_LINE_LENGTH))
    {
        if (strlen(line) != 0)
        {
            const char *token = strtok(line, separator);

            if (*token != _commentCharacter)
            {
                if (token != 0)
                {
                    string key(token);
                    lineType *newLine = new lineType;
                    token = strtok(0, separator);

                    while (token != 0)
                    {
                        (*newLine).push_back(token);
                        token = strtok(0, separator);
                    }
                    
                    pair<mapIteratorType, bool> p;
                    p = _lineMap.insert(mapType::value_type(key, newLine));
                }
            }
        }
    }
    _fileStream.close();
    return;
}

//
//Function: setCommentCharacter
//
//Description:
//    Set character which starts comment line.
//

void pfFileParser :: setCommentCharacter(char commentCharacter_)
{
    _commentCharacter = commentCharacter_;
    return;
}

//
//Function: initMap
//
//Description:
//    Initialize map iterators. This must be called before 
//    to start iterate variables.
//

void pfFileParser :: initMap(void)
{
    _current = _lineMap.begin();
    _end = _lineMap.end();
    return;
}

//
//Function: getNextVariable
//
//Description:
//    Get next variable from map and store it to given parameter.
//    Boolean value false is returned when no more variables are
//    founded from map.
//

bool pfFileParser :: getNextVariable(string &variable_)
{
    bool result = false;
    if (_current != _end)
    {
        variable_ = (*_current).first;
        _current++;
        result = true;
    }
    return result;
}

//
//Function: initLine
//
//Description:
//    Initialize line iterators mapped with variable. This must 
//    be called before to start iterate values in current line.
//    Boolean return value indicates, that is variable founded.
//

bool pfFileParser :: initLine(string variable_)
{
    bool result = false;
    mapIteratorType i = _lineMap.find(variable_);
    if (i != _lineMap.end())
    {
        lineType *line = (*i).second;
        
        _currentValue = (*line).begin();
        _endLine = (*line).end();
        _initDone = true;
        result = true;
    }
    return result;
}

//
//Function: getNextValue
//
//Description:
//    Get next value from line list and store it to given parameter.
//    Boolean value false is returned when no more variables are
//    founded from list. InitLine method is used to choose line.
//

bool pfFileParser :: getNextValue(string &value_)
{
    bool result = false;
    if (_currentValue != _endLine && _initDone == true)
    {
        value_ = (*_currentValue);
        _currentValue++;
        result = true;
    }
    return result;
}

//
//Function: getIntegerValue
//
//Description:
//    This method can be used to get one integer value.
//    InitLine and getNextValue must be used for list of values.
//    Boolean return value indicates, is variabled founded.
//

bool pfFileParser :: getIntegerValue(string variable_, pfUlong &value_)
{
    bool result = false;
    if (initLine(variable_) == true)
    {
        string value;
        result = getNextValue(value);
        value_ = atoi(value.c_str());
    }
    return result;
}

//
//Function: getStringValue
//
//Description:
//    This method can be used to get one string value.
//    InitLine and getNextValue must be used for list of values.
//    Boolean return value indicates, is variabled founded.
//

bool pfFileParser :: getStringValue(string variable_, string &value_)
{
    bool result = false;
    if (initLine(variable_) == true)
    {
        result = getNextValue(value_);
    }
    return result;
}
