// JSkype.cpp : Defines the entry point for the DLL.
// Copyright (C) 2004  B. Lamot

/***********************************************************
* This is a DLL needed for the JNI interaction with the  
* Skype API.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
************************************************************/

#include "stdafx.h"


#define JSKYPE_MSG _T("SkypeControlAPI")

// data ready message
static UINT uiGlobal_MsgID_SkypeControlAPI;
static HWND hGlobal_SkypeAPIWindowHandle=NULL;

// thread id
UINT uThreadId;
// cache for the JNIEnv* pointer
JNIEnv* g_pEnv = NULL;
// cache for the JavaVM* pointer
JavaVM* g_pJvm = NULL;



// cache for the instance handle
HINSTANCE hInstance;

// not visible window handle
HWND hInit_MainWindowHandle;

// debug messages switch
BOOL fGlobal_DumpWindowsMessages=false;


// forward declaration
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void RegisterWindowClass();
unsigned WINAPI CreateWndThread(LPVOID);
void SkypeMsgToJava(unsigned long,const char*);
void SkypeFoundToJava();
void ErrorHandler(LPCTSTR);


BOOL APIENTRY DllMain(HINSTANCE hinstDll, DWORD dwReasion, LPVOID lpReserved) {	
	if(dwReasion == DLL_PROCESS_ATTACH) {
		//printf("DllMain start \n");
		hInstance = hinstDll;
		uiGlobal_MsgID_SkypeControlAPI = RegisterWindowMessage(JSKYPE_MSG);		
		RegisterWindowClass();		
		HANDLE hThread;
		hThread = (HANDLE)_beginthreadex(NULL, 0, &CreateWndThread, NULL, 0, &uThreadId);
		if(!hThread) 
		{
			MessageBox(NULL, _T("Fail creating thread"), NULL, MB_OK);
			return FALSE;
		}
	}
	//printf("DllMain end \n");
	return TRUE;
}

void RegisterWindowClass() {
	//printf("RegisterWindowClass start \n");
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX); 
	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= 0;
	wcex.hCursor		= 0;
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName	= 0;
	wcex.lpszClassName	= _T("dummy window");
	wcex.hIconSm		= 0;

	RegisterClassEx(&wcex);
	//printf("RegisterWindowClass end \n");
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMessage, WPARAM uiParam, LPARAM ulParam) {	
	//printf("WndProc start \n");
	LRESULT lReturnCode;
	bool fIssueDefProc;

	lReturnCode=0;
	fIssueDefProc=false;
	switch(uiMessage)
		{
		case WM_DESTROY:
			hInit_MainWindowHandle=NULL;
			PostQuitMessage(0);
			break;
		case WM_COPYDATA:
			if( hGlobal_SkypeAPIWindowHandle==(HWND)uiParam )
				{				
				PCOPYDATASTRUCT poCopyData=(PCOPYDATASTRUCT)ulParam;				
				printf( "Message from Skype(%u): %.*s\n", poCopyData->dwData, poCopyData->cbData, poCopyData->lpData);
				lReturnCode=1;
				SkypeMsgToJava(poCopyData->dwData,(const char*)poCopyData->lpData);				
				}
			break;
		default:			
			if( hGlobal_SkypeAPIWindowHandle==NULL &&
					((HWND)uiParam)!=hInit_MainWindowHandle && uiMessage==uiGlobal_MsgID_SkypeControlAPI )
				{
				//ErrorHandler(_T("Skype found"));
				hGlobal_SkypeAPIWindowHandle=(HWND)uiParam;
				SkypeFoundToJava();
				lReturnCode=1;
				break;
				}			
			fIssueDefProc=true;
			break;
		}
	if( fIssueDefProc )
		lReturnCode=DefWindowProc( hWnd, uiMessage, uiParam, ulParam);
	if( fGlobal_DumpWindowsMessages )
		{
		printf( "WindowProc: hWindow=0x%08X, MainWindow=0x%08X, Message=%5u, WParam=0x%08X, LParam=0x%08X; Return=%ld%s\n",
			hWnd, hInit_MainWindowHandle, uiMessage, uiParam, ulParam, lReturnCode, fIssueDefProc? " (default)":"");
		}
	//printf("WndProc end \n");
	return(lReturnCode);	
}

