#include <windows.h>
#include <time.h>
#include "postgres.h"
#include "storage/ipc.h"

#define IPC_NMAXSHM	10

/* Semaphores and shared memory are implemented using native NT system
** services. However, a mapping function is necessary to go between they
** keys used by the Unix calls and the handles used by NT. To store the
** mapping a fixed-size table, whose size is determined by the
** IPC_NMAXSEM and IPC_NMAXSHM constants. Semaphore IDs and shared memory
** keys are just indexes into this table. -1 is always an invalid
** semaphore ID or shared memory ID.
** Each semaphore consists of an arbitrary key value, which serves
** to identify the semaphore in a process specific manner, and
** some number of Pg_ipc_value structures coming off
** the header in a linked list, where the actual number is determined
** by the numsem argument to the semget call.
** Unlike Unix semaphores, NT semaphores have no adjust-on-exit ability.
*/

int Pg_next_ipc = 0;

struct Pg_ipc
{
	key_t	Pg_ipc_key;
	HANDLE *Pg_ipc_handle;
} Pg_ipc[IPC_NMAXSEM];

semop(int semid, struct sembuf *sops, u_int nsops)
{
	int i, result;
	HANDLE hndl;

	/* Go through all the sops structures passed */
	for (i = 0; i < nsops; i++)
	{
		struct sembuf *sptr;
		int semval;
		int av_sem_op;

		sptr = &sops[i];
		/*
		printf("performing %d in sem # %d\n", sptr->sem_op, sptr->sem_num);
		*/
		if (sptr->sem_op == -255)
			sptr->sem_op = -1;
		else if (sptr->sem_op == 255)
			sptr->sem_op = 1;

		/* 1 = signaled, 0 = unsignaled */
		semval = _get_sem_val(semid, sptr->sem_num);
		hndl = Pg_ipc[semid].Pg_ipc_handle[sptr->sem_num];

		if (sptr->sem_op == 0)
		{
			if (semval == 0)
				return(0);
			else
			{
				if (sptr->sem_flg & IPC_NOWAIT)
					return(1);
				else
					result = WaitForSingleObject(hndl, 5000);
			}
		}

		av_sem_op = abs(sptr->sem_op);

		/* If a lock is being attempted */
		if (sptr->sem_op < 0)
		{
			if (semval >= av_sem_op)
			{
				semval -= av_sem_op;
				if (semval <= 0)
					result = WaitForSingleObject(hndl, 5000);
			}
			else
			{
				if (sptr->sem_flg & IPC_NOWAIT)
					return(1);
				else
					result = WaitForSingleObject(hndl, 5000);
			}
		}

		/* If a lock is being released */
		if (sptr->sem_op > 0)
		{
			semval += av_sem_op;
			if (semval > 0)
				ReleaseSemaphore(hndl, 1, NULL);
		}
	}
}

int
semget(key_t key, int nsems, int semflg)
{
	int id, new_sem;

	/* If nmsems is 0 then assume that we're just checking whether
	** the semaphore identified by key exists. Assume that
	** if key is IPC_PRIVATE that this should always fail.
	*/
	if (nsems == 0)
	{
		if (key == IPC_PRIVATE)
			return(-1);
		else
		{
			id = _get_id(key);
			return(id);
		}
	}

	/* See if there's already a semaphore with the key.
	** If not, record the key, allocate enough space for the
	** handles of the semaphores, and then create the semaphores.
	*/
	id = _get_id(key);
	if (id == -1)
	{
		register int i;

		new_sem = Pg_next_ipc++;
		Pg_ipc[new_sem].Pg_ipc_key = key;
		Pg_ipc[new_sem].Pg_ipc_handle = malloc(nsems * sizeof (HANDLE));

		for (i = 0; i < nsems; i++)
			Pg_ipc[new_sem].Pg_ipc_handle[i] = CreateSemaphore(NULL, 1, 255, NULL);
		return(new_sem);
	}
	return(id);
}

/* Given a key, return the coresponding id */
_get_id(key_t key)
{
	register int i;

	/* Go through the ipc table looking for a ipc
	** whose key matches what we're looking for
	*/
	for (i = 0; i < Pg_next_ipc; i++)
		if (Pg_ipc[i].Pg_ipc_key == key)
			return(i);

	/* Return -1 if we didn't find a match */
	return(-1);
}

