#include <cstdlib>
#include <cstring>
#include <rapidjson/document.h>
#include <rapidjson/filewritestream.h>
#include <rapidjson/prettywriter.h>

#include <cstdio>
#include <iostream>
#include <time.h>
#include <sstream>


#define RAND(min,max) (rand()%((max)-(min)+1)+(min))

using namespace std;
using namespace rapidjson;

int main(int argc, char **argv){
    // Setup seed
    if(argc!=20){
        cerr << "Usage: " << argv[0] <<
            " <seed> <simtime> <wakeupevery> <wakeupfor> <n_nodes>" <<
            " <extended> <hint> <poff> <pon> <prx> <ptx> <datasize> <bitrate> <hintsize> <latency> <shutdown_on_rcv> <unschedule_on_rcv> <farhint>" <<
            endl;
        exit(1);
    }

    // Init parameters
    int seed=atoi(argv[1]);
    double simtime=stod(argv[2]);
    unsigned int wakeupevery=atoi(argv[3]);
    unsigned int wakeupfor=stoi(argv[4]);
    unsigned int n_nodes=atoi(argv[5]);
    bool extended=!strcmp("true",argv[6]);
    bool hint=!strcmp("true",argv[7]);
    double poff=stod(argv[8]);
    double pon=stod(argv[9]);
    double prx=stod(argv[10]);
    double ptx=stod(argv[11]);
    unsigned int datasize=atoi(argv[12]);
    string bitrate(argv[13]);
    unsigned int hintsize=atoi(argv[14]);
    double latency=stod(argv[15]);
    bool shutdown_on_rcv=!strcmp("true",argv[16]);
    bool unschedule_on_rcv=!strcmp("true",argv[17]);
    bool farhint=!strcmp("true",argv[18]);
    double hintdist=stod(argv[19]);


    // Setup seed
    srand(seed);

    // Create document
    Document d;
    d.SetObject();
    d.AddMember("seed",Value().SetInt(seed),d.GetAllocator());
    Value bitrateValue;
    bitrateValue.SetString(bitrate.c_str(),bitrate.size(),d.GetAllocator());
    d.AddMember("bitrate",bitrateValue,d.GetAllocator());
    d.AddMember("latency",latency,d.GetAllocator());
    d.AddMember("extended",extended,d.GetAllocator());
    d.AddMember("hint_size",hintsize,d.GetAllocator());
    d.AddMember("shutdown_on_rcv",shutdown_on_rcv,d.GetAllocator());
    d.AddMember("unschedule_on_rcv",unschedule_on_rcv,d.GetAllocator());
    d.AddMember("farhint",farhint,d.GetAllocator());
    d.AddMember("hintdist",hintdist,d.GetAllocator());

    // Create nodes
    Value nodes(kObjectType);
    for(int i=0;i<n_nodes;i++){
        Value node(kObjectType);
        node.SetObject();
        node.AddMember("use_hint",hint,d.GetAllocator());
        node.AddMember("power_off",poff,d.GetAllocator());
        node.AddMember("power_on",pon,d.GetAllocator());
        node.AddMember("power_rx",prx,d.GetAllocator());
        node.AddMember("power_tx",ptx,d.GetAllocator());
        node.AddMember("is_sender",i==0,d.GetAllocator());
        node.AddMember("data_size",datasize,d.GetAllocator());

        // Setup ts and durations
        Value ts(kArrayType);
        Value duration(kArrayType);
        for(unsigned int i=0;i<simtime;i+=wakeupevery){
            ts.PushBack(Value().SetDouble(RAND(i,i+wakeupevery-wakeupfor)),d.GetAllocator());
            duration.PushBack(Value().SetDouble(wakeupfor),d.GetAllocator());
        }
        node.AddMember("wake_ts",ts,d.GetAllocator());
        node.AddMember("wake_duration",duration,d.GetAllocator());


        // Add node to nodes
        std::ostringstream ss;
        ss<< "on" <<i;
        Value key(ss.str().c_str(), d.GetAllocator());
        nodes.AddMember(key,node,d.GetAllocator());
    }
    d.AddMember("nodes",nodes,d.GetAllocator());


    // Write to stdout
    StringBuffer buffer;
    PrettyWriter<StringBuffer> writer(buffer);
    d.Accept(writer);
    cout << buffer.GetString();

    return 0;
}