/*
 * Copyright 2004,2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include <stdio.h>
#include <axis2_error_default.h>
#include <axis2_log.h>
#include <axis2_log_default.h>
#include <axis2_allocator.h>
#include <axis2_env.h>
#include <axis2.h>
#include <axis2_thread.h>
#include <axis2_thread_mutex.h>

static axis2_thread_mutex_t *thread_lock = NULL;
static axis2_thread_once_t *control = NULL;
static int x = 0;
static int value = 0;

static axis2_thread_t *t1 = NULL;
static axis2_thread_t *t2 = NULL;

/*for detach tests*/
static axis2_thread_t *t3 = NULL;
static axis2_thread_t *t4 = NULL;

static void init_func(void)
{
    value++;
}

static void thread_init(axis2_env_t *env)
{
    axis2_allocator_t *allocator = NULL;
	axis2_status_t rv;

    	
	allocator = env->allocator;

	rv = axis2_thread_once_init(&control, allocator);

	if (AXIS2_SUCCESS == rv) printf("success - thread_init - axis2_thread_once_init \n");
	else printf("failure - thread_init - axis2_thread_once_init \n");

    thread_lock = axis2_thread_mutex_create(allocator, AXIS2_THREAD_MUTEX_UNNESTED); 

    if (NULL != thread_lock) printf("success - thread_init - axis2_thread_mutex_create \n");
	else printf("failure - thread_init - axis2_thread_mutex_create \n");
}

void * AXIS2_CALL test_function(axis2_thread_t *td,void *param)
{
	int i;
	i = *((int*)param);
	printf("thread data = %d \n",i);

	axis2_thread_once(control, init_func);

	axis2_thread_mutex_lock(thread_lock);
	printf ("x = %d \n",++x);
	axis2_thread_mutex_unlock(thread_lock);

	axis2_thread_exit(td);

	return (void*)1;
}

axis2_env_t * create_env_with_error_log()
{
	axis2_error_t *error = NULL;
	axis2_log_t *log22 = NULL;
	axis2_env_t *env = NULL;
    axis2_allocator_t *allocator = axis2_allocator_init(NULL);
    if (!allocator)
    {
        printf("allocator is NULL\n");
        return NULL;
    }
    error = axis2_error_create(allocator);
    if (!error)
    {
        printf("cannot create error\n");
        return NULL;
    }

    log22  = axis2_log_create (allocator, NULL,"test123.log");
    if (!log22)
    {
        printf("cannot create log\n");
        return NULL;
    }
	/*
	 * allow all types of logs
 	 */
    log22->level = AXIS2_LOG_LEVEL_DEBUG;
/*	log22->enabled = 0;*/
    env = axis2_env_create_with_error_log(allocator, error, log22);
    if (!env)
    {
        printf("cannot create env with error and log\n");
        return NULL;
    }
	printf("create_env_with_error_log success \n");
	return env;
}

void test_axis2_thread_create(axis2_env_t *env)
{
	axis2_status_t rv = AXIS2_FAILURE;
	axis2_allocator_t *allocator = NULL;
	int *i = NULL, *j = NULL;

	allocator = env->allocator;
	i = AXIS2_MALLOC(allocator,sizeof(int));
	*i = 5;
	t1 = axis2_thread_create(allocator,NULL,test_function,(void*)i);

	if (t1) printf("success - test_axis2_thread_create - axis2_thread_create \n");
	else printf("failure - test_axis2_thread_create - axis2_thread_create \n");

	j = AXIS2_MALLOC(allocator,sizeof(int));
	*j = 25;

	t2 = axis2_thread_create(allocator,NULL,test_function,(void*)j);

	if (t2) printf("success - test_axis2_thread_create - axis2_thread_create \n");
	else printf("failure - test_axis2_thread_create - axis2_thread_create \n");
	

	rv = axis2_thread_join(t1);
	
	if (AXIS2_SUCCESS == rv) printf("success - test_axis2_thread_create - axis2_thread_join \n");
	else printf("failure - thread_init - test_axis2_thread_create - axis2_thread_join \n");

	rv = axis2_thread_join(t2);

	if (AXIS2_SUCCESS == rv) printf("success - test_axis2_thread_create - axis2_thread_join \n");
	else printf("failure - thread_init - test_axis2_thread_create - axis2_thread_join \n");

}

