/*********************************************************************
 * This file is part of the cpplibs suite.
 *
 * Copyright (C) 2001-2003 Topi Mäenpää
 * All rights reserved.
 *
 * This program is free software. You can redistribute and/or modify
 * it under the terms of the free software licence found in the
 * accompanying file "COPYING". The licence terms must always be
 * redistributed with this source file. The above copyright notice
 * must be reproduced in all modified and unmodified copies of this
 * source file.
 *
 * $Revision: 1.5 $
 *********************************************************************/

#ifndef _BLOB_H
#define _BLOB_H

#include "Object.h"

namespace util
{
	/**
	 * Blob (Binary Large OBject) is a class for storing a pointer to
	 * data and the size of the data. As a template, Blob can store
	 * pointers to any type of data.
	 **/
	template <class T> class Blob : virtual public Object
	{
	public:
		/**
		 * Create a new Blob.
		 *
		 * @param ptr a pointer to data
		 * @param length the number of items that can be sequentially accessed at the pointer
		 * @param release if true, the memory pointed to by <i>ptr</i> is released upon
		 * deletion of the Blob
		 * @param array if true, and release is true, then delete[] is
		 * used when destroying the internal pointer (instead of delete,
		 * which is used by default)
		 **/
		Blob(T* ptr = NULL, int len = 0, bool release = false, bool array = false) :
			_pData(ptr), _iLen(len), _bRelease(release), _bArray(array) {}
		/**
		 * Copy a Blob. The memory pointed by the pointer in <i>other</i>
		 * is not copied. Instead, the two Blobs now reference the same
		 * memory location.
		 **/
		Blob(const Blob& other) :
			_pData(other._pData), _iLen(other._iLen), _bRelease(false), _bArray(other._bArray) {}

		/**
		 * Destroy a Blob.
		 **/
		~Blob() { if (_bRelease) deleteData(); }

		/**
		 * Copy a blob. If the release flag is true, the memory pointer is
		 * deleted. Upon copying, the release flag is always set to false
		 * to ensure no data is deleted multiple times.
		 **/
		Blob& operator= (const Blob& other)
		{
			if (other._pData != _pData)
				{
					if (_bRelease) deleteData(data);
					_pData = other._pData;
					_iLen = other._iLen;
					_bArray = other._bArray;
					_bRelease = false;
				}
		}

		/**
		 * Returns true if and only if the two blobs point to the same
		 * memory location.
		 **/
		bool operator== (const Blob& other) const { return _pData == other._pData; }

		/**
		 * Get a pointer to the internal data.
		 **/
		const T* getData() const { return _pData; }

		/**
		 * Set the internal data pointer. If the release flag is true, the
		 * old data is deleted.
		 **/
		void setData(T* data)
		{
			if (data != _pData && _bRelease)
				deleteData();
			_pData = data;
		}
		/**
		 * Get a pointer to the internal data.
		 **/
		T* getData() { return _pData; }
		/**
		 * Get the size of the data.
		 **/
		int getLength() const { return _iLen; }
		/**
		 * Release the data. The release flag is set to false, and the
		 * internal pointer is returned.
		 **/
		T* release() { _bRelease = false; return _pData; }

		/**
		 * Check the release flag. If release is true, this blob is the
		 * "owner" of its internal pointer.
		 **/
		bool isOwner() const { return _bRelease; }

		/**
		 * Set the ownership of the internal pointer.
		 *
		 * @param release if true, this blob deletes its internal pointer
		 * when destroyed
		 **/
		void setOwner(bool release) { _bRelease = release; }

		/**
		 * Check whether the internal pointer is an array. If it is,
		 * delete[] is used instead of delete when destroying the pointer.
		 **/
		bool isArray() const { return _bArray; }

		/**
		 * Set the type of the internal pointer.
		 *
		 * @param array if true, delete[] is used instead of delete (the
		 * default) when destroying the internal pointer
		 **/
		void setArray(bool array) { _bArray = array; }
	private:
		T* _pData;
		int _iLen;
		bool _bRelease, _bArray;

		void deleteData()
		{
			if (_bArray)
				delete[] _pData;
			else
				delete _pData;
		}
	};
}

#endif
