
// BKOscScr.cpp : файл реализации
//

#include "stdafx.h"
#include "BKOscScr.h"
#include "Config.h"

#undef BKOSCDLL_EXPORTS

#include "BKOscScrOGL\BKOscScrOGL.h"
#include "BKOscScrD2D\BKOscScrD2D.h"
#include "BKOscScrGDI\BKOscScrGDI.h"

#include "BKErrMsgSys.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// диалоговое окно CBKOscScr
IMPLEMENT_DYNAMIC(CBKOscScr, CWnd)


#ifdef _WIN64
#define BK_OSCOGLDLLNAME _T("BKOscScrOGL_x64.dll")
#define BK_OSCD2DDLLNAME _T("BKOscScrD2D_x64.dll")
#define BK_OSCGDIDLLNAME _T("BKOscScrGDI_x64.dll")
#else
#define BK_OSCOGLDLLNAME _T("BKOscScrOGL.dll")
#define BK_OSCD2DDLLNAME _T("BKOscScrD2D.dll")
#define BK_OSCGDIDLLNAME _T("BKOscScrGDI.dll")
#endif

#define BK_OSCSCRDLLFUNC "GetBKOscScr"

CBKOscScr::CBKOscScr(int nRenderType)
	: m_pSharedFunc(nullptr)
	, m_hModule(nullptr)
	, m_hwndScreen(nullptr)  // Screen View window handle
	, m_inBuf(nullptr)
	, m_inLen(0)
	, m_inLenByte(0)
{
	switch (nRenderType)//Берём номер из конфига. 0 - OGL, 1 - D2D
	{
		default:
		case CONF_OSCILL_RENDER_OGL:
			m_strDllName = BK_OSCOGLDLLNAME;
			break;

		case CONF_OSCILL_RENDER_D2D:
			m_strDllName = BK_OSCD2DDLLNAME;
			break;

		case CONF_OSCILL_RENDER_GDI:
			m_strDllName = BK_OSCGDIDLLNAME;
			break;
	}

	m_hModule = LoadLibrary(m_strDllName);

	if (m_hModule)
	{
		auto pGetBKOSC = reinterpret_cast<GETBKOSC>(GetProcAddress(m_hModule, BK_OSCSCRDLLFUNC));

		if (pGetBKOSC)
		{
			switch (nRenderType)//Берём номер из конфига. 0 - OGL, 1 - D2D, 2 - GDI+ (глючный)
			{
				default:
				case 0:
					m_pSharedFunc = dynamic_cast<CBKOscScrOGL *>(pGetBKOSC());
					break;

				case 1:
					m_pSharedFunc = dynamic_cast<CBKOscScrD2D *>(pGetBKOSC());
					break;

				case 2:
					m_pSharedFunc = dynamic_cast<CBKOscScrGDI *>(pGetBKOSC());
					break;
			}
		}
		else
		{
			CString str;
			str.Format(g_pstrErrors[BK_ERROR_SCRDLLFUNCERR], _T(BK_OSCSCRDLLFUNC));
			CBKMessageBox(str, MB_OK);
		}
	}
	else
	{
		CString str;
		str.Format(g_pstrErrors[BK_ERROR_SCRDLLINITERR], m_strDllName);
		CBKMessageBox(str, MB_OK);
	}
}

CBKOscScr::~CBKOscScr()
{
	if (m_pSharedFunc)
	{
		delete m_pSharedFunc;
	}

	if (m_hModule)
	{
		FreeLibrary(m_hModule);
	}
}

BEGIN_MESSAGE_MAP(CBKOscScr, CWnd)
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_SIZE()
END_MESSAGE_MAP()


// обработчики сообщений CBKOscScr


int CBKOscScr::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
	{
		return -1;
	}

	if (m_pSharedFunc == nullptr)
	{
		CBKMessageBox(g_pstrErrors[BK_ERROR_SCRDLLFUNCPTRERR], MB_OK);
		return -1;
	}

	m_hwndScreen = GetSafeHwnd();

	if (m_hwndScreen != nullptr)
	{
		if (SUCCEEDED(m_pSharedFunc->BKOSC_Screen_Init(this)))
		{
			return TRUE;  // возврат значения TRUE, если фокус не передан элементу управления
		}
		else
		{
			CString str;
			str.Format(g_pstrErrors[BK_ERROR_SCRDLLINITERR], m_strDllName);
			CBKMessageBox(str, MB_OK);
			m_pSharedFunc->BKOSC_Screen_Done();
			return -1;
		}
	}

	return -1;
}

void CBKOscScr::OnDestroy()
{
	//перед выходом, дождёмся прекращения рисования
	{
		std::lock_guard<std::mutex> lk(m_lockBusy);
		//и заблокируем рисование во избежание потенциальных дедлоков
		m_pSharedFunc->BKOSC_Screen_Done();
	}
	SAFE_DELETE_ARRAY(m_inBuf);
	CWnd::OnDestroy();
}


void CBKOscScr::OnPaint()
{
	std::lock_guard<std::mutex> lk(m_lockBusy);
	CPaintDC dc(this); // device context for painting
	// TODO: добавьте свой код обработчика сообщений
	// Не вызывать CBKOscScr::OnPaint() для сообщений рисования
	m_pSharedFunc->BKOSC_OnDisplay(m_inBuf, m_inLen);
}

void CBKOscScr::OnSize(UINT nType, int cx, int cy)
{
	std::lock_guard<std::mutex> lk(m_lockBusy);
	CWnd::OnSize(nType, cx, cy);
	m_pSharedFunc->BKOSC_OnSize(cx, cy);
}

BOOL CBKOscScr::OnEraseBkgnd(CDC *pDC)
{
	return TRUE;
}


void CBKOscScr::SetBuffer(int buffer_len)
{
	if (m_inLenByte != buffer_len)
	{
		m_inLenByte = buffer_len;
		m_inLen = buffer_len / SAMPLE_LENGTH; //длина буфера в сэмплах
		SAFE_DELETE_ARRAY(m_inBuf); //ранее созданны массив надо удалить, если он был
		m_inBuf = new SAMPLE_TYPE[buffer_len / sizeof(SAMPLE_TYPE)]; //новый массив новой длины
		m_pSharedFunc->BKOSC_OnSetBuffer(buffer_len);
	}
}

void CBKOscScr::FillBuffer(uint8_t *inBuf)
{
	std::lock_guard<std::mutex> lk(m_lockBusy);
	memcpy(m_inBuf, inBuf, m_inLenByte);
}