void * AXIS2_CALL test_function2(axis2_thread_t *td,void *param)
{
	printf("thread \n");
	axis2_thread_exit(td);

	return (void*)1;
}

void test_axis2_thread_detach(axis2_env_t *env)
{
	axis2_threadattr_t *attr = NULL;
	axis2_allocator_t *allocator = NULL;
	axis2_status_t rv = AXIS2_FAILURE;

	allocator = env->allocator;
	attr = axis2_threadattr_create(allocator);
	if (!attr)
	{
		printf("failure - test_axis2_thread_detach\n");
		return;
	}
	rv = axis2_threadattr_detach_set(attr,1);

	if (AXIS2_SUCCESS != rv)
	{
		printf("failure - test_axis2_thread_detach\n");
		return;
	}
	t3 = axis2_thread_create(allocator,attr,test_function2,NULL);

	if (!t3)
	{
		printf("failure - test_axis2_thread_detach\n");
		return;
	}

	/*
	 * thread is already detached - should return AXIS2_FAILURE
	 */
	rv = axis2_thread_detach(t3);
	
	if (AXIS2_FAILURE != rv)
	{
		printf("failure - test_axis2_thread_detach\n");
		return;
	}
	
	/*
	 * thread is already detached - should return AXIS2_FAILURE
	 * cannot join detached threads
	 */
	rv = axis2_thread_join(t3);
	if (AXIS2_FAILURE != rv)
	{
		printf("failure - test_axis2_thread_detach\n");
		return;
	}
	printf("success - test_axis2_thread_detach\n");
}

void test_axis2_thread_detach2(axis2_env_t *env)
{
	axis2_threadattr_t *attr = NULL;
	axis2_allocator_t *allocator = NULL;
	axis2_status_t rv = AXIS2_FAILURE;

	allocator = env->allocator;
	attr = axis2_threadattr_create(allocator);
	if (!attr)
	{
		printf("failure - test_axis2_thread_detach2\n");
		return;
	}
	
	t4 = axis2_thread_create(allocator,attr,test_function2,NULL);

	if (!t4)
	{
		printf("failure - test_axis2_thread_detach2\n");
		return;
	}

	/*
	 * thread is not detached yet - should return AXIS2_SUCCESS
	 */
	rv = axis2_thread_detach(t4);
	
	if (AXIS2_SUCCESS != rv)
	{
		printf("failure - test_axis2_thread_detach\n");
		return;
	}

	/*
	 * thread is already detached - should return AXIS2_FAILURE
	 * cannot join detached threads
	 */
	rv = axis2_thread_join(t4);
	if (AXIS2_FAILURE != rv)
	{
		printf("failure - test_axis2_thread_detach2\n");
		return;
	}
	printf("success - test_axis2_thread_detach2\n");
}

static void check_locks()
{
    if (2 == x) printf ("success - check_locks \n");
	else printf ("failure - check_locks \n");

}

static void check_thread_once()
{
    if (1 == value) printf ("success - check_thread_once \n");
	else printf ("failure - check_thread_once \n");
}
void run_thread_test(axis2_env_t *env)
{
	thread_init(env);
	test_axis2_thread_create(env);
	check_locks();
	check_thread_once();
	test_axis2_thread_detach(env);
	test_axis2_thread_detach2(env);
}
int main (void)
{
	axis2_env_t *env = create_env_with_error_log();

	if (!env)
		return -1;
	run_thread_test(env);
	Sleep(1000);/*win32 specific - to give time for detached threads to execute*/
	axis2_thread_mutex_destroy(thread_lock);
	
	return 0;
}