#include "StdAfx.h"
#include <windows.h>
#include <dshow.h>
#include <jni.h>
#include "DirectShowVideoSystem.h"

jobject exceptionClassRef;

static LPWSTR ToErrorMessage(HRESULT hRes)
{
	LPWSTR errMsg = NULL;
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hRes, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),errMsg, 0, NULL);
	return errMsg;
}

DirectShowVideoSystem::DirectShowVideoSystem(void)
{
}




JNIEXPORT jint JNICALL Java_ips_media_jnm_impl_directshow_DSVideoSystem_init(JNIEnv *env, jobject jobj){
	jclass exceptionCls = env->FindClass("ips/media/NativeMediaSystemException");
	if (exceptionCls == NULL){
		printf("Could not find exception class\n");
		fflush(stdout);
		return NATIVE_API_VERSION;
	}
	//exceptionClassRef=env->NewWeakGlobalRef(exceptionCls);
	exceptionClassRef = env->NewGlobalRef(exceptionCls);
	if (exceptionClassRef == NULL){
		printf("Could not get excption class reference\n");
		fflush(stdout);
	}

	HRESULT hr = CoInitialize(NULL);
	if (FAILED(hr))
	{
		printf("COM init failed\n");
		fflush(stdout);
		//return NULL;
	}
	else{
#ifdef DEBUG
		printf("DirectShow JNM initialized (native API version %d)\n",NATIVE_API_VERSION);
		fflush(stdout);
#endif
	}
	return NATIVE_API_VERSION;

}

JNIEXPORT void JNICALL Java_ips_media_jnm_impl_directshow_DSVideoSystem_enumerateVideoCaptureSources(JNIEnv *env, jobject obj){
	
HRESULT hr=EnumerateVideoDevices();
}


JNIEXPORT jlong JNICALL Java_ips_media_jnm_impl_directshow_DSVideoSystem_nativeJFXWindowHwn(JNIEnv *env, jobject obj,jobject jfxWindow){

	// Get toolkit stage (class TKStage) from JavaFX abstract Window
	jclass wCls=env->FindClass("javafx/stage/Window");
	jclass tkStCls = env->FindClass("com/sun/javafx/tk/TKStage");
	// Java 9 ea
	jmethodID mId1 = env->GetMethodID(wCls, "getPeer", "()Lcom/sun/javafx/tk/TKStage;");
	if (mId1 == NULL || env->ExceptionOccurred()){
		env->ExceptionClear();
		 // Java 8
		mId1 = env->GetMethodID(wCls, "impl_getPeer", "()Lcom/sun/javafx/tk/TKStage;");
	}
	jobject tkStage = env->CallObjectMethod(jfxWindow, mId1);
	
	jclass wStCls = env->FindClass("com/sun/javafx/tk/quantum/WindowStage");
	jmethodID mId2 = env->GetMethodID(wStCls, "getPlatformWindow", "()Lcom/sun/glass/ui/Window;");

	jobject glassW= env->CallObjectMethod(tkStage, mId2);
	jclass glassWCls = env->FindClass("com/sun/glass/ui/Window");
	//jmethodID mId3 = env->GetMethodID(glassWCls, "getNativeHandle", "()J");
	jmethodID mId3 = env->GetMethodID(glassWCls, "getNativeWindow", "()J");
	jlong hwnd = env->CallLongMethod(glassW, mId3);

	return hwnd;
}


JNIEXPORT void JNICALL Java_ips_media_jnm_impl_directshow_DSVideoSystem_release(JNIEnv *env, jobject jobj){
CoUninitialize();
}


HRESULT EnumerateVideoDevices()
{
	IEnumMoniker* enumMoniker;
    // Create the System Device Enumerator.
    ICreateDevEnum *pDevEnum;
    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,  
        CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));

    if (SUCCEEDED(hr))
    {
        // Create an enumerator for the category.
        hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &enumMoniker, 0);
        if (hr != S_OK)
        {
            //hr = VFW_E_NOT_FOUND;  // The category is empty. Treat as an error.
			if(hr==S_FALSE){

			}
			pDevEnum->Release();
			if(hr==S_FALSE){
				// successfull enumeration, but no devices found
				return S_OK;
			}else{
				// error 
				return hr;
			}
        }
        pDevEnum->Release();

		IMoniker *pMoniker = NULL;

    while (enumMoniker->Next(1, &pMoniker, NULL) == S_OK)
    {
        IPropertyBag *pPropBag;
        HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
        if (FAILED(hr))
        {
            pMoniker->Release();
            continue;  
        } 
		IMalloc* pMalloc;
		CoGetMalloc(1,&pMalloc);
		LPOLESTR displayName;
		pMoniker->GetDisplayName(0,0,&displayName);
		printf("display name: %S\n", displayName);
		pMalloc->Free(displayName);

        VARIANT var;
        VariantInit(&var);

        // Get description or friendly name.
        hr = pPropBag->Read(L"Description", &var, 0);
        if (FAILED(hr))
        {
            hr = pPropBag->Read(L"FriendlyName", &var, 0);
        }
        if (SUCCEEDED(hr))
        {
            printf("%S\n", var.bstrVal);
            VariantClear(&var); 
        }

        //hr = pPropBag->Write(L"FriendlyName", &var);

        // WaveInID applies only to audio capture devices.
        hr = pPropBag->Read(L"WaveInID", &var, 0);
        if (SUCCEEDED(hr))
        {
            printf("WaveIn ID: %d\n", var.lVal);
            VariantClear(&var); 
        }

        hr = pPropBag->Read(L"DevicePath", &var, 0);
        if (SUCCEEDED(hr))
        {
            // The device path is not intended for display.
            printf("Device path: %S\n", var.bstrVal);
            VariantClear(&var); 
        }
	/*
		IROTData* iRotData;
		hr = pMoniker->QueryInterface(IID_IROTData, (void **)&iRotData);
	if(FAILED(hr))return hr;
	iRotData->GetComparisonData(
*/
        pPropBag->Release();
        pMoniker->Release();
    }
	}
	fflush(stdout);
    return hr;
}

DirectShowVideoSystem::~DirectShowVideoSystem(void)
{

}
