root/src/JsonDrooler.cpp

////////////////////////////////////////////////////////////////////////
// Copyright (c) Nehmulos 2011-2014
// This file is part of N0 Strain Serialization Library.
//
// N0Strain-Serialization-Library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// N0Strain-Serialization-Library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with N0Strain-Serialization-Library.  If not, see https://gnu.org/licenses/lgpl-3.0
////////////////////////////////////////////////////////////////////////




#include "JsonDrooler.h"

namespace nw {


JsonDrooler::JsonDrooler(const String filename) : level(0)
{
        isFirstElement = true;
        level = 0;
        file.open(filename.c_str(), std::fstream::out);
        push("");
}

JsonDrooler::~JsonDrooler()
{
        this->close();
}

void JsonDrooler::describeName(const String name)
{
        writeComma();
        file << tabsForLevel() << '"' << name << '"' << ": ";
}

void JsonDrooler::describeValue( float & ref)
{
        writeValueArrayComma();
        file << ref;
}




bool JsonDrooler::isInWriteMode()
{
        return true;
}



void JsonDrooler::describeValue( unsigned char & ref)
{
        writeValueArrayComma();
        file << (int)ref;
}



void JsonDrooler::describeValue( unsigned int & ref)
{
        writeValueArrayComma();
        file << ref;
}

void JsonDrooler::pop()
{
        --level;
        file << SYSTEM_NEW_LINE << tabsForLevel() << "}";
}

void JsonDrooler::describeValue( char & ref)
{
        writeValueArrayComma();
        file << (int)ref;
}

void JsonDrooler::describeSimpleArray(const String arrayName, unsigned int size)
{
        file << tabsForLevel() << '"' << arrayName << "\": [" << SYSTEM_NEW_LINE;

        JsonWriterArray newArray;
        newArray.size = size;
        newArray.wroteFirstElement = false;
        newArray.nameOfArray = arrayName;
        openArrays.push(newArray);
}

template<class T> void JsonDrooler::pushValueToSimpleArray(T& value)
{
}

void JsonDrooler::describeValueArray(const String arrayName, unsigned int size)
{
        describeArray(arrayName, "", size);
        openArrays.top().isValueArray = true;
}

void JsonDrooler::describeArray(const String arrayName, const String elementsName, unsigned int size)
{
        JsonWriterArray newArray;
        newArray.size = size;
        newArray.nameOfArray = arrayName;
        newArray.isValueArray = false;
        openArrays.push(newArray);

        writeComma();
        file << tabsForLevel() << '"' << arrayName << "\": " << SYSTEM_NEW_LINE << tabsForLevel() << '[' << SYSTEM_NEW_LINE;

        ++level;
        isFirstElement = true;
}


bool JsonDrooler::enterNextElement(unsigned int iterator)
{
        if(!openArrays.empty())
        {
                if(openArrays.top().isValueArray)
                {
                        if(iterator < openArrays.top().size)
                                return true;
                        --level;
                        file << SYSTEM_NEW_LINE << tabsForLevel() <<  "]";
                        openArrays.pop();
                        return false;
                }

                if(iterator != 0 && iterator != openArrays.top().size)
                {
                        pop();
                }

                if(iterator < openArrays.top().size)
                {
                        push("");
                        return true;
                }
                else
                {
                        if(iterator != 0)
                        {
                                pop();
                        }
                        --level;
                        isFirstElement = false;
                        file << SYSTEM_NEW_LINE << tabsForLevel() << ']';
                        openArrays.pop();
                        return false;
                }

        }
        return false; // TODO check
}



void JsonDrooler::describeValue( double & ref)
{
        writeValueArrayComma();
        file << ref;
}



void JsonDrooler::describeValue( int & ref)
{
        writeValueArrayComma();
        file << ref;
}



void JsonDrooler::describeValue( bool & ref)
{
        writeValueArrayComma();
        if(ref == true)
                file << "true";
        else
                file << "false";
}



void JsonDrooler::describeValue( Pointer ref)
{
        writeValueArrayComma();
        unsigned int id = Describer::getIDForSerializedObject(ref);
        file << id;
}



void JsonDrooler::describeValue( String &ref)
{
        writeValueArrayComma();
        file << '"' << ref << '"';
}

void JsonDrooler::describeBlob(const String childName, nw::Pointer blob, unsigned int blobSize)
{
        this->push(childName);
//        const char* tmp = (const char*)blob;
        // FIXME check dat code I'm not using tmp why? wtf is going on here
          String value;

          if(Describer::encodingUsed == N0Slib_BinaryToTextEncoding_Base64)
                  value = utils::toBase64((const char*)blob, blobSize);
          else if(Describer::encodingUsed == N0Slib_BinaryToTextEncoding_Hexadecimal)
                  value = utils::toHex((const char*)blob, blobSize);
          else
                  std::cout << "unknown encoding" << std::endl;

          String encoding = N0Slib_BinaryToTextEncoding_Default;
          this->describe("encoding", encoding);
          this->describe("value", value );
        this->pop();
}

void JsonDrooler::describeValue( signed char& ref)
{
        writeValueArrayComma();
        file << (int)ref;
}
void JsonDrooler::describeValue( short& ref)
{
        writeValueArrayComma();
        file << ref;
}
void JsonDrooler::describeValue( unsigned short& ref)
{
        writeValueArrayComma();
        file << ref;
}
void JsonDrooler::describeValue( long& ref)
{
        writeValueArrayComma();
        file << ref;
}
void JsonDrooler::describeValue( unsigned long& ref)
{
        writeValueArrayComma();
        file << ref;
}
void JsonDrooler::describeValue( long long& ref)
{
        writeValueArrayComma();
        file << ref;
}
void JsonDrooler::describeValue( long double& ref)
{
        writeValueArrayComma();
        file << ref;
}

void JsonDrooler::comment(const String text)
{
        //Json doesn't support comments, may use Javascript comments
//      //write one line C++ Comment
//      if(text.find('\n') == String::npos) //npos == No position (not found)
//      {
//              file << SYSTEM_NEW_LINE << tabsForLevel() << "//" << text << SYSTEM_NEW_LINE;
//      }
//      //write C comment
//      else
//      {
//              file << SYSTEM_NEW_LINE << tabsForLevel() << "/*" << SYSTEM_NEW_LINE << text << SYSTEM_NEW_LINE << "*/" << SYSTEM_NEW_LINE;
//      }
}



bool JsonDrooler::push(const String childName)
{
        writeComma();
        //has a name // workaround for objects in arrays
        if(!childName.empty())
        {
                file << tabsForLevel() << '"' << childName << '"' << ": " << SYSTEM_NEW_LINE;
        }
        file << tabsForLevel() << '{' << SYSTEM_NEW_LINE;
        ++level;
        isFirstElement = true;
        return true;
}



void JsonDrooler::close()
{
        if(file.is_open())
        {
                pop();
                file.close();
        }
}


String JsonDrooler::tabsForLevel()
{
        std::stringstream ss;
        for (unsigned int i = 0; i < level; ++i) {
                ss << '\t';
        }
        return ss.str();
}

void JsonDrooler::writeComma()
{
        if(isFirstElement == false)
        {
                file << ',' << SYSTEM_NEW_LINE;
        }
        else
        {
                isFirstElement = false;
        }
}

void JsonDrooler::writeValueArrayComma()
{
        if(!openArrays.empty() && openArrays.top().isValueArray)
        {
                writeComma();
                file << tabsForLevel();
        }
}

}  // namespace nw