/**
{file:
	{name: LmiAndroid.h}
	{description: Registers global Android objects.}
	{copyright:
		(c) 2011-2016 Vidyo, Inc.,
		433 Hackensack Avenue,
		Hackensack, NJ  07601.

		All rights reserved.

		The information contained herein is proprietary to Vidyo, Inc.
		and shall not be reproduced, copied (in whole or in part), adapted,
		modified, disseminated, transmitted, transcribed, stored in a retrieval
		system, or translated into any language in any form by any means
		without the express written consent of Vidyo, Inc.
				  ***** CONFIDENTIAL *****
	}
}
*/
#ifndef LMI_LMIANDROID_H
#define LMI_LMIANDROID_H

#include <Lmi/Utils/LmiTypes.h>
#include <Lmi/Os/LmiMutex.h>

LMI_BEGIN_EXTERN_C

LmiBool LmiAndroidInitialize(void);
void LmiAndroidUninitialize(void);

#if ANDROID
#include <jni.h>
#else /* ANDROID */
typedef LmiInt JavaVM;
typedef LmiInt JNIEnv;
typedef LmiVoidPtr jobject;
typedef LmiInt jclass;
typedef LmiVoidPtr jmethodID;
typedef LmiVoidPtr jfieldID;
#endif /* ANDROID */

#define LMI_ANDROID_CHECK_ERROR(condition, category, message, label) \
if(condition) { \
    LmiLogError(category, message); \
    goto label; \
}

#define LMI_ANDROID_CHECK_EXCEPTION(env, category, message, label) \
if(LmiAndroidCheckException(env, category, message)) \
    goto label; \


/*
{function:
	{name: LmiAndroidRegisterDefaultVM}
	{parent: LmiAndroid}
	{description: Registers the default Android Virtual Machine pointer that will be used for JNI calls.}
	{prototype: void LmiAndroidRegisterDefaultVM(JavaVM *vm)}
	{parameter: {name: vm} {description: A pointer to the Java Virtual Machine.}}
	{note: This function must be called on Android platforms before any SDK functions.}
}
*/
void LmiAndroidRegisterDefaultVM(JavaVM *vm);

/*
{function:
	{name: LmiAndroidUnregisterDefaultVM}
	{parent: LmiAndroid}
	{description: Unregisters the default Android Virtual Machine pointer.}
	{prototype: void LmiAndroidRegisterDefaultVM(void)}
	{note: This function must be called on Android platforms before resources are released.}
}
*/
void LmiAndroidUnregisterDefaultVM(void);

/*
{function:
	{name: LmiAndroidGetDefaultVM}
	{parent: LmiAndroid}
	{description: Gets the default Android Virtual Machine pointer.}
	{prototype: JavaVM *LmiAndroidGetDefaultVM(void)}
	{return: A pointer to the default Android Virtual Machine on success, or NULL on failure.}
}
*/
JavaVM *LmiAndroidGetDefaultVM(void);

/*
{function:
	{name: LmiAndroidRegisterDefaultContext}
	{parent: LmiAndroid}
	{description: Registers the current Context object that will be used to construct Cameras and Windows.}
	{prototype: void LmiAndroidRegisterDefaultContext(JNIEnv* env, jobject context)}
	{parameter: {name: env} {description: Current JNI environment.}}
	{parameter: {name: context} {description: An android.content.Context Java object.}}
	{note: In most circumstances, the Context will be the application's Activity or Application. Some functions (notably, LmiWindowConstruct, though not LmiWindowConstructChildOfExternal) will require an actual Activity class.}
	{note: This function must be called on Android platforms before
		any SDK DeviceManager or Ui functions.  It may be called again at any time to change the default Context.}
}
*/
void LmiAndroidRegisterDefaultContext(JNIEnv* env, jobject context);

/*
{function:
	{name: LmiAndroidUnregisterDefaultContext}
	{parent: LmiAndroid}
	{description: Unregisters the current Context object that will be used to construct Cameras and Windows.}
	{prototype: void LmiAndroidUnregisterDefaultContext(JNIEnv* env)}
	{parameter: {name: env} {description: Current JNI environment.}}
	{note: This function must be called on Android platforms for resources to be released.}
}
*/
void LmiAndroidUnregisterDefaultContext(JNIEnv* env);

/*
{function:
	{name: LmiAndroidGetDefaultContext}
	{parent: LmiAndroid}
	{description: Gets the current Context object.}
	{prototype: jobject LmiAndroidGetDefaultContext(void)}
	{return: The default Context object on success, or NULL on failure.}
}
*/
jobject LmiAndroidGetDefaultContext(void);


/**
{type:
	{name: LmiAndroid}
	{parent: Os}
	{include: Lmi/Os/LmiAndroid.h}
	{description: Stores global state of android applications.}
}
*/

