/*
 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
 * storing and accessing finite element mesh data.
 * 
 * Copyright 2004 Sandia Corporation.  Under the terms of Contract
 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
 * retains certain rights in this software.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 */

/**\file FileOptions.hpp
 *\author Jason Kraftcheck (kraftche@cae.wisc.edu)
 *\date 2007-08-21
 */

#ifndef FILE_OPTIONS_HPP
#define FILE_OPTIONS_HPP

#include "moab_export.h"

#include <string>
#include <vector>
#include "moab/Types.hpp"

namespace moab {

/**\brief Parse options string passed to file IO routines
 *
 * This is a utility class used by file-IO-related code to 
 * parse the options string passed to Core::load_file and
 * Core::write_file
 */
class MOAB_EXPORT FileOptions {
public:

  /*\param options_string The concatenation of a list of 
   *          options, separated either by the default separator
   *          (semicolon) with a custom separator specified at
   *          the beginning of the string (semicolon followed by
   *          destired separator character.)
   */
  FileOptions( const char* option_string);
  
  FileOptions( const FileOptions& copy );
  FileOptions& operator=( const FileOptions& copy );
  
  ~FileOptions();
  
  /**\brief Check for option with no value 
   *
   * Check for an option w/out a value.
   *\param name The option name
   *\return - MB_SUCCESS if option is found
   *        - MB_TYPE_OUT_OF_RANGE if options is found, but has value
   *        - MB_ENTITY_NOT_FOUND if option is not found.
   */
  ErrorCode get_null_option( const char* name ) const;
  
  
  /**\brief Check for option with boolean (true/false, yes/no) value.
   *
   * Check for an option with a true/false value.  Allowable values
   * are "true", "false", "yes", "no", "1", "0", "on", "off".
   *\param name The option name
   *\param default_value The value to return if the option is not specified.
   *\param value The resulting value.  This argument is set to the passed
   *            default value if the option is not found.
   *\return - MB_TYPE_OUT_OF_RANGE if options is found, but has an invalid value
   *        - MB_SUCCESS otherwise
   */
  ErrorCode get_toggle_option( const char* name, 
                               bool default_value,
                               bool& value ) const;
   
  /**\brief Check for option with an integer value.
   *
   * Check for an option with an integer value
   *\param name The option name
   *\param value Output. The value.
   *\return - MB_SUCCESS if option is found
   *        - MB_TYPE_OUT_OF_RANGE if options is found, but does not have an integer value
   *        - MB_ENTITY_NOT_FOUND if option is not found.
   */
  ErrorCode get_int_option( const char* name, int& value ) const;
  
  /**\brief Check for option with an integer value.  Accept option with no value.
   *
   * Check for an option with an integer value.
   * If the option is found but has no value specified, then
   * pass back the user-specified default value.
   *
   *\NOTE:  This function will not pass back the default_val, but will instead
   *        return MB_ENTITY_NOT_FOUND if the option is not specified at all.
   *        The default value is returned only when the option is specified,
   *        but is specified w/out a value.
   *
   *\param name The option name
   *\param default_val The default value for the option.
   *\param value Output. The value.
   *\return - MB_SUCCESS if option is found
   *        - MB_TYPE_OUT_OF_RANGE if options is found but has a value that cannot be parsed as an int
   *        - MB_ENTITY_NOT_FOUND if option is not found.
   */
  ErrorCode get_int_option( const char* name, int default_val, int& value ) const;
  
  /**\brief Check for option with a double value.
   *
   * Check for an option with a double value
   *\param name The option name
   *\param value Output. The value.
   *\return - MB_SUCCESS if option is found
   *        - MB_TYPE_OUT_OF_RANGE if options is found, but does not have a double value
   *        - MB_ENTITY_NOT_FOUND if option is not found.
   */
  ErrorCode get_real_option( const char* name, double& value ) const;
  
  /**\brief Check for option with any value.
   *
   * Check for an option with any value.
   *\param name The option name
   *\param value Output. The value.
   *\return - MB_SUCCESS if option is found
   *        - MB_TYPE_OUT_OF_RANGE if options is found, but does not have a value
   *        - MB_ENTITY_NOT_FOUND if option is not found.
   */
  ErrorCode get_str_option( const char* name, std::string& value ) const;
  
