// JniorSimulator.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "JniorSimulator.h"
#include "Lock.h"

#include <map>
#include <iostream>
using namespace std;

#include "jnior.h"

#ifdef _MANAGED
#pragma managed(push, off)
#endif



#define INVALID_JNIOR_HANDLE		-1


	
bool QUIT = false;

static WSADATA wd;				// winsock data
bool initialized;				// wisock initialized sucessfully ?

HANDLE* hServerThread = NULL;
DWORD* dwServerThreadId = NULL;

std::map<int, CJnior*> connections;
CONNECT_PARAMS* m_cp;

Mutex m_mutex;

CALLBACKNOTIFY ServerInfoNotify = NULL;


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	// Startup Winsock
	int iResult = WSAStartup( MAKEWORD(2,2), &wd );
	if ( iResult != NO_ERROR )
	{
		initialized = FALSE;
		printf("Error at WSAStartup()\n");
		return FALSE;
	}


	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		QUIT = true;
		break;
	}
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif



int CreateJniorConnection(CONNECT_PARAMS* cp) {
	CJnior* jnior = new CJnior(cp);
	connections[cp->port] = jnior;

	return jnior->m_handle;
}

extern "C" JNIORDLL_API int StartServer(CONNECT_PARAMS* cp, int count) {
	hServerThread = new HANDLE[count];
	dwServerThreadId = new DWORD[count];

	m_cp = new CONNECT_PARAMS();
	m_cp->host = new char[strlen(cp->host) + 1];
	strncpy(m_cp->host, cp->host, strlen(cp->host));
	m_cp->host[strlen(cp->host)] = '\0';
	m_cp->port = cp->port;

	Logger( "Simulator.log", "Starting JNIOR Simulator Server!" );

	//ServerInfoNotify = lProcAddress;

	for (int i = 0; i < count; i++) {
		CONNECT_PARAMS* newCp = new CONNECT_PARAMS();
		newCp->host = new char[strlen(cp->host) + 1];
		strncpy(newCp->host, cp->host, strlen(cp->host));
		newCp->host[strlen(cp->host)] = '\0';
		newCp->port = cp->port + i;

		int handle = CreateJniorConnection(newCp);
		CJnior* jnior = connections[m_cp->port + handle];

		jnior->ServerInfoNotify = ServerInfoNotify;

		hServerThread[i] = CreateThread(
			NULL,										// default security attributes 
			0,											// use default stack size  
			(LPTHREAD_START_ROUTINE) jnior->AcceptConnections,	// thread function 
			jnior,											// argument to thread function 
			0,											// use default creation flags 
			&dwServerThreadId[i]);							// returns the thread identifier 
	}

	return 0;
}



extern "C" JNIORDLL_API int SetInputCount(int handle, int inputCount) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;
	jnior->SetInputCount(inputCount);
}

extern "C" JNIORDLL_API int GetInputCount(int handle) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;
	return jnior->GetInputCount();
}

extern "C" JNIORDLL_API int GetInput(int handle, int channel) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;

	return jnior->GetInput(channel);
}

extern "C" JNIORDLL_API int GetInputs(int handle) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;

	return jnior->GetInputs();
}

extern "C" JNIORDLL_API int SetInput(int handle, int channel, int state) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;

	return jnior->SetInputs(1 << channel, state << channel);
}

extern "C" JNIORDLL_API int SetInputs(int handle, int channelMask, int stateMask) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;

	return jnior->SetInputs(channelMask, stateMask);
}

extern "C" JNIORDLL_API int SetOutputCount(int handle, int outputCount) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;
	jnior->SetOutputCount(outputCount);
}

extern "C" JNIORDLL_API int GetOutputCount(int handle) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;
	return jnior->GetOutputCount();
}

extern "C" JNIORDLL_API int GetOutput(int handle, int channel) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;

	return jnior->GetOutput(channel);
}

extern "C" JNIORDLL_API int GetOutputs(int handle) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;

	return jnior->GetOutputs();
}

extern "C" JNIORDLL_API int SetOutput(int handle, int channel, int state) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;

	return jnior->SetOutputs(1 << channel, state << channel);
}

extern "C" JNIORDLL_API int SetOutputs(int handle, int channelMask, int stateMask) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;

	return jnior->SetOutputs(channelMask, stateMask);
}

extern "C" JNIORDLL_API int Disconnect(int handle) {
	if (connections.size() == 0) return STATUS_FAILED;
	CJnior* jnior = connections[m_cp->port + handle];
	if (jnior == NULL) return INVALID_JNIOR_HANDLE;

	return jnior->Disconnect();
}



extern "C" JNIORDLL_API int SetServerInfoCallback(CALLBACKNOTIFY lProcAddress)
{
	ServerInfoNotify = lProcAddress;

	return 0;
}