/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0

#define LOG_TAG "AudioVolumeGroups-JNI"

#include <inttypes.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"

#include <utils/Log.h>
#include <vector>

#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>

#include <nativehelper/ScopedUtfChars.h>

#include "android_media_AudioAttributes.h"
#include "android_media_AudioErrors.h"

// ----------------------------------------------------------------------------

using namespace android;

// ----------------------------------------------------------------------------
static const char* const kClassPathName = "android/media/audiopolicy/AudioVolumeGroup";
static const char* const kAudioVolumeGroupClassPathName =
        "android/media/audiopolicy/AudioVolumeGroup";

static jclass gAudioVolumeGroupClass;
static jmethodID gAudioVolumeGroupCstor;
static struct {
    jfieldID    mName;
    jfieldID    mId;
} gAudioVolumeGroupFields;

static jclass gArrayListClass;
static jmethodID gArrayListCstor;
static struct {
    jmethodID    add;
    jmethodID    toArray;
} gArrayListMethods;


static jint convertAudioVolumeGroupsFromNative(
        JNIEnv *env, jobject *jGroup, const AudioVolumeGroup &group)
{
    jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
    jstring jName = NULL;
    jint Id = NULL;

    jintArray jLegacyStreamTypes = NULL;
    jobjectArray jAudioAttributes = NULL;
    jint numAttributes;
    jobject jAudioAttribute = NULL;

    jName = env->NewStringUTF(group.getName().c_str());
    Id = static_cast<jint>(group.getId());

    // Legacy stream types array
    jLegacyStreamTypes = env->NewIntArray(group.getStreamTypes().size());
    if (jLegacyStreamTypes == NULL) {
        jStatus = (jint)AUDIO_JAVA_ERROR;
        goto exit;
    }
    for (size_t streamIndex = 0; streamIndex < group.getStreamTypes().size(); streamIndex++) {
        jint jStream = group.getStreamTypes()[streamIndex];
        env->SetIntArrayRegion(jLegacyStreamTypes, streamIndex, 1, &jStream);
    }

    // Audio Attributes array
    numAttributes = group.getAudioAttributes().size();
    jStatus = JNIAudioAttributeHelper::getJavaArray(env, &jAudioAttributes, numAttributes);
    if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
        goto exit;
    }

    for (size_t j = 0; j < static_cast<size_t>(numAttributes); j++) {
        auto attributes = group.getAudioAttributes()[j];

        jStatus = JNIAudioAttributeHelper::nativeToJava(env, &jAudioAttribute, attributes);
        if (jStatus != AUDIO_JAVA_SUCCESS) {
            goto exit;
        }
        env->SetObjectArrayElement(jAudioAttributes, j, jAudioAttribute);
    }

    *jGroup = env->NewObject(gAudioVolumeGroupClass, gAudioVolumeGroupCstor,
                             jName, Id, jAudioAttributes, jLegacyStreamTypes);
exit:
    if (jName != NULL) {
        env->DeleteLocalRef(jName);
    }
    return jStatus;
}

static jint
android_media_AudioSystem_listAudioVolumeGroups(JNIEnv *env, jobject clazz, jobject jVolumeGroups)
{
    if (env == NULL) {
        return AUDIO_JAVA_DEAD_OBJECT;
    }
    if (jVolumeGroups == NULL) {
        ALOGE("listAudioVolumeGroups NULL AudioVolumeGroups");
        return (jint)AUDIO_JAVA_BAD_VALUE;
    }
    if (!env->IsInstanceOf(jVolumeGroups, gArrayListClass)) {
        ALOGE("listAudioVolumeGroups not an arraylist");
        return (jint)AUDIO_JAVA_BAD_VALUE;
    }

    status_t status;
    AudioVolumeGroupVector groups;
    jint jStatus;
    jobject jGroup = NULL;

    status = AudioSystem::listAudioVolumeGroups(groups);
    if (status != NO_ERROR) {
        ALOGE("AudioSystem::listAudioVolumeGroups error %d", status);
        return nativeToJavaStatus(status);
    }
    for (const auto &group : groups) {
        jStatus = convertAudioVolumeGroupsFromNative(env, &jGroup, group);
        if (jStatus != AUDIO_JAVA_SUCCESS) {
            goto exit;
        }
        env->CallBooleanMethod(jVolumeGroups, gArrayListMethods.add, jGroup);
    }
exit:
    if (jGroup != NULL) {
        env->DeleteLocalRef(jGroup);
    }
    return jStatus;
}

/*
 * JNI registration.
 */
static const JNINativeMethod gMethods[] = {
    {"native_list_audio_volume_groups", "(Ljava/util/ArrayList;)I",
                        (void *)android_media_AudioSystem_listAudioVolumeGroups},
};

int register_android_media_AudioVolumeGroups(JNIEnv *env)
{
    jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
    gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
    gArrayListCstor = GetMethodIDOrDie(env, arrayListClass, "<init>", "()V");
    gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
    gArrayListMethods.toArray = GetMethodIDOrDie(env, arrayListClass,
                                                 "toArray", "()[Ljava/lang/Object;");

    jclass audioVolumeGroupClass = FindClassOrDie(env, kAudioVolumeGroupClassPathName);
    gAudioVolumeGroupClass = MakeGlobalRefOrDie(env, audioVolumeGroupClass);
    gAudioVolumeGroupCstor = GetMethodIDOrDie(
                env, audioVolumeGroupClass, "<init>",
                "(Ljava/lang/String;I[Landroid/media/AudioAttributes;[I)V");

    gAudioVolumeGroupFields.mName = GetFieldIDOrDie(
                env, audioVolumeGroupClass, "mName", "Ljava/lang/String;");
    gAudioVolumeGroupFields.mId = GetFieldIDOrDie(
                env, audioVolumeGroupClass, "mId", "I");

    env->DeleteLocalRef(audioVolumeGroupClass);

    return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
