#include "ProgressTracker.h"
#include <stdio.h>
/* Helper class for managing valid chunks in non-sequential scenarios 
e.g. progressive downloading */

ProgressTracker::ProgressTracker()
{
	current_position=0;
	current_chunk=0;
	chunks[0]=0;
	chunks[null_position]=null_position;
};

void ProgressTracker::Write(uint64_t bytes_written)
{
	nu::AutoLock list_lock(list_guard);
	ChunkList::iterator next, itr = chunks.find(current_chunk);
	current_position += bytes_written;
	if (itr->second < current_position)
		itr->second = current_position;

	for (;;)
	{
		next = itr;
		next++;
		if (next != chunks.end() && (next->first <= itr->second))
		{
			itr->second = next->second;
			chunks.erase(next);
		}
		else
			break;
	}
}

bool ProgressTracker::Valid(uint64_t requested_position, uint64_t requested_end, uint64_t *available) 
{
	nu::AutoLock list_lock(list_guard);
	for (ChunkList::iterator itr=chunks.begin();itr!=chunks.end();itr++)
	{
		if (requested_position >= itr->first)
		{
			if (requested_position < itr->second)
			{
				if (available)
					*available = itr->second - requested_position;

				if (requested_end <= itr->second)
					return true;
				else
					return false;

			}
		}
	}
	if (available)
		*available = 0;
	return false;
}

bool ProgressTracker::Seek(uint64_t requested_position, uint64_t requested_end, uint64_t *new_start, uint64_t *new_end)
{
	nu::AutoLock list_lock(list_guard);
	uint64_t last_good_start=0;
	ChunkList::iterator itr;
	for (itr=chunks.begin();itr!=chunks.end();itr++)
	{
		if (requested_position >= itr->first)
		{
			current_chunk = itr->first;
			if (requested_position <= itr->second)
			{
				ChunkList::iterator next = itr;
				next++;
				*new_end = next->first;

				*new_start = current_position = itr->second;

				if (requested_end <= itr->second)
				{
					return true;
				}
				else
				{
					return false;
				}
			}
			else
			{
				last_good_start = itr->second;
			}
		}
	}
	if (last_good_start > requested_position)
		*new_start = current_position = last_good_start;
	else
	{

		*new_start = current_chunk = current_position = requested_position;
		chunks[current_chunk] = current_chunk;
	}
	*new_end = null_position;
	return false;
}

void ProgressTracker::Dump()
{
	ChunkList::iterator itr;
	for (itr=chunks.begin();itr!=chunks.end();itr++)
	{
		printf("%llu - %llu\n", itr->first, itr->second);
	}

}


const uint64_t ProgressTracker::null_position = (uint64_t)-1;