/*
 * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
 *
 * 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.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <json-c/json.h>
#include <glib.h>
#include "soundmanager.h"
#include "audiomanager_proxy.h"
#include "sm-def.h"
#include "sm-error.h"
#include "sm-helper.h"
#include "sm-pending.h"

struct event{
    char* name;
    struct afb_event* event;
    };

static struct pending* pending_list = NULL;

static int SOUNDMANAGER_DOMAIN_ID;
static struct event command_event_list[COMMAND_EVENT_NUM];
static struct event routing_event_list[ROUTING_EVENT_NUM];

static struct afb_event ev_new_connection;
static struct afb_event ev_removed_main_connection;
static struct afb_event ev_volume_changed;
static struct afb_event ev_sink_mute_state_changed;
static struct afb_event ev_main_connection_state_changed;

/* Routing interface event */
static struct afb_event ev_set_routing_ready;
static struct afb_event ev_set_routing_rundown;
static struct afb_event ev_async_connect;
static struct afb_event ev_async_disconnect;
static struct afb_event ev_async_set_source_state;
static struct afb_event ev_stream_state_event;

/* Client context */
typedef struct source {
    int sourceID;
    int mainConnectionID;
} source;

typedef struct sink {
    int endpointID;
    int endpointType;
    int sinkID;
} sink;

typedef struct events {
    afb_event asyncSetSourceState;
} events;

typedef struct smClientCtxt{
    char* appname;
    source source;
    sink sink;
    events events;
} smClientCtxt;

static void on_client_context_terminated(void *data);
static void create_client_context(afb_req request, guint16 source_id, guint16 sink_id, int endpoint_type);

/*
********** Method of Sound Manager (API) **********
*/

void connect (struct afb_req request)
{
    AFB_DEBUG("call %s", __FUNCTION__);
    guint16 source_id = 0, sink_id = 0;
    int main_connectionID = 0;
    REQ_ERROR req_err1 = REQ_FAIL;
    REQ_ERROR req_err2 = REQ_FAIL;

    req_err1 = get_value_uint16(request, KEY_SOURCE_ID, &source_id);
    /* ToDo: Hardware abstraction for application user is needed.
    select appname(speaker) or sourceID(sinkID). If appname is desired, it changes to sourceID(sinkID) */

    const char* default_sink = afb_req_value (request, KEY_SINK_ID);
    if(default_sink != NULL){
        if((strlen("default") == strlen(default_sink)) &&
           (0 == strncmp("default", default_sink, strlen("default")))){
            sink_id = DEFAULT_SINK;
            req_err2 = REQ_OK;
        }
        else{
            req_err2 = get_value_uint16(request, KEY_SINK_ID, &sink_id);
        }
    }

    if((req_err1 != REQ_OK) || (req_err2 != REQ_OK))
    {
        AFB_INFO("get_value_uint16 source ret = %d,sink ret = %d", source_id, sink_id);
        AFB_NOTICE("wrong request");
        afb_req_fail(request,"wrong-request",NULL);
        return;
    }

    ErrorCode ec = am_proxy_connect(source_id, sink_id, &main_connectionID);

    if(!SEND_RESULT(ec, request)) return;

    /* ToDo Remember appname(key) and tie to sourceID(value) */

    /*create response json object*/
    struct json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 4,
        "error", ec,
        KEY_MAIN_CONNECTION_ID, main_connectionID);
    const char* info = get_response_audiomanager_massage_error(ec);
    afb_req_success(request, res, info);
}

void disconnect (struct afb_req request)
{
    AFB_DEBUG("call %s", __FUNCTION__);

    guint16 main_connection_id;
    REQ_ERROR req_err;

    req_err = get_value_uint16(request, KEY_MAIN_CONNECTION_ID, &main_connection_id);
    AFB_DEBUG( "requested %s = %d", KEY_MAIN_CONNECTION_ID, main_connection_id);

    if(req_err != REQ_OK)
    {
        afb_req_fail(request,"wrong-request",afb_req_value (request, KEY_MAIN_CONNECTION_ID));
        return;
    }
    ErrorCode ec = am_proxy_disconnect(main_connection_id);
    AFB_DEBUG( "ret = %d", ec);

    if(!SEND_RESULT(ec, request)) return;

    struct json_object* res_obj = json_object_new_object();
    sm_add_object_to_json_object_func(res_obj, __FUNCTION__, 2,
        KEY_ERROR, ec);
    const char* info = get_response_audiomanager_massage_error(ec);

    afb_req_success(request, res_obj, info); /* return error num as status */
}

void setVolume (struct afb_req request)
{
    AFB_DEBUG("call %s", __FUNCTION__);

    guint16 sink_id, vol;
    REQ_ERROR req_err1, req_err2;

    req_err1 = get_value_uint16(request, KEY_SINK_ID, &sink_id);
    req_err2 = get_value_int16(request, KEY_VOLUME, &vol);
    AFB_DEBUG( "requested %s = %d, %s = %d",KEY_SINK_ID, sink_id, KEY_VOLUME, vol);
    if((req_err1 != REQ_OK) || (req_err2 != REQ_OK))
    {
        afb_req_fail(request,"wrong-request", NULL);
        return;
    }

    ErrorCode ec = am_proxy_set_volume(sink_id, vol);
    AFB_DEBUG( "ret = %d", ec);

    if(!SEND_RESULT(ec, request)) return;

    struct json_object* res_obj = json_object_new_object();
    sm_add_object_to_json_object_func(res_obj, __FUNCTION__, 2,
        "error", ec);
    const char* info = get_response_audiomanager_massage_error(ec);

    afb_req_success(request, res_obj, info); /* return error num as status */
}

