// configuration.inline.hpp
//
// (C) 2006-2009 MicroNeil Research Corporation.
//
// This program is part of the MicroNeil Research Open Library Project. For
// more information go to http://www.microneil.com/OpenLibrary/index.html
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA

// See configuration.hpp for details

//// Configuration Element /////////////////////////////////////////////////////

inline ConfigurationElement::ConfigurationElement(const char* Name) :           // Construct with a cstring.
  myName(string(Name)),
  myParent(NULL),
  myLine(0),
  myIndex(0),
  myLength(0),
  myCleanFlag(true),
  myInitOnInterpretFlag(false) {
}

inline ConfigurationElement::ConfigurationElement(const string Name) :          // Construct with a c++ string.
  myName(Name),
  myParent(NULL),
  myLine(0),
  myIndex(0),
  myLength(0),
  myCleanFlag(true),
  myInitOnInterpretFlag(false) {
}

inline ConfigurationElement::ConfigurationElement(                              // Construct sub element w/ cstring.
  const char* Name,
  ConfigurationElement& Parent) :

  myName(string(Name)),
  myParent(&Parent),
  myLine(0),
  myIndex(0),
  myLength(0),
  myCleanFlag(true),
  myInitOnInterpretFlag(false) {
}

inline ConfigurationElement::ConfigurationElement(                              // Construct sub element w/ string.
  const string Name,
  ConfigurationElement& Parent) :

  myName(Name),
  myParent(&Parent),
  myLine(0),
  myIndex(0),
  myLength(0),
  myCleanFlag(true),
  myInitOnInterpretFlag(false) {
}

inline string ConfigurationElement::Name() { return myName; }                   // Get the name of this element.

inline ConfigurationElement& ConfigurationElement::Parent() {                   // Get the parrent of this element.
    if(NULL != myParent) {                                                      // If I have a parent
        return (*myParent);                                                     // then I dereference and return it.
    }                                                                           // If I don't have a parent
    return (*this);                                                             // then I return myself.
}

inline ConfigurationElement& ConfigurationElement::Parent(                      // Set the parrent of this element.
  ConfigurationElement& Parent) {                                               // Given this parent
    myParent = &Parent;                                                         // I take and store it's address
    return (*myParent);                                                         // then dereference and return it.
}

inline int ConfigurationElement::Line() { return myLine; }                      // Get the last line number.

inline int ConfigurationElement::Index() { return myIndex; }                    // Get the last data position.

inline int ConfigurationElement::Length() { return myLength; }                  // Get the last length.

inline void ConfigurationElement::notifyDirty() { myCleanFlag = false; }        // Attributes do this when they change.

inline ConfigurationElement& ConfigurationElement::Element(const char* Name) {  // Add a new sub element by c string name.
    return Element(string(Name));                                               // Use the string name version
}

inline ConfigurationElement& ConfigurationElement::Element(const string Name) { // Add a new sub element by c++ string name.
    ConfigurationElement* N = new ConfigurationElement(                         // Create a new Element with the
      Name,                                                                     // name provided and
      (*this));                                                                 // myself as the parent.

    myElements.push_back(N);                                                    // Add it to the list.
    return (*N);                                                                // Return the new element.
}

inline ConfigurationElement& ConfigurationElement::Element(                     // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  ConfigurationTranslator& newTranslator) {                                     // Add a Translator to this element.
    return Element(string(Name), newTranslator);                                // Use the string name version
}

inline ConfigurationElement& ConfigurationElement::Element(                     // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  string& x, string init) {                                                     // Map to a string.
    return Element(string(Name), x, init);                                      // Use the string name version
}

inline ConfigurationElement& ConfigurationElement::Element(                     // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  int& x, int init, int radix) {                                                // Map to an int.
    return Element(string(Name), x, init, radix);                               // Use the string name version
}

inline ConfigurationElement& ConfigurationElement::Element(                     // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  double& x, double init) {                                                     // Map to a double.
    return Element(string(Name), x, init);                                      // Use the string name version
}

