/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library 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 
 * OpenSceneGraph Public License for more details.
*/

#ifndef OSG_ARGUMENTPARSER
#define OSG_ARGUMENTPARSER 1

#include <osg/Export>

#include <map>
#include <string>
#include <iostream>

namespace osg {

// forward declare
class ApplicationUsage;

class SG_EXPORT ArgumentParser
{
    public:
        ArgumentParser(int* argc,char **argv);

        void setApplicationUsage(ApplicationUsage* usage) { _usage = usage; }
        ApplicationUsage* getApplicationUsage() { return _usage; }
        const ApplicationUsage* getApplicationUsage() const { return _usage; }

        /** return the argument count.*/
        int& argc() { return *_argc; }

        /** return the argument array.*/
        char** argv() { return _argv; }

        /** return char* argument at specificed position.*/
        char* operator [] (int pos) { return _argv[pos]; }

        /** return const char* argument at specificed position.*/
        const char* operator [] (int pos) const { return _argv[pos]; }

        /** return the application name, as specified by argv[0] */
        std::string getApplicationName() const;

        /** return the position of an occurance of a string in the argument list.
          * return -1 when no string is found.*/      
        int find(const std::string& str) const;

        /** return true if specified argument matches string.*/        
        bool match(int pos, const std::string& str) const;

        /** return return true if specified parameter is an option in the form of -option or --option .*/
        bool isOption(int pos) const;
        
        /** return return true if specified parameter is an string, which can be any other string apart from an option.*/
        bool isString(int pos) const;
        
        /** return return true if specified parameter is an number.*/
        bool isNumber(int pos) const;
        
        bool containsOptions() const;

        /** remove one or more arguments from the argv argument list, and decrement the argc respectively.*/
        void remove(int pos,int num=1);
        
        /** search for an occurance of a string in the argument list, on sucess
          * remove that occurance from the list and return true, otherwise return false.*/
        bool read(const std::string& str);

        /** search for an occurance of a string in the argument list followed by a string,
          * on sucess set the value string with the second parameters and then
          * remove the two entries from the list and return true, otherwise return false.*/
        bool read(const std::string& str,std::string& value1);

        /** search for an occurance of a string in the argument list followed by a two strings,
          * on sucess set the value strings with the second & third parameters and then
          * remove the three entries from the list and return true, otherwise return false.*/
        bool read(const std::string& str,std::string& value1,std::string& value2);

        /** search for an occurance of a string in the argument list followed by a three strings,
          * on sucess set the value strings with the second & third & fourth parameters and then
          * remove the four entries from the list and return true, otherwise return false.*/
        bool read(const std::string& str,std::string& value1,std::string& value2,std::string& value3);
        
        
        /** search for an occurance of a string in the argument list followed by a numeric value,
          * on sucess set the values with the second parameter and then
          * remove the two entries from the list and return true, otherwise return false.*/
        bool read(const std::string& str,float& value);

        /** search for an occurance of a string in the argument list followed by two numeric values,
          * on sucess set the values with the second & third parameters and then
          * remove the three entries from the list and return true, otherwise return false.*/
        bool read(const std::string& str,float& value1,float& value2);

        /** search for an occurance of a string in the argument list followed by three numeric values,
          * on sucess set the values with the second & third & fourth parameters and then
          * remove the four entries from the list and return true, otherwise return false.*/
        bool read(const std::string& str,float& value1,float& value2,float& value3);


        enum ErrorSeverity
        {
            BENIGN = 0,
            CRITICAL = 1
        };

        typedef std::map<std::string,ErrorSeverity> ErrorMessageMap;

        /** return the error flag, true if an error has occured when reading arguments.*/
        bool errors(ErrorSeverity severity=BENIGN) const;

        /** report an error message by adding to the ErrorMessageMap.*/
        void reportError(const std::string& message,ErrorSeverity severity=CRITICAL);

        /** for each remaining option report it as an unrecongnized.*/
        void reportRemainingOptionsAsUnrecognized(ErrorSeverity severity=BENIGN);
        
        /** return the error message, if any has occured.*/
        ErrorMessageMap& getErrorMessageMap() { return _errorMessageMap; }
      
        /** return the error message, if any has occured.*/
        const ErrorMessageMap& getErrorMessageMap() const { return _errorMessageMap; }

        /** write out error messages at an above specified .*/
        void writeErrorMessages(std::ostream& output,ErrorSeverity sevrity=BENIGN);

  
  protected:
        
        int*                _argc;
        char**              _argv;
        ErrorMessageMap     _errorMessageMap;
        ApplicationUsage*   _usage;
        
};

}

#endif