void volumeStep (struct afb_req request)
{
    AFB_DEBUG("call %s", __FUNCTION__);

    guint16 sink_id, vol;
    REQ_ERROR req_err1, req_err2;

    req_err1 = get_value_uint16(request, KEY_SINK_ID, &sink_id);
    req_err2 = get_value_int16(request, KEY_VOLUME_STEP, &vol);
    AFB_DEBUG( "requested %s = %d, %s = %d",KEY_SINK_ID, sink_id, KEY_VOLUME_STEP, vol);
    if((req_err1 != REQ_OK) || (req_err2 != REQ_OK))
    {
        afb_req_fail(request,"wrong-request", NULL);
        return;
    }

    ErrorCode ec = am_proxy_volume_step(sink_id, vol);
    AFB_DEBUG( "ret = %d", ec);

    if(!SEND_RESULT(ec, request)) return;

    struct json_object* res_obj = json_object_new_object();
    sm_add_object_to_json_object_func(res_obj, __FUNCTION__, 2,
        "error", ec);
    const char* info = get_response_audiomanager_massage_error(ec);

    afb_req_success(request, res_obj, info); /* return error num as status */
}

void setSinkMuteState(struct afb_req request)
{
    AFB_DEBUG("call %s", __FUNCTION__);

    guint16 sink_id, mute;
    REQ_ERROR req_err1, req_err2;

    req_err1 = get_value_uint16(request, KEY_SINK_ID, &sink_id);
    req_err2 = get_value_int16(request, KEY_MUTE_STATE, &mute);
    AFB_DEBUG( "requested %s = %d, %s = %d",KEY_SINK_ID, sink_id, KEY_MUTE_STATE, mute);

    if((req_err1 != REQ_OK) || (req_err2 != REQ_OK))
    {
        afb_req_fail(request,"wrong-request", NULL);
        return;
    }

    ErrorCode ec = am_proxy_set_sink_mute_state(sink_id, mute);
    AFB_DEBUG( "ret = %d", ec);

    if(!SEND_RESULT(ec, request)) return;

    struct json_object* res_obj = json_object_new_object();
    sm_add_object_to_json_object_func(res_obj, __FUNCTION__, 2,
        "error", ec);
    const char* info = get_response_audiomanager_massage_error(ec);

    afb_req_success(request, res_obj, info); /* return error num as status */
}

void getListMainConnections(struct afb_req request)
{
    AFB_DEBUG("call getListMainConnections");

    GVariant* mainConnectionList;

    ErrorCode ec = am_proxy_get_list_main_connections(&mainConnectionList);

    if(!SEND_RESULT(ec, request)) return;

    /* create response */
    struct json_object *response = json_object_new_object();
    gsize size = g_variant_n_children(mainConnectionList);
    AFB_DEBUG("mainConnectionList size is %u",(uint16_t)size);
    sm_add_object_to_json_object_func(response, __FUNCTION__, 0);
    if(size <= 0)
    {
        AFB_NOTICE( "mainConnectionList size is 0");
    }
    else{
        struct json_object *array_res = json_object_new_array();
        for(int i = 0; i < size; ++i)
        {
            guint16 mcid, srcid, sinkid;
            gint16 delay, constate;
            g_variant_get_child(
                mainConnectionList,i,"(qqqnn)",
                &mcid, &srcid, &sinkid, &delay, &constate
                );

            struct json_object* res_obj = json_object_new_object();
            sm_add_object_to_json_object(res_obj,10,
                KEY_MAIN_CONNECTION_ID, mcid,
                KEY_SOURCE_ID, srcid,
                KEY_SINK_ID, sinkid,
                KEY_DELAY, delay,
                KEY_CONNECTION_STATE, constate
            );
            json_object_array_add(array_res,res_obj);
        }
        json_object_object_add(response, "connections", array_res);
    }
    AFB_DEBUG("json object :%s:",json_object_to_json_string(response));
    afb_req_success(request, response, "Success to get main connection list");
    g_variant_unref(mainConnectionList);
}

void getListMainSources(struct afb_req request)
{
    AFB_DEBUG("call %s", __FUNCTION__);

    GVariant* mainSourceList;

    ErrorCode ec = am_proxy_get_list_main_sources(&mainSourceList);

    if(!SEND_RESULT(ec, request)) return;

    /* create response */
    struct json_object *response = json_object_new_object();
    gsize size = g_variant_n_children(mainSourceList);
    AFB_DEBUG( "%s size is %u",__FUNCTION__, (uint16_t)size);
    sm_add_object_to_json_object_func(response, __FUNCTION__, 0);
    if(size <= 0)
    {
        AFB_NOTICE("%s size is 0", __FUNCTION__);
    }
    else{
        struct json_object *array_res = json_object_new_array();
        for(int i = 0; i < size; ++i)
        {
            guint16 sourceid, sourceclassid;
            gchar* sourcename;

            gint16 av;
            gint16 avr;
            GVariant* child = g_variant_get_child_value(mainSourceList, i);
            g_variant_get(
                child,"(qs(nn)q)",
                &sourceid, &sourcename, &av, &avr, &sourceclassid);
            AFB_DEBUG( "sourceID: %d, sourceName: %s, availability: %d, availableReason: %d, sourceClassID: %d",
                sourceid, sourcename, av, avr, sourceclassid);

            struct json_object* res_obj = json_object_new_object();
            sm_add_object_to_json_object(res_obj, 2, KEY_SOURCE_ID, sourceid);
            json_object_object_add(res_obj, KEY_SINK_NAME, json_object_new_string(sourcename));
            sm_add_object_to_json_object(res_obj,6,
                KEY_AVAILABILITY, av,
                KEY_AVAILABILITY_REASON, avr,
                KEY_SOURCE_CLASS_ID, sourceclassid);
            json_object_array_add(array_res,res_obj);
            g_variant_unref(child);
        }
        json_object_object_add(response, "sources", array_res);
    }
    afb_req_success(request, response, "Success to get main source list");
    g_variant_unref(mainSourceList);
}

