/*
 * Copyright (C) 2011-2017 Redis Labs Ltd.
 *
 * This file is part of memtier_benchmark.
 *
 * memtier_benchmark is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 2.
 *
 * memtier_benchmark is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with memtier_benchmark.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <string.h>

#include "JSON_handler.h"


/**
 * C'tor
 * -----
 * Opens the file named jsonfilename and sets the first nesting as NESTED_GENERAL
 * In case of failure to create the file, will state the error perror
 */
json_handler::json_handler(const char * jsonfilename) : m_json_file(NULL)
{
    // Try to open a file and add the first level
    m_json_file = fopen(jsonfilename, "w");
    if (!m_json_file) {
        perror(jsonfilename);
    }
    // opening the JSON
    fprintf(stderr, "Json file %s created...\n", jsonfilename);
    fprintf(m_json_file,"{");
    m_nest_closer_types.push_back(NESTED_GENERAL);
    beutify();
}

/**
 * D'tor
 * -----
 * Closes all the nesting and the file pointer.
 */
json_handler::~json_handler()
{
    if (m_json_file){
        // close nesting...
        while (close_nesting());
        fclose(m_json_file);
        fprintf(stderr, "Json file closed.\n");
    }
}

/**
 * Write singel object named objectname to the JSON with values stated in ...
 * based on the format defined
 * basically uses fprintf with the same parameters.
 */
void json_handler::write_obj(const char * objectname, const char * format, ...)
{
    fprintf(m_json_file, "\"%s\": ", objectname);
    va_list argptr;
    va_start(argptr, format);
    vfprintf(m_json_file, format, argptr);
    va_end(argptr);
    beutify();
    fprintf(m_json_file, ",");
}

/**
 * Starts a nesting with a title as defined in objectname
 * in case objectname == NULL it will not add the title and just start nesting
 * The type defines the kind of charecters that will be used
 */
void json_handler::open_nesting(const char * objectname,eJSON_NESTED_TYPE type /*= NESTED_GENERAL*/)
{
    const char * nestStart = (type == NESTED_GENERAL) ? "{" : "[";
    if (objectname != NULL){
        fprintf(m_json_file, "\"%s\":", objectname);
    }
    fprintf(m_json_file, "%s", nestStart);
    // Adding the type to the nesting closer list to be able to close it properly
    m_nest_closer_types.push_back(type);
    beutify(false);
}

/**
 * Ends the nesting
 * Closes the nesting based on the nesting list
 * Returns = the nested levels left after the closing
 */
int json_handler::close_nesting()
{
    int nest_level = m_nest_closer_types.size();
    if (nest_level > 0)
    {
        eJSON_NESTED_TYPE type = m_nest_closer_types.back();
        m_nest_closer_types.pop_back();
        // as we assume that the last value is always a ',' or '\n' we need to remove it first
        fseek(m_json_file, -1, SEEK_CUR);
        const char * nestEnd = (type == NESTED_GENERAL) ? "}" : "]";
        fprintf(m_json_file, "%s", nestEnd);
        beutify();
        if (nest_level > 1)
        {
            fprintf(m_json_file, ",");
        }
    }
    return m_nest_closer_types.size();
}

/**
 * Add tabls and new line (if only_tabs==true will only add tabs)
 */
void json_handler::beutify(bool only_tabs)
{
    if (only_tabs == false)
    {
        fprintf(m_json_file, "\n");
    }
    int nest_level = m_nest_closer_types.size();
    for(;nest_level>0;nest_level--)
    {
        fprintf(m_json_file, "\t");
    }

}