// Everest.cpp : Defines the initialization routines for the DLL.
//
// created by Unwinder
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"

#include <float.h>
#include <shlwapi.h>
#include <afxdllx.h>
#include <winbase.h>
 
#include "Everest.h"
#include "RivaTunerExports.h"
#include "EverestDataSources.h"
#include "MonitoringSourceDesc.h"
/////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
static AFX_EXTENSION_MODULE EverestDLL = { NULL, NULL };
/////////////////////////////////////////////////////////////////////////////
HINSTANCE					g_hModule						= 0;
BOOL						g_bExport						= FALSE;

CEverestDataSources			g_sources;

CString						g_strCache						= "";
/////////////////////////////////////////////////////////////////////////////
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	UNREFERENCED_PARAMETER(lpReserved);

	if (dwReason == DLL_PROCESS_ATTACH)
	{
		if (!AfxInitExtensionModule(EverestDLL, hInstance))
			return 0;

		new CDynLinkLibrary(EverestDLL);

		g_hModule = hInstance;
	}
	else if (dwReason == DLL_PROCESS_DETACH)
	{
		AfxTermExtensionModule(EverestDLL);
	}
	return 1;
}
//////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to get a number of
// data sources in this plugin
//////////////////////////////////////////////////////////////////////
EVEREST_API DWORD GetSourcesNum()
{
	if (!g_sources.GetCount())
		//we'll init sources list if it is not initialized yet
	{
		//get fully qulified path to .cfg file

		char szCfgPath[MAX_PATH];
		GetModuleFileName(g_hModule, szCfgPath, MAX_PATH);
		
		PathRenameExtension(szCfgPath, ".cfg");

		//initialize sources list

		g_sources.Init(szCfgPath);
	}

	return g_sources.GetCount();

}
//////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to get descriptor
// for the specified data source
//////////////////////////////////////////////////////////////////////
EVEREST_API BOOL GetSourceDesc(DWORD dwIndex, LPMONITORING_SOURCE_DESC pDesc)
{
	//get host application module handle

	HMODULE hHost = GetModuleHandle(NULL);
	if (!hHost)
		return FALSE;

	//we'll use this condition to verify if we're under RivaTuner v2.0 RC 15.7
	//(older versions are not supported) or any other compatible host

	GET_HOST_APP_ID_PROC pGetHostAppID = (GET_HOST_APP_ID_PROC)GetProcAddress(hHost, "GetHostAppID");
	if (!pGetHostAppID)
		return FALSE;

	if (!g_sources.GetCount())
		//we'll init sources list if it is not initialized yet
	{
		//get fully qulified path to .cfg file

		char szCfgPath[MAX_PATH];
		GetModuleFileName(g_hModule, szCfgPath, MAX_PATH);
		
		PathRenameExtension(szCfgPath, ".cfg");

		//initialize sources list

		g_sources.Init(szCfgPath);

		//initialize settings

		g_bExport	= GetPrivateProfileInt("Settings", "Export", 0, szCfgPath);
		g_strCache	= "";
	}

	if (dwIndex < (DWORD)g_sources.GetCount())
	{
		LPEVEREST_DATA_SOURCE_DESC pEverestDesc = g_sources.GetSourceDesc(dwIndex);
			//try to get Everest source by index

		if (pEverestDesc)
		{
			//init monitoring source descriptor by Everest monitoring source descriptor
	
			strcpy(pDesc->szName	, pEverestDesc->szName);
			strcpy(pDesc->szDim		, pEverestDesc->szDim);

			pDesc->fltMaxLimit		= pEverestDesc->fltMaxLimit;
			pDesc->fltMinLimit		= pEverestDesc->fltMinLimit;
			pDesc->fltGridDim		= pEverestDesc->fltGridDim;

			if (pDesc->dwVersion >= 0x00010002)
				strcpy(pDesc->szGroup, pEverestDesc->szGroup);

			strcpy(pDesc->szDesc	, pEverestDesc->szDesc);
			return TRUE;
		}
	}

	return FALSE;
}
//////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to get capabilities
// for the specified data source
//////////////////////////////////////////////////////////////////////
EVEREST_API BOOL GetSourceCaps(DWORD dwIndex, DWORD dwCaps, LPDWORD lpResult)
{
	//all sources are system wide monitoring so it is safe to ignore passed
	//index and check just the capability

	switch (dwCaps)
	{
	case  MONITORING_SOURCE_CAPS_SYSTEM_WIDE:
		*lpResult = 1;
		return TRUE;
	}

	return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// This helper function adds specified line to log file
/////////////////////////////////////////////////////////////////////////////
void AppendLog(LPCSTR lpLine, BOOL bAppend)
{
	char szLogPath[MAX_PATH];
	GetModuleFileName(g_hModule, szLogPath, MAX_PATH);
	
	PathRenameExtension(szLogPath, ".log");

	CStdioFile logFile;

	if (bAppend)
	{
		if (!logFile.Open(szLogPath, CFile::modeWrite|CFile::shareDenyWrite))
			if (!logFile.Open(szLogPath, CFile::modeCreate|CFile::modeWrite|CFile::shareDenyWrite))
				return;
	}
	else
		if (!logFile.Open(szLogPath, CFile::modeCreate|CFile::modeWrite|CFile::shareDenyWrite))
			return;

	logFile.SeekToEnd();


	SYSTEMTIME sysTime;
	GetLocalTime(&sysTime);

	CString strTime; strTime.Format("%.2d-%.2d-%.2d, %.2d:%.2d:%.2d ", sysTime.wDay, sysTime.wMonth, sysTime.wYear, sysTime.wHour, sysTime.wMinute, sysTime.wSecond);

	logFile.WriteString(strTime);
	logFile.WriteString(lpLine);
	logFile.WriteString("\n");

	logFile.Close();
	logFile.Flush();
}
/////////////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to poll data sources
/////////////////////////////////////////////////////////////////////////////
EVEREST_API FLOAT GetSourceData(DWORD dwIndex)
{
	FLOAT result = g_sources.GetSourceData(dwIndex);

	if (g_bExport)
		//check if we need to export Everest XML-styled shared memory to log file
	{
		CString strCache = g_sources.GetCache();
			//get last precached Everest XML-styled shared memory

		if (strcmp(g_strCache, strCache))
			//we'll export precached Everest XML-styled shared memory to log file only
			//when it actually changes
		{
			BOOL bAppend = !g_strCache.IsEmpty();
				//we'll overwrite log during the first write in monitorring session and
				//append it during subsequent writes

			AppendLog(strCache, bAppend);
				//write precached Everest XML-styled shared memory to log file and 
				//overwrite log during the first write

			g_strCache = strCache;
				//save last precached Everest XML-styled shared memory
		}
	}

	return result;
}
/////////////////////////////////////////////////////////////////////////////