void getListMainSinks(struct afb_req request)
{
    AFB_DEBUG("call %s", __FUNCTION__);

    GVariant* mainSinkList;

    ErrorCode ec = am_proxy_get_list_main_sinks(&mainSinkList);

    if(!SEND_RESULT(ec, request)) return;

    /* create response */
    struct json_object *response = json_object_new_object();
    gsize size = g_variant_n_children(mainSinkList);
    AFB_DEBUG( "%s size is %u",__FUNCTION__, (uint16_t)size);
    sm_add_object_to_json_object_func(response, __FUNCTION__, 0);
    if(size <= 0)
    {
        AFB_NOTICE("%s size is 0", __FUNCTION__);
    }
    else{
        struct json_object *array_res = json_object_new_array();
        for(int i = 0; i < size; ++i)
        {
            guint16 sinkid, sinkclassid;
            gchar* sinkname;

            gint16 av;
            gint16 avr;
            gint16 volume, mutestate;
            GVariant* child = g_variant_get_child_value(mainSinkList, i);
            g_variant_get(
                child,"(qs(nn)nnq)",
                &sinkid, &sinkname, &av, &avr, &volume, &mutestate, &sinkclassid);
            AFB_DEBUG( "sinkID: %d, sinkName: %s, availability: %d, availableReason: %d, volume: %d, muteState: %d, sinkClassID: %d",
                sinkid, sinkname, av, avr, volume, mutestate, sinkclassid);

            struct json_object* res_obj = json_object_new_object();
            sm_add_object_to_json_object(res_obj,2,KEY_SINK_ID, sinkid);
            json_object_object_add(res_obj, KEY_SINK_NAME, json_object_new_string(sinkname));
            sm_add_object_to_json_object(res_obj,10,
                KEY_AVAILABILITY, av,
                KEY_AVAILABILITY_REASON, avr,
                KEY_VOLUME, volume,
                KEY_MUTE_STATE, mutestate,
                KEY_SINK_CLASS_ID, sinkclassid);
            json_object_array_add(array_res,res_obj);
            g_variant_unref(child);
        }
        json_object_object_add(response, "sinks", array_res);
    }
    afb_req_success(request, response, "Success to get main sink list");
    g_variant_unref(mainSinkList);
}

/*
*
****** Routing Interface method(API) ***********
*
*/

void ackConnect(struct afb_req request)
{
    /* This function will be deprecated */
    AFB_DEBUG("call %s", __FUNCTION__);
    guint16 handle, connection_id, error;
    guint16 ret = 0;
    REQ_ERROR req_err1, req_err2 , req_err3;

    req_err1 = get_value_uint16(request, KEY_HANDLE, &handle);
    req_err2 = get_value_uint16(request, KEY_CONNECTION_ID, &connection_id);
    req_err3 = get_value_uint16(request, KEY_ERROR, &error);

    if((req_err1 != REQ_OK) || (req_err2 != REQ_OK) || (req_err3 != REQ_OK))
    {
        afb_req_fail(request,"wrong-request", NULL);
        return;
    }
    if(connection_id == 0)
    {
        afb_req_fail(request,"wrong-request", "connectionID is more than 0");
        return;
    }

    ErrorCode ec = am_proxy_ack_connect(handle, connection_id, error);

    if(!SEND_RESULT(ec, request)) return;

    /*create response json object*/
    struct json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 2,
        KEY_ERROR, ret);
    const char* info = get_response_audiomanager_massage_error(ret);
    afb_req_success(request, res, info);
}

void ackDisconnect(struct afb_req request)
{
    /* This function will be deprecated */
    AFB_DEBUG("call %s", __FUNCTION__);
    guint16 handle, connection_id, error;
    guint16 ret = 0;
    REQ_ERROR req_err1, req_err2 , req_err3;

    req_err1 = get_value_uint16(request, KEY_HANDLE, &handle);
    req_err2 = get_value_uint16(request, KEY_CONNECTION_ID, &connection_id);
    req_err3 = get_value_uint16(request, KEY_ERROR, &error);

    if((req_err1 != REQ_OK) || (req_err2 != REQ_OK) || (req_err3 != REQ_OK))
    {
        afb_req_fail(request,"wrong-request", "connectionID is more than 0");
        return;
    }
    if(connection_id == 0)
    {
        afb_req_fail(request,"wrong-request", "connectionID is more than 0");
        return;
    }

    ErrorCode ec = am_proxy_ack_disconnect(handle, connection_id, error);

    if(!SEND_RESULT(ec, request)) return;

    /*create response json object*/
    struct json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 2,
        KEY_ERROR, ret);
    const char* info = get_response_audiomanager_massage_error(ret);
    afb_req_success(request, res, info);
}

void ackSetSourceState(struct afb_req request)
{
    AFB_DEBUG("call %s", __FUNCTION__);
    guint16 handle, error;
    guint16 ret = 0;
    REQ_ERROR req_err1, req_err2;

    req_err1 = get_value_uint16(request, KEY_HANDLE, &handle);
    req_err2 = get_value_uint16(request, KEY_ERROR, &error);

    if((req_err1 != REQ_OK) || (req_err2 != REQ_OK))
    {
        AFB_DEBUG("wrong request");
        afb_req_fail(request,"wrong-request", NULL);
        return;
    }

    ErrorCode ec = am_proxy_ack_set_source_state(handle, error);

    if(!SEND_RESULT(ec, request)) return;

    /*create response json object*/
    struct json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 2,
        KEY_ERROR, ec);
    const char* info = get_response_audiomanager_massage_error(ec);
    afb_req_success(request, res, info);
}

