/**
 *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

typedef boost::shared_ptr<PartData::UsedRange> UsedRangePtr;

class PartData {
public:
	PartData(const std::string &name, uint64_t size);

	//! Allows modules to register chunk availability maps, so PartData
	//! can decide the lowest-available chunk to be returned from get*
	//! methods
	void addChunkMask(uint32_t chunkSize, std::vector<bool> chunks);

	//! @name Getters
	//! All of these take size argument, which indicates how large the
	//! resulting used range should be. This should match whatever the
	//! module passes to addChunkMask() in order for getLeastAvailFree()
	//! to work properly (it relies on that data).
	//! @{
	//! Gets a truly random unused range.
	UsedRangePtr getRandomFree(uint32_t size);
	//! Gets next unused range, starting from beginning
	UsedRangePtr getNextFree(uint32_t size);
	//! Gets the currnetly least available range
	UsedRangePtr getLeastAvailFree(uint32_t size);
	//!@}

	//! Write method simply writes data starting at specified offset. If
	//! there are no locks currently on the range, and the range is indeed
	//! incomplete, everything works. If something goes wrong, exceptions
	//! will be generated.
	void write(uint64_t beginOffset, const std::string &data);

	//! Check for completeness, either the entire file (used internally), or
	//! a specific subrange (also used internally). Public only for
	//! completeness.
	bool isComplete();
	bool isComplete(Range64 subRange);
private:
	//! Copying part files is not allowed
	PartData(const PartData&);
	PartData& operator=(const PartData&);

	//! Only allowed by SharedFile
	~PartData();

	//! UsedRange concept is similar to many thread libraries lock object
	//! concepts - you retrieve one via get() methods in PartData, and when
	//! it is destroyed, it takes care that all used/locked ranges do get
	//! freed properly. This object may only be used when wrapped in
	//! boost::shared_ptr.
	class UsedRange : public Range64 {
	public:
		//! Hard-lock a subrange. Note that the lock is freed when this
		//! UsedRange object is destroyed, when the locked range is
		//! populated via write() method, or via explicit free() call.
		void lock(Range64 subRange);

		//! Free a previosly hard-locked range
		void free(Range64 subRange);

		//! Identical method as in PartData class, this is provided for
		//! completeness.
		void write(uint64_t beginOffset, const std::string &data);
	private:
		friend class boost::checked_deleter;
		friend class PartData;

		//! Allowed only by PartData. UsedRange keeps a pointer back to
		//! its parent object, and also sets up event handers as
		//! neccesery to ensure the pointer remains valid.
		UsedRange(PartData *parent);

		//! Destruction is only allowed by PartData (not used) and
		//! boost::checked_deleter, which is used by shared_ptr wrapper.
		~UsedRange();

		//! copying is not allowed
		UsedRange(const UsedRange&);
		UsedRange& operator=(const UsedRange&);

		//! Ranges that are locked within this usedrange
		RangeList64 m_locked;
	};

	//! All that are complete
	RangeList64 m_complete;

	//! We keep weak references to all used ranges we have given out, for
	//! cases where we end up needing to return one of these (e.g. no other
	//! range can be found).
	RangeList<boost::weak_ptr<UsedRange> > m_used;

	//! Availability map. Outer key is chunksize, internal vector contains
	//! number of times a chunk has been seen on net.
	std::map<uint32_t, std::vector<uint32_t> > m_avail;
};