#if !defined(__ARG_WRAPPER__)
#define __ARG_WRAPPER__
#if defined(__DB_OFFLINE__)
#include "enumlit.hpp"
#else
#include <shlu2/BasicUtils/enumlit.hpp>
#endif
#include <corelib/ncbiargs.hpp>
#include <corelib/ncbitype.h>
#include <corelib/ncbienv.hpp>
#include <corelib/ncbifile.hpp>
#include <string>
#include <list>

/**********************************************************************
*   Definitions in core toolkit
enum ncbi::CArgDescriptions::EType
{
	eString = 0, ///< An arbitrary string
	eBoolean,    ///< {'true', 't', 'false', 'f'},  case-insensitive
	eInt8,       ///< Convertible into an integer number (Int8 only)
	eInteger,    ///< Convertible into an integer number (int or Int8)
	eDouble,     ///< Convertible into a floating point number (double)
	eInputFile,  ///< Name of file (must exist and be readable)
	eOutputFile, ///< Name of file (must be writable)
	eIOFile,     ///< Name of file (must be writable)
	eDirectory,  ///< Name of file directory
	eDataSize,   ///< Integer number with possible "software" qualifiers (KB, KiB, et al)
	eDateTime,   ///< DateTime string, formats:
	             ///< "M/D/Y h:m:s", "Y-M-DTh:m:g", "Y/M/D h:m:g", "Y-M-D h:m:g".
	             ///< Time string can have trailing 'Z' symbol, specifying that
	             ///< it represent time in the UTC format.
	k_EType_Size ///< For internal use only
};

enum ncbi::CArgDescriptions::EFlags
{
	// File related flags:
	
	/// Open file right away; for eInputFile, eOutputFile, eIOFile
	fPreOpen = (1 << 0),
	/// Open as binary file; for eInputFile, eOutputFile, eIOFile
	fBinary  = (1 << 1), 
	/// Append to end-of-file; for eOutputFile or eIOFile 
	fAppend    = (1 << 2),
	/// Delete contents of an existing file; for eOutputFile or eIOFile 
	fTruncate  = (1 << 12),
	/// If the file does not exist, do not create it; for eOutputFile or eIOFile 
	fNoCreate = (1 << 11),
	/// If needed, create directory where the file is located
	fCreatePath = (1 << 8),
	
	/// Mask for all file-related flags
	fFileFlags = fPreOpen | fBinary | fAppend | fTruncate | fNoCreate | fCreatePath,
	// multiple keys flag:
	
	/// Repeated key arguments are legal (use with AddKey)
	fAllowMultiple = (1 << 3),
	
	// Error handling flags:
	
	/// Ignore invalid argument values. If not set, exceptions will be
	/// thrown on invalid values.
	fIgnoreInvalidValue = (1 << 4),
	/// Post warning when an invalid value is ignored (no effect
	/// if fIgnoreInvalidValue is not set).
	fWarnOnInvalidValue = (1 << 5),
	
	/// Allow to ignore separator between the argument's name and value.
	/// Usual ' ' or '=' separators can still be used with the argument.
	/// The following restrictions apply to a no-separator argument:
	///   - the argument must be a key (including optional or default);
	///   - the argument's name must be a single char;
	///   - no other argument's name can start with the same char,
	///     unless fOptionalSeparatorAllowConflict is also specified.
	fOptionalSeparator = (1 << 6),
	/// For arguments with fOptionalSeparator flag, allow
	/// other arguments which names begin with the same char.
	fOptionalSeparatorAllowConflict = (1 << 9),
	
	/// Require '=' separator
	fMandatorySeparator = (1 << 7),
	
	/// Hide it in Usage
	fHidden = (1 << 10),
	
	/// Confidential argument
	/// Such arguments can be read from command line, from file, or from
	/// console.
	/// On command line, they can appear in one of the following forms:
	///   -key                 -- read value from console, with automatically
	///                           generated prompt
	///   -key-file fname      -- read value from file 'fname',
	///                           if 'fname' equals '-',  read value from
	///                           standard input (stdin) without any prompt
	///   -key-verbatim value  -- read value from the command line, as is
	fConfidential  = (1 << 13)
};

enum EConstraintNegate
{
	eConstraintInvert,  ///< Logical NOT
	eConstraint         ///< Constraint is not inverted (taken as is)
};
 -- old POD 
**********************************************************************/

template <typename TEnumLitType>
ncbi::CArgAllow * AllowEnumLits();

// -- numeric to default literature
template <typename TNumeric>
const char * NumericDefVal(TNumeric n);


struct TArgDefinition
{
	enum EArgCategory
	{
		eKey,
		ePos,	//Positional
		eOpenPos,	//Opening positional
		eFlag,
		eNegFlag
	};
	static const char EMPTYSTR[];
	
	const char * name;
	EArgCategory cat;
	ncbi::CArgDescriptions::EType type;
	const char * descr;
	bool optional;	//with eFlag, this field serve as enum EFlagValue {eFlagHasValueIfMissed = 0, eFlagHasValueIfSet = 1}
	const char * synopsis;
	const char * alias;
	ncbi::CArgDescriptions::TFlags flags;	//flags
	const char * val_env;	//environment contains the value
	const char * def_val;	//default value for optional arguments
	ncbi::CArgAllow * constraint;
	ncbi::CArgDescriptions::EConstraintNegate neg_constraint;
	std::vector<unsigned int> required_args;	//required argument (indexes)
	std::vector<unsigned int> excluded_args;	//exclude argument (indexes)
	
};

struct TExtraArg
{
	unsigned int n_mandatory;
	unsigned int n_optional;
	const char * descr;
	ncbi::CArgDescriptions::EType type;
	ncbi::CArgDescriptions::TFlags flags;	//flags	
};




// -- binname = the binary name, usually argv[0]


//enum EMiscFlags
//{
//	fNoUsage        = 1 << 0,  ///< Do not print USAGE on argument error.
//	fUsageIfNoArgs  = 1 << 1,  ///< Force printing USAGE (and then exit)
//	                           ///< if no command line args are present.
//	fUsageSortArgs  = 1 << 2,  ///< Sort args when printing USAGE.
//	fDupErrToCerr   = 1 << 3,  ///< Print arg error to both log and cerr.
//	
//	fMisc_Default   = 0
//};

ncbi:: CArgDescriptions * ProcessArgDefinitions(const std::string &binname, const std::string &usage, const std::string &descr, const TArgDefinition *pDefs, size_t ndef, const TExtraArg *pExtra = nullptr, size_t nextra = 0, ncbi::CArgDescriptions::EMiscFlags miscflgs = ncbi::CArgDescriptions::fMisc_Default);


// -- registry utils














#include "impl/argwrapper_impl.hpp"
#endif

