/*
 * createUnique.hpp
 *
 *  Created on: Nov 11, 2016
 *      Author: Jan Travnicek
 */

#ifndef CREATE_UNIQUE_H_
#define CREATE_UNIQUE_H_

#include <alib/type_traits>
#include <alib/set>
#include "exception/CommonException.h"
#include <climits>
#include <alib/algorithm>
#include <alib/functional>

namespace common {

template < class T >
inline void inc ( T & object ) {
	++ object;
}

template < >
inline void inc ( std::string & object ) {
	object.push_back ( '\'' );
}

template < >
inline void inc ( ext::string & object ) {
	object.push_back ( '\'' );
}

/**
 * Creates a unique object of type T. If given object is already used in sets alphabets, the function attempts to make it unique.
 *
 * The code tries to call preincrement operator on the object as many times as needed until the result is not in any set alphabets.
 * @param name name of the state
 *
 * @throws exception::CommonException if the symbol could not be created
 *
 * @return created symbol
 */
template < class T, class ... Alphabets >
T createUnique ( T object, const Alphabets & ... alphabets ) {
	unsigned i = 0;

	do {
		if ( ( ... && ( alphabets.count ( ext::poly_comp ( object ) ) == 0 ) ) )
			return object;

		inc ( object );
	} while ( i++ < INT_MAX );

	throw exception::CommonException ( "Could not create unique symbol." );
}

}

#endif /* CREATE_UNIQUE_H_ */
