/*
 * Class:     org_iotivity_ca_jar_caleinterface
 * Method:    caManagerLeServicesDiscoveredCallback
 * Signature: (Landroid/bluetooth/BluetoothGatt;I)V
 */
JNIEXPORT void JNICALL
Java_org_iotivity_ca_CaLeClientInterface_caManagerLeServicesDiscoveredCallback(JNIEnv *env,
                                                                               jobject obj,
                                                                               jobject gatt,
                                                                               jint status)
{
    OIC_LOG_V(DEBUG, TAG, "caManagerLeServicesDiscoveredCallback - status %d: ", status);
    VERIFY_NON_NULL_VOID(env, TAG, "env");
    VERIFY_NON_NULL_VOID(obj, TAG, "obj");
    VERIFY_NON_NULL_VOID(gatt, TAG, "gatt");

    if (GATT_SUCCESS == status)
    {
        jstring jni_address = CAManagerGetAddressFromGatt(env, gatt);
        if (!jni_address)
        {
            OIC_LOG(ERROR, TAG, "CAManagerGetAddressFromGatt is null");
            return;
        }

        char* address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
        if (!address)
        {
            OIC_LOG(ERROR, TAG, "address is null");
            return;
        }
        OIC_LOG_V(DEBUG, TAG, "ServicesDiscovered device : %s", address);

        // target address for auto connection will be set in device list.
        // check set connected address information by user
        jclass jni_cls_set = (*env)->FindClass(env, "java/util/HashSet");
        if (!jni_cls_set)
        {
            OIC_LOG(ERROR, TAG, "jni_cls_set is null");
            return;
        }

        jmethodID jni_mid_iterator = (*env)->GetMethodID(env, jni_cls_set, "iterator", "()Ljava/util/Iterator;");
        if (!jni_mid_iterator)
        {
            OIC_LOG(ERROR, TAG, "jni_mid_iterator is null");
            return;
        }

        jobject jni_obj_iter = (*env)->CallObjectMethod(env, g_connectedDeviceSet, jni_mid_iterator);
        if (!jni_obj_iter)
        {
            OIC_LOG(ERROR, TAG, "jni_obj_iter is null");
            return;
        }

        // Get the Iterator method IDs
        jclass jni_cls_iterator = (*env)->FindClass(env, "java/util/Iterator");
        if (!jni_cls_iterator)
        {
            OIC_LOG(ERROR, TAG, "jni_cls_iterator is null");
            return;
        }

        jmethodID jni_mid_hasNext = (*env)->GetMethodID(env, jni_cls_iterator, "hasNext", "()Z");
        if (!jni_mid_hasNext)
        {
            OIC_LOG(ERROR, TAG, "jni_mid_hasNext is null");
            return;
        }

        jmethodID jni_mid_next = (*env)->GetMethodID(env, jni_cls_iterator, "next", "()Ljava/lang/Object;");
        if (!jni_mid_next)
        {
            OIC_LOG(ERROR, TAG, "jni_mid_next is null");
            return;
        }

        // Iterate over the entry Set
        while ((*env)->CallBooleanMethod(env, jni_obj_iter, jni_mid_hasNext))
        {
            jstring jni_str_entry = (jstring)(*env)->CallObjectMethod(env, jni_obj_iter, jni_mid_next);
            const char* foundAddress = (*env)->GetStringUTFChars(env, jni_str_entry, NULL);
            if (!foundAddress)
            {
                OIC_LOG(ERROR, TAG, "addr is null");
                return;
            }
            OIC_LOG_V(INFO, TAG, "found last connected address [%s] from SharedPreferences",
                      foundAddress);

            if (!strcmp(foundAddress, address))
            {
                // if BLE address is matched each other
                // this address will be added into auto connection list.
                OIC_LOG(INFO, TAG, "AC list - address will be added into ACData list");
                CAManagerAddACData(env, jni_address);
                CAManagerSetAutoConnectionFlag(env, jni_address, false);

                // next connection will be requested as JNI_TRUE flag
                // after first connection
                CALEClientSetAutoConnectFlag(env, jni_str_entry, JNI_TRUE);
            }
            else
            {
                OIC_LOG(INFO, TAG, "AC list - device is not matched");
            }

            (*env)->ReleaseStringUTFChars(env, jni_str_entry, foundAddress);
            (*env)->DeleteLocalRef(env, jni_str_entry);
        }

        if (g_connStateCB)
        {
            g_connStateCB(CA_ADAPTER_GATT_BTLE, address, true);
            OIC_LOG(DEBUG, TAG, "LE Connected callback is called");
        }
        (*env)->ReleaseStringUTFChars(env, jni_address, address);
        (*env)->DeleteLocalRef(env, jni_address);
        (*env)->DeleteLocalRef(env, jni_cls_set);
        (*env)->DeleteLocalRef(env, jni_obj_iter);
        (*env)->DeleteLocalRef(env, jni_cls_iterator);

        OIC_LOG(INFO, TAG, "ServicesDiscovery is successful");
    }
    else
    {
        OIC_LOG(ERROR, TAG, "ServicesDiscovery has failed");
    }
}
/*
 * Class:     org_iotivity_ca_jar_caleinterface
 * Method:    caManagerLeServicesDiscoveredCallback
 * Signature: (Landroid/bluetooth/BluetoothGatt;I)V
 */
JNIEXPORT void JNICALL
Java_org_iotivity_ca_CaLeClientInterface_caManagerLeServicesDiscoveredCallback(JNIEnv *env,
                                                                               jobject obj,
                                                                               jobject gatt,
                                                                               jint status)
{
    OIC_LOG_V(INFO, TAG, "caManagerLeServicesDiscoveredCallback - status %d", status);
    VERIFY_NON_NULL_VOID(env, TAG, "env");
    VERIFY_NON_NULL_VOID(obj, TAG, "obj");
    VERIFY_NON_NULL_VOID(gatt, TAG, "gatt");

    if (GATT_SUCCESS == status)
    {
        if (!g_connectedDeviceSet)
        {
            OIC_LOG(ERROR, TAG, "g_connectedDeviceSet is null");
            return;
        }

        jstring jni_address = CALEGetAddressFromGatt(env, gatt);
        if (!jni_address)
        {
            OIC_LOG(ERROR, TAG, "CALEGetAddressFromGatt is null");
            return;
        }

        char* address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
        if (!address)
        {
            OIC_LOG(ERROR, TAG, "address is null");
            (*env)->DeleteLocalRef(env, jni_address);
            return;
        }

        OIC_LOG_V(DEBUG, TAG, "ServicesDiscovered device : %s", address);

        if (CAManagerIsConnectedDeviceAddress(env, g_context, jni_address, g_connectedDeviceSet))
        {
            OIC_LOG(INFO, TAG, "AC list - the address will be added to ACData list");
            CAManagerAddACData(env, jni_address);
            CAManagerSetAutoConnectingFlag(env, jni_address, false);

            // next connection will be requested with JNI_TRUE on autoConnect flag
            // after first connection
            CALEClientSetFlagToState(env, jni_address, CA_LE_AUTO_CONNECT_FLAG, JNI_TRUE);
        }
        else
        {
            OIC_LOG(DEBUG, TAG, "AC list - the address is not set to AutoConnect");
        }

        (*env)->ReleaseStringUTFChars(env, jni_address, address);
        (*env)->DeleteLocalRef(env, jni_address);

        OIC_LOG(INFO, TAG, "ServicesDiscovery is successful");
    }
    else
    {
        OIC_LOG(ERROR, TAG, "ServicesDiscovery has failed");
    }
}