#include "stdafx.h"

#ifdef _WIN64
#import "..\\vstx64.dll" raw_interfaces_only
#pragma comment(lib,"..\\vstx64.lib")
#else
#import "..\\vstx32.dll" raw_interfaces_only
#pragma comment(lib,"..\\vstx32.lib")
#endif
#include "..\\vstx.h"



typedef int(_stdcall *HandleF)(const TCHAR*, const TCHAR*, WIN32_FIND_DATA*, LPARAM, int);
int _stdcall h(const TCHAR*, const TCHAR*, WIN32_FIND_DATA*, LPARAM, int);
void CheckFiles(const TCHAR * VeryBasePath, const TCHAR * pszPath, TCHAR * pszBase,
	LPARAM data, HandleF HandleFile, int deep)
{
	WIN32_FIND_DATA w32fd;
	HANDLE hFind;
	DWORD dwAtt;
	TCHAR acPath[MAX_PATH];
	TCHAR acBase[MAX_PATH];

	if ('.' == *(pszPath + _tcslen(pszPath) - 1))
		return;

	if (pszBase)
		_stprintf_s(acPath, MAX_PATH, _T("%s\\%s"), pszBase, pszPath);
	else
		_tcscpy_s(acPath, MAX_PATH, pszPath);

	_tcscpy_s(acBase, MAX_PATH, acPath);

	dwAtt = GetFileAttributes(acPath);

	if (0xffffffff == dwAtt)
		// error ...
		return;

	if ((FILE_ATTRIBUTE_DIRECTORY & dwAtt) != 0)
	{
		if ('\\' == acPath[_tcslen(acPath) - 1])
			_tcscat_s(acPath, MAX_PATH, _T("*.*"));
		else
			_tcscat_s(acPath, MAX_PATH, _T("\\*.*"));
	}

	hFind = FindFirstFile(acPath, &w32fd);

	if (hFind == INVALID_HANDLE_VALUE)
		return;

	// recurse if directory...
	if ((FILE_ATTRIBUTE_DIRECTORY & w32fd.dwFileAttributes) != 0 && deep != -2)
	{
		HandleFile(VeryBasePath, acBase, &w32fd, data, deep);
		CheckFiles(VeryBasePath, w32fd.cFileName, acBase, data, HandleFile,
			deep + 1);
	}
	else
		HandleFile(VeryBasePath, acBase, &w32fd, data, deep);

	while (FindNextFile(hFind, &w32fd))
	{
		// recurse if directory...
		if ((FILE_ATTRIBUTE_DIRECTORY & w32fd.dwFileAttributes) != 0 && deep != -2)
		{
			HandleFile(VeryBasePath, acBase, &w32fd, data, deep);
			CheckFiles(VeryBasePath, w32fd.cFileName, acBase, data, HandleFile,
				deep + 1);
		}
		else
			HandleFile(VeryBasePath, acBase, &w32fd, data, deep);
	}

	FindClose(hFind);
}



int wmain(int argc,wchar_t** argv)
	{
	WSADATA wData;
	WSAStartup(MAKEWORD(2, 2), &wData);
	CoInitializeEx(0, COINIT_APARTMENTTHREADED);
	SetErrorMode(SEM_FAILCRITICALERRORS);

	wstring fi2;
	if (argc <= 1)
	{
		printf("usage: scan <path>");
		exit(1);
	}
	else
		fi2 = argv[1];
	vector<wstring> files;

	CheckFiles(fi2.c_str(), fi2.c_str(), 0, (LPARAM)&files,
		[](const TCHAR* a1, const TCHAR* a2, WIN32_FIND_DATA* e, LPARAM rr, int) -> int
		{
			wstring fi = a2;
			fi += L"\\";
			fi += e->cFileName;

			auto e1 = wcsstr(e->cFileName, L".dll");
			auto e2 = wcsstr(e->cFileName, L".vst3");
			if (!e1 && !e2)
				return 1;

			if (e->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
				return 1;
			vector<wstring>* r = (vector<wstring>*)rr;
			r->push_back(fi);
			return 1;

		}
	, 0);

	HANDLE hE = CreateEvent(0, 0, 0, 0);
	HANDLE hE2 = CreateEvent(0, 0, 0, 0);
	auto fr = [](wstring fi,HANDLE hE,HANDLE hE2)
	{
		using namespace vstxlib;

		CoInitializeEx(0, COINIT_APARTMENTTHREADED);
		SetEvent(hE);
		AddVectoredExceptionHandler(1, [](_EXCEPTION_POINTERS *ExceptionInfo) -> LONG
			{
				Sleep(500);
				return EXCEPTION_CONTINUE_EXECUTION;
				ExitThread(0);
				return 0;
			});
		CoInitializeEx(0, COINIT_APARTMENTTHREADED);


		int vt = 0;
		auto hm = LoadTry(fi.c_str(), vt);
		if (vt == 0)
		{
			SetEvent(hE2);
			return;
		}
		if (vt == 1)
		{
			FreeLibrary(hm);
			SetEvent(hE2);
			return;
		}
		if (vt == 5)
		{
#ifdef _WIN64
			wprintf(L" x86 plugin\r\n");
#else
			wprintf(L" x64 plugin\r\n");
#endif
			SetEvent(hE2);
			return;
		}

		VSTSCAN v;

		CComPtr<VSTZ> vv = 0;
		if (vt == 2)
			CreateVST(2, (IUnknown**)&vv);
		else
			CreateVST(3, (IUnknown**)&vv);
//		c((IUnknown**)&vv);

		if (!vv)
		{
			SetEvent(hE2);
			return;
		}

		v.Type = vt;
		v.f = fi;
		auto ei = vv->Load(_bstr_t(fi.c_str()), (ULONG_PTR)hm,0);
		if (FAILED(ei))
		{
			v.Type = 1;
		}

		else
		{
			INT a[4];
			vv->get_Ports(&a[0], &a[1], &a[2], &a[3]);
			v.wins = a[0];
			v.wouts = a[1];
			v.mins = a[2];
			v.mouts = a[3];
			vv->Unload();

			// Show it
			wprintf(L"  ");
			if (v.Type == 2) wprintf(L" VST 2   ");
			if (v.Type == 3) wprintf(L" VST 3   ");
			if (v.Type == 4) wprintf(L" VST 2/3 ");
			wprintf(L"%02u/%02u/%02u/%02u\r\n", a[0], a[1], a[2], a[3]);
		}
		SetEvent(hE2);
	};


	for (auto& fi : files)
	{
		wprintf(L"%s...\r\n", fi.c_str());
		ResetEvent(hE);
		std::thread t(fr, fi,hE,hE2);
		WaitForSingleObject(hE, INFINITE);
		HANDLE hT = (HANDLE)t.native_handle();
		t.detach();
		auto ti = WaitForSingleObject(hE2, 5000);
		if (ti == WAIT_TIMEOUT)
		{
			TerminateThread(hT, 0);
		}

	}


	return 0;
}