
/**------------------------------------------------------------------------
 * @file
 *
 * Copyright 2001 by the University of Toronto (UT).
 *
 *                       All Rights Reserved
 * 
 * Permission to copy and modify this software and its documentation 
 * only for internal use in your organization is hereby granted, 
 * provided that this notice is retained thereon and on all copies.  
 * UT makes no representations as to the suitability and operability 
 * of this software for any purpose.  It is provided "as is" without 
 * express or implied warranty.
 *
 * UT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
 * SHALL UT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 * No other rights, including for example, the right to redistribute 
 * this software and its documentation or the right to prepare 
 * derivative works, are granted unless specifically provided in a 
 * separate license agreement.
 *
 * Author: Diego Macrini
 * 
 * $Log: CmdLineParser.h,v $
 * Revision 1.1.1.1  2002/03/10 07:38:08  dmac
 * Imported sources
 *
 *
 *-----------------------------------------------------------------------*/
#ifndef __CMD_LINE_PARSER_H__
#define __CMD_LINE_PARSER_H__

#include <iostream>
#include <vector>
#include <string>
#include <BasicUtils.h>

#ifdef WIN32
# ifndef _GETOPT_H
	struct option
	{
		const char *name;
		int has_arg;
		int *flag;
		int val;
	};
# endif
#else
# include <getopt.h>
#endif

#define MAX_OPT_ARGS 500

class CmdLineParser;

typedef bool (CmdLineParser::*CLP_ACTION)();
typedef const char* LPCSTR;

LPCSTR asciitoascii(LPCSTR sz);

class CmdLineArgT
{
	char m_cShortName;
	LPCSTR m_szLongName;
	LPCSTR m_szDesc;
	CLP_ACTION m_pfAction;
	bool m_bSelected;
	int m_nOrder;

public:
	CmdLineArgT(char cShortName, LPCSTR szLongName, LPCSTR szDesc, CLP_ACTION pfAction = NULL)
	{
		m_bSelected = false;
		m_cShortName = cShortName;
		m_szLongName = szLongName;
		m_szDesc = szDesc;
		m_pfAction = pfAction;
		m_nOrder = 0;
	}

	virtual ~CmdLineArgT() {}
	virtual void Select(LPCSTR szOptArg) { m_bSelected = true; }
	virtual bool HasOptArg() const { return false; }
	virtual bool Print(std::ostream& os = std::cout, bool newLine = true) const { return false; }

	void SetOrder(int i) { m_nOrder = i; }
	int GetOrder() const { return m_nOrder; }

	bool HasShortName() const { return m_cShortName != 0; }
	bool HasLongName() const { return m_szLongName != 0 && *m_szLongName != '\0'; }
	bool IsSelected() const { return m_bSelected; }
	bool HasAction() const { return m_pfAction != 0; }
	CLP_ACTION GetAction() const { return m_pfAction; }
	char GetShortName() const { return m_cShortName; }
	LPCSTR GetLongName() const { return m_szLongName; }
	LPCSTR GetDesc() const { return m_szDesc; }
};

template<class T> class CmdLineArg : public CmdLineArgT
{
	T* m_pOptArg;
	T (*m_pfAtoT)(LPCSTR);
	
public:
	CmdLineArg(char cShortName, LPCSTR szLongName, LPCSTR szDesc, 
		T* pOptArg, const T& defVal, CLP_ACTION pfAction, T (*pfAtoT)(LPCSTR)) 
		: CmdLineArgT(cShortName, szLongName, szDesc, pfAction)
	{ 
		m_pOptArg = pOptArg; 
		*m_pOptArg = defVal; 
		m_pfAtoT = pfAtoT;
	}

	void Select(LPCSTR szOptArg)
	{
		CmdLineArgT::Select(szOptArg);
		*m_pOptArg = (*m_pfAtoT)(szOptArg); 
	}

	bool Print(std::ostream& os = std::cout, bool newLine = true) const 
	{ 
		os << GetLongName() << " = " << *m_pOptArg;
		
		if (newLine)
			os << std::endl; 
			
		return true;
	}

	bool HasOptArg() const { return true; }
};

struct OPTION : public option
{
	void operator=(const CmdLineArgT& arg)
	{
		name = arg.GetLongName();
		has_arg = arg.HasOptArg();
		flag = 0;
		val = arg.GetShortName();
	}

	void SetToZero()
	{
		name = 0;
		has_arg = 0;
		flag = 0;
		val = 0;
	}
};

/*!
	@brief Parser for the command-line arguments	

	IPORTANT: The actions' order of addition matters. It determines
	the priority of the action. Then, if more than one action is selected, 
	the action's priority specifies the execution order.
*/
class CmdLineParser
{
protected:
	CmdLineArgT* m_pOptArgs[MAX_OPT_ARGS];
	char** m_pNonOptArgs;
	int m_nOptArgs;
	int m_nNonOptArgs;
	const char* m_szProgramName;
	const char* m_szOptArgHelp;

	int m_localArgc;
	char** m_localArgv;
	
public:	
	CmdLineParser()
	{
		m_pNonOptArgs = NULL;
		m_nOptArgs = 0;
		m_nNonOptArgs = 0;
		m_szProgramName = "prgname";
		m_szOptArgHelp = NULL;

		m_localArgc = 0;
		m_localArgv = NULL;
	}

	~CmdLineParser()
	{
		while (m_nOptArgs) 
			delete m_pOptArgs[--m_nOptArgs];

		for (int i = 0; i < m_localArgc; i++)
			delete[] m_localArgv[i];

		delete[] m_localArgv;
	}

	int GetArgCount() const { return m_nNonOptArgs; }
	const char* GetArg(int i) const { return m_pNonOptArgs[i]; }
	
	void Add(char cShortName, LPCSTR szLongName, LPCSTR szDesc, CLP_ACTION pfAction = NULL)
	{
		m_pOptArgs[m_nOptArgs++] = new CmdLineArgT(cShortName, szLongName, 
			szDesc, pfAction);
	}

	void Add(char cShortName, LPCSTR szLongName, LPCSTR szDesc,
		int* pOptArg, int defVal, CLP_ACTION pfAction = NULL)
	{ 
		m_pOptArgs[m_nOptArgs++] = new CmdLineArg<int>(cShortName, szLongName, 
			szDesc, pOptArg, defVal, pfAction, atoi);
	}

	void Add(char cShortName, LPCSTR szLongName, LPCSTR szDesc,
		double* pOptArg, double defVal, CLP_ACTION pfAction = NULL)
	{ 
		m_pOptArgs[m_nOptArgs++] = new CmdLineArg<double>(cShortName, szLongName, 
			szDesc, pOptArg, defVal, pfAction, atof);
	}

	void Add(char cShortName, LPCSTR szLongName, LPCSTR szDesc,
		LPCSTR* pOptArg, LPCSTR defVal, CLP_ACTION pfAction = NULL)
	{ 
		m_pOptArgs[m_nOptArgs++] = new CmdLineArg<LPCSTR>(cShortName, szLongName, szDesc, 
			pOptArg, defVal, pfAction, asciitoascii);
	}

	void SetOptArgHelp(const char* szOptArgHelp) 
	{ 
		m_szOptArgHelp = szOptArgHelp; 
	}

	void SetPrgName(const char* szProgramName);
	const char* GetPrgName() const { return m_szProgramName; }

	std::ostream& Print(std::ostream& os = std::cout);

	void ShowUsageMsg();
	void ShowErrorMsg(LPCSTR szPgmName) const;
	bool Parse(int argc, char** argv);
	bool ParseArguments(int argc, char** argv);
	bool ParseArguments(const char* argv0, const std::string& args);
	void ExecActions();
	int GetArgIndex(char c);
	int GetArgIndex(const char* szArgName);
	bool IsSelected(char c);
	bool IsSelected(const char* szArgName);

	virtual void InitOptions() = 0;
	virtual bool ExecAction(CLP_ACTION pAction) = 0;
	virtual void ShowUsageExamples() {}
};

#endif //__CMD_LINE_PARSER_H__
