/* +---------------------------------------------------------------------------+
   |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
   |                                                                           |
   |                   http://mrpt.sourceforge.net/                            |
   |                                                                           |
   |   Copyright (C) 2005-2008  University of Malaga                           |
   |                                                                           |
   |    This software was written by the Perception and Robotics               |
   |      research group, University of Malaga (Spain).                        |
   |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
   |                                                                           |
   |  This file is part of the MRPT project.                                   |
   |                                                                           |
   |     MRPT is free software: you can redistribute it and/or modify          |
   |     it under the terms of the GNU General Public License as published by  |
   |     the Free Software Foundation, either version 3 of the License, or     |
   |     (at your option) any later version.                                   |
   |                                                                           |
   |   MRPT is distributed in the hope that it will be useful,                 |
   |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
   |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
   |     GNU General Public License for more details.                          |
   |                                                                           |
   |     You should have received a copy of the GNU General Public License     |
   |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
   |                                                                           |
   +---------------------------------------------------------------------------+ */
#ifndef  MRPT_OS_H
#define  MRPT_OS_H

#include <MRPT/config.h>

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


// Define a decl. modifier for printf-like format checks at compile time:
#ifdef __GNUC__
#	define MRPT_printf_format_check(_FMT_,_VARARGS_)  __attribute__ ((__format__ (__printf__, _FMT_,_VARARGS_)))
#else
#	define MRPT_printf_format_check(_FMT_,_VARARGS_)
#endif

// Define a decl. modifier for scanf-like format checks at compile time:
#ifdef __GNUC__
#	define MRPT_scanf_format_check(_FMT_,_VARARGS_)  __attribute__ ((__format__ (__scanf__, _FMT_,_VARARGS_)))
#else
#	define MRPT_scanf_format_check(_FMT_,_VARARGS_)
#endif


/** Used after member declarations */
#define MRPT_NO_THROWS		throw()



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

		/** This structure contains the information needed to interface the threads API on each platform:
		  */
		struct TThreadHandle
		{
#ifdef MRPT_OS_WINDOWS
			TThreadHandle()  :  //!< Sets the handle to a predefined value meaning it is uninitialized.
				hThread(NULL),
				idThread(0)
			{
			}

			/** Mark the handle as invalid.
			  * \sa isClear
			  */
			void clear()
			{
				idThread = 0;
				hThread  = NULL;
			}
			void			*hThread;		//!< The thread "HANDLE"
# if defined(_MSC_VER) && (_MSC_VER>=1400)
			uintptr_t		idThread;		//!< The thread ID.
# else
			unsigned long	idThread;		//!< The thread ID.
# endif
#endif
#ifdef MRPT_OS_LINUX
			TThreadHandle() : idThread(0)  //!< Sets the handle to a predefined value meaning it is uninitialized.
			{
			}
			unsigned long	idThread;		//!< The thread ID.

			/** Mark the handle as invalid.
			  * \sa isClear
			  */
			void clear()
			{
				idThread = 0;
			}
#endif
			/** Returns true if the handle is uninitialized */
			bool isClear() { return idThread==0; }
		};



	/** 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)
		  *  \sa UTILS::format
		  */
		int sprintf(char *buf, size_t bufSize, const char *format, ...) MRPT_NO_THROWS MRPT_printf_format_check(3,4);

		/** 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) MRPT_NO_THROWS;

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

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

		/** An OS-independent version of fprintf
		  */
		int fprintf(FILE *fil, const char *format, ...)  MRPT_NO_THROWS MRPT_printf_format_check(2,3);

		/** An OS-independent version of fscanf
		  * \return The number of fields correctly assigned
		  */
		int fscanf(FILE *fil, const char *format, ...)  MRPT_NO_THROWS MRPT_scanf_format_check(2,3);

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

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

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

		/** 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) MRPT_NO_THROWS;

		/** 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) MRPT_NO_THROWS;

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

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

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

		/** 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 ) MRPT_NO_THROWS;

		/** 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 ) MRPT_NO_THROWS;

		/** 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 ) MRPT_NO_THROWS;

		/** 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 ) MRPT_NO_THROWS;


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

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

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

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

        /** Creates a new thread.
          *  This function creates, and start, a new thread running some code given by a function.
          *  The thread function should end by returning as normal.
          * \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 A structure that represents the thread (it contains its ID and, in Windows, its HANDLE).
          * \exception std::exception If the operation fails
          * \sa endThread, joinThread
          */
        TThreadHandle createThread(
             void       ( *func )( void * ),
             void       *param
             );

        /** Waits until the given thread ends.
          * \sa createThread, endThread
          */
        void joinThread( const TThreadHandle &threadHandle );

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

		/** 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() MRPT_NO_THROWS;


		/** Returns the current working directory.
		  */
		std::string getcwd();

	} // End of namespace

} // End of namespace

#endif
