#include "c4d_omp.h"

#ifndef C4D_USE_OPENMP

// compatibility functions if OpenMP is not used for compiling
// taken from the OpenMP specifications at www.openmp.org

#include <stdio.h>
#include <stdlib.h>
#ifdef __API_INTERN__
#include "ge_tools.h"
#else
#include "c4d_general.h"
#endif

void omp_set_num_threads(int num_threads)
{
}

int omp_get_num_threads(void)
{
	return 1;
}

int omp_get_max_threads(void)
{
	return 1;
}

int omp_get_thread_num(void)
{
	return 0;
}

int omp_get_num_procs(void)
{
	return 1;
}

void omp_set_dynamic(int dynamic_threads)
{
}

int omp_get_dynamic(void)
{
	return 0;
}

int omp_in_parallel(void)
{
	return 0;
}

void omp_set_nested(int nested)
{
}
int omp_get_nested(void)
{
	return 0;
}

enum {UNLOCKED = -1, INIT, LOCKED};
typedef int omp_lock_t;
void omp_init_lock(omp_lock_t *lock)
{
	*lock = UNLOCKED;
}

void omp_destroy_lock(omp_lock_t *lock)
{
	*lock = INIT;
}

void omp_set_lock(omp_lock_t *lock)
{
	if (*lock == UNLOCKED) 
	{
		*lock = LOCKED;
	} 
	else if (*lock == LOCKED) 
	{
		fprintf(stderr, "error: deadlock in using lock variable\n");
		exit(1);
	} 
	else 
	{
		fprintf(stderr, "error: lock not initialized\n");
		exit(1);
	}
}

void omp_unset_lock(omp_lock_t *lock)
{
	if (*lock == LOCKED) 
	{
		*lock = UNLOCKED;
	} 
	else if (*lock == UNLOCKED) 
	{
		fprintf(stderr, "error: lock not set\n");
		exit(1);
	} 
	else 
	{
		fprintf(stderr, "error: lock not initialized\n");
		exit(1);
	}
}

int omp_test_lock(omp_lock_t *lock)
{
	if (*lock == UNLOCKED) 
	{
		*lock = LOCKED;
		return 1;
	} 
	else if (*lock == LOCKED) 
	{
		return 0;
	} 
	fprintf(stderr, "error: lock not initialized\n");
	exit(1);
}

#ifndef OMP_NEST_LOCK_T
typedef struct { /* This really belongs in omp.h */
	int owner;
	int count;
} omp_nest_lock_t;
#endif

enum {MASTER = 0};
void omp_init_nest_lock(omp_nest_lock_t *lock)
{
	lock->owner = UNLOCKED;
	lock->count = 0;
}

void omp_destroy_nest_lock(omp_nest_lock_t *lock)
{
	lock->owner = UNLOCKED;
	lock->count = UNLOCKED;
}

void omp_set_nest_lock(omp_nest_lock_t *lock)
{
	if (lock->owner == MASTER && lock->count >= 1) 
	{
		lock->count++;
	} 
	else if (lock->owner == UNLOCKED && lock->count == 0) 
	{
		lock->owner = MASTER;
		lock->count = 1;
	} 
	else 
	{
		fprintf(stderr, "error: lock corrupted or not initialized\n");
		exit(1);
	}
}

void omp_unset_nest_lock(omp_nest_lock_t *lock)
{
	if (lock->owner == MASTER && lock->count >= 1) 
	{
		lock->count--;
		if (lock->count == 0) 
		{
			lock->owner = UNLOCKED;
		}
	} 
	else if (lock->owner == UNLOCKED && lock->count == 0) 
	{
		fprintf(stderr, "error: lock not set\n");
		exit(1);
	} 
	else 
	{
		fprintf(stderr, "error: lock corrupted or not initialized\n");
		exit(1);
	}
}

int omp_test_nest_lock(omp_nest_lock_t *lock)
{
	omp_set_nest_lock(lock);
	return lock->count;
}

double omp_get_wtime(void)
{
	/* This function does not provide a working
	wallclock timer. Replace it with a version
	customized for the target machine.
	*/
	//return 0.0;

	return ((double)GeGetTimer()) / 1000.0;
}

double omp_get_wtick(void)
{
	/* This function does not provide a working
	clock tick function. Replace it with
	a version customized for the target machine.
	*/
	return 365. * 86400.;
}



#endif // C4D_USE_OPENMP

