/*
 * Copyright (C) 2012 by
 *   MetraLabs GmbH (MLAB), GERMANY
 * and
 *   Neuroinformatics and Cognitive Robotics Labs (NICR) at TU Ilmenau, GERMANY
 * All rights reserved.
 *
 * Contact: info@mira-project.org
 *
 * Commercial Usage:
 *   Licensees holding valid commercial licenses may use this file in
 *   accordance with the commercial license agreement provided with the
 *   software or, alternatively, in accordance with the terms contained in
 *   a written agreement between you and MLAB or NICR.
 *
 * GNU General Public License Usage:
 *   Alternatively, this file may be used under the terms of the GNU
 *   General Public License version 3.0 as published by the Free Software
 *   Foundation and appearing in the file LICENSE.GPL3 included in the
 *   packaging of this file. Please review the following information to
 *   ensure the GNU General Public License version 3.0 requirements will be
 *   met: http://www.gnu.org/copyleft/gpl.html.
 *   Alternatively you may (at your option) use any later version of the GNU
 *   General Public License if such license has been publicly approved by
 *   MLAB and NICR (or its successors, if any).
 *
 * IN NO EVENT SHALL "MLAB" OR "NICR" BE LIABLE TO ANY PARTY FOR DIRECT,
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
 * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF "MLAB" OR
 * "NICR" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * "MLAB" AND "NICR" SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND "MLAB" AND "NICR" HAVE NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS.
 */

/**
 * @file vector
 *    Serialization/Deserialization of STL vector.
 *
 *    The filename was chosen to match the STL standard.
 *    Instead of
 *      #include <vector>
 *    use
 *      #include <serialization/adapters/std/vector>
 *
 * @author Erik Einhorn
 * @date   2010/07/16
 */

#ifndef _MIRA_SERIALIZATION_VECTOR_
#define _MIRA_SERIALIZATION_VECTOR_

#include <vector>

#include <serialization/ReflectorInterface.h>
#include <serialization/Array.h>

#include <serialization/IsTransparentSerializable.h>

namespace mira {

////////////////////////////////////////////////////////////////////////////////

/// Specialization of the non-intrusive reflect for std::vector
template<typename Reflector, typename T, typename Allocator>
void reflectRead(Reflector& r, std::vector<T, Allocator>& c)
{
	// store the size first
	uint32 count = c.size();

	typedef std::vector<T, Allocator> vector;
	static const std::string contextCount = typeName<vector>() + " ReflectCollectionCount";
	MIRA_REFLECT_CALL(Reflector, r, contextCount.c_str(),
	                 (serialization::ReflectCollectionCount<Reflector,vector>::reflect(r, count)));
	
	// store the elements as array
	serialization::PlainArray<T> array(c.data(), c.size());
	r.delegate(array); // no REFLECT_CTRLFLAG_TEMP_TRACKING here: the PlainArray itself is not trackable,
	                   // the content is just wrapped at its original position
}

/// Specialization of the non-intrusive reflect for std::vector
template<typename Reflector, typename T, typename Allocator>
void reflectWrite(Reflector& r, std::vector<T, Allocator>& c)
{
	// restore the size first
	uint32 count;
	{
		typedef std::vector<T, Allocator> vector;
		static const std::string contextCount = typeName<vector>() + " ReflectCollectionCount";
		MIRA_REFLECT_CALL(Reflector, r, contextCount.c_str(),
			              (serialization::ReflectCollectionCount<Reflector,vector>::reflect(r, count)));
	}
	// reserve the space and create the elements
	c.resize(count);
	// restore the elements as array
	serialization::PlainArray<T> array(c.data(), c.size());
	r.delegate(array);
}

////////////////////////////////////////////////////////////////////////////////

namespace serialization {

////////////////////////////////////////////////////////////////////////////////

/**
 * Reflection of vector<bool> items.
 * This is needed for the read case (only), in order to enable specialization
 * for the MetaSerializer. 
 */
template<typename Reflector, typename Allocator>
struct ReflectReadBoolVectorItems
{
	static void reflect(Reflector& r, std::vector<bool, Allocator>& c)
	{
		uint32 count = c.size();

		// store each item
		for(uint32 id=0; id<count; ++id)
		{
			bool data = c[id]; // explicitly convert _Bit_reference to bool
			MIRA_PROPERTY_WITH_ID(r, "item", "item["+toString(id)+"]", data, "");
		}
	}
};

////////////////////////////////////////////////////////////////////////////////

} // namespace

////////////////////////////////////////////////////////////////////////////////

/**
 * Specialization of the non-intrusive reflect for std::vector<bool> because
 * the internal array of std::vector<bool> is a _Bit_reference* and can not be used
 * directly.
 */
template<typename Reflector, typename Allocator>
void reflectRead(Reflector& r, std::vector<bool, Allocator>& c)
{
	// store the size first
	uint32 count = c.size();
	{
		typedef std::vector<bool, Allocator> vector;
		MIRA_REFLECT_CALL(Reflector, r, "std::vector<bool> ReflectCollectionCount",
			              (serialization::ReflectCollectionCount<Reflector,vector>::reflect(r, count)));
	}

	serialization::ReflectReadBoolVectorItems<Reflector, Allocator>::reflect(r, c);
}

/**
 * Specialization of the non-intrusive reflect for std::vector<bool> because
 * the internal array of std::vector<bool> is a _Bit_reference* and can not be used
 * directly.
 */
template<typename Reflector, typename Allocator>
void reflectWrite(Reflector& r, std::vector<bool, Allocator>& c)
{
	// restore the size first
	uint32 count;
	{
		typedef std::vector<bool, Allocator> vector;
		MIRA_REFLECT_CALL(Reflector, r, "std::vector<bool> ReflectCollectionCount",
			              (serialization::ReflectCollectionCount<Reflector,vector>::reflect(r, count)));
	}
	// reserve the space and create the elements
	c.resize(count);
	// restore the elements as array
	for(uint32 id=0; id<count; ++id)
	{
		bool data; // need tmp bool here
		MIRA_PROPERTY_WITH_ID(r, "item", "item["+toString(id)+"]", data, "");
		c[id] = data;
	}
}

/// non-intrusive reflect for std::vector
template<typename Reflector, typename T, typename Allocator>
void reflect(Reflector& r, std::vector<T, Allocator>& c)
{
	splitReflect(r, c);
}

template<typename T, typename Allocator>
class IsCollection<std::vector<T, Allocator>> : public std::true_type {};

////////////////////////////////////////////////////////////////////////////////

} // namespace

#endif
