/*
 * 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 "qlibsoundmanager.h"
#include <QJsonDocument>
using namespace std;

static int create_json_object(const QJsonObject& obj, struct json_object* jobj);
static bool put_val_to_jobj(const char* key, const QJsonValue& val, struct json_object* jobj);
QSoundmanager* me;

static void cbEvent_static(const std::string& event, struct json_object* event_contents)
{
    const QString event_name = QString(event.c_str());
    QString str = QString(json_object_get_string(event_contents));
    QJsonParseError error;
    QJsonDocument jdoc = QJsonDocument::fromJson(str.toUtf8(), &error);
    const QJsonObject jobj = jdoc.object();
    emit me->event(event_name, jobj);
}

static void cbReply_static(struct json_object* replyContents)
{
    if(me == nullptr){
        return;
    }
    QString str = QString(json_object_get_string(replyContents));
    QJsonParseError error;
    QJsonDocument jdoc = QJsonDocument::fromJson(str.toUtf8(), &error);
    QJsonObject jobj = jdoc.object();
    emit me->reply(jobj);
}

QSoundmanager::QSoundmanager(QObject *parent) :
    QObject(parent)
{
}

QSoundmanager::~QSoundmanager()
{
}

int QSoundmanager::init(int port, const QString& token)
{
    string ctoken = token.toStdString();
    int rc = Soundmanager::init(port, ctoken);
    if(rc != 0){
        return rc;
    }
    me = this;

    Soundmanager::registerCallback(
        cbEvent_static,
        cbReply_static);
    return rc;
}

int QSoundmanager::call(const QString &verb, const QJsonObject &arg)
{
    // translate QJsonObject to struct json_object
    struct json_object* jobj = json_object_new_object();
    int ret = create_json_object(arg, jobj);
    if(ret < 0)
    {
        return -1;
    }
    return Soundmanager::call(verb.toStdString().c_str(), jobj);
}

int QSoundmanager::connect(int sourceID, const QString& sinkName){
    string str = sinkName.toStdString();
    return Soundmanager::connect(sourceID, str);
}

int QSoundmanager::connect(int sourceID, int sinkID){
    return Soundmanager::connect(sourceID, sinkID);
}

int QSoundmanager::disconnect(int connectionID){
    return Soundmanager::disconnect(connectionID);
}
int QSoundmanager::ackSetSourceState(int handle, int errorcode){
    return Soundmanager::ackSetSourceState(handle, errorcode);
}
int QSoundmanager::registerSource(const QString& audio_role){
    string str = audio_role.toStdString();
    return Soundmanager::registerSource(str);
}
int QSoundmanager::getListMainSources(){
    return Soundmanager::getListMainSources();
}
int QSoundmanager::getListMainSinks(){
    return Soundmanager::getListMainSinks();
}
int QSoundmanager::getListMainConnections(){
    return Soundmanager::getListMainConnections();
}
int QSoundmanager::stream_open(const QString& audio_role, int endpoint_id){
    string arole = audio_role.toStdString();
    return Soundmanager::stream_open(arole, endpoint_id);
}
int QSoundmanager::stream_open(const QString& audio_role, const QString& endpoint_id){
    string arole = audio_role.toStdString();
    string eid   = endpoint_id.toStdString();
    return Soundmanager::stream_open(arole, eid);
}

int QSoundmanager::stream_close(int stream_id){
    return Soundmanager::stream_close(stream_id);
}
int QSoundmanager::set_stream_state(int stream_id, int mute){
    return Soundmanager::set_stream_state(stream_id, mute);
}


static int create_json_object(const QJsonObject& obj, struct json_object* jobj)
{
    try{
        for(auto itr = obj.begin(); itr != obj.end();++itr)
        {
            string key = itr.key().toStdString();
            //const char* key = itr.key().toStdString().c_str(); // Do not code like this. string is removed if size is over 16!!

            bool ret = put_val_to_jobj(key.c_str(), itr.value(),jobj);
            if(!ret){
                /*This is not implemented*/
                qDebug("JsonArray can't parse for now");
                return -1;
            }
        }
    }
    catch(...){
        qDebug("Json parse error occured");
        return -1;
    }
    return 0;
}

static bool put_val_to_jobj(const char* key, const QJsonValue& val, struct json_object* jobj)
{
    if(val.isArray()){
        return false;  // FIXME: Array can't input
    }
    if(val.isString()){
        string value = val.toString().toStdString();
        json_object_object_add(jobj, key, json_object_new_string(value.c_str()));
    }
    else{
        const int value = val.toInt();
        json_object_object_add(jobj, key, json_object_new_int(value));
    }
    return true;
}


void QSoundmanager::subscribe(const QString event_name)
{
    std::string str = event_name.toStdString();
    Soundmanager::subscribe(str);
}

void QSoundmanager::unsubscribe(const QString event_name)
{
    std::string str = event_name.toStdString();
    Soundmanager::unsubscribe(str);
}