#include "literals.hpp"

#include <algorithm>

namespace Compiler
{
    int Literals::getIntegerSize() const
    {
        return static_cast<int>(mIntegers.size() * sizeof(Interpreter::Type_Integer));
    }

    int Literals::getFloatSize() const
    {
        return static_cast<int>(mFloats.size() * sizeof(Interpreter::Type_Float));
    }

    int Literals::getStringSize() const
    {
        int size = 0;

        for (std::vector<std::string>::const_iterator iter(mStrings.begin()); iter != mStrings.end(); ++iter)
            size += static_cast<int>(iter->size()) + 1;

        if (size % 4) // padding
            size += 4 - size % 4;

        return size;
    }

    void Literals::append(std::vector<Interpreter::Type_Code>& code) const
    {
        for (const int& mInteger : mIntegers)
            code.push_back(*reinterpret_cast<const Interpreter::Type_Code*>(&mInteger));

        for (const float& mFloat : mFloats)
            code.push_back(*reinterpret_cast<const Interpreter::Type_Code*>(&mFloat));

        int stringBlockSize = getStringSize();
        int size = static_cast<int>(code.size());

        code.resize(size + stringBlockSize / 4);

        size_t offset = 0;

        for (const auto& mString : mStrings)
        {
            size_t stringSize = mString.size() + 1;

            std::copy(mString.c_str(), mString.c_str() + stringSize, reinterpret_cast<char*>(&code[size]) + offset);
            offset += stringSize;
        }
    }

    int Literals::addInteger(Interpreter::Type_Integer value)
    {
        int index = static_cast<int>(mIntegers.size());

        mIntegers.push_back(value);

        return index;
    }

    int Literals::addFloat(Interpreter::Type_Float value)
    {
        int index = static_cast<int>(mFloats.size());

        mFloats.push_back(value);

        return index;
    }

    int Literals::addString(const std::string& value)
    {
        int index = static_cast<int>(mStrings.size());

        mStrings.push_back(value);

        return index;
    }

    void Literals::clear()
    {
        mIntegers.clear();
        mFloats.clear();
        mStrings.clear();
    }
}