/*---------------------------------------------------------------
	FILE: MRPT_OS.h
	USE: See description below.

   Part of the MRPT Library
   ISA - Universidad de Malaga - http://www.isa.uma.es
  ---------------------------------------------------------------*/
#ifndef  MRPT_OS_H
#define  MRPT_OS_H

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string>
#include <deque>
#include <vector>

/*---------------------------------------------------------------
	Class
  ---------------------------------------------------------------*/
namespace UTILS
{

	/** This namespace provides a OS-independent interface to many common functions, among with some string manipulation utilities.
	 * Up to the current date, most of these functions are converted into calls to the standard
	 * functions, unless we are into Visual Studio 2005 (or newer). In that case the secure version
	 * of the standard library functions (prefix "_s") are used instead.
	 */
	namespace MRPT_OS
	{
		/** An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compilers)
		  */
		int sprintf(char *buf, size_t bufSize, const char *format, ...);

		/** An OS-independent version of vsprintf (Notice the bufSize param, which may be ignored in some compilers)
		  */
		int vsprintf(char *buf, size_t bufSize, const char *format, va_list args);

		/** An OS-independent version of fopen.
		  * \return It will always return NULL on any error.
		  */
		FILE * fopen(const char *fileName,const char *mode);

		/** An OS-independent version of MRPT_OS::fprintf
		  */
		int fprintf(FILE *fil, const char *format, ...);

		/** An OS-independent version of fclose.
		  */
		void fclose(FILE *f);

		/** An OS-independent version of strcat.
		  * \return It will always return the "dest" pointer.
		  */
		char * strcat(char *dest, size_t destSize, const char *source);

		/** An OS-independent version of strcpy.
		  * \return It will always return the "dest" pointer.
		  */
		char * strcpy(char *dest, size_t destSize, const char *source);

		/** An OS-independent version of strcmpi.
		  * \return It will return 0 when both strings are equal, casi sensitive.
		  */
		int _strcmp(const char*str1,const char*str2);

		/** An OS-independent version of strcmpi.
		  * \return It will return 0 when both strings are equal, casi insensitive.
		  */
		int _strcmpi(const char*str1,const char*str2);

		/** An OS and compiler independent version of "memcpy"
		  */
		void memcpy(
			void		*dest,
			size_t		destSize,
			const void	*src,
			size_t		copyCount );

		/** An OS-independent version of getch, which waits until a key is pushed.
		  * \return The pushed key code
		  */
		int getch();

		/** An OS-independent version of kbhit, which returns true if a key has been pushed.
		  */
		bool kbhit();

		/** An OS-independent method for sending the current thread to "sleep" for a given period of time.
		  * \param time_ms The sleep period, in miliseconds.
		  */
		void sleep( int time_ms );

		/** An OS-independent method for tokenizing a string.
		  * The extra parameter "context" must be a pointer to a "char*" variable, which needs no initialization and is used to save information between calls to strtok.
		  * \sa MRPT_OS::tokenize
		  */
		char *strtok( char *str, const char *strDelimit, char **context );

		/** Tokenizes a string according to a set of delimiting characters.
		  * Example:
		  * \code
		  std::vector<std::string>	tokens;
		  tokenize( " - Pepe-Er  Muo"," -",tokens);
		  * \endcode
		  *
		  *  Will generate 3 tokens:
		  *		- "Pepe"
		  *		- "Er"
		  *		- "Muo"
		  */
		void  tokenize(
			const std::string			&inString,
			const std::string			&inDelimiters,
			std::deque<std::string>		&outTokens );

		/** Tokenizes a string according to a set of delimiting characters.
		  * Example:
		  * \code
		  std::vector<std::string>	tokens;
		  tokenize( " - Pepe-Er  Muo"," -",tokens);
		  * \endcode
		  *
		  *  Will generate 3 tokens:
		  *		- "Pepe"
		  *		- "Er"
		  *		- "Muo"
		  */
		void  tokenize(
			const std::string			&inString,
			const std::string			&inDelimiters,
			std::vector<std::string>		&outTokens );


        /** Returns true if the number is NaN.
          */
        bool  isNaN(float  f);

        /** Returns true if the number is NaN.
          */
        bool  isNaN(double f);

        /** Returns true if the number is non infinity.
          */
        bool  isFinite(float f);

        /** Returns true if the number is non infinity.
          */
        bool  isFinite(double f);

        /** Creates a new thread.
          *  This function creates, and start, a new thread running some code given by a function.
          *  IMPORTANT: The thread function MUST end by explicitly calling MRPT_OS::endThread
          * \param func The function with the code to run in the thread.
          * \param param The parameter to be passed to the new thread function.
          * \return An ID of the new thread (Windows: The thread ID as returned by GetThreadId(), Linux: the pthread_xxx thread id).
          * \exception std::exception If the operation fails
          * \sa endThread, joinThread
          */
        unsigned long createThread(
             void       ( *func )( void * ),
             void       *param
             );

        /** Must be called at the end of a thread created by MRPT_OS::createThread
          * \sa createThread, joinThread
          */
        void endThread( );

        /** Waits until the given thread ends.
          * \sa createThread, endThread
          */
        void joinThread( unsigned long threadId );

        /** Returns the ID of the current thread.
          */
        unsigned long getCurrentThreadId();

		/** Returns the creation and exit times of a given thread and its CPU time consumed.
		  * \param threadId The thread ID, as given by getCurrentThreadId or createThread.
		  * \param creationTime The creation time of the thread.
		  * \param exitTime The exit time of the thread, or undefined if it is still running.
		  * \param cpuTime The CPU time consumed by the thread, in seconds.
          * \exception std::exception If the operation fails
          * \sa getCurrentThreadId, createThread
          */
		void getThreadTimes(
			unsigned long	threadId,
			time_t			&creationTime,
			time_t			&exitTime,
			double			&cpuTime );


		/** Shows the message "Press any key to continue" to the current standard output and returns when a key is pressed.
		  */
		void pause();


	} // End of namespace

} // End of namespace

#endif