typedef struct LmiAndroid_ {
	JavaVM *vm;
	JNIEnv *env;
	jobject classLoader;
	jmethodID classLoaderLoadClass;
	jmethodID stringReplace;
	LmiBool isAttached;
	LmiMutex lock;
} LmiAndroid;

/**
{function:
	{name: LmiAndroidConstruct}
	{parent: LmiAndroid}
	{description: Constructs a LmiAndroid object that keeps global Android data.}
	{prototype: LmiAndroid *LmiAndroidConstruct(LmiAndroid *a)}
	{parameter: {name: a} {description: The LmiAndroid object.}}
	{return: A pointer to a constructed object on success, or NULL on failure.}
	{note: On Android platform, some objects need to be stored globally so that
		they can be accessed by various Android specific SDK components. }
}
*/
LmiAndroid *LmiAndroidConstruct(LmiAndroid *a);

/**
{function:
	{name: LmiAndroidDestruct}
	{parent: LmiAndroid}
	{description: Destructs an LmiAndroid object.}
	{prototype: void LmiAndroidDestruct(LmiAndroid *a)}
	{parameter: {name: a} {description: The LmiAndroid object.}}
}
*/
void LmiAndroidDestruct(LmiAndroid *a);

/*
{function:
	{name: LmiAndroidGetEnv}
	{parent: LmiAndroid}
	{description: Gets a thread local JNIEnv pointer from LmiAndroid object.}
	{prototype: JNIEnv *LmiAndroidGetEnv(LmiAndroid *a)}
	{parameter: {name: a} {description: The LmiAndroid object.}}
	{return: A thread local JNIEnv pointer on success, or NULL on failure.}
	{note: This function call must be followed by a call to LmiAndroidReleaseEnv() and
		the thread calling LmiAndroidGetEnv() should not wait on another thread
		before calling LmiAndroidReleaseEnv(). }
}
*/
JNIEnv *LmiAndroidGetEnv(LmiAndroid *a);

/*
{function:
	{name: LmiAndroidReleaseEnv}
	{parent: LmiAndroid}
	{description: Releases a thread local JNIEnv pointer from LmiAndroid object.}
	{prototype: void LmiAndroidReleaseEnv(LmiAndroid *a)}
	{parameter: {name: a} {description: The LmiAndroid object.}}
	{note: Follow the note on LmiAndroidGetEnv(). }
}
*/
void LmiAndroidReleaseEnv(LmiAndroid *a);

/*
{function:
	{name: LmiAndroidCheckExceptionDefault}
	{parent: LmiAndroid}
	{description: Clears JNI exception on env and print message to default log category.}
	{prototype: LmiBool LmiAndroidCheckExceptionDefault(JNIEnv *env, const char *message)}
	{parameter: {name: env} {description: The current JNI environment.}}
	{parameter: {name: message} {description: Exception message.}}
	{return: If there was an exception to be cleared LMI_TRUE, otherwise LMI_FALSE.}
}
*/
LmiBool LmiAndroidCheckExceptionDefault(JNIEnv *env, const char *message);

/*
{function:
	{name: LmiAndroidCheckException}
	{parent: LmiAndroid}
	{description: Clears JNI exception on env and print message to specific log category.}
	{prototype: LmiBool LmiAndroidCheckException(JNIEnv *env, LmiLogCategory logCategory, const char *message)}
	{parameter: {name: env} {description: The current JNI environment.}}
	{parameter: {name: logCategory} {description: Log category to which print exception message.}}
	{parameter: {name: message} {description: Exception message.}}
	{return: If there was an exception to be cleared LMI_TRUE, otherwise LMI_FALSE.}
}
*/
LmiBool LmiAndroidCheckException(JNIEnv *env, LmiLogCategory logCategory, const char *message);

/* private */
typedef void (*LmiSchedulerRunnable)(JNIEnv *env, void *userData);

typedef enum {
	LMI_ANDROID_THREAD_TYPE_MAIN = 0,
	LMI_ANDROID_THREAD_TYPE_NEW = 1
} LmiAndroidThreadType;

void LmiAndroidRunOnThreadBlocking(LmiAndroidThreadType threadType, LmiSchedulerRunnable runnable, void *userData);

jclass *LmiAndroidGetCacheClassReference(LmiAndroid *a, const char *classPath);
void LmiAndroidReleaseCacheClassReference(LmiAndroid *a, jclass jClass);
jmethodID LmiAndroidGetMethodId(LmiAndroid *a, jclass jClass, const char *methodName, const char *methodSignature);
jmethodID LmiAndroidGetStaticMethodId(LmiAndroid *a, jclass jClass, const char *methodName, const char *methodSignature);
jfieldID LmiAndroidGetFieldId(LmiAndroid *a, jclass jClass, const char *fieldName, const char *fieldSignature);
jfieldID LmiAndroidGetStaticFieldId(LmiAndroid *a, jclass jClass, const char *fieldName, const char *fieldSignature);

LMI_END_EXTERN_C
#endif /* LMI_LMIANDROID_H */
