/**
 * @file /include/ecl/threads/priority_win.hpp
 *
 * @brief Priority scheduling for Windows.
 *
 * @date April 2013.
 */
/*****************************************************************************
** Ifdefs
*****************************************************************************/

#ifndef ECL_THREADS_PRIORITY_WIN_HPP_
#define ECL_THREADS_PRIORITY_WIN_HPP_

/*****************************************************************************
** Platform Check
*****************************************************************************/

#include <ecl/config/ecl.hpp>
#if defined(ECL_IS_WIN32)

/*****************************************************************************
** Includes
*****************************************************************************/

#include <windows.h>
#include <string>
#include <sstream>
#include <errno.h>
#include <ecl/config/ecl.hpp>
#include <ecl/exceptions/macros.hpp>
#include <ecl/exceptions/standard_exception.hpp>
#include "priority_common.hpp"
#include "macros.hpp"

/*****************************************************************************
** Namespaces
*****************************************************************************/

namespace ecl {

/**
 * @brief Sets the priority of current thread.
 *
 * The ecl Priority levels that are spread across this weighting system include
 * (from lowest priority to highest) :
 *
 * - BackgroundPriority
 * - LowPriority
 * - NormalPriority
 * - HighPriority
 * - CriticalPriority
 *
 * The real time priority group is treated one - time critical priority
 *
 * - RealTimePriority1
 * - RealTimePriority2
 * - RealTimePriority3
 * - RealTimePriority4
 *
 * @param priority_level : the priority level requested for this process.
 * @return bool : true if success, false if failed and exceptions aren't enabled.
 * @exception StandardException : throws if configuration fails.
 */
bool ecl_threads_PUBLIC set_priority(Priority priority_level) ecl_debug_throw_decl(StandardException);
/**
 * @brief Returns the priority of current thread.
 *
 * @return Priority : the process priority enumeration (UnknownPriority if it fails and exceptions aren't enabled).
 * @exception StandardException : if exceptions enabled, throws if the call fails.
 */
Priority ecl_threads_PUBLIC get_priority() ecl_debug_throw_decl(StandardException);

/**
 * @brief Print priority diagnostics to a string.
 * @return string : insert into a stream to display/log.
 * @exception StandardException : if exceptions enabled, throws if any call fails.
 */
std::string ecl_threads_PUBLIC print_priority_diagnostics() ecl_debug_throw_decl(StandardException);

/*****************************************************************************
** Namespace
*****************************************************************************/

namespace threads {

/**
 * @brief Worker function to configure the real time priorities.
 *
 * Configures the process with real time scheduling and prioritisation.
 *
 * Warning: the specified level will be ignored if you are using PAM and
 * it is larger than the user's specified rtprio limit. In this case, it
 * defaults back to its parent's priority.
 *
 * @param policy : either SCHED_OTHER or SCHED_RR.
 * @param priority_level : a value converted from one of the PriorityLevel abstractions.
 * @return bool : true if it works, false if not (or unsupported).
 *
 * @exception StandardException : if exceptions are enabled, throws if the operation fails or is not supported.
 */
bool ECL_LOCAL set_real_time_priority(int policy,int priority_level) ecl_debug_throw_decl(StandardException);

} // namespace threads
} // namespace ecl

/*****************************************************************************
** Interface [Exceptions]
*****************************************************************************/

#if defined(ECL_HAS_EXCEPTIONS)
namespace ecl {
namespace threads {

/*****************************************************************************
** Interface [Priority Exceptions]
*****************************************************************************/
/**
 * This function generates a custom StandardException response
 * for posix error numbers generated by priority function calls.
 *
 * @param loc : use with the LOC macro, identifies the line and file of the code.
 */
/**
 * This function generates a custom StandardException response
 * for posix error numbers generated by <i>usleep and nanosleep</i> posix
 * functions used in the sleeper classes.
 * @param loc : use with the LOC macro, identifies the line and file of the code.
 */
inline StandardException ECL_LOCAL throwPriorityException(const char* loc ) {
	int error_result = errno;
    switch (error_result) {
        case ( EINVAL ) : return StandardException(loc, ecl::InvalidInputError, "The specified param structure or priority group was invalid.");
        case ( ESRCH  ) : return StandardException(loc, ecl::InvalidInputError, "The process specified could not be found.");
        case ( EPERM  ) : return StandardException(loc, ecl::PermissionsError, "The caller does not have the appropriate privileges for realtime scheduling (http://snorriheim.dnsdojo.com/doku/doku.php/en:linux:admin:priorities).");
        case ( EACCES ) : return StandardException(loc, ecl::PermissionsError, "The caller does not have the appropriate privileges for elevating the process priority by reducing the niceness value (http://snorriheim.dnsdojo.com/doku/doku.php/en:linux:admin:priorities).");
		default         :
		{
			std::ostringstream ostream;
			ostream << "Unknown posix error " << error_result << ": " << strerror(error_result) << ".";
			return StandardException(loc, UnknownError, ostream.str());
		}
    }
}


}; // namespace threads
} // namespace ecl
#endif /* ECL_HAS_EXCEPTIONS */
#endif /* ECL_IS_WIN32 */
#endif /* ECL_THREADS_PRIORITY_WIN_HPP_ */