unsigned WINAPI CreateWndThread(LPVOID pThreadParam) {
	//printf("CreateWndThread start \n");
	hInit_MainWindowHandle = CreateWindow(_T("dummy window"), NULL, WS_OVERLAPPEDWINDOW,
						CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
						NULL, NULL, hInstance, NULL);
	if(hInit_MainWindowHandle == NULL) {
		MessageBox(NULL, _T("Failed create dummy window"), "Failed", MB_OK | MB_ICONERROR);
		return 0;
	}
	
	jint nSize = 1;
	jint nVms;
	jint nStatus = JNI_GetCreatedJavaVMs(&g_pJvm, nSize, &nVms);

	if(nStatus == 0) {
		nStatus = g_pJvm->AttachCurrentThread(reinterpret_cast<void**>(&g_pEnv), NULL);
		if(nStatus != 0) ErrorHandler(_T("Can not attach thread"));
	}
	else {
		ErrorHandler(_T("Can not get the jvm"));
	}
	
	SendMessage( HWND_BROADCAST, uiGlobal_MsgID_SkypeControlAPI, (WPARAM)hInit_MainWindowHandle, 0);		

	MSG Msg;
	while(GetMessage(&Msg, 0, 0, 0)) {
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	}
	//printf("CreateWnd end \n");
	return Msg.wParam;
} 

void SkypeMsgToJava(unsigned long skypeID,const char* message) {
	//printf("SkypeMsgToJava start \n");
	if(g_pEnv == NULL) {
		ErrorHandler(_T("Callback; cannot do a callback"));
		return;
	}

	jclass cls = g_pEnv->FindClass("net/lamot/java/jskype/windows/Messenger");
	jmethodID mid = g_pEnv->GetStaticMethodID(cls, "onCallback","(ILjava/lang/String;)V");
	if (mid == 0) {
		ErrorHandler(_T("Method onCallback not found"));
	}
	else {
		g_pEnv->ExceptionClear();
		g_pEnv->CallStaticVoidMethod(cls,mid, skypeID, g_pEnv->NewStringUTF(message));				
	}
	//printf("SkypeMsgToJava end \n");
}

void SkypeFoundToJava() {
	//printf("SkypeFoundToJava start \n");
	if(g_pEnv == NULL) {
		ErrorHandler(_T("SkypeFoundToJava; cannot do a callback"));
		return;
	}

	jclass cls = g_pEnv->FindClass("net/lamot/java/jskype/windows/Messenger");
	jmethodID mid = g_pEnv->GetStaticMethodID(cls, "onSkypeFound","()V");
	if (mid == 0) {
		ErrorHandler(_T("Method onSkypeFound not found"));
	}
	else {
		g_pEnv->ExceptionClear();
		g_pEnv->CallStaticVoidMethod(cls,mid, NULL);		
	}
	//printf("SkypeFoundToJava end \n");
}


void ErrorHandler(LPCTSTR pszErrorMessage) {
	//printf("ErrorHandler start \n");
	MessageBox(NULL, pszErrorMessage, _T("Error"), MB_OK | MB_ICONERROR);
}


JNIEXPORT jint JNICALL Java_net_lamot_java_jskype_windows_Messenger_nativeInit
  (JNIEnv *env, jclass jklass)
 {	
	//printf("nativeInit start \n");
	//We could do something here....	
	return 0;
}

JNIEXPORT jint JNICALL Java_net_lamot_java_jskype_windows_Messenger_nativeDestroy
  (JNIEnv *env, jclass jklass)
 {
	PostThreadMessage(uThreadId, WM_QUIT, 0, 0);
	return 0;
}

JNIEXPORT jint JNICALL Java_net_lamot_java_jskype_windows_Messenger_nativeSendMessage
  (JNIEnv *env, jclass jklass, jstring msg) {
	//	printf("nativeSendMessage start \n");
		const char *str;		
		str = env->GetStringUTFChars(msg, 0);
		printf("Sendmessage -->%s<-- lengte: %i\n",str,strlen(str));
		
		//printf( "WindowProc: hWindow=0x%08X, MainWindow=0x%08X, Message=%s",
		//	hGlobal_SkypeAPIWindowHandle, hInit_MainWindowHandle, str);
		COPYDATASTRUCT oCopyData;

		// send command to skype
		oCopyData.dwData=0;
		oCopyData.lpData=(void *)str;
		oCopyData.cbData=strlen(str);
		
		if( SendMessage( hGlobal_SkypeAPIWindowHandle, WM_COPYDATA, (WPARAM)hInit_MainWindowHandle, (LPARAM)&oCopyData)==FALSE ) {
				ErrorHandler(_T("Couldn't send message"));			
				//todo 
				//notify java with this... :)
			
		}
		env->ReleaseStringChars(msg,(const unsigned short*)str);
        return 0;		 
}

