text: // Copyright (C) 2004, 2006 International Business Machines and others.
  // All Rights Reserved.
  // This code is published under the Common Public License.
  //
  // $Id: IpOptionsList.hpp 759 2006-07-07 03:07:08Z andreasw $
  //
  // Authors:  Carl Laird, Andreas Waechter     IBM    2004-08-13
  
  #ifndef __IPOPTLIST_HPP__
  #define __IPOPTLIST_HPP__
  
  #include "IpUtils.hpp"
  #include "IpReferenced.hpp"
  #include "IpException.hpp"
  #include "IpRegOptions.hpp"
  
  #include <iostream>
  #include <map>
  
  namespace SimTKIpopt
  {
    /** Exception that can be used to indicate errors with options */
    DECLARE_STD_EXCEPTION(OPTION_INVALID);
  
    /** This class stores a list of user set options.  Each options is
     *  identified by a case-insensitive keyword (tag).  Its value is
     *  stored internally as a string (always lower case), but for
     *  convenience set and get methods are provided to obtain Index and
     *  Number type values.  For each keyword we also keep track of how
     *  often the value of an option has been requested by a get method.
     */
    class OptionsList : public ReferencedObject
    {
      /** Class for storing the value and counter for each option in
       *  OptionsList. */
      class OptionValue
      {
      public:
        /**@name Constructors/Destructors */
        //@{
        /** Default constructor (needed for the map) */
        OptionValue()
            :
            initialized_(false)
        {}
  
        /** Constructor given the value */
        OptionValue(std::string value, bool allow_clobber, bool dont_print)
            :
            value_(value),
            counter_(0),
            initialized_(true),
            allow_clobber_(allow_clobber),
            dont_print_(dont_print)
        {}
  
        /** Copy Constructor */
        OptionValue(const OptionValue& copy)
            :
            value_(copy.value_),
            counter_(copy.counter_),
            initialized_(copy.initialized_),
            allow_clobber_(copy.allow_clobber_),
            dont_print_(copy.dont_print_)
        {}
  
        /** Equals operator */
        void operator=(const OptionValue& copy)
        {
          value_=copy.value_;
          counter_=copy.counter_;
          initialized_=copy.initialized_;
          allow_clobber_=copy.allow_clobber_;
          dont_print_=copy.dont_print_;
        }
  
        /** Default Destructor */
        ~OptionValue()
        {}
        //@}
  
        /** Method for retrieving the value of an option.  Calling this
         *  method will increase the counter by one. */
        std::string GetValue() const
        {
          DBG_ASSERT(initialized_);
          counter_++;
          return value_;
        }
  
        /** Method for retrieving the value without increasing the
         *  counter */
        std::string Value() const
        {
          DBG_ASSERT(initialized_);
          return value_;
        }
  
        /** Method for accessing current value of the request counter */
        Index Counter() const
        {
          DBG_ASSERT(initialized_);
          return counter_;
        }
  
        /** True if the option can be overwritten */
        bool AllowClobber() const
        {
          DBG_ASSERT(initialized_);
          return allow_clobber_;
        }
  
        /** True if this option is not to show up in the
         *  print_user_options output */
        bool DontPrint() const
        {
          DBG_ASSERT(initialized_);
          return dont_print_;
        }
  
      private:
        /** Value for this option */
        std::string value_;
  
        /** Counter for requests */
        mutable Index counter_;
  
        /** for debugging */
        bool initialized_;
  
        /** True if the option can be overwritten */
        bool allow_clobber_;
  
        /** True if this option is not to show up in the
         *  print_user_options output */
        bool dont_print_;
      };
  
    public:
      /**@name Constructors/Destructors */
      //@{
      OptionsList(SmartPtr<RegisteredOptions> reg_options, SmartPtr<Journalist> jnlst)
          : reg_options_(reg_options), jnlst_(jnlst)
      {}
  
      OptionsList()
      {}
  
      /** Copy Constructor */
      OptionsList(const OptionsList& copy)
      {
        // copy all the option strings and values
        options_ = copy.options_;
        // copy the registered options pointer
        reg_options_ = copy.reg_options_;
      }
  
      /** Default destructor */
      virtual ~OptionsList()
      {}
  
      /** Overloaded Equals Operator */
      void operator=(const OptionsList& source)
      {
        options_ = source.options_;
      }
      //@}
  
      /** @name Get / Set Methods */
      //@{
      void SetRegisteredOptions(const SmartPtr<RegisteredOptions> reg_options)
      {
        reg_options_ = reg_options;
      }
      void SetJournalist(const SmartPtr<Journalist> jnlst)
      {
        jnlst_ = jnlst;
      }
      //@}
      /** @name Methods for setting options */
      //@{
      bool SetStringValue(const std::string& tag, const std::string& value,
                          bool allow_clobber = true, bool dont_print = false);
      bool SetNumericValue(const std::string& tag, Number value,
                           bool allow_clobber = true, bool dont_print = false);
      bool SetIntegerValue(const std::string& tag, Index value,
                           bool allow_clobber = true, bool dont_print = false);
      //@}
  
      /** @name Methods for retrieving values from the options list.  If
       *  a tag is not found, the methods return false, and value is set
       *  to the default value defined in the registered options. */
      //@{
      bool GetStringValue(const std::string& tag, std::string& value,
                          const std::string& prefix) const;
      bool GetEnumValue(const std::string& tag, Index& value,
                        const std::string& prefix) const;
      bool GetBoolValue(const std::string& tag, bool& value,
                        const std::string& prefix) const;
      bool GetNumericValue(const std::string& tag, Number& value,
                           const std::string& prefix) const;
      bool GetIntegerValue(const std::string& tag, Index& value,
                           const std::string& prefix) const;
      //@}
  
      /** Get a string with the list of all options (tag, value, counter) */
      void PrintList(std::string& list) const;
  
      /** Get a string with the list of all options set by the user
       *  (tag, value, use/notused).  Here, options with dont_print flag
       *  set to true are not printed. */
      void PrintUserOptions(std::string& list) const;
  
      /** Read options from the stream is.  Returns false if
       *  an error was encountered. */
      bool ReadFromStream(const Journalist& jnlst, std::istream& is);
  
    private:
      /**@name Default Compiler Generated Methods
       * (Hidden to avoid implicit creation/calling).
       * These methods are not implemented and 
       * we do not want the compiler to implement
       * them for us, so we declare them private
       * and do not define them. This ensures that
       * they will not be implicitly created/called. */
      //@{
      /** Default Constructor */
      //    OptionsList();
  
      //@}
  
      /** map for storing the options */
      std::map< std::string, OptionValue > options_;
  
      /** list of all the registered options to validate against */
      SmartPtr<RegisteredOptions> reg_options_;
  
      /** Journalist for writing error messages, etc. */
      SmartPtr<Journalist> jnlst_;
  
      /** auxilliary method for converting sting to all lower-case
       *  letters */
      const std::string& lowercase(const std::string tag) const;
  
      /** auxilliary method for finding the value for a tag in the
       *  options list.  This method first looks for the concatenated
       *  string prefix+tag (if prefix is not ""), and if this is not
       *  found, it looks for tag.  The return value is true iff
       *  prefix+tag or tag is found.  In that case, the corresponding
       *  string value is copied into value. */
      bool find_tag(const std::string& tag, const std::string& prefix,
                    std::string& value) const;
  
      /** tells whether or not we can clobber a particular option.
       *  returns true if the option does not already exist, or if
       *  the option exists but is set to allow_clobber
       */
      bool will_allow_clobber(const std::string& tag) const;
  
      /** read the next token from stream is.  Returns false, if EOF was
       *  reached before a tokens was ecountered. */
      bool readnexttoken(std::istream& is, std::string& token);
  
      /** auxilliary string set by lowercase method */
      mutable std::string lowercase_buffer_;
    };
  
  } // namespace Ipopt
  
  #endif
  