semctl(int semid, int semnum, int cmd, void *y)
{
	int old_val;

	switch (cmd)
	{
	case SETALL:
	case SETVAL:
		/* We can't change the value of a semaphore under
		** NT except by releasing it or waiting for it.
		*/
		return(0);

	case GETVAL:
		old_val = _get_sem_val(semid, semnum);
		return(old_val);
	}
}

/* Get the current value in semaphore group of semaphore semnum */
int
_get_sem_val(int semid, int semnum)
{
	HANDLE hnd;
	DWORD waitresult;

	/* Get the handle for the semaphore in question */
	hnd = Pg_ipc[semid].Pg_ipc_handle[semnum];

	/* Try to get the semaphore */
	waitresult = WaitForSingleObject(hnd, 0L);

	/* Check what the value of the semaphore was */
	switch(waitresult)
	{
	/* The semaphore was signaled so we just got it. Now
	** release it.
	*/
	case WAIT_OBJECT_0:
		ReleaseSemaphore(hnd, 1, NULL);
		return(1);

	/* The semaphore was non-signaled. */
	case WAIT_TIMEOUT:
		return(0);
	}
}

int
shmget(key_t key, uint32 size, int flags)
{
	HANDLE hnd;
	char name[32];
	int id;
	int jon;

	/* We use negative keys to show that they're shared
	** memory keys.
	*/
	key = -key;

	/* Get the handle for the key, if any. */
	id = _get_id(key);

	/* If we're really going to create a new mapping */
	if (flags != 0)
	{
		/* if the key is already being used return an error */
		if (id != -1)
			return(-1);

		/* convert the key to a character string */
		sprintf(name, "%d", key);
	
		hnd = CreateFileMapping((HANDLE)0xffffffff,
			(LPSECURITY_ATTRIBUTES) NULL,
			PAGE_READWRITE,
			0, size,
			name);
	
		if (hnd == NULL)
		{
			jon = GetLastError();
			return(-1);
		}
		else
		{
			int new_ipc;

			new_ipc = Pg_next_ipc++;
			Pg_ipc[new_ipc].Pg_ipc_key = key;
			Pg_ipc[new_ipc].Pg_ipc_handle = hnd;
			return(new_ipc);
		}
	}

	/* flags is 0 so we just want the id for the existing mapping */
	else
		return(id);
}

shmdt(char *shmaddr)
{
	int x = 0;
	x = x / x;
}

shmctl(IpcMemoryId shmid, int cmd, struct shmid_ds *buf)
{
	int x = 0;
	x = x / x;
}

LPVOID *
shmat(int shmid, void *shmaddr, int shmflg)
{
	LPVOID *ret_addr;

	ret_addr = MapViewOfFile(Pg_ipc[shmid].Pg_ipc_handle,
		FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
	return(ret_addr);
}

setuid(int i)
{
	int x = 1;
	x = x / x;
}

setsid()
{
	int x = 1;
	x = x / x;
}

vfork(void)
{
	int x = 0;
	x = x / x;
}

ttyname(int y)
{
	int x = 0;
	x = x / x;
}

step(char *string, char *expbuf)
{
	int x = 0;
	x = x / x;
}

siglongjmp(int env, int value)
{
	int x = 0;
	x = x / x;
}

pause(void)
{
	int x = 0;
	x = x / x;
}

/* this is from utils/fmgr/dfmgr.c */
void
load_file(char *filename)
{
	int x = 0;
	x = x / x;
}

kill(int process, int signal)
{
	int x = 1;
	x = x / x;
}

getuid(void)
{
	int x = 1;
	x = x / x;
}

geteuid( void )
{
	int x = 1;
	x = x / x;
}

int
fsync(int filedes)
{
}

fork(void)
{
	int x = 0;
	x = x / x;
}

fmgr_dynamic(Oid procedureId, int *pronargs)
{
	int x = 0;
	x = x / x;
}

char *
compile(char *instring,char *expbuf,char *endbuf,int eof)
{
	int x = 0;
	x = x / x;
}

beginRecipe(char *s)
{
	int x = 0;
	x = x / x;
}

_isinf(double a)
{
	int x = 0;
	x = x / x;
}
