/* Copyright 2013 The MathWorks, Inc. */

#ifndef coder_tgtsvc_MessageAssembler_hpp
#define coder_tgtsvc_MessageAssembler_hpp

#include <memory>

namespace coder { namespace tgtsvc {

struct MessageAssembler
{
    enum Return {
        SUCCESS,
        INCOMPLETE,
        NO_RESOURCES
    };

    MessageAssembler() : pos_(0) {}

    template <typename Iterator>
    Return assemble(Iterator &it, Iterator end) {
        while (it != end) {

            while (it != end && pos_ < sizeof(MessageHeader)) {
                headerAddr()[pos_++] = *it++;
            }
            if (pos_ < sizeof(MessageHeader)) break;

            if (!msg_) {
                msg_.reset(Message::alloc(hdr_.payloadSize()));
                if (!msg_) return NO_RESOURCES;
                msg_->header(hdr_);
            }

            while (it != end && pos_ < msg_->transmitSize()) {
                msg_->transmitStart()[pos_++] = *it++;
            }

            if (pos_ == msg_->transmitSize()) {
                pos_ = 0;
                return SUCCESS;
            }
        }
        return INCOMPLETE;
    }

    std::unique_ptr<Message> message() { return std::move(msg_); }

    void reset() {
        msg_.reset();
        pos_ = 0;
    }

private:
    std::unique_ptr<Message> msg_;
    size_t pos_;                  
    MessageHeader hdr_;           

    uint8_t *headerAddr() { return reinterpret_cast<uint8_t*>(&hdr_); }
};

}}

#endif