//------------------------------------------------------------------------------
// <copyright file="RawSerializationBuffer.cpp" company="LiquidRobotics">
//
// Copyright (c) 2014 Liquid Robotics, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// This software is associated with a release.  Liquid Robotics makes no
// representation that the design, interfaces or component distribution will
// remain unchanged in future releases.
//
// </copyright>
//
// <summary>
// </summary>
//
// <owner></owner>
//------------------------------------------------------------------------------


#include <sstream>
#include "RawSerializationBuffer.h"

using namespace std;

namespace LiquidRobotics {
namespace PayloadInterface {

static const string count_less_than_zero = "count cannot be less than 0";
static const string offset_less_than_zero = "offset cannot be less than 0";
static const string pData_is_null = "pData cannot be null";
static const string data_array_is_null = "data array cannot constitute a null reference";
static const string offset_plus_count_beyond_array = "the combination of the offset and the count cannot extend beyond the data length";


RawSerializationBuffer::RawSerializationBuffer(Endianness::EEndian eEndian)
: pArrayRead(NULL)
, pData(NULL)
, count(-1)
, offset(0)
, reading(false)
, endianness(eEndian)
{
}

RawSerializationBuffer::RawSerializationBuffer(Endianness::EEndian eEndian, int _count)
: pArrayRead(NULL)
, pData(NULL)
, count(_count)
, offset(0)
, reading(false)
, endianness(eEndian)
{
	arrayWrite.reserve(_count);
}

RawSerializationBuffer::RawSerializationBuffer(Endianness::EEndian eEndian, const byte* _pData, int _count, int _offset)
: pArrayRead(NULL)
, pData(_pData)
, count(_count)
, offset(_offset)
, reading(true)
, endianness(eEndian)
{
	if (count < 0) 			throw invalid_argument(count_less_than_zero);
	if (offset < 0) 		throw invalid_argument(offset_less_than_zero);
	if (pData == NULL) 		throw invalid_argument(pData_is_null);
}

RawSerializationBuffer::RawSerializationBuffer(Endianness::EEndian eEndian, const ByteArray& _data, int _count, int _offset)
: pArrayRead(&_data)
, pData(NULL)
, count(_count)
, offset(_offset)
, reading(true)
, endianness(eEndian)
{
	if (pArrayRead == NULL)						throw invalid_argument(data_array_is_null);
	if (count < 0) 								throw invalid_argument(count_less_than_zero);
	if (offset < 0) 							throw invalid_argument(offset_less_than_zero);
	if ((count+offset) >= pArrayRead->size()) 	throw invalid_argument(offset_plus_count_beyond_array);
}

RawSerializationBuffer::~RawSerializationBuffer()
{
}

byte RawSerializationBuffer::Get()
{

}

void RawSerializationBuffer::Put(byte b)
{

}


RawSerializationBuffer::string EEndian_ToString(EEndian eEndian)
{
	RawSerializationBuffer::string result;

	if (eEndian == BIG)
		result = "BIG";
	else if (eEndian == LITTLE)
		result = "LITTLE";
	else
	{
		stringstream sstm;

		sstm << (int) eEndian << "?";
		result = sstm.str();
	}

	return result;
}

ostream operator<<(std::ostream& out, const RawSerializationBuffer::Endianness& endianness)
{
	out << EEndian_ToString(endianness.GetDesired()) << " (reverse=" << (endianness.NumbersReversed() ? "true" : "false") << ")";
}

std::ostream& operator<<(std::ostream& out, const RawSerializationBuffer& buffer)
{
	out << "index=" << buffer.Index()
	   << " remaining=" << buffer.Remaining()
	   << " reading=" << (buffer.IsReadStream() ? "true" : "false")
	   << " endian={ " << endianness << " }";

	return out;
}

}
}