void registerSource(struct afb_req request)
{
    AFB_DEBUG("call %s", __FUNCTION__);

    guint16 source_id; /* q  0 is for dynamic id*/
    guint16 domain_id;  /* q */
    guint16 source_class_id;   /* q */
    gint32  source_state; /* i  */
    gint16  volume;  /* n */

    if(REQ_OK != get_value_uint16(request, KEY_SOURCE_ID, &source_id)){
        source_id = DYNAMIC_SOURCE_ID;  /* if 0, dynamic source id will be applied */
    }
    REQ_ERROR req_err = get_value_uint16(request, KEY_DOMAIN_ID, &domain_id);
    if( req_err != REQ_OK){
        if(req_err == REQ_FAIL)
        {
            domain_id = SOUNDMANAGER_DOMAIN_ID;    /* default in AGL */
        }
        else{
            afb_req_fail(request,"wrong-request", "Please input domainID as uint16, otherwise no value is OK");
            return;
        }
    }
    if(domain_id == 0)
    {
        afb_req_fail(request,"wrong-request", "domainID should be more than 0");
        return;
    }
    const gchar* name = afb_req_value(request, KEY_APPNAME);  /* s */
    if(!name)
    {
        char* info = "Must specify the name. Please input json arg such as {\"audio_role\":\"radio\"}";
        afb_req_fail(request, "wrong-request", info);
        return;
    }
    if(REQ_OK != get_value_uint16(request, KEY_SOURCE_CLASS_ID, &source_class_id)){
        source_class_id = DEFAULT_SOURCE_CLASS_ID;    /* BASE */
    }
    if(REQ_OK != get_value_int32(request, KEY_SOURCE_STATE, &source_state)){
        source_state = DEFAULT_SOURCE_STATE; /* SS_OFF */
    }
    if(REQ_OK != get_value_int16(request, KEY_VOLUME, &volume)){
        volume = DEFAULT_VOLUME;
    }
    gboolean visible = TRUE;   /* b */
    struct availability_s available;     /* (ii) */
    available.availability = DEFAULT_AVAILABLES;         /* A_UNKNOWN */
    available.avalilable_reason = 0;    /* AR_UNKNOWN */

    guint16 interrupt;
    if(REQ_OK != get_value_int16(request, KEY_INTERRUPT, &interrupt)){
        interrupt = DEFAULT_INTERRUPT;  /* q IS_OFF */
    }
    struct sound_property_s sound_property_list;   /* a(in) */
    sound_property_list.type = 0;
    sound_property_list.value = 0;     /* in reality, this is array of struct */

    gint32 connection_format_list = DEFAULT_CONNECTION_FORMAT; /* ai */
    struct  main_sound_property_s main_property_list;    /* a(in) */
    main_property_list.type = 0;
    main_property_list.value = 0;

    struct notification_config_s nconf_routing;
    struct notification_config_s nconf_command; /* a(iin)a(iin) */
    nconf_routing.type = 0;
    nconf_routing.status = 0;
    nconf_routing.parameter = 0;

    nconf_command.type = 0;
    nconf_command.status = 0;
    nconf_command.parameter = 0;

    /* acquire data */
    int acquire_source_id;


    GVariant* sourceData = create_source_data (source_id, domain_id, name, source_class_id,
        source_state, volume, visible, available, interrupt,
        sound_property_list, connection_format_list, main_property_list,
        nconf_routing, nconf_command);

    ErrorCode ec = am_proxy_register_source(sourceData, &acquire_source_id);

    if(!SEND_RESULT(ec, request)) return;

    /*create response json object*/
    struct json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 4,
        KEY_ERROR, ec,
        KEY_SOURCE_ID, acquire_source_id);
    const char* info = get_response_audiomanager_massage_error(ec);
    afb_req_success(request, res, info);
}

void deregisterSource(struct afb_req request)
{
    guint16 source_id;

    GError *err = NULL;

    if(REQ_OK != get_value_uint16(request, KEY_SOURCE_ID, &source_id)){
        afb_req_fail(request, "wrong-request", NULL);
    }
    ErrorCode ec = am_proxy_deregister_source(source_id);
    if(!SEND_RESULT(ec, request)) return;

    /*create response json object*/
    struct json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 2,
        KEY_ERROR, ec);
    const char* info = get_response_audiomanager_massage_error(ec);
    afb_req_success(request, res, info);

}

void subscribe(struct afb_req request)
{
    const char *value = afb_req_value(request, KEY_EVENT);
    AFB_DEBUG( "%s %s", __FUNCTION__, value);
    int ret = 0;
    if(value) {
        int index = sm_search_event_name_index(value);
        if(index < 0)
        {
            index = sm_search_routing_event_name_index(value);
            if(index < 0)
            {
                AFB_NOTICE( "dedicated event doesn't exist");
                ret = EVENT_SUBSCRIBE_ERROR_CODE;
            }
            else
            {
                afb_req_subscribe(request, *routing_event_list[index].event);
            }
        }
        else
        {
            afb_req_subscribe(request, *command_event_list[index].event);
        }
    }
    else{
        AFB_NOTICE( "Please input event name");
        ret = EVENT_SUBSCRIBE_ERROR_CODE;
    }
    /*create response json object*/
    struct json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 2,
        KEY_ERROR, ret);
    const char* info = get_response_audiomanager_massage_error(ret);
    afb_req_success(request, res, info);
}

