#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _DEBUG
#include <crtdbg.h>
#endif

#include "aosdk/ao.h"
#include "aosdk/eng_protos.h"

#include "xsfc/xsfdrv.h"

#if _MSC_VER >= 1200
#ifdef _WIN64
#pragma comment(linker, "/EXPORT:XSFSetup")
#else
#pragma comment(linker, "/EXPORT:XSFSetup=_XSFSetup@8")
#endif
#endif

#if defined(_MSC_VER) && !defined(_DEBUG)
#pragma comment(linker,"/MERGE:.rdata=.text")
#endif

static void * PASCAL SSFLibAlloc(DWORD dwSize)
{
	return malloc(dwSize);
}
static void PASCAL SSFLibFree(void *lpPtr)
{
	free(lpPtr);
}
static int PASCAL SSFStart(void *lpPtr, DWORD dwSize)
{
	return AO_SUCCESS != ssf_start(lpPtr, dwSize);
}
static void PASCAL SSFGen(void *lpPtr, DWORD dwSamples)
{
	ssf_gen(lpPtr, dwSamples);
}
static void PASCAL SSFTerm(void)
{
	ssf_stop();
}

UINT32 dwChannelMute = 0;

static void PASCAL SSFSetChannelMute(DWORD dwPage, DWORD dwMute)
{
	if (dwPage == 0)
		dwChannelMute = dwMute;
/*
	dwChannelMute &= ~(1 << dwChannel);
	dwChannelMute |= (dwMute & 1) << dwChannel;
*/
}

static void *lpUserWrok = 0;
static LPFNGETLIB_XSFDRV lpfnAOGetLib = 0;
static IXSFDRV ifaossf =
{
	SSFLibAlloc,
	SSFLibFree,
	SSFStart,
	SSFGen,
	SSFTerm,
	2,
	SSFSetChannelMute,
};

IXSFDRV * PASCAL XSFSetup(LPFNGETLIB_XSFDRV lpfn, void *lpWork)
{
	lpfnAOGetLib = lpfn;
	lpUserWrok = lpWork;
	return &ifaossf;
}

int ao_get_lib(char *filename, uint8 **pbuffer, uint64 *plength)
{
	DWORD length32;
	if (!lpfnAOGetLib || lpfnAOGetLib(lpUserWrok, filename, pbuffer, &length32)) return AO_FAIL;
	if (plength) *plength = length32;
	return AO_SUCCESS;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH)
    {
#if defined(_MSC_VER) && defined(_DEBUG)
        _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
        DisableThreadLibraryCalls(hinstDLL);
    }
    return TRUE;
}