inline ConfigurationElement& ConfigurationElement::Element(                     // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  bool& x, bool init) {                                                         // Map to a boolean.
    return Element(string(Name), x, init);                                      // Use the string name version
}

inline ConfigurationElement& ConfigurationElement::End() {                      // Return this element's parent.
    return Parent();                                                            // Borrow Parent()
}

inline ConfigurationElement& ConfigurationElement::End(const char* Name) {      // Check the name and return the parent
    return End(string(Name));                                                   // Borrow End(string)
}

inline ConfigurationElement& ConfigurationElement::End(const string Name) {     // if the name is correct - or throw!
    if(0 != Name.compare(myName)) {                                             // If Name is not myName
        throw EndNameDoesNotMatch();                                            // throw an exception!
    }                                                                           // If the names match then
    return Parent();                                                            // return the parent.
}

inline ConfigurationAttribute& ConfigurationElement::Attribute(                 // Add an attribute using a cstring.
  const char* Name) {                                                           // Given this cstring name
    return Attribute(string(Name));                                             // Convert it to a string and borrow
}                                                                               // Attribute(string)

inline ConfigurationAttribute& ConfigurationElement::Attribute(                 // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  ConfigurationTranslator& newTranslator) {                                     // Add a Translator to this element.
    return Attribute(string(Name), newTranslator);                              // Borrow the string name version
}

inline ConfigurationAttribute& ConfigurationElement::Attribute(                 // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  string& x, string init) {                                                     // Map to a string.
    return Attribute(string(Name), x, init);                                    // Borrow the string name version
}

inline ConfigurationAttribute& ConfigurationElement::Attribute(                 // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  int& x, int init, int radix) {                                                // Map to an int.
    return Attribute(string(Name), x, init);                                    // Borrow the string name version
}

inline ConfigurationAttribute& ConfigurationElement::Attribute(                 // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  double& x, double init) {                                                     // Map to a double.
    return Attribute(string(Name), x, init);                                    // Borrow the string name version
}

inline ConfigurationAttribute& ConfigurationElement::Attribute(                 // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  bool& x, bool init) {                                                         // Map to a boolean.
    return Attribute(string(Name), x, init);                                    // Borrow the string name version
}

inline ConfigurationElement& ConfigurationElement::setInitOnInterpret() {       // Set the init on interpret flag.
    myInitOnInterpretFlag = true;                                               // Set the flag.
    return(*this);                                                              // Dereference and return self.
}

inline ConfigurationElement& ConfigurationElement::atStartCall(                 // Add an atStart call-back.
  Configurator& Functor) {                                                      // Given this Functor,
    myStartConfigurators.push_back(&Functor);                                   // add it to my atStart list then
    return(*this);                                                              // dereference and return myself.
}

inline ConfigurationElement& ConfigurationElement::atEndCall(                   // Add an atEnd call-back.
  Configurator& Functor) {                                                      // Given this Functor,
    myEndConfigurators.push_back(&Functor);                                     // add it to my atEnd list then
    return(*this);                                                              // dereference and return myself.
}

inline ConfigurationElement& ConfigurationElement::Mnemonic(                    // Add a mnemonic using c strings.
  const char* name, const char* value) {                                        // Given char* and char*
    return Mnemonic(string(name), string(value));                               // make strings and borrow that method.
}

inline ConfigurationElement& ConfigurationElement::Mnemonic(                    // Add a mnemonic using mixed strings.
  const char* name, const string value) {                                       // Given char* and string
    return Mnemonic(string(name), value);                                       // make strings and borrow that method.
}

inline ConfigurationElement& ConfigurationElement::Mnemonic(                    // Add a mnemonic using mixed strings.
  const string name, const char* value) {                                       // Given string and char*
    return Mnemonic(name, string(value));                                       // make strings and borrow that method.
}

