root/src/MarkupWriter.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 "MarkupWriter.h"

namespace nw
{

String MarkupWriter::motherTagName = N0Ware_Default_MotherTagName;

MarkupWriter::MarkupWriter(std::ostream& output) : Writer(), output(output)
{
        motherTag = new Tag(motherTagName);
        currentTag = motherTag;
        selectedTag = motherTag;
        didWrite = false;
}

MarkupWriter::MarkupWriter(const String filepath) : Writer(), output(file) {
        openFile(filepath);
        motherTag = new Tag(motherTagName);
        currentTag = motherTag;
        selectedTag = motherTag;
        didWrite = false;
}

MarkupWriter::~MarkupWriter()
{
        if(!didWrite) {
                std::cout << "Warning: Deconstructing Writer without closing."
                                         " Data might not be written." << std::endl;
                if (file.is_open()) {
                        file.close();
                }
        }
        delete motherTag; // delete recursively
}

bool MarkupWriter::openFile(const String filepath) {
        file.open(filepath.c_str(), std::fstream::out);
        return file.is_open();
}


bool MarkupWriter::push(const String tagName)
{
        this->currentTag->addNewChild(tagName);
        this->currentTag = currentTag->getLastChild();
        return true;
}
void MarkupWriter::describeArray(const String arrayName, const String elementsName, unsigned int size)
{
        if(!arrayName.empty())
                push(arrayName);

        MetaArray newArray;
        newArray.nameOfArray = arrayName;
        newArray.nameOfElements = elementsName;
        newArray.size = size;
        newArray.isValueArray = false;
        openArrays.push(newArray);
}

void MarkupWriter::describeValueArray(const String arrayName, unsigned int size)
{
        describeArray(arrayName, "", size);
        openArrays.top().isValueArray = true;
        currentTag->setIsValueArray(true);
}

bool MarkupWriter::enterNextElement(unsigned int iterator)
{
        if(!openArrays.empty() && openArrays.top().isValueArray)
        {
                if(iterator < openArrays.top().size)
                {
                        return true;
                }
                openArrays.pop();
                pop();
                return false;
        }

        if(iterator != 0)
                pop();
        if(iterator < openArrays.top().size)
        {
                if(!openArrays.top().isValueArray)
                        push(openArrays.top().nameOfElements);
                return true;
        }
        else
        {
                if(!openArrays.top().nameOfArray.empty())
                        pop(); //Close array wrapper with arrayName

                openArrays.pop();
                return false;
        }
}

Tag* MarkupWriter::getCurrentTag()
{
        return this->currentTag;
}

Tag* MarkupWriter::getMotherTag() {
        return this->motherTag;
}

std::vector<Tag*>& MarkupWriter::getChildren()
{
        if(this->currentTag != NULL)
        return this->currentTag->getChildren();
        std::vector<Tag*> *children = new std::vector<Tag*>();
        return *children;
}

void MarkupWriter::pop()
{
        Tag* nextTag;
        if(this->currentTag == NULL)
        {
                nextTag = motherTag;
                std::cout << "warning using pop more often than push currentTag is NULL";
        }
        else
        {
                nextTag = this->currentTag->getParent();
        }

        if(nextTag == NULL)
        {
                nextTag = motherTag;
        }
        this->currentTag = nextTag;
}

void MarkupWriter::close()
{
        if (!didWrite) {
                writeToOutput();
                didWrite = true;
                if (file.is_open()) {
                        file.close();
                }
        }
}
void MarkupWriter::describeName(const String name)
{
        selectedTag = currentTag->addNewChild(name);
}

void MarkupWriter::describeValueConst(const String& ref)
{
        addTag(ref);
}
void MarkupWriter::describeValueConst(const double& ref)
{
        addTag(ref);
}
void MarkupWriter::describeValueConst(const char& ref)
{
        short numValue = ref;
        addTag(numValue);

}
void MarkupWriter::describeValueConst(const unsigned char& ref)
{
        short numValue = ref;
        addTag(numValue);
}
void MarkupWriter::describeValueConst(const int& ref)
{
        addTag(ref);
}
void MarkupWriter::describeValueConst(const unsigned int& ref)
{
        addTag(ref);
}
void MarkupWriter::describeValueConst(const float& ref)
{
        addTag(ref);
}
void MarkupWriter::describeValueConst(const bool& ref)
{
        String booleanString;
        if(ref)
                booleanString = "true";
        else
                booleanString = "false";

        addTag(booleanString);
}
void MarkupWriter::describeValueConst(const Pointer ref)
{
        unsigned int id = Describer::getIDForSerializedObject(ref);
        addTag(id);
}
void MarkupWriter::describeBlobConst(const String blobName, const nw::Pointer blob, unsigned int blobSize)
{
        this->push(blobName);

          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 MarkupWriter::describeValueConst(const signed char& ref)
{
        short numValue = ref;
        addTag(numValue);
}
void MarkupWriter::describeValueConst(const short& ref)
{
        addTag(ref);
}
void MarkupWriter::describeValueConst(const unsigned short& ref)
{
        addTag(ref);
}
void MarkupWriter::describeValueConst(const long& ref)
{
        addTag(ref);
}
void MarkupWriter::describeValueConst(const unsigned long& ref)
{
        addTag(ref);
}
void MarkupWriter::describeValueConst(const long long& ref)
{
        addTag(ref);
}
void MarkupWriter::describeValueConst(const long double& ref)
{
        addTag(ref);
} //TODO parse these things in the Tag class

void MarkupWriter::comment(const String text)
{
        this->currentTag->addComment(text);
}

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

template<class T>
void MarkupWriter::addTag(T& ref)
{
        if(!openArrays.empty() && openArrays.top().isValueArray)
        {
                describeName("");
        }

        String stringValue;
        std::stringstream ss;
        ss << ref;
        ss >> stringValue;
        selectedTag->setValue(stringValue);
}

void MarkupWriter::addTag(String& ref)
{
        if(!openArrays.empty() && openArrays.top().isValueArray)
        {
                describeName("");
        }

        selectedTag->setValue(ref);
}

}