void unsubscribe(struct afb_req request)
{
    const char *value = afb_req_value(request, KEY_EVENT);
    AFB_DEBUG( "%s %s", __FUNCTION__, value);
    int ret = 0;
    if(value) {
        int index = sm_search_event_name_index(value);
        if(index < 0)
        {
            index = sm_search_routing_event_name_index(value);
            if(index < 0)
            {
                AFB_NOTICE( "dedicated event doesn't exist");
                ret = EVENT_SUBSCRIBE_ERROR_CODE;
            }
            else
            {
                afb_req_unsubscribe(request, *routing_event_list[index].event);
            }
        }
        else
        {
            afb_req_unsubscribe(request, *command_event_list[index].event);
        }
    }
    else{
        AFB_NOTICE( "Please input event name");
        ret = EVENT_SUBSCRIBE_ERROR_CODE;
    }
    /*create response json object*/
    struct json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 2,
        KEY_ERROR, ret);
    const char* info = get_response_audiomanager_massage_error(ret);
    afb_req_success(request, res, info);
}

/*
*
****** High Level API ***********
*
*/


#ifdef ENABLE_AGL_AHL

void stream_open(struct afb_req request){
    AFB_DEBUG("call %s", __FUNCTION__);
    // register audio role and endpoint
    // get audio_role
    const gchar* audio_role = afb_req_value(request, KEY_AHL_AUDIO_ROLE);  /* s */
    if(!audio_role)
    {
        afb_req_fail(request, "wrong request", "Please input 'audio_role' as key");
        return;
    }
    // get endpoint
    guint16 endpoint_type = ENDPOINT_SOURCE, endpoint_id = 0;
    if(REQ_OK != get_sink_id(request, KEY_AHL_ENDPOINT_ID, &endpoint_id)){return;}
    get_value_uint16(request, KEY_AHL_ENDPOINT_TYPE, &endpoint_type);

    if(endpoint_type != ENDPOINT_SOURCE){
        AFB_WARNING("register sink from application is not supported");
        afb_req_fail(request,"wrong-request", "register source from application is only supported");
        return;
    }
    // call registerSource
    json_object *jreq = afb_req_json(request);
    json_object *response = json_object_new_object();
    json_object_object_add(jreq, KEY_APPNAME, json_object_new_string(audio_role));

    afb_service_call_sync("soundmanager", "registerSource", jreq, &response);
    // jreq is released by afb_service_call_sync then don't release jreq here.

    AFB_DEBUG("request result :%s",  json_object_to_json_string_ext(response, JSON_C_TO_STRING_PRETTY));

    json_object *j_resp, *j_sid, *j_err;
    int sid = -1, ret = -1;
    if(json_object_object_get_ex(response, KEY_RESPONSE, &j_resp)){
        AFB_DEBUG("Get response success: %s", json_object_to_json_string_ext(j_resp, JSON_C_TO_STRING_PRETTY));
        json_object_object_get_ex(j_resp, KEY_SOURCE_ID, &j_sid);
        json_object_object_get_ex(j_resp, KEY_ERROR, &j_err);
        // registerSource must return sourceID and error then I don't check whether sid and ret is in json_object.
        sid = json_object_get_int(j_sid);
        ret = json_object_get_int(j_err);
        json_object_put(j_resp);
        json_object_put(j_sid);
        json_object_put(j_err);
        json_object_put(response);
    }else {
        afb_req_fail(request, "unknown-error", "Failed stream_open");
        json_object_put(response);
        return;
    }

    json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 4,
        KEY_ERROR, ret,
        KEY_AHL_REP_STREAM_ID, sid);
    const char* info = get_response_audiomanager_massage_error(ret);
    create_client_context(request, sid, endpoint_id, endpoint_type);
    int index = sm_search_routing_event_name_index(SM_EVENT_STREAM_STATE_EVENT);
    afb_req_subscribe(request, *routing_event_list[index].event);
    afb_req_success(request, res, info);
}

void stream_close(struct afb_req request){
    ErrorCode ec;
    gint16 source_id = 0;
    smClientCtxt* ctxt = afb_req_context_get(request);
    if(NULL == ctxt){
        AFB_ERROR("Context is not registered");
        afb_req_fail(request, "wrong-request", "call stream_open at first");
        return;
    }
    if(REQ_OK != get_value_uint16(request, KEY_SOURCE_ID, &source_id)){
        if(REQ_OK != get_value_uint16(request, KEY_AHL_REP_STREAM_ID, &source_id)){
            afb_req_fail(request, "wrong-request", "Unable to find sourceID");
            return;
        }
    }
    if(source_id != ctxt->source.sourceID){
        AFB_ERROR("requested sourceID is %d, but your sourceID is %d", source_id, ctxt->source.sourceID);
        afb_req_fail(request, "wrong-request", "sourceID is not yours");
        return;
    }
    if(ctxt->source.mainConnectionID > 0){
        pending_list = add_pending(pending_list, source_id);
        ec = am_proxy_disconnect(ctxt->source.mainConnectionID);
        if(!SEND_RESULT(ec, request)) {
            del_pending(pending_list, source_id);
            return;
        }
        ctxt->source.mainConnectionID = -1;
    }
    else{
        AFB_NOTICE("Stream %d doesn't have connection. Ignore disconnect", ctxt->source.sourceID);
        return;
    }
    /*create response json object*/
    struct json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 2,
        KEY_ERROR, ec);
    const char* info = get_response_audiomanager_massage_error(ec);
    afb_req_success(request, res, info);
}

void set_stream_state(struct afb_req request){
    gint16 source_id = 0;
    int main_connection_id = -1;
    ErrorCode ec = OK;
    int mute_state;
    smClientCtxt* ctxt = afb_req_context_get(request);
    if(NULL == ctxt){
        AFB_ERROR("Context is not registered");
        afb_req_fail(request, "wrong-request", "call stream_open at first");
        return;
    }

    // get sourceID from request
    if(REQ_OK != get_value_uint16(request, KEY_SOURCE_ID, &source_id)){
        if(REQ_OK != get_value_uint16(request, KEY_AHL_REP_STREAM_ID, &source_id)){
            afb_req_fail(request, "wrong-request", "Unable to find sourceID");
            return;
        }
    }
    if(source_id != ctxt->source.sourceID){
        AFB_ERROR("requested sourceID is %d, but your sourceID is %d", source_id, ctxt->source.sourceID);
        afb_req_fail(request, "wrong-request", "sourceID is not yours");
        return;
    }
    if(REQ_OK != get_value_int32(request, KEY_AHL_MUTE, &mute_state)){
        mute_state = AHL_STREAM_UNMUTE;
        AFB_INFO("Mute state is not set. Set mute state %d(unmute) as default.", mute_state);
    }
    AFB_INFO("souceID: %d , mute : %d", source_id, mute_state);

    if(AHL_STREAM_MUTE == mute_state){
        if(ctxt->source.mainConnectionID > 0){
            pending_list = add_pending(pending_list, source_id);
            ec = am_proxy_disconnect(ctxt->source.mainConnectionID);
            if(!SEND_RESULT(ec, request)){
                del_pending(pending_list, source_id);
                return;
            }
            ctxt->source.mainConnectionID = -1;
        }
        else{
            AFB_NOTICE("Stream %d doesn't have connection. Ignore disconnect", ctxt->source.sourceID);
            ec = ACTION_IMPOSSIBLE;
        }
    }
    else{
        pending_list = add_pending(pending_list, source_id);
        ec = am_proxy_connect(source_id, ctxt->sink.sinkID, &main_connection_id);
        ctxt->source.mainConnectionID = main_connection_id;
        if(!SEND_RESULT(ec, request)) {
            del_pending(pending_list, source_id);
            return;
        }
    }
    /*create response json object*/
    struct json_object *res = json_object_new_object();
    sm_add_object_to_json_object_func(res, __FUNCTION__, 2,
        KEY_ERROR, ec);
    const char* info = get_response_audiomanager_massage_error(ec);
    afb_req_success(request, res, info);
}
#endif

/*
********** Callback Function invoked by Audio Manager **********
*/

static void on_new_main_connection(int mainConnectioID,
    int sourceID, int sinkID, int delay, int connectionState)
{
    AFB_DEBUG("%s is called",__FUNCTION__);

    struct json_object* res_obj = json_object_new_object();
    sm_add_object_to_json_object(res_obj,10,
        KEY_MAIN_CONNECTION_ID, mainConnectioID,
        KEY_SOURCE_ID, sourceID,
        KEY_SINK_ID, sinkID,
        KEY_DELAY, delay,
        KEY_CONNECTION_STATE, connectionState);
    afb_event_push(ev_new_connection, res_obj);
}

static void on_removed_main_connection(int mainConnectionID)
{
    AFB_DEBUG("%s is called",__FUNCTION__);

    struct json_object* res_obj = json_object_new_object();
    json_object_object_add(res_obj, KEY_MAIN_CONNECTION_ID, json_object_new_int(mainConnectionID));
    afb_event_push(ev_removed_main_connection, res_obj);
}

static void on_main_connection_state_changed(int connectionID, int connectionState)
{
    AFB_DEBUG("%s is called",__FUNCTION__);

    struct json_object* res_obj = json_object_new_object();
    sm_add_object_to_json_object(res_obj, 4,
        KEY_CONNECTION_ID, connectionID,
        KEY_CONNECTION_STATE, connectionState);
    afb_event_push(ev_main_connection_state_changed, res_obj);
}

static void on_volume_changed(int sinkID, int volume)
{
    AFB_DEBUG("%s is called",__FUNCTION__);
    struct json_object* res_obj = json_object_new_object();
    sm_add_object_to_json_object(res_obj, 4,
        KEY_SINK_ID, sinkID,
        KEY_VOLUME, volume);
    afb_event_push(ev_volume_changed, res_obj);
}

static void on_sink_mute_state_changed(int sinkID, int mute)
{
    AFB_DEBUG("%s is called",__FUNCTION__);
    struct json_object* res_obj = json_object_new_object();
    sm_add_object_to_json_object(res_obj, 4,
        KEY_SINK_ID, sinkID,
        KEY_MUTE_STATE, mute);
    afb_event_push(ev_sink_mute_state_changed, res_obj);
}

/*
********** Callback Function invoked by Audio Manager Routing Interface**********
*/
static void on_set_routing_ready(void)
{
    AFB_DEBUG("%s is called",__FUNCTION__);
    struct domain_data ddata = {
        .domainID   = DYNAMIC_DOMAIN_ID,
        .name       = "SoundManager",
        .busname    = SOUND_MANAGER_BUS_NAME,
        .nodename   = "soundmanager",
        .early      = FALSE,
        .complete   = TRUE,
        .state      = DS_CONTROLLED
    };
    ErrorCode ec = am_proxy_register_domain(create_domain_data(&ddata) , &SOUNDMANAGER_DOMAIN_ID);
    if(!SEND_RESULT_NO_RESP(ec)){
        AFB_WARNING("Failed to re-gisterDomain when asyncAbort");
        return;
    }
    AFB_NOTICE("Sound Manager re-register domain, the old infomation may be lost");
    afb_event_push(ev_set_routing_ready, NULL);
}

static void on_set_routing_rundown(void)
{
    AFB_DEBUG("%s is called",__FUNCTION__);
    afb_event_push(ev_set_routing_ready, NULL);
}



/*
********** Callback Function invoked by Sound Manager Adapter Interface**********
*
*   For now, there may be no need to send events to applications from these invocation.
*   Sound Manager just sends ack to Audio Manager in charge of applications.
*
*/
static void on_async_abort(int handle)
{
    AFB_DEBUG( "%s called", __FUNCTION__);
    /* Nothing To Do. If it is better to implement something, I will implement */
}

static void on_async_connect(int handle, int connectionID,
    int sourceID, int sinkID, int connectionFormat)
{
    AFB_DEBUG( "%s called", __FUNCTION__);

    struct json_object* ev_obj = json_object_new_object();
    sm_add_object_to_json_object(ev_obj, 10,
        KEY_HANDLE, handle,
        KEY_CONNECTION_ID, connectionID,
        KEY_SOURCE_ID, sourceID,
        KEY_SINK_ID, sinkID,
        KEY_CONNECTION_FORMAT, connectionFormat);
    afb_event_push(ev_async_connect, ev_obj);
}

static void on_async_disconnect(int handle, int connectionID)
{
    AFB_DEBUG( "%s called", __FUNCTION__);
    struct json_object* ev_obj = json_object_new_object();
    sm_add_object_to_json_object(ev_obj, 4,
        KEY_HANDLE, handle,
        KEY_CONNECTION_ID, connectionID);
    afb_event_push(ev_async_disconnect, ev_obj);
}

static void on_async_set_sink_volume(int handle, int sinkID,
    int volume, int ramp, int time)
{
    AFB_DEBUG( "%s called", __FUNCTION__);
}

static void on_async_set_source_state(int handle, int sourceID, int sourceState)
{
    AFB_INFO( "%s called. handle : %d, sourceID: %d, state: %s", __FUNCTION__, handle, sourceID, get_source_state_key(sourceState));
    struct json_object* ev_obj = json_object_new_object();
    const char* ss_key = get_source_state_key(sourceState);
    sm_add_object_to_json_object(ev_obj, 4,
        KEY_HANDLE, handle,
        KEY_SOURCE_ID, sourceID);
    json_object_object_add(ev_obj, KEY_SOURCE_STATE, json_object_new_string(ss_key));
#ifdef ENABLE_AGL_AHL
    struct pending* pd = get_pending(pending_list, sourceID);
    if(pd != NULL){
        int ack_ok = 0;
        am_proxy_ack_set_source_state(handle, ack_ok);
        pending_list = del_pending(pending_list, sourceID);
    }
    json_object_object_add(ev_obj, KEY_AHL_EVENT_NAME, json_object_new_string(AHL_EVENT_NAME));
    sm_add_object_to_json_object(ev_obj, 4,
        KEY_AHL_REP_STREAM_ID, sourceID,
        KEY_AHL_STATE_EVENT, sourceState);
    json_object_get(ev_obj);
    afb_event_push(ev_stream_state_event, ev_obj);
#endif
    afb_event_push(ev_async_set_source_state, ev_obj);
    /* Applications must return ackSetSourceState to look sourceID, then Sound Manager doen't return ackSetSourceState */
    /*audiomanager_routinginterface_call_ack_set_source_state_sync(
        am_route_bus,
        handle,
        NULL,
        NULL, &err);*/
}

/*
*
********** Internal Function used by Sound Manager **********
*
*/

static void on_client_context_terminated(void *data){
    smClientCtxt* ctxt = (smClientCtxt*)data;
    if(NULL == ctxt){
        return;
    }
    AFB_DEBUG("Client %s session is closed", ctxt->appname);
    free(ctxt->appname);
    free(ctxt);
    // TODO : After application is terminated, what should we do?
}

static void create_client_context(afb_req request, guint16 source_id, guint16 sink_id, int endpoint_type){
    AFB_DEBUG("");
    static int applicationID_debug = 0;
    smClientCtxt* ctxt = malloc(sizeof(smClientCtxt));
    ctxt->appname = malloc(MAX_LENGTH_STR * sizeof(char));
    char *appid = afb_req_get_application_id(request);
    if(NULL == appid){
        char debug[MAX_LENGTH_STR];
        //char* debug;
        snprintf(debug, MAX_LENGTH_STR, "%s%d", "applicationID_debug", ++applicationID_debug);
        AFB_INFO("application id is not set. Define as %s", debug);
        strncpy(ctxt->appname, debug, MAX_LENGTH_STR);
    }
    else{
        strncpy(ctxt->appname, appid, MAX_LENGTH_STR);
    }
    ctxt->source.sourceID = source_id;
    ctxt->sink.endpointID = sink_id;
    ctxt->sink.sinkID = sink_id;
    ctxt->sink.endpointType = endpoint_type;
    afb_req_context_set(request, ctxt, on_client_context_terminated);
}

void set_default_sink(){
    GVariant *mainSinkList;
    ErrorCode ec = am_proxy_get_list_main_sinks(&mainSinkList);
    if(ec != OK){
        return;
    }

    gsize size = g_variant_n_children(mainSinkList);

    if(0 == size){
        AFB_NOTICE("Sink is not registered in Audio Manaager then can't set default sinkID, then set as %d", DEFAULT_SINK);
        return;
    }

    guint16 sinkid, sinkclassid;
    gchar* sinkname;
    gint16 av, avr, volume, mutestate;

    // Take the first one as default sinkID
    GVariant* child = g_variant_get_child_value(mainSinkList, 0);
    g_variant_get(
        child,"(qs(nn)nnq)",
        &sinkid, &sinkname, &av, &avr, &volume, &mutestate, &sinkclassid);
    AFB_DEBUG( "sinkID: %d, sinkName: %s, availability: %d, availableReason: %d, volume: %d, muteState: %d, sinkClassID: %d",
        sinkid, sinkname, av, avr, volume, mutestate, sinkclassid);
    g_variant_unref(child);
    g_variant_unref(mainSinkList);

    set_default_sinkID(sinkid);
}

