/* $Id$
 *
 * Misc. utility functions.
 *
 * Copyright (C) 2007-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#ifndef __MISC_UTIL_HPP_INCLUDED
#define __MISC_UTIL_HPP_INCLUDED

#include <list>
#include <algorithm>
#include <string>

namespace util {

/** This class aggregates misc. static utility functions.
 */
class MiscUtil {
public:
	/** functor, to compare to pointers by their 
	 *  == operator.
	 *  @param obj1 first object to compare.
	 *  @param obj2 second object to compare.
	 *  @return true if both object pointers are nonnull and the
	 *          == operator returns true.
	 */
	template<typename T> 
	static bool compareObject(const T* obj1, const T* obj2);

	/** compare two lists of pointers.
	 *  @param l1 first list of pointers.
	 *  @param l2 second list of pointers.
	 *  @return true only if the lists have the same length and
	 *          the == operator of each object at the same 
	 *          position in the list returns true.
	 */
	template<typename T>
	static bool listMatch(const std::list<T*>& l1, 
			      const std::list<T*>& l2);

	/** compare two lists of pointers.
	 *  @param l1 first list of pointers.
	 *  @param l2 second list of pointers.
	 *  @param compare comparison functor.
	 *  @return true only if the lists have the same length and
	 *          the given compare functor of each object at the same 
	 *          position in the list returns true.
	 */
	template<typename T>
	static bool listMatch(const std::list<T*>& l1, 
			      const std::list<T*>& l2,
			      bool (*compare)(const T*, const T*));

	//! convert val to a string using << operator overloads.
	/** Template restriction: An overloaded << operator for T
          * must exist.
          * @param val value that should get converted to a string.
          * @result val converted to a string.
          */
	template <typename T>
	static std::string toString(const T &val);

	//! check if needle is in haystack dereferencing pointers.
	/** check if the element needle is contained in iteratable haystack
	 *  dereferncing pointers for comparison.
	 *  @param needle element to look for
	 *  @param haystack list which gets iterated over
	 *  @return true if needle is in haystack
	 */
	template <typename T, typename U>
	static bool listContainsObj(const T& haystack, const U needle);

	//! check if reference starts with begin (dereferncing ptrs.)
	/** check if the list reference starts with the list beginning
	 *  dereferencing pointers for comparison.
	 *  @param begin possible beginning of reference.
	 *  @param list that may contain begin.
	 *  @return true, if reference starts with begin.
	 */
	template <typename T>
	static bool listStartsWith(const std::list<T*> begin, 
				   const std::list<T*> reference);

	//! apply delete on every element of a list and clear the list.
	/** delete any element of a list, and clear the list.
	 *  @param l list that should get its elements deleted.
	 */
	template <typename T>
	static void ldelete(T& l);

	//! apply decRef on every element of a list.
	/** apply decRef on every element of a list and delete the list
	 *  afterwards.
	 *  @param l pointer to list in question.
	 */
	template <typename T>
	static void lterminate(T*& l);

	//! check if item is non-null and call decRef() if so.
	/** check if item is non-null and call decRef() if so.
	 *  @param item AstNode that should get terminated.
	 */
	template <typename T>
	static void terminate(T& item);

	//! remove and delete contents of a list if functor yields true.
	/** remove and delete contents of given list l in case the
	  * functor returns true for an element of the list.
	  * @param l work list, that should get filtered.
	  * @param functor predicate (instance/function), that can be called
	  *        with a T* element as argument and returns true or false.
	  */         
	template <typename T, typename U>
	static void ldelete_if(T& l, U functor);

	//! functor: return the second element of a pair
	/** @param t pair
	 *  @return second element
	 */
	template <typename T>
	static typename T::second_type select2nd(T& t) {
		return t.second;
	}

	//! functor: return the first element of a pair
	/** @param t pair
	 *  @return first element
	 */
	template <typename T>
	static typename T::first_type select1st(T& t) {
		return t.first;
	}


	//! Predicate class: set operation not in 
	/** This class can be used when the predicate "not in" is needed.
	 *  T: any forward iteratible sequence (that goes through std::fine).
	 */
	template <typename T>
	class NotIn {
	public:
		//! C'tor
		/** @param refContainer reference sequence container.
		 */
		NotIn(T &refContainer) : ref(refContainer) {};

		//! predicate operator
		/** @param i object that will be checked if it is contained in
		 *           the reference sequence.
		 *  @return true, if i is not in reference, false otherwise.
		 */
		template <typename U>
		bool operator()(U i) {
			if (std::find(ref.begin(), ref.end(), i) == ref.end()) {
				return true;
			}
			return false;
		}

	private:
		//! reference container
		T &ref;
	};

	/** Take a list of pointers and output each one to stream via <<.
	 *  @param l pointer to list, may be NULL.
	 *  @param stream stream to put elements to.
	 *  @param delim use this char as a delimiter between two 
	 *         elements.
	 */
	template <typename T>
	static void listPut(T *l, std::ostream &stream, const char *delim);
};
	
}; /* namespace util */

#include "util/MiscUtil.tpp"

#endif /* __MISC_UTIL_HPP_INCLUDED */
