#ifndef _DWC_MUTEX_C
#define _DWC_MUTEX_C

/*--------------------------------------------------------------------------
 *  Copyright (c) 2001-2004 Igor Daniloff. 
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at this directory.
 *------------------------------------------------------------------------*/
 
#include "dwc_err.h"
#include "dwc_mutex.h"

#if defined(__THREAD_BASED_DW)

#ifndef lint
static const char rcsid[] = "$Id: dwc_mutex.c,v 1.20 2005/09/21 09:20:44 asv Exp $";
#endif

#include <stdlib.h>
#include <string.h>

#include "dwc_macro.h"
#if defined(__UNIX_DW)
#include "dwc_lib.h"
#endif /* UNIX */
#if defined(__WIN32_DW)
#include "dw_winlib.h"
#endif /* WIN32 */

struct DWC_int_mutex_t {
    DWC_string_t      name;
    dwc_sysmutex_t    handle;
};

/* -------------------------------------------------------------------- */
DWC_mutex_t dwc_mutex_create( DWC_const_string_t name )
{
    int         error;
    DWC_mutex_t mutex;

    mutex = DWC_Malloc( DWC_mutex_t, sizeof(struct DWC_int_mutex_t) );
    if( !mutex )
    {
        if( name )
            printLib( DW_LL_ERROR, "dwlib: mutex: creating '%s' failed - no memory", name );
        else
            printLib( DW_LL_ERROR, "dwlib: mutex: creating anonymous failed - no memory" );
        return NULL;
    }
    if( name )
    {
        mutex->name = DWC_Strdup( name );
    }
    else
    {
        mutex->name = DWC_Strdup( "anonymous" );
    }
    if( !mutex->name )
    {
        if( name )
            printLib( DW_LL_ERROR, "dwlib: mutex: creating '%s' failed - no memory", name );
        else
            printLib( DW_LL_ERROR, "dwlib: mutex: creating anonymous failed - no memory" );
        DWC_Free( mutex );
        return NULL;
    }
#if defined(__UNIX_DW)
    error = pthread_mutex_init( &mutex->handle, NULL );
#endif /* __UNIX_DW */
#if defined(__WIN32_DW)
    mutex->handle = CreateMutex( NULL, FALSE, mutex->name );
    if( !mutex->handle )
    {
        error = GetLastError();
    }
    else
    {
        error = 0;
    }
#endif /* __WIN32_DW */
    if( error != 0 )
    {
        printLib( DW_LL_ERROR, "dwlib: mutex: creating '%s' failed - %s", mutex->name, stdlib_error( error ) );
        DWC_Free( mutex->name );
        DWC_Free( mutex );
        return NULL;
    }
    printLib( DW_LL_DEBUG, "dwlib: mutex: '%s' created", mutex->name );
    return mutex;
}

/* -------------------------------------------------------------------- */
dwc_sysmutex_t* dwc_mutex_handle( DWC_mutex_t mutex )
{
    if( !mutex )
    {
        printLib( DW_LL_DEBUG, "dwlib: mutex: null mutex passed for lock" );
        return NULL;
    }
    return &mutex->handle;
}

/* -------------------------------------------------------------------- */
DWC_bool_t dwc_mutex_lock( DWC_mutex_t mutex )
{
    int         error;

    if( !mutex )
    {
        printLib( DW_LL_DEBUG, "dwlib: mutex: null mutex passed for lock" );
        return TRUE;
    }
#if defined(__UNIX_DW)
    error = pthread_mutex_lock( &mutex->handle );
#endif /* __UNIX_DW */
#if defined(__WIN32_DW)
    if( WaitForSingleObject( mutex->handle, INFINITE ) == WAIT_OBJECT_0 )
    {
        error = 0;
    }
    else
    {
        error = GetLastError();
    }
#endif /* __WIN32_DW */
    if( error )
    {
        if( mutex != err_mutex )
            printLib( DW_LL_ERROR, "dwlib: mutex: locking '%s' failed - %s", mutex->name, stdlib_error( error ) );
        else
            printLib( DW_LL_ERROR, "dwlib: mutex: locking '%s' failed", mutex->name );
    }
    else
    {
        printLib( DW_LL_DEBUG, "dwlib: mutex: '%s' locked", mutex->name );
    }
    return ( !error ? TRUE : FALSE );
}

/* -------------------------------------------------------------------- */
DWC_bool_t dwc_mutex_unlock( DWC_mutex_t mutex )
{
    int         error;

    if( !mutex )
    {
        printLib( DW_LL_DEBUG, "dwlib: mutex: null mutex passed for unlock" );
        return TRUE;
    }
#if defined(__UNIX_DW)
    error = pthread_mutex_unlock( &mutex->handle );
#endif /* __UNIX_DW */
#if defined(__WIN32_DW)
    if( ReleaseMutex( mutex->handle ) )
    {
        error = 0;
    }
    else
    {
        error = GetLastError();
    }
#endif /* __WIN32_DW */
    if( error )
    {
        if( mutex != err_mutex )
            printLib( DW_LL_ERROR, "dwlib: mutex: unlocking '%s' failed - %s", mutex->name, stdlib_error( error ) );
        else 
            printLib( DW_LL_ERROR, "dwlib: mutex: unlocking '%s' failed", mutex->name );
    }
    else
    {
        printLib( DW_LL_DEBUG, "dwlib: mutex: '%s' unlocked", mutex->name );
    }
    return ( !error ? TRUE : FALSE );
}

/* -------------------------------------------------------------------- */
DWC_error_code_t dwc_mutex_destroy( DWC_mutex_t mutex )
{
    DWC_error_code_t    retcode;
    int                 error;

    if( !mutex )
    {
        printLib( DW_LL_DEBUG, "dwlib: mutex: null mutex passed for destroy" );
        return DWC_NOERROR;
    }
#if defined(__UNIX_DW)
    error = pthread_mutex_destroy( &mutex->handle );
#endif /* __UNIX_DW */
#if defined(__WIN32_DW)
    if( CloseHandle( mutex->handle ) )
    {
        error = 0;
    }
    else
    {
        error = errno;
    }
#endif /* __WIN32_DW */
    if( error != 0 )
    {
        printLib( DW_LL_ERROR, "dwlib: mutex: destroying '%s' failed - %s", mutex->name, stdlib_error( error ) );
        retcode = DWC_COMMONERROR;
    }
    else
    {
        printLib( DW_LL_DEBUG, "dwlib: mutex: '%s' deleted", mutex->name );
        retcode = DWC_NOERROR;
    }
    DWC_Free( mutex->name );
    DWC_Free( mutex );
    return retcode;
}

#else /* !__THREAD_BASED_DW */

/* -------------------------------------------------------------------- */
DWC_mutex_t dwc_mutex_create( DWC_const_string_t ignore )
{
    return 1;
}

/* -------------------------------------------------------------------- */
dwc_sysmutex_t* dwc_mutex_handle( DWC_mutex_t mutex )
{
    return NULL;
}

/* -------------------------------------------------------------------- */
DWC_bool_t dwc_mutex_lock( DWC_mutex_t ignore )
{
    return TRUE;
}
/* -------------------------------------------------------------------- */
DWC_bool_t dwc_mutex_unlock( DWC_mutex_t ignore )
{
    return TRUE;
}
/* -------------------------------------------------------------------- */
DWC_error_code_t dwc_mutex_destroy( DWC_mutex_t ignore )
{
    return DWC_NOERROR;
}

#endif /* __THREAD_BASED_DW */

#endif /* _DWC_MUTEX_C */