int preinit()
{
    AFB_INFO("Initialize Dbus object");

    /* Initialize Dbus interface */
    ErrorCode ec = initialize_proxy();
    if(ec == NOT_INITIALIZED){
        AFB_ERROR("Failed to initialize");
        return -1;
    }

    AFB_NOTICE( "Finish Initialize");
    return 0;
}

int sm_init()
{
    AFB_NOTICE("Initialize event receive setting");

    /* Initialize make event */
    size_t size = sizeof cmd_evlist / sizeof *cmd_evlist;
    ErrorCode ec;

    /*create event*/
    /*ToDo Hash table is better. And event should be created in the loop
      I would like to change */
    ev_volume_changed = afb_daemon_make_event(cmd_evlist[0]);
    ev_new_connection = afb_daemon_make_event(cmd_evlist[1]);
    ev_removed_main_connection   = afb_daemon_make_event(cmd_evlist[2]);
    ev_sink_mute_state_changed  = afb_daemon_make_event(cmd_evlist[3]);
    ev_main_connection_state_changed    = afb_daemon_make_event(cmd_evlist[4]);
    command_event_list[0].name = strdup(cmd_evlist[0]);
    command_event_list[0].event = &ev_volume_changed;
    command_event_list[1].name = strdup(cmd_evlist[1]);
    command_event_list[1].event = &ev_new_connection;
    command_event_list[2].name = strdup(cmd_evlist[2]);
    command_event_list[2].event = &ev_removed_main_connection;
    command_event_list[3].name = strdup(cmd_evlist[3]);
    command_event_list[3].event = &ev_sink_mute_state_changed;
    command_event_list[4].name = strdup(cmd_evlist[4]);
    command_event_list[4].event = &ev_main_connection_state_changed;

    /* create routing event */
    ev_set_routing_ready = afb_daemon_make_event(route_evlist[0]);
    ev_set_routing_rundown = afb_daemon_make_event(route_evlist[1]);
    ev_async_connect = afb_daemon_make_event(route_evlist[2]);
    ev_async_set_source_state = afb_daemon_make_event(route_evlist[3]);
    ev_async_disconnect = afb_daemon_make_event(route_evlist[4]);
#ifdef ENABLE_AGL_AHL
    ev_stream_state_event = afb_daemon_make_event(route_evlist[5]);
#endif

    routing_event_list[0].name = strdup(route_evlist[0]);
    routing_event_list[0].event = &ev_set_routing_ready;
    routing_event_list[1].name = strdup(route_evlist[1]);
    routing_event_list[1].event = &ev_set_routing_rundown;
    routing_event_list[2].name = strdup(route_evlist[2]);
    routing_event_list[2].event = &ev_async_connect;
    routing_event_list[3].name = strdup(route_evlist[3]);
    routing_event_list[3].event = &ev_async_set_source_state;
    routing_event_list[4].name = strdup(route_evlist[4]);
    routing_event_list[4].event = &ev_async_disconnect;
#ifdef ENABLE_AGL_AHL
    routing_event_list[5].name = strdup(route_evlist[5]);
    routing_event_list[5].event = &ev_stream_state_event;
#endif

    am_event callback = {
        .on_new_main_connection = on_new_main_connection,
        .on_removed_main_connection = on_removed_main_connection,
        .on_main_connection_state_changed = on_main_connection_state_changed,
        .on_volume_changed = on_volume_changed,
        .on_sink_mute_state_changed = on_sink_mute_state_changed,
        .on_set_routing_ready = on_set_routing_ready,
        .on_set_routing_rundown = on_set_routing_rundown
    };
    set_event_callback(&callback);

    /* Get soundmanager adapter bus */
    am_instruction instruction = {
        .on_async_abort = on_async_abort,
        .on_async_connect = on_async_connect,
        .on_async_disconnect = on_async_disconnect,
        .on_async_set_sink_volume = on_async_set_sink_volume,
        .on_async_set_source_state = on_async_set_source_state
    };
    ec = open_soundmanager_interface(&instruction);
    if(ec != OK){
        AFB_ERROR("Failed to create sound manager interface");
        return -1;
    }

    GError* err = NULL;
    struct domain_data ddata = {
        .domainID   = DYNAMIC_DOMAIN_ID,
        .name       = "SoundManager",
        .busname    = SOUND_MANAGER_BUS_NAME,
        .nodename   = "soundmanager",
        .early      = FALSE,
        .complete   = TRUE,
        .state      = DS_CONTROLLED
    };
    ec = am_proxy_register_domain(create_domain_data(&ddata) , &SOUNDMANAGER_DOMAIN_ID);
    if(!SEND_RESULT_NO_RESP(ec)){
        return -1;
    }
    if(ec != OK){
        AFB_ERROR("Failed to registerDomain : %s", get_response_audiomanager_massage_error(ec));
        return -1;
    }
    AFB_DEBUG("domainID : %d", SOUNDMANAGER_DOMAIN_ID);

    set_default_sink();
    return 0;
}

void onevent(const char *event, struct json_object *object)
{
   AFB_NOTICE("on_event %s", event);
}