//==============================================================================
/*! \file
 * OpenMesh Toolkit for mesh analysis    \n
 * Copyright (c) 2010 by Rostislav Hulik     \n
 *
 * Author:  Rostislav Hulik, rosta.hulik@gmail.com  \n
 * Date:    2010/10/20                          \n
 *
 * This file is part of software developed for support of Rostislav Hulik's dissertation thesis at dcgm-robotics@FIT group.
 *
 * This file 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.
 * 
 * This file 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 this file.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Description:
 * - Class implements a serializable matrix concept to be used in mesh property
 */

#ifndef _OM_SERIALIZABLE_MATRIX_H_
#define _OM_SERIALIZABLE_MATRIX_H_

#include <MDSTk\Math\mdsMatrix.h>
#include <OpenMesh\Core\Utils\BaseProperty.hh>
#include <OMToolkit\IO\OMStoreRestore.h>

namespace OMToolkit {
namespace Types {

	/**
	 * Class is supposed to be used as mesh property - can be serialized
	 */
	template <typename T>
	class OMSerializableMatrix : public Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::AutoAlign>
	{
		public:
		
			/**
			 * Constructor with specified size
			 * @param nRows Number of matrix rows
			 * @param nCols Number of matrix collumns
			 */
			OMSerializableMatrix(int nRows, int nCols) : Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::AutoAlign>()
			{
				resize(nRows, nCols);
			}

			/**
			 * Constructor creates empty matrix
			 */
			OMSerializableMatrix() : Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::AutoAlign>()
			{
			}
	}; // class OMSerializableMatrix
} // namespace Types
} // namespace OMToolkit

namespace OpenMesh{
namespace IO{

	/**
	 * Binary serializer for OMSerializableMatrix
	 */
	template <class T> struct binary<OMToolkit::Types::OMSerializableMatrix<T>>
    {
		/**
		 * Definition of value type
		 */
		typedef OMToolkit::Types::OMSerializableMatrix<T> value_type;

		/**
		 * Must be defined for writer/reader
		 */
		static const bool is_streamable = true;

		/**
		 * Static sizeof method - we have unknown size
		 */

		static size_t size_of(void) 
		{ 
			return UnknownSize;
		}

		/**
		 * Dynamic sizeof method - computes size of serialized structure
		 */
		static size_t size_of(const value_type& _v) 
		{ 
			return _v.size() * sizeof(T) + 2 * sizeof(int);
		}
    
		/**
		 * Store into output stream
		 * Stores two ints as size of matrix and then sequence of values
		 */
		static size_t store(std::ostream& _os, const value_type& _v, bool _swap=false)
		{ 
			size_t bytes;
			int size = _v.size();
			bytes = IO::store( _os, _v.rows(), _swap);
			bytes += IO::store( _os, _v.cols(), _swap);
			for (int i = 0; i < size; ++i)
				bytes += IO::store( _os, _v(i), _swap );
			return _os.good() ? bytes : 0;
		}

		/**
		 * Restore from intput stream
		 * Restores size of matrix, reallocates _v and restores values
		 */
		static size_t restore( std::istream& _is, value_type& _v, bool _swap=false)
		{ 
			size_t bytes;
			int rows, cols;
			bytes = IO::restore( _is, rows, _swap );
			bytes += IO::restore( _is, cols, _swap );
			_v.resize(rows, cols);
			unsigned int size = rows * cols;

			for (unsigned int i = 0; i < size && _is.good(); ++i)
				bytes += IO::restore( _is, _v(i), _swap );
			return _is.good() ? bytes : 0;
		}
    };
} // namespace IO
} // namespace OpenMesh

#endif //_OM_SERIALIZABLE_MATRIX_H_