#ifndef _CDEV_PLATFORMS_H_
#define _CDEV_PLATFORMS_H_

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <signal.h>

#ifdef _WIN32
	#include <time.h>
	
	#ifndef CDEV_REACTOR_API
	// *********************************************************************
	// * _CDEV_REACTOR_EXPORTS :
	// * This definition allows cdevReactor DLL components to be imported 
	// * and exported by other applications and libraries.
	// *********************************************************************
	#ifdef _CDEV_REACTOR_EXPORTS_
		#define CDEV_REACTOR_API __declspec(dllexport)
	#else
		#define CDEV_REACTOR_API __declspec(dllimport)
	#endif
	#endif

	#ifndef GENERIC_SERVER_API
	// *********************************************************************
	// * _GENERIC_SERVER_EXPORTS :
	// * This definition allows Generic Server DLL components to be imported
	// * and exported by other applications and libraries.
	// *********************************************************************
	#ifdef _GENERIC_SERVER_EXPORTS_
		#define GENERIC_SERVER_API __declspec(dllexport)
	#else
		#define GENERIC_SERVER_API __declspec(dllimport)
	#endif
	#endif
	
	#include <WinSock2.h>
	#include <io.h>
	#include <fcntl.h>
	#include <WinBase.h>
	#include <lmcons.h>
	#include <process.h>
	#include <sys/types.h>
	#include <xdr.h>
		
	typedef signed long ssize_t;
	
	#define MAXHOSTNAMELEN 128
	#define EWOULDBLOCK    WSAEWOULDBLOCK
	#define EINPROGRESS    WSAEINPROGRESS
	#define EISCONN        WSAEISCONN
	#define SELECT_PARM fd_set *
	
	#ifndef O_NONBLOCK
		#define O_NONBLOCK 1
	#endif

	// *********************************************************************
	// * SOCKOPT_SIZE_PARM :
	// * This is the datatype of the parameter that is sent to getsockopt,
	// * setsockopt, and getsockname.
	// *********************************************************************
	typedef int SOCKOPT_SIZE_PARM;
	
	inline int GetSocketErrno ( void ) 
		{
		return WSAGetLastError(); 
		}
		
	inline int GetSelectErrno ( void )
		{
		return WSAGetLastError();
		}
		
	inline int InitializeNetwork ( void )
		{
		WORD    version_requested = MAKEWORD (2, 0);
		WSADATA wsa_data;
		return  WSAStartup(version_requested, &wsa_data);
		}
		
	inline int TerminateNetwork ( void )
		{
		return WSACleanup();
		}

	inline char * ultoa ( unsigned long val )
		{
		static char buf[64];
		return _ultoa(val, buf, 10);
		}

	inline char * ltoa ( long val )
		{
		static char buf[64];
		return _ltoa(val, buf, 10);
		}
						
	inline int usleep ( unsigned int useconds )
		{
		int retval = 0;
		if(useconds<100000) Sleep(useconds/1000);
		else retval = -1;
		return retval;
		}

	inline unsigned int sleep ( unsigned int seconds )
		{
		Sleep(seconds*1000);
		return seconds;
		}
		
	// *********************************************************************
	// * This version of pipe is provided because the file descriptors
	// * generated by the Windows NT version of pipe cannot be used with the
	// * select system call.
	// *********************************************************************	
	inline int pipe ( int fd[2] )
		{
		int retval = 0;
		sockaddr_in   addr[2];
		hostent     * hostptr;
		char          hostname[MAXHOSTNAMELEN];
		unsigned long ipAddr;
		unsigned long blockFlag = 1;
	
		gethostname(hostname, MAXHOSTNAMELEN);
		hostptr = ::gethostbyname(hostname);
		ipAddr  = *(unsigned long *)hostptr->h_addr;

		for(int i=0; i<2; i++)
			{
			addr[i].sin_family                  = AF_INET;
			addr[i].sin_port                    = htons(0);
			*(unsigned long *)&addr[i].sin_addr = ipAddr;
			if((fd[i] = socket(PF_INET, SOCK_DGRAM,0))>0 && 
			   bind(fd[i], (sockaddr *)&addr[i], sizeof(addr[i]))==0)
				{
				int addrLen = sizeof(addr[i]);
				getsockname(fd[i], (sockaddr *)&addr[i], &addrLen);
				ioctlsocket(fd[i], FIONBIO, &blockFlag);
				}
			else fd[i] = -1;
			}
		if(fd[0]>0 && fd[1]>0)
			{
			::connect(fd[0], (sockaddr *)&addr[1], sizeof(addr[1]));
			::connect(fd[1], (sockaddr *)&addr[0], sizeof(addr[0]));
			}
		else
			{
			if(fd[0]>0) close(fd[0]);
			if(fd[1]>0) close(fd[1]);
			fd[0] = (fd[1] = (retval = -1));
			}
		return retval;
		}

	inline int FileTimeToTimeVal ( FILETIME * tfile, struct timeval * tv )
		{
		if(tfile && tv)
			{
			ULARGE_INTEGER _100ns = {tfile->dwLowDateTime,
						 tfile->dwHighDateTime};
		
			_100ns.QuadPart -= 0x19db1ded53e8000i64;
		
			tv->tv_sec  = long  (_100ns.QuadPart / (10000 * 1000));
			tv->tv_usec = long ((_100ns.QuadPart % (10000 * 1000)) / 10);
			
			return 0;
			}
		return -1;
		}

	inline int gettimeofday (struct timeval *tv)
		{
		FILETIME       tfile;
		
		GetSystemTimeAsFileTime(&tfile);
		
		return FileTimeToTimeVal(&tfile, tv);
		}

	inline int cdevSelect (
		int              size, 
		fd_set         * read_set,
		fd_set         * write_set,
		fd_set         * except_set,
		struct timeval * timeout )
		{
		int result = select(size, read_set, write_set, except_set, timeout);
		
		if(result<0 && GetSelectErrno()==WSAEINVAL)
			{
			if(timeout)
				{
				unsigned long millisec = timeout->tv_sec*1000+timeout->tv_usec/1000;
				Sleep(millisec);
				}
			result = 0;
			}
		else if (result<0 && GetSelectErrno()==WSAEINPROGRESS)
			{
			result = 0;
			}
		return result;	
		}
#else
	#include <sys/time.h>

	#define CDEV_REACTOR_API 
	#define GENERIC_SERVER_API
		
	#ifdef __VMS
		#ifdef _TGV_MULTINET
			// *****************************************************
			// * Under TGV multinet and VMS, if you want sys/types.h
			// * you need to have types.h already pulled in because
			// * sys/types.h makes it look like types.h is loaded. 
			// * Then when types.h does get loaded, it is ignored 
			// * because it looks like it is already loaded -- 
			// * Mr. Danial Van Olst
			// *****************************************************
			#include <types.h>
	
			// *****************************************************
			// * Under TGV Multinet and VMS, the file sys/param.h 
			// * does not define NOFILE (max number of open files 
			// * per process).  FD_SETSIZE seems to be the correct 
			// * value for NOFILE.
			// * See Multinet's sys/types.h file for more info on 
			// * FD_SETSIZE. - Daniel Van Olst
			// *****************************************************
			#ifndef NOFILE
				#define NOFILE FD_SETSIZE
			#endif 
		#endif 
	#endif 

	#ifdef SYSV
		#include <poll.h>
	#endif
	
	#include <unistd.h>
	#include <fcntl.h>
	#include <sys/utsname.h>
	#include <sys/types.h>
	#include <sys/param.h>
	#include <sys/ioctl.h>
	#include <grp.h>
	#include <rpc/rpc.h>
	#include <sys/socket.h>
	#include <netinet/tcp.h>
	#include <netinet/in.h>
	#include <netdb.h>
	#include <arpa/inet.h>

	
	#if defined (__hpux)
		#include <sys/pstat.h>
	#endif
	
	#if defined (AIX)
		#include <sys/select.h>
	#endif
	
	#if defined(solaris) || defined(SunOS)
		#include <sys/filio.h>
		extern "C" { int gethostname(char *name, int namelen); }
	#endif 

	#ifdef _SELECT_USES_INT_
		#define SELECT_PARM int *
	#else 
		#define SELECT_PARM fd_set *
	#endif
	
	#ifndef min
		#define min(a,b) ((a<b)?a:b)
	#endif
	
	#ifndef max
		#define max(a,b) ((a>b)?a:b)
	#endif

	// *********************************************************************
	// * SOCKOPT_SIZE_PARM :
	// * This is the datatype of the parameter that is sent to getsockopt,
	// * setsockopt, and getsockname.
	// *********************************************************************
	#if defined(AIX) || defined(__linux)
		typedef unsigned int SOCKOPT_SIZE_PARM;
	#else
		typedef int SOCKOPT_SIZE_PARM;
	#endif
		
	inline int GetSocketErrno ( void ) 
		{
		return errno; 
		}

	inline int GetSelectErrno ( void )
		{
		return errno;
		}
		
	inline int InitializeNetwork ( void )
		{
		return 0;
		}
		
	inline int TerminateNetwork ( void )
		{
		return 0;
		}
		
	inline int gettimeofday (struct timeval * tv)
		{
		struct timezone tz;
		
		return ::gettimeofday(tv, &tz);
		}

	inline int cdevSelect (int nfds, fd_set *r, fd_set *w, fd_set *e, struct timeval *t)
		{
		return ::select(nfds, (SELECT_PARM)r, (SELECT_PARM)w, (SELECT_PARM)e, t);
		}
#endif

#endif /* _CDEV_PLATFORMS_H_ */