inline ConfigurationElement& ConfigurationElement::Mnemonic(                    // Add a mnemonic using c++ strings.
  const string name, const string value) {                                      // Givent string and string
    ConfigurationMnemonic* N =                                                  // Create a new Mnemonic
      new ConfigurationMnemonic(name, value);                                   // using the values provided,
    myMnemonics.push_back(N);                                                   // add it to my list, then
    return(*this);                                                              // dereference and return myself.
}

//// Configuration Attribute ///////////////////////////////////////////////////

inline ConfigurationAttribute::ConfigurationAttribute(                          // Attributes are constructed with a
  const char* Name, ConfigurationElement& Parent) :                             // Name and a Parent.
  myName(string(Name)),                                                         // We convert the name to a string.
  myParent(Parent),                                                             // We just grab the parent.
  myLine(0),                                                                    // Everything else gets zeroed.
  myIndex(0),
  myLength(0) {
}

inline ConfigurationAttribute::ConfigurationAttribute(                          // Attributes are constrictued with a
  const string Name, ConfigurationElement& Parent) :                            // Name and a Parent.
  myName(Name),                                                                 // We grab them and zero the rest.
  myParent(Parent),
  myLine(0),
  myIndex(0),
  myLength(0) {
}

inline string ConfigurationAttribute::Name() {                                  // Get the name of this attribute.
    return myName;
}

inline ConfigurationElement& ConfigurationAttribute::Parent() {                 // Get the parent of this attribute.
    return myParent;
}

inline int ConfigurationAttribute::Line() {                                     // Get the last line number.
    return myLine;
}

inline int ConfigurationAttribute::Index() {                                    // Get the last data position.
    return myIndex;
}

inline int ConfigurationAttribute::Length() {                                   // Get the last length.
    return myLength;
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Add a new sub element by c string name.
  const char* Name) {
    return myParent.Element(Name);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Add a new sub element by c++ string name.
  const string Name) {
    return myParent.Element(Name);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  ConfigurationTranslator& newTranslator) {                                     // Add a Translator to this element.
    return myParent.Element(Name, newTranslator);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  string& x, string init) {                                                     // Map to a string.
    return myParent.Element(Name, x, init);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  int& x, int init, int radix) {                                                // Map to an int.
    return myParent.Element(Name, x, init, radix);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  double& x, double init) {                                                     // Map to a double.
    return myParent.Element(Name, x, init);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  bool& x, bool init) {                                                         // Map to a boolean.
    return myParent.Element(Name, x, init);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Mapping factory for convenience,
  const string Name,                                                            // requires a name, of course,
  ConfigurationTranslator& newTranslator) {                                     // Add a Translator to this element.
    return myParent.Element(Name, newTranslator);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Mapping factory for convenience,
  const string Name,                                                            // requires a name, of course,
  string& x, string init) {                                                     // Map to a string.
    return myParent.Element(Name, x, init);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Mapping factory for convenience,
  const string Name,                                                            // requires a name, of course,
  int& x, int init, int radix) {                                                // Map to an int.
    return myParent.Element(Name, x, init, radix);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Mapping factory for convenience,
  const string Name,                                                            // requires a name, of course,
  double& x, double init) {                                                     // Map to a double.
    return myParent.Element(Name, x, init);
}

inline ConfigurationElement& ConfigurationAttribute::Element(                   // Mapping factory for convenience,
  const string Name,                                                            // requires a name, of course,
  bool& x, bool init) {                                                         // Map to a boolean.
    return myParent.Element(Name, x, init);
}

inline ConfigurationElement& ConfigurationAttribute::End() {                    // Return this element's parent.
    return myParent.End();
}

inline ConfigurationElement& ConfigurationAttribute::End(const char* Name) {    // Check the name and return the parent
    return myParent.End(Name);
}

