// ======HEADER========
#ifndef _LOM_DOWNLOADER_
#define _LOM_DOWNLOADER_

#if 0
#include "../Utility/Filesystem.h"
#include "../Utility/Logger.h"
#endif

#define CURL_STATICLIB
#include "curl/curl.h"

#include "SDL/SDL_thread.h"

#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

// do not use this in header
using std::string;
using std::vector;
using std::endl;

struct internalData
{
	bool			*finishedPtr;
	std::string		*urlPtr;
	std::string		*dataPtr;
	float			*progressPtr;
	vector<string>	*errorMessageList;
};



class Downloader
{
public:
	Downloader();
	~Downloader();

	void download(const char* url);
	bool downloadFinished();
	std::string getData();
	int getSize()			{ return mSize; }
	
	double getProgress()	{ return mProgress; }

private:
	static int writer(char *data, size_t size, size_t nmemb, std::string  
*writerData);

    // static to non-static wrappers
	static int cb_progress(void *ptr, double dlTotalSize, double dlCurrentSize, double ul, double ut) {
        Downloader *dnl = static_cast<Downloader *>(ptr);
        return dnl->progress(dlTotalSize, dlCurrentSize, ul, ut);
    }
    int progress(double dlTotalSize, double dlCurrentSize, double ul, double ut);

	static int download_func(void *progressPtr);

	SDL_Thread			*downloadThread;
	SDL_mutex			*progressMutex;

	std::string			mData;
	std::string			mDownloadURL;

	float				mProgress;
	bool				mIsFinished;

	int					mSize;

	std::vector<string>	mErrorMessages;

	internalData		classData;
		
};
#endif






// ======CPP===========
// #include "Downloader.h"

Downloader::Downloader() :	downloadThread(NULL),
							mData(""),
							mDownloadURL(""),
							mProgress(0.0),
							mIsFinished(false),
							mSize(0)
{
	// Set up the class data stuff so we can properly access it.
	classData.urlPtr			= &mDownloadURL;
	classData.dataPtr			= &mData;
	classData.progressPtr		= &mProgress;
	classData.finishedPtr		= &mIsFinished;
	classData.errorMessageList	= &mErrorMessages;

}


Downloader::~Downloader()
{
	for(unsigned int i = 0; i < mErrorMessages.size(); i++)
		std::cerr << mErrorMessages[i] << endl;
}


void Downloader::download(const char* url)
{
	mDownloadURL = url;
	if(mIsFinished)
	{
		mData = "";
		mIsFinished = false;
		mProgress = 0.0;
	}
	
	

	/*if(downloadThread == NULL)
		downloadThread = SDL_CreateThread(*/Downloader::download_func(/*,  */&classData);
	/*else
		mErrorMessages.push_back("You tard! There's a download already in progress!!");*/
	

}

int Downloader::writer(char *data, size_t size, size_t nmemb,  
std::string *buffer)
{
	// What we will return
	int result = 0;

	// Check that our buffer is not NULL.
	if (buffer != NULL)
	{
		// Append the data to the buffer
		buffer->append(data, size * nmemb);

		// How much did we write?
		result = size * nmemb;
	}

	return result;
}

int Downloader::progress(double dlTotalSize, double  dlCurrentSize, double, double)
{
    if (0.0 < dlTotalSize && 0.0 < dlCurrentSize)
        std::cerr << std::setw(5) << std::setprecision(1) << std::fixed << dlCurrentSize/dlTotalSize*100.0 << "%" << endl;
	
	return 0;
}


int Downloader::download_func(void *ptr)
{
	internalData *iData = reinterpret_cast<internalData *>(ptr);
	
	CURL *mCurl;
	mCurl = curl_easy_init();
	//float progressN = 0;
	std::string dataN;
	dataN = "";

    Downloader *downloader = new Downloader;
	
	curl_easy_setopt(mCurl, CURLOPT_VERBOSE, 1) ;
	curl_easy_setopt(mCurl, CURLOPT_HEADER, 0);
	curl_easy_setopt(mCurl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(mCurl, CURLOPT_NOPROGRESS, 0);
	curl_easy_setopt(mCurl, CURLOPT_PROGRESSFUNCTION, &Downloader::cb_progress);
	curl_easy_setopt(mCurl, CURLOPT_PROGRESSDATA, downloader);
	curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, writer);
	curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, &dataN);
	
	std::cerr << "(INF) Requesting URL '" << iData->urlPtr->c_str()  
<< "'..." << endl;
	curl_easy_setopt(mCurl, CURLOPT_URL, iData->urlPtr->c_str());

	*iData->finishedPtr = false;
	CURLcode returnCode = curl_easy_perform(mCurl);
	*iData->finishedPtr = true;
	
	if(returnCode == CURLE_OK)
		*iData->finishedPtr = true;
	else
		iData->errorMessageList->push_back(curl_easy_strerror(returnCode));

	std::cerr << "(INF) File has been downloaded." << endl;
	
	curl_easy_cleanup(mCurl);
	curl_global_cleanup();

	return 0;
}


bool Downloader::downloadFinished()
{
#if 0
	if(mIsFinished)
	{
		if(downloadThread != NULL)
		{
			SDL_KillThread(downloadThread);
			downloadThread = NULL;
		}
	}
#endif

	return mIsFinished;
}


std::string Downloader::getData()
{
	if(mIsFinished)
		return mData;
	else
		return "";
}

int main() {
    Downloader().download("http://www.curl.haxx.se/download/curl-7.19.6.tar.lzma");
}

