#include "CriticalSection.h"

#include <stdlib.h>
#include <stdio.h>

#include "CountdownTimer.h"

#include "YBWCManager.h"
extern YBWCManager* g_pYBWCManagerInstance;

static long gnGlobalEnterTimeOutCount = 0;
static long gnGlobalEnteredCount	    = 0;

CriticalSection* CriticalSection_Construct(CriticalSection* pThis, char* sCriticalSectionName)
{
#if defined(_WIN32) || defined(_WIN64)
  pThis->hMutexCriticalSection            = NULL;
  pThis->sCriticalSectionName[0]          = '\0';
  pThis->bEntered                         = FALSE;

  strcpy(pThis->sCriticalSectionName, sCriticalSectionName);

	pThis->hMutexCriticalSection = CreateMutex(NULL,				                // pointer to security attributes
										                         false,				                // flag for initial ownership
										                         pThis->sCriticalSectionName  // pointer to mutex-object name
	       							                       );
	if(pThis->hMutexCriticalSection)
  {
    if(g_pYBWCManagerInstance->pFruitConfiguration->nFruitDebugLevel >= FRUIT_DEBUG_LEVEL_FORCE_OUTPUT)
    {
      YBWCManager_Printf(g_pYBWCManagerInstance, 
                         "INFO CriticalSection_Construct(... <%s> successful created\n",
                         pThis->sCriticalSectionName);
    }
  }
  else
	{
    if(g_pYBWCManagerInstance->pFruitConfiguration->nFruitDebugLevel >= FRUIT_DEBUG_LEVEL_FORCE_OUTPUT)
    {
      YBWCManager_Printf(g_pYBWCManagerInstance, 
                         "ERROR CriticalSection_Construct(... create for <%s> failed\n",
                         pThis->sCriticalSectionName);
    }
	}

  return pThis;

#else // assume POSIX

// kh 19.02.07 not really supported for linux, because the PSHARED parameter ist still(?) not supported

  int nResult;

  pThis->sCriticalSectionName[0]          = '\0';
  pThis->bEntered                         = FALSE;

  strcpy(pThis->sCriticalSectionName, sCriticalSectionName);

  nResult = 0; // kh 25.05.07 disable sem_... all references 
/*
	nResult = sem_init(&pThis->sem, 
                     1,                    // kh 16.02.07 make it process shared
                     1);                   // kh 16.02.07 initial value
*/

	if(nResult != -1)
  {
    if(g_pYBWCManagerInstance->pFruitConfiguration->nFruitDebugLevel >= FRUIT_DEBUG_LEVEL_FORCE_OUTPUT)
    {
      YBWCManager_Printf(g_pYBWCManagerInstance, 
                         "INFO CriticalSection_Construct(... <%s> successful created\n",
                         pThis->sCriticalSectionName);
    }
  }
  else
	{
    if(g_pYBWCManagerInstance->pFruitConfiguration->nFruitDebugLevel >= FRUIT_DEBUG_LEVEL_FORCE_OUTPUT)
    {
      YBWCManager_Printf(g_pYBWCManagerInstance, 
                         "ERROR CriticalSection_Construct(... create for <%s> failed\n",
                         pThis->sCriticalSectionName);
    }
	}

  return pThis;

#endif
}

void CriticalSection_Destruct(CriticalSection* pThis)
{
#if defined(_WIN32) || defined(_WIN64)
	if(pThis->hMutexCriticalSection)
	{
		if(pThis->bEntered)
		{

// kh 16.02.07 defensive, because CloseHandle(... has no implicit ReleaseMutex(...
			CriticalSection_Leave(pThis);
		}

		if(CloseHandle(pThis->hMutexCriticalSection))
    {
    }
    else
		{
      if(g_pYBWCManagerInstance->pFruitConfiguration->nFruitDebugLevel >= FRUIT_DEBUG_LEVEL_FORCE_OUTPUT)
      {
        YBWCManager_Printf(g_pYBWCManagerInstance, 
                           "ERROR CriticalSection_Destruct(... close handle for <%s> failed\n",
                           pThis->sCriticalSectionName);
      }
		}
	}

#else // assume POSIX

// kh 19.02.07 not really supported for linux, because the PSHARED parameter ist still(?) not supported

//if(pThis->hMutexCriticalSection)
	{
		if(pThis->bEntered)
		{

// kh 16.02.07 defensive, because CloseHandle(... has no implicit ReleaseMutex(...
			CriticalSection_Leave(pThis);
		}

// kh 25.05.07 disable sem_... all references 
/*
		sem_destroy(&pThis->sem);
*/

    if(true)
    {
    }
    else
		{
      if(g_pYBWCManagerInstance->pFruitConfiguration->nFruitDebugLevel >= FRUIT_DEBUG_LEVEL_FORCE_OUTPUT)
      {
        YBWCManager_Printf(g_pYBWCManagerInstance, 
                           "ERROR CriticalSection_Destruct(... sem_destroy(... for <%s> failed\n",
                           pThis->sCriticalSectionName);
      }
		}
	}
#endif
}

void CriticalSection_Enter(CriticalSection* pThis)
{
#if defined(_WIN32) || defined(_WIN64)
	DWORD dwResult;

  while((dwResult = WaitForSingleObject(pThis->hMutexCriticalSection, 
                                        CRITICAL_SECTION_ENTER_TIMEOUT_INTERVAL)) != WAIT_OBJECT_0)
	{	
    if(g_pYBWCManagerInstance->pFruitConfiguration->nFruitDebugLevel >= FRUIT_DEBUG_LEVEL_FORCE_OUTPUT)
    {
      YBWCManager_Printf(g_pYBWCManagerInstance, 
                         "INFO <%s> waiting for void CriticalSection_Enter(...\n",
                         pThis->sCriticalSectionName);
    }

// kh 16.02.07 not at the moment for performance reasons (rather used for profiling anyway)
//  InterlockedIncrement(&gnGlobalEnterTimeOutCount); 
	}

	pThis->bEntered = TRUE;
	gnGlobalEnteredCount++;

#else // assume POSIX

// kh 19.02.07 not really supported for linux, because the PSHARED parameter ist still(?) not supported

// kh 25.05.07 disable sem_... all references 
/*
  sem_wait(&pThis->sem);
*/

	pThis->bEntered = TRUE;
	gnGlobalEnteredCount++;

#endif
}

void CriticalSection_Leave(CriticalSection* pThis)
{
#if defined(_WIN32) || defined(_WIN64)
	if(ReleaseMutex(pThis->hMutexCriticalSection))
  {
  }
  else
	{
    if(g_pYBWCManagerInstance->pFruitConfiguration->nFruitDebugLevel >= FRUIT_DEBUG_LEVEL_FORCE_OUTPUT)
    {
      YBWCManager_Printf(g_pYBWCManagerInstance, 
                         "ERROR CriticalSection_Leave(... ReleaseMutex for <%s> failed\n",
                         pThis->sCriticalSectionName);
    }
	}

	pThis->bEntered = FALSE;
	gnGlobalEnteredCount--;

#else // assume POSIX

// kh 19.02.07 not really supported for linux, because the PSHARED parameter ist still(?) not supported

// kh 25.05.07 disable sem_... all references 
/*
  sem_post(&pThis->sem);
*/

	pThis->bEntered = FALSE;
	gnGlobalEnteredCount--;

#endif
}