inline ConfigurationElement& ConfigurationAttribute::End(const string Name) {   // if the name is correct - or throw!
    return myParent.End(Name);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Add an attribute using a cstring.
  const char* Name) {
    return myParent.Attribute(Name);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Add an attribute using a c++ string.
  const string Name) {
    return myParent.Attribute(Name);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  ConfigurationTranslator& newTranslator) {                                     // Add a Translator to this element.
    return myParent.Attribute(Name, newTranslator);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  string& x, string init) {                                                     // Map to a string.
    return myParent.Attribute(Name, x, init);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  int& x, int init, int radix) {                                                // Map to an int.
    return myParent.Attribute(Name, x, init, radix);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  double& x, double init) {                                                     // Map to a double.
    return myParent.Attribute(Name, x, init);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Mapping factory for convenience,
  const char* Name,                                                             // requires a name, of course,
  bool& x, bool init) {                                                         // Map to a boolean.
    return myParent.Attribute(Name, x, init);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Mapping factory for convenience,
  const string Name,                                                            // requires a name, of course,
  ConfigurationTranslator& newTranslator) {                                     // Add a Translator to this element.
    return myParent.Attribute(Name, newTranslator);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Mapping factory for convenience,
  const string Name,                                                            // requires a name, of course,
  string& x, string init) {                                                     // Map to a string.
    return myParent.Attribute(Name, x, init);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Mapping factory for convenience,
  const string Name,                                                            // requires a name, of course,
  int& x, int init, int radix) {                                                // Map to an int.
    return myParent.Attribute(Name, x, init, radix);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Mapping factory for convenience,
  const string Name,                                                            // requires a name, of course,
  double& x, double init) {                                                     // Map to a double.
    return myParent.Attribute(Name, x, init);
}

inline ConfigurationAttribute& ConfigurationAttribute::Attribute(               // Mapping factory for convenience,
  const string Name,                                                            // requires a name, of course,
  bool& x, bool init) {                                                         // Map to a boolean.
    return myParent.Attribute(Name, x, init);
}

inline ConfigurationElement& ConfigurationAttribute::setInitOnInterpret() {     // Set the init on interpret flag.
    return myParent.setInitOnInterpret();
}

inline ConfigurationElement& ConfigurationAttribute::atStartCall(               // Add an atStart call-back to this element.
  Configurator& Functor) {
    return myParent.atStartCall(Functor);
}

inline ConfigurationElement& ConfigurationAttribute::atEndCall(                 // Add an atEnd call-back to this element.
  Configurator& Functor) {
    return myParent.atEndCall(Functor);
}

inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic(                // Add a mnemonic using c strings.
  const char* name, const char* value) {                                        // Given char* and char*
    return Mnemonic(string(name), string(value));                               // make strings and borrow that method.
}

inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic(                // Add a mnemonic using mixed strings.
  const char* name, const string value) {                                       // Given char* and string
    return Mnemonic(string(name), value);                                       // make strings and borrow that method.
}

inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic(                // Add a mnemonic using mixed strings.
  const string name, const char* value) {                                       // Given string and char*
    return Mnemonic(name, string(value));                                       // make strings and borrow that method.
}

inline ConfigurationAttribute& ConfigurationAttribute::Mnemonic(                // Add a mnemonic using c++ strings.
  const string name, const string value) {                                      // Givent string and string
    ConfigurationMnemonic* N =                                                  // Create a new Mnemonic
      new ConfigurationMnemonic(name, value);                                   // using the values provided,
    myMnemonics.push_back(N);                                                   // add it to my list, then
    return(*this);                                                              // dereference and return myself.
}

//// Configuration Data ////////////////////////////////////////////////////////

inline char ConfigurationData::Data(int Index) {                                // Returns char from Data[Index]
    if(0 > Index || Index >= myBufferSize) {                                    // Check that index is in range
        return 0;                                                               // and return 0 if it is not.
    }                                                                           // If Index is within range then
    return myDataBuffer[Index];                                                 // return the byte requested.
}

inline int ConfigurationData::Index() {                                         // Reads the current Index.
    return myIndex;
}

inline int ConfigurationData::Index(int i) {                                    // Changes the current Index.
    if(0 > i || i >= myBufferSize) {                                            // If i is out of range then
        return myIndex;                                                         // return the current Index unchanged.
    }                                                                           // If i is within range then
    myIndex = i;                                                                // change the Index to i and
    return myIndex;                                                             // return the changed Index.
}

inline int ConfigurationData::Line() {                                          // Reads the current Line number.
    return myLine;
}

inline int ConfigurationData::addNewLines(int Count) {                          // Increments the Line number.
    myLine += Count;                                                            // Add the number of new lines.
    return myLine;                                                              // Return the current Line number.
}

//// Configuration Translator //////////////////////////////////////////////////

inline StringTranslator::StringTranslator(                                      // Construct this with
  string& Variable,                                                             // the variable to map,
  string Initializer) :                                                         // and the default value.
  myVariable(Variable),
  myInitializer(Initializer) {
}

inline void StringTranslator::translate(const char* Value) {                    // Provide a translation method.
    myVariable = string(Value);                                                 // String to String = simple copy.
}

inline void StringTranslator::initialize() {                                    // Provide an initialization method.
    myVariable = myInitializer;                                                 // Revert to the initializer value.
}

inline IntegerTranslator::IntegerTranslator(                                    // Construct this with
  int& Variable,                                                                // the variable to map,
  int Initializer,                                                              // and the default value.
  int Radix) :                                                                  // For this one we also need a Radix.
  myVariable(Variable),
  myInitializer(Initializer),
  myRadix(Radix) {
}

inline void IntegerTranslator::translate(const char* Value) {                   // Provide a translation method.
    char* dummy;                                                                // Throw away ptr for strtol().
    myVariable = strtol(Value, &dummy, myRadix);                                // Convert the string w/ strtol().
}

inline void IntegerTranslator::initialize() {                                   // Provide an initialization method.
    myVariable = myInitializer;                                                 // Revert to the initializer value.
}

inline DoubleTranslator::DoubleTranslator(                                      // Construct this with
  double& Variable,                                                             // the variable to map,
  double Initializer) :                                                         // and the default value.
  myVariable(Variable),
  myInitializer(Initializer) {
}

inline void DoubleTranslator::translate(const char* Value) {                    // Provide a translation method.
    char* dummy;                                                                // Throw away ptr for strtod().
    myVariable = strtod(Value, &dummy);                                         // Convert the string w/ strtod().
}

inline void DoubleTranslator::initialize() {                                    // Provide an initialization method.
    myVariable = myInitializer;                                                 // Revert to the initializer value.
}

inline BoolTranslator::BoolTranslator(                                          // Construct this with
  bool& Variable,                                                               // the variable to map,
  bool Initializer) :                                                           // and the default value.
  myVariable(Variable),
  myInitializer(Initializer) {
}

inline void BoolTranslator::translate(const char* Value) {                      // Provide a translation method.
    if(
      (0 == strcmp(Value,"on")) ||
      (0 == strcmp(Value,"true")) ||                                            // on, true, yes, and 1 are
      (0 == strcmp(Value, "yes")) ||                                            // interpreted as a boolean true.
      (0 == strcmp(Value, "1"))
      ) {
        myVariable = true;
    } else {                                                                    // Anything else is interpreted as
        myVariable = false;                                                     // boolean false.
    }
}

inline void BoolTranslator::initialize() {                                      // Provide an initialization method.
    myVariable = myInitializer;                                                 // Revert to the initializer value.
}

//// Configuration Mnemonic ////////////////////////////////////////////////////

inline ConfigurationMnemonic::ConfigurationMnemonic(                            // To make one, provide both parts.
  string Name, string Value) :
  myName(Name),
  myValue(Value) {
}

inline bool ConfigurationMnemonic::test(string Name) {                          // Test to see if this Mnemonic matches.
    return (0 == Name.compare(myName));                                         // Return true if Name and myName match.
}

inline string ConfigurationMnemonic::Value() {                                  // If it does then we will need it's value.
    return myValue;
}