  /**\brief Check for option 
   *
   * Check for an option
   *\param name The option name
   *\param value The option value, or an empty string if no value.
   *\return MB_SUCCESS or MB_ENTITY_NOT_FOUND
   */
  ErrorCode get_option( const char* name, std::string& value ) const;
  
  /**\brief Check the string value of an option
   *
   * Check which of a list of possible values a string option contains.
   *\param name The option name
   *\param values A NULL-terminated array of C-style strings enumerating
   *              the possible option values.
   *\param index  Output: The index into <code>values</code> for the
   *              option value.
   *\return MB_SUCCESS if matched name and value.
   *        MB_ENTITY_NOT_FOUND if the option was not specified
   *        MB_FAILURE if the option value is not in the input <code>values</code> array.
   */
  ErrorCode match_option( const char* name, const char* const* values, int& index ) const;
  
  /**\brief Check if an option matches a string value
   *
   * Check if the value for an option is the passed string.
   *\param name The option name
   *\param value The expected value.
   *\return MB_SUCCESS if matched name and value.
   *        MB_ENTITY_NOT_FOUND if the option was not specified
   *        MB_FAILURE if the option value doesn't match the passed string/
   */
  ErrorCode match_option( const char* name, const char* value) const;
  
  /**\brief Check for option for which the value is a list of ints
   *
   * Check for an option which is an int list.  The value is expected to
   * be a comma-separated list of int ranges, where an int range can be 
   * either a single integer value or a range of integer values separated
   * by a dash ('-').
   *
   *\param name The option name
   *\param values Output. The list of integer values.
   *\return - MB_SUCCESS if option is found
   *        - MB_TYPE_OUT_OF_RANGE if options is found, but does not contain an ID list
   *        - MB_ENTITY_NOT_FOUND if option is not found.
   */
  ErrorCode get_ints_option( const char* name, std::vector<int>& values) const;
  
  /**\brief Check for option for which the value is a list of doubles
   *
   * Check for an option which is a double list.  The value is expected to
   * be a comma-separated list of double values
   *
   *\param name The option name
   *\param values Output. The list of double values.
   *\return - MB_SUCCESS if option is found
   *        - MB_TYPE_OUT_OF_RANGE if options is found, but does not contain an ID list
   *        - MB_ENTITY_NOT_FOUND if option is not found.
   */
  ErrorCode get_reals_option( const char* name, std::vector<double>& values) const;
  
  /**\brief Check for option for which the value is a list of strings
   *
   * Check for an option which is a string list.  The value is expected to
   * be a comma-separated list of string values, with no embedded spaces or commas.
   *
   *\param name The option name
   *\param values Output. The list of string values.
   *\return - MB_SUCCESS if option is found
   *        - MB_TYPE_OUT_OF_RANGE if options is found, but does not contain a string list
   *        - MB_ENTITY_NOT_FOUND if option is not found.
   */
  ErrorCode get_strs_option( const char* name, std::vector<std::string>& values) const;
  
  /** number of options */
  inline unsigned size() const 
    { return mOptions.size(); }
  
  /** true if no options */
  inline bool empty() const 
    { return mOptions.empty(); }
  
  /** Get list of options */
  void get_options( std::vector<std::string>& list ) const;
  
  /** Check if all options have been looked at */
  bool all_seen() const;
  
  /** Mark all options as seen.  USed for non-root procs during bcast-delete read */
  void mark_all_seen() const;
  
  /** Get first unseen option */
  ErrorCode get_unseen_option( std::string& value ) const;
  
private:
  
  /**\brief Check for option 
   *
   * Check for an option
   *\param name The option name
   *\param value The option value, or an empty string if no value.
   *\return MB_SUCCESS or MB_ENTITY_NOT_FOUND
   */
  ErrorCode get_option( const char* name, const char*& value) const;

  char* mData;
  std::vector<const char*> mOptions;
  mutable std::vector<bool> mSeen;

    /** Case-insensitive compare of name with option value. */
  static bool compare( const char* name, const char* option );
};
  
} // namespace moab

#endif

