#ifndef TCLAP_XORHANDLER_H
#define TCLAP_XORHANDLER_H

/****************************************************************************** 
 * 
 *  file:  XorHandler.h
 * 
 *  Copyright (c) 2003, Michael E. Smoot .
 *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
 *  All rights reverved.
 * 
 *  See the file COPYING in the top directory of this distribution for
 *  more information.
 *  
 *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 *  DEALINGS IN THE SOFTWARE.  
 *  
 *****************************************************************************/ 

#include <string>
#include <vector>
#include <algorithm>
#include <iostream>

#include <ims/tclap/Arg.h>

namespace TCLAP {

/**
 * This class handles lists of Arg's that are to be XOR'd on the command
 * line.  This is used by CmdLine and you shouldn't ever use it.
 */
class XorHandler {
	protected:

		/**
		 * The list of of lists of Arg's to be or'd together.
		 */
		std::vector< std::vector<Arg*> > _orList;

	public:

		/**
		 * Constructor.  Does nothing.
		 */
		XorHandler( ) {}

		/**
		 * Add a list of Arg*'s that will be orred together.
		 * \param ors - list of Arg* that will be xor'd.
		 */
		void add( std::vector<Arg*>& ors );
			
		/**
		 * Checks whether the specified Arg is in one of the xor lists and
		 * if it does match one, returns the size of the xor list that the
		 * Arg matched.  If the Arg matches, then it also sets the rest of
		 * the Arg's in the list. You shouldn't use this.  
		 * \param a - The Arg to be checked.
		 */
		int check( const Arg* a );

		/**
		 * Returns the XOR specific short usage.
		 */
		std::string shortUsage();

		/**
		 * Prints the XOR specific long usage.
		 * \param os - Stream to print to.
		 */
		void printLongUsage(std::ostream& os);

		/**
		 * Simply checks whether the Arg is contained in one of the arg
		 * lists.
		 * \param a - The Arg to be checked.
		 */
		bool contains( const Arg* a );

		std::vector< std::vector<Arg*> >& getXorList(); 

};


//////////////////////////////////////////////////////////////////////
//BEGIN XOR.cpp
//////////////////////////////////////////////////////////////////////
inline void XorHandler::add( std::vector<Arg*>& ors ) { 
	_orList.push_back( ors );
}

/*
inline std::string XorHandler::shortUsage() {
        std::string out = "";
	for ( int i = 0; (unsigned int)i < _orList.size(); i++ ) {
		out += " {";
		for ( ArgVectorIterator it = _orList[i].begin(); 
						it != _orList[i].end(); it++ ) {
			out += (*it)->shortID() + "|";
		}
		out[out.length()-1] = '}';
	}

	return out;
}

inline void XorHandler::printLongUsage( std::ostream& os ) {
	for ( int i = 0; (unsigned int)i < _orList.size(); i++ ) {
		for ( ArgVectorIterator it = _orList[i].begin(); 
			  it != _orList[i].end(); 
			  it++ ) {
			spacePrint( os, (*it)->longID(), 75, 3, 3 );
			spacePrint( os, (*it)->getDescription(), 75, 5, 0 );

			if ( it+1 != _orList[i].end() ) {
				spacePrint(os, "-- OR --", 75, 9);
			}
		}
		os << std::endl << std::endl;
	}
}
*/
inline int XorHandler::check( const Arg* a ) {
	// iterate over each XOR list
	for ( int i = 0; (unsigned int)i < _orList.size(); i++ ) {
		// if the XOR list contains the arg..
		if ( std::find( _orList[i].begin(), _orList[i].end(), a ) != 
				   _orList[i].end() ) {
			// go through and set each arg that is not a
			for ( ArgVectorIterator it = _orList[i].begin(); 
				  it != _orList[i].end(); 
				  it++ ) {	
				if ( a != (*it) ) {
					(*it)->xorSet();
				}
			}
			// return the number of required args that have now been set
			return (a->isRequired())? (int)_orList[i].size(): 0;
		}
	}

	return (a->isRequired())? 1: 0;
}

inline bool XorHandler::contains( const Arg* a ) {
	for ( int i = 0; (unsigned int)i < _orList.size(); i++ ) {
		for ( ArgVectorIterator it = _orList[i].begin(); 
			  it != _orList[i].end(); 
			  it++ ) {
			if ( a == (*it) ) {
				return true;
			}
		}
	}
	return false;
}

inline std::vector< std::vector<Arg*> >& XorHandler::getXorList() {
	return _orList;
} 



//////////////////////////////////////////////////////////////////////
//END XOR.cpp
//////////////////////////////////////////////////////////////////////

} //namespace TCLAP

#endif