/*
	Neutrino-GUI  -   DBoxII-Project

	Copyright (C) 2001 Steffen Hehn 'McClean'
	Homepage: http://dbox.cyberphoria.org/

	Kommentar:

	Diese GUI wurde von Grund auf neu programmiert und sollte nun vom
	Aufbau und auch den Ausbaumoeglichkeiten gut aussehen. Neutrino basiert
	auf der Client-Server Idee, diese GUI ist also von der direkten DBox-
	Steuerung getrennt. Diese wird dann von Daemons uebernommen.


	License: GPL

	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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/* include <config.h> before <gui/filebrowser.h> to enable 64 bit file offsets */
#include <gui/filebrowser.h>

#include <gui/widget/buttons.h>
#include <gui/widget/icons.h>
#include <gui/widget/messagebox.h>

#include <driver/encoding.h>

#include <algorithm>
#include <iostream>
#include <cctype>

#include <global.h>
#include <neutrino.h>

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sstream>

#include <sys/stat.h>

#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>

#include <driver/encoding.h>

#include <xmltree/xmlinterface.h>

#ifdef __USE_FILE_OFFSET64
typedef struct dirent64 dirent_struct;
#define my_alphasort alphasort64
#define my_scandir scandir64
typedef struct stat64 stat_struct;
#define my_stat stat64
#define my_lstat lstat64
#else
typedef struct dirent dirent_struct;
#define my_alphasort alphasort
#define my_scandir scandir
typedef struct stat stat_struct;
#define my_stat stat
#define my_lstat lstat
#error not using 64 bit file offsets
#endif

#define SMSKEY_TIMEOUT 2000
//------------------------------------------------------------------------
size_t CurlWriteToString(void *ptr, size_t size, size_t nmemb, void *data)
{
	std::string* pStr = (std::string*) data;
	pStr->append((char*) ptr, nmemb); // do only add the correct size, do not go until end of data (chunked transfer)
	return size*nmemb;
}

//------------------------------------------------------------------------
//------------------------------------------------------------------------

SMSKeyInput::SMSKeyInput()
{
	resetOldKey();
	m_timeout = SMSKEY_TIMEOUT;
}
//------------------------------------------------------------------------

unsigned char SMSKeyInput::handleMsg(const neutrino_msg_t msg)
{
	timeval keyTime;
	gettimeofday(&keyTime,NULL);
	bool timeoutNotReached = (keyTime.tv_sec*1000+keyTime.tv_usec/1000
				  <= m_oldKeyTime.tv_sec*1000+m_oldKeyTime.tv_usec/1000 + m_timeout);

// 	printf("act: %ld , old: %ld (diff: %ld ) , timeout: %ld => timout= %d\n",
// 	       keyTime.tv_sec*1000+keyTime.tv_usec/1000,
// 	       m_oldKeyTime.tv_sec*1000+m_oldKeyTime.tv_usec/1000,
// 	       keyTime.tv_sec*1000+keyTime.tv_usec/1000 -
// 	       m_oldKeyTime.tv_sec*1000+m_oldKeyTime.tv_usec/1000,
// 	       m_timeout,!timeoutNotReached);

	unsigned char key = 0;
	if(msg == CRCInput::RC_1)
	{
			key = '1';
	}
	if(msg == CRCInput::RC_2)
	{
		if(m_oldKey == 'a' && timeoutNotReached)
			key = 'b';
		else if(m_oldKey == 'b' && timeoutNotReached)
			key = 'c';
		else if(m_oldKey == 'c' && timeoutNotReached)
			key = '2';
		else
			key = 'a';
	}
	else if(msg == CRCInput::RC_3)
	{
		if(m_oldKey == 'd' && timeoutNotReached)
			key = 'e';
		else if(m_oldKey == 'e' && timeoutNotReached)
			key = 'f';
		else if(m_oldKey == 'f' && timeoutNotReached)
			key = '3';
		else
			key = 'd';
	}
	else if(msg == CRCInput::RC_4)
	{
		if(m_oldKey == 'g' && timeoutNotReached)
			key = 'h';
		else if(m_oldKey == 'h' && timeoutNotReached)
			key = 'i';
		else if(m_oldKey == 'i' && timeoutNotReached)
			key = '4';
		else
			key = 'g';
	}
	else if(msg == CRCInput::RC_5)
	{
		if(m_oldKey == 'j' && timeoutNotReached)
			key = 'k';
		else if(m_oldKey == 'k' && timeoutNotReached)
			key = 'l';
		else if(m_oldKey == 'l' && timeoutNotReached)
			key = '5';
		else
			key = 'j';
	}
	else if(msg == CRCInput::RC_6)
	{
		if(m_oldKey == 'm' && timeoutNotReached)
			key = 'n';
		else if(m_oldKey == 'n' && timeoutNotReached)
			key = 'o';
		else if(m_oldKey == 'o' && timeoutNotReached)
			key = '6';
		else
			key = 'm';
	}
	else if(msg == CRCInput::RC_7)
	{
		if(m_oldKey == 'p' && timeoutNotReached)
			key = 'q';
		else if(m_oldKey == 'q' && timeoutNotReached)
			key = 'r';
		else if(m_oldKey == 'r' && timeoutNotReached)
			key = 's';
		else if(m_oldKey == 's' && timeoutNotReached)
			key = 's';
		else
			key = 'p';
	}
	else if(msg == CRCInput::RC_8)
	{
		if(m_oldKey == 't' && timeoutNotReached)
			key = 'u';
		else if(m_oldKey == 'u' && timeoutNotReached)
			key = 'v';
		else if(m_oldKey == 'v' && timeoutNotReached)
			key = '8';
		else
			key = 't';
	}
	else if(msg == CRCInput::RC_9)
	{
		if(m_oldKey == 'w' && timeoutNotReached)
			key = 'x';
		else if(m_oldKey == 'x' &&timeoutNotReached)
			key = 'y';
		else if(m_oldKey == 'y' &&timeoutNotReached)
			key = 'z';
		else if(m_oldKey == 'z' && timeoutNotReached)
			key = '9';
		else
			key = 'w';
	}
	else if(msg == CRCInput::RC_0)
	{
		key = '0';
	}
	m_oldKeyTime=keyTime;
	m_oldKey=key;
	return key;
}
//------------------------------------------------------------------------

void SMSKeyInput::resetOldKey()
{
	m_oldKeyTime.tv_sec = 0;
	m_oldKeyTime.tv_usec = 0;
	m_oldKey = 0;
}

unsigned char SMSKeyInput::getOldKey() const
{
	return m_oldKey;
}

const timeval* SMSKeyInput::getOldKeyTime() const
{
 	return &m_oldKeyTime;
}

time_t SMSKeyInput::getOldKeyTimeSec() const
{
	return m_oldKeyTime.tv_sec;
}


int SMSKeyInput::getTimeout() const
{
	return m_timeout;
}

void SMSKeyInput::setTimeout(int timeout)
{
	m_timeout = timeout;
}


//------------------------------------------------------------------------
//------------------------------------------------------------------------

bool comparetolower(const char a, const char b)
{
	return tolower(a) < tolower(b);
};

// sort operators
bool sortByName (const CFile& a, const CFile& b)
{
	if (std::lexicographical_compare(a.Name.begin(), a.Name.end(), b.Name.begin(), b.Name.end(), comparetolower))
		return true;

	if (std::lexicographical_compare(b.Name.begin(), b.Name.end(), a.Name.begin(), a.Name.end(), comparetolower))
		return false;

	return a.Mode < b.Mode;
/*
	int result = __gnu_cxx::lexicographical_compare_3way(a.Name.begin(), a.Name.end(), b.Name.begin(), b.Name.end(), comparetolower);

	if (result == 0)
		return a.Mode < b.Mode;
	else
		return result < 0;
*/
}

bool sortByNameDirsFirst(const CFile& a, const CFile& b)
// Sorts alphabetically with Directories first
{
	int typea, typeb;
	typea = a.getType();
	typeb = b.getType();

	if (typea == CFile::FILE_DIR)
		if (typeb == CFile::FILE_DIR)
			//both directories
			return sortByName(a, b);
		else
			//only a is directory
			return true;
	else if (typeb == CFile::FILE_DIR)
		//only b is directory
		return false;
	else
		//no directory
		return sortByName(a, b);
}

bool sortByType (const CFile& a, const CFile& b)
{
	if(a.Mode == b.Mode)
		return sortByName(a, b);
	else
		return a.Mode < b.Mode;
}

bool sortByDate (const CFile& a, const CFile& b)
{
	if(a.getFileName()=="..")
		return true;
	if(b.getFileName()=="..")
		return false;
	return a.Time < b.Time ;
}

bool sortBySize (const CFile& a, const CFile& b)
{
	if(a.getFileName()=="..")
		return true;
	if(b.getFileName()=="..")
		return false;
	return a.Size < b.Size;
}

bool (* const sortBy[FILEBROWSER_NUMBER_OF_SORT_VARIANTS])(const CFile& a, const CFile& b) =
{
	&sortByName,
	&sortByNameDirsFirst,
	&sortByType,
	&sortByDate,
	&sortBySize
};

const neutrino_locale_t sortByNames[FILEBROWSER_NUMBER_OF_SORT_VARIANTS] =
{
	LOCALE_FILEBROWSER_SORT_NAME,
	LOCALE_FILEBROWSER_SORT_NAMEDIRSFIRST,
	LOCALE_FILEBROWSER_SORT_TYPE,
	LOCALE_FILEBROWSER_SORT_DATE,
	LOCALE_FILEBROWSER_SORT_SIZE
};

//------------------------------------------------------------------------

CFileBrowser::CFileBrowser()
{
	commonInit();
	base = "";
	m_Mode = ModeFile;
}

CFileBrowser::CFileBrowser(const char * const _base, const tFileBrowserMode mode)
{
	commonInit();
	base = _base;
	m_Mode = mode;
}

void CFileBrowser::commonInit()
{
	frameBuffer = CFrameBuffer::getInstance();

	Filter = NULL;
	use_filter = true;
	Multi_Select = false;
	Dirs_Selectable = false;
	Dir_Mode = false;
	Hide_records = false;
	selected = 0;
	selections.clear();

	x = g_settings.screen_StartX + 20;
	y = g_settings.screen_StartY + 20;

	width = (g_settings.screen_EndX - g_settings.screen_StartX - 40);
	height = (g_settings.screen_EndY - g_settings.screen_StartY - 40);

	theight = g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_TITLE]->getHeight();
	fheight = g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->getHeight();
	if (fheight == 0)
		fheight = 1; /* avoid div by zero on invalid font */
	foheight = 30;

	liststart = 0;
	listmaxshow = std::max(1,(int)(height - theight - 2 * foheight)/fheight);

	//recalc height
	height = theight + listmaxshow * fheight + 2 * foheight;

	m_SMSKeyInput.setTimeout(SMSKEY_TIMEOUT);
}

//------------------------------------------------------------------------


CFileBrowser::~CFileBrowser()
{
}

//------------------------------------------------------------------------

CFile *CFileBrowser::getSelectedFile()
{
	if ((!(filelist.empty())) && (!(filelist[selected].Name.empty())))
		return &filelist[selected];
	else
		return NULL;
}

//------------------------------------------------------------------------

void CFileBrowser::ChangeDir(const std::string & filename, int selection)
{
	std::string newpath;
	if((m_Mode != ModeSC) && (filename == ".."))
	{
		std::string::size_type pos = Path.substr(0,Path.length()-1).rfind('/');

#ifdef ENABLE_MOVIEPLAYER_VLC
		bool is_vlc = (strncmp(Path.c_str(), VLC_URI, strlen(VLC_URI)) == 0);
#endif
		if (pos == std::string::npos)
		{
			newpath = Path;
		}
		else
		{
#ifdef ENABLE_MOVIEPLAYER_VLC
			if (is_vlc && (pos < strlen(VLC_URI) - 1))
				newpath = VLC_URI;
			else
#endif
				newpath = Path.substr(0, pos + 1);
		}

#ifdef ENABLE_MOVIEPLAYER_VLC
		if (strncmp(is_vlc ? &(newpath.c_str()[strlen(VLC_URI)]) : newpath.c_str(), base.c_str(), base.length()) != 0)
			return;
#endif
	}
	else
	{
		newpath=filename;
	}
	if(m_Mode != ModeSC && (newpath.rfind('/') != newpath.length()-1 || newpath.length() == 0))
	{
		newpath += '/';
	}
	filelist.clear();
	Path = newpath;
	name = newpath;
	CFileList allfiles;
	readDir(newpath, &allfiles);
	// filter
	CFileList::iterator file = allfiles.begin();
	for(; file != allfiles.end() ; file++)
	{
		if(Filter != NULL && (!S_ISDIR(file->Mode)) && use_filter)
		{
			if(!Filter->matchFilter(file->Name))
			{
				continue;
			}
			if(Hide_records) {
				int ext_pos = file->Name.rfind('.');
				if( ext_pos > 0) {
					std::string extension = file->Name.substr(ext_pos + 1, name.length() - ext_pos);
					if(strcasecmp(extension.c_str(), "ts") == 0) {
						std::string fname = file->Name.substr(0, ext_pos) + ".xml";
						if(access(fname.c_str(), F_OK) == 0)
							continue;
					}
				}
			}
		}
		if(Dir_Mode && (!S_ISDIR(file->Mode)))
		{
			continue;
		}
		filelist.push_back(*file);
	}
	// sort result
	sort(filelist.begin(), filelist.end(), sortBy[g_settings.filebrowser_sortmethod]);

	selected = 0;
	if ((selection != -1) && (selection < (int)filelist.size()))
		selected = selection;
	paintHead();
	paint();
}

//------------------------------------------------------------------------
bool CFileBrowser::readDir(const std::string & dirname, CFileList* flist)
{
	bool ret;

#ifdef ENABLE_INTERNETRADIO
	if (m_Mode == ModeSC) {
		ret = readDir_sc(dirname, flist);
	}
	else
#endif
#ifdef ENABLE_MOVIEPLAYER_VLC
	if (strncmp(dirname.c_str(), VLC_URI, strlen(VLC_URI)) == 0)
	{
		ret = readDir_vlc(dirname, flist);
	}
	else
#endif
	{
		ret = readDir_std(dirname, flist);
	}
	return ret;
}

#ifdef ENABLE_MOVIEPLAYER_VLC
bool CFileBrowser::readDir_vlc(const std::string & dirname, CFileList* flist)
{
//	printf("readDir_vlc %s\n",dirname.c_str());
	std::string answer="";
	char *dir_escaped = curl_escape(dirname.substr(strlen(VLC_URI)).c_str(), 0);
	std::string url = m_baseurl;
	url += dir_escaped;
	curl_free(dir_escaped);
	std::cout << "[FileBrowser] vlc URL: " << url << std::endl;
	CURL *curl_handle;
	CURLcode httpres;
	/* init the curl session */
	curl_handle = curl_easy_init();
	/* timeout. 15 seconds should be enough */
	curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 15);
	/* specify URL to get */
	curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
	/* send all data to this function  */
	curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, CurlWriteToString);
	/* we pass our 'chunk' struct to the callback function */
	curl_easy_setopt(curl_handle, CURLOPT_FILE, (void *)&answer);
	/* Generate error if http error >= 400 occurs */
	curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
	/* error handling */
	char error[CURL_ERROR_SIZE];
	curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error);
	/* get it! */
	httpres = curl_easy_perform(curl_handle);
	/* cleanup curl stuff */
	curl_easy_cleanup(curl_handle);

	// std::cout << "Answer:" << std::endl << "----------------" << std::endl << answer << std::endl;

	if (!answer.empty() && httpres == 0)
	{
		xmlDocPtr answer_parser = parseXml(answer.c_str());

		if (answer_parser != NULL) {
			xmlNodePtr element = xmlDocGetRootElement(answer_parser);
			element = element->xmlChildrenNode;
			char *ptr;
			if (element == NULL) {
				printf("[FileBrowser] vlc: Drive is not readable. Possibly no disc inserted\n");
				CFile file;
				file.Mode = S_IFDIR + 0777 ;
				file.Name = dirname + "..";
				file.Size = 0;
				file.Time = 0;
				flist->push_back(file);
			} else {
				while (element) {
					CFile file;
					ptr = xmlGetAttribute(element, "type");
					if (strcmp(ptr, "directory")==0)
						file.Mode = S_IFDIR + 0777 ;
					else
						file.Mode = S_IFREG + 0777 ;

					file.Name = dirname + xmlGetAttribute(element, "name");
					ptr = xmlGetAttribute(element, "size");
					if (ptr)
						file.Size = atoi(ptr);
					else
						file.Size = 0;
					file.Time = 0;

					element = element->xmlNextNode;
					flist->push_back(file);
				}
			}
			xmlFreeDoc(answer_parser);
			return true;
		}
	}

	/* since all CURL error messages use only US-ASCII characters, when can safely print them as if they were UTF-8 encoded */
	if (httpres == 22) {
	    strcat(error, "\nProbably wrong vlc version\nPlease use vlc 0.8.5 or higher");
	}
	DisplayErrorMessage(error); // UTF-8
	CFile file;

	file.Name = dirname + "..";
	file.Mode = S_IFDIR + 0777;
	file.Size = 0;
	file.Time = 0;
	flist->push_back(file);

	return false;
}
#endif /* ENABLE_MOVIEPLAYER_VLC */

#ifdef ENABLE_INTERNETRADIO
bool CFileBrowser::readDir_sc(const std::string & dirname, CFileList* flist)
{
#define GET_SHOUTCAST_TIMEOUT	60
/* how the shoutcast xml interfaces looks/works:
1st step: get http://www.shoutcast.com/sbin/newxml.phtml
example answer:

<genrelist>
...
<genre name="Trance"/>
<genre name=...
...

2nd step: get http://www.shoutcast.com/sbin/newxml.phtml?genre=Trance
example answer:

<stationlist>
<tunein base="/sbin/tunein-station.pls"/>
<station name="TechnoBase.FM - 24h Techno, Dance, Trance, House and More - 128k MP3" mt="audio/mpeg" id="524" br="128" genre="Techno Trance Dance House" ct="We aRe oNe" lc="4466"/>
<station name=...
...

3rd step: get/decode playlist http://www.shoutcast.com/sbin/tunein-station.pls?id=524
and add to neutrino playlist

4th step: play from neutrio playlist
*/

//	printf("readDir_sc %s\n",dirname.c_str());
	std::string answer="";
//	char *dir_escaped = curl_escape(dirname.c_str(), 0);
	std::string url = m_baseurl;
//	url += dir_escaped;
//	curl_free(dir_escaped);
	url += dirname;
	std::cout << "[FileBrowser] SC URL: " << url << std::endl;
	CURL *curl_handle;
	CURLcode httpres;
	/* init the curl session */
	curl_handle = curl_easy_init();
	/* specify URL to get */
	curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str());
	/* send all data to this function  */
	curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, CurlWriteToString);
	/* we pass our 'chunk' struct to the callback function */
	curl_easy_setopt(curl_handle, CURLOPT_FILE, (void *)&answer);
	/* Generate error if http error >= 400 occurs */
	curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
	/* set timeout to 30 seconds */
	curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, GET_SHOUTCAST_TIMEOUT);

	/* error handling */
	char error[CURL_ERROR_SIZE];
	curl_easy_setopt(curl_handle, CURLOPT_ERRORBUFFER, error);
	/* get it! */
	httpres = curl_easy_perform(curl_handle);
	/* cleanup curl stuff */
	curl_easy_cleanup(curl_handle);

	//std::cout << "Answer:" << std::endl << "----------------" << std::endl << answer << std::endl;

	if (!answer.empty() && httpres == 0)
	{
printf("CFileBrowser::readDir_sc: read done, size %d\n", answer.size());
		xmlDocPtr answer_parser = parseXml(answer.c_str());

		if (answer_parser != NULL) {
			char *ptr;
			unsigned char xml_decode = 0;
			xmlNodePtr element = xmlDocGetRootElement(answer_parser);

			if (strcmp(xmlGetName(element), "genrelist") == 0)
				xml_decode = 1;
			else if (strcmp(xmlGetName(element), "stationlist") == 0)
				xml_decode = 2;
			element = element->xmlChildrenNode;

			if (element == NULL) {
				printf("[FileBrowser] SC: Directory cannot be read.\n");
				CFile file;
				file.Mode = S_IFDIR + 0777 ;
				file.Name = dirname + "..";
				file.Size = 0;
				file.Time = 0;
				flist->push_back(file);
			} else {
				char * tunein_base = NULL;

				if (xml_decode == 1) {
					CFile file;
					file.Mode = S_IFDIR + 0777 ;
					file.Name = " Top500"; // use space to have it at the beginning of the list
					file.Url = "/sbin/newxml.phtml?genre=Top500";
					file.Size = 0;
					file.Time = 0;
					flist->push_back(file);
				} else if (xml_decode == 2) {
					CFile file2;
					file2.Mode = S_IFDIR + 0777 ;
					file2.Name = "..";
					file2.Url = "/sbin/newxml.phtml";
					file2.Size = 0;
					file2.Time = 0;
					flist->push_back(file2);
				}
				while (element) {
					CFile file;
					if (xml_decode == 1) {
						file.Mode = S_IFDIR + 0777 ;
						file.Name = xmlGetAttribute(element, "name");
						file.Url = "/sbin/newxml.phtml?genre=" + file.Name;
						file.Size = 0;
						file.Time = 0;
						flist->push_back(file);
					}
					else if (xml_decode == 2) {
						ptr = xmlGetName(element);
						if (ptr != NULL) {
							if (strcmp(ptr, "tunein")==0) {
								ptr = xmlGetAttribute(element, "base");
								if (ptr)
									tunein_base = ptr;
							} else if (strcmp(ptr, "station")==0) {
								ptr = xmlGetAttribute(element, "mt");
								if (ptr && (strcmp(ptr, "audio/mpeg")==0)) {
									file.Mode = S_IFREG + 0777 ;
									file.Name = xmlGetAttribute(element, "name");
									file.Url = base + tunein_base + (std::string)"?id=" + xmlGetAttribute(element, "id");
									//printf("adding %s (%s)\n", file.Name.c_str(), file.Url.c_str());
									ptr = xmlGetAttribute(element, "br");
									if (ptr) {
										file.Size = atoi(ptr);
										file.Time = atoi(ptr);
									} else {
										file.Size = 0;
										file.Time = 0;
									}
									flist->push_back(file);
								}
							}
						}
					}
					element = element->xmlNextNode;
				}
			}
			xmlFreeDoc(answer_parser);
			return true;
		}
	}

	/* since all CURL error messages use only US-ASCII characters, when can safely print them as if they were UTF-8 encoded */
	if (httpres == 22) {
	    strcat(error, "\nProbably wrong link.");
	}
printf("CFileBrowser::readDir_sc: httpres %d error, %s\n", httpres, error);
	DisplayErrorMessage(error); // UTF-8
	CFile file;

	file.Name = dirname + "..";
	file.Mode = S_IFDIR + 0777;
	file.Size = 0;
	file.Time = 0;
	flist->push_back(file);

	return false;
}
#endif

bool CFileBrowser::readDir_std(const std::string & dirname, CFileList* flist)
{
//	printf("readDir_std %s\n",dirname.c_str());
	stat_struct statbuf;
	dirent_struct **namelist;
	int n;

	n = my_scandir(dirname.c_str(), &namelist, 0, my_alphasort);
	if (n < 0)
	{
		perror(("Filebrowser scandir: "+dirname).c_str());
		return false;
	}
	for(int i = 0; i < n;i++)
	{
		CFile file;
		if(strcmp(namelist[i]->d_name,".") != 0)
		{
			file.Name = dirname + namelist[i]->d_name;

//			printf("file.Name: '%s', getFileName: '%s' getPath: '%s'\n",file.Name.c_str(),file.getFileName().c_str(),file.getPath().c_str());
			if(my_stat((file.Name).c_str(),&statbuf) != 0)
				perror("stat error");
			else
			{
				file.Mode = statbuf.st_mode;
				file.Size = statbuf.st_size;
				file.Time = statbuf.st_mtime;
				flist->push_back(file);
			}
		}
		free(namelist[i]);
	}

	free(namelist);

	return true;
}

//------------------------------------------------------------------------

bool CFileBrowser::exec(const char * const dirname)
{
	neutrino_msg_t      msg;
	neutrino_msg_data_t data;

	bool res = false;

#ifdef ENABLE_INTERNETRADIO
	if (m_Mode == ModeSC) {
		m_baseurl = base;
	} else
#endif
	{
		m_baseurl = "http://" + g_settings.streaming_server_ip + ':'
			  + g_settings.streaming_server_port + "/requests/browse.xml?dir=";
	}
	name = dirname;
	std::replace(name.begin(), name.end(), '\\', '/');

	paintHead();
	ChangeDir(name);
	paint();
	paintFoot();

	int oldselected = selected;

	uint64_t timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_FILEBROWSER]);

	bool loop=true;
	while (loop)
	{
		g_RCInput->getMsgAbsoluteTimeout( &msg, &data, &timeoutEnd );
		neutrino_msg_t msg_repeatok = msg & ~CRCInput::RC_Repeat;

		if ( msg <= CRCInput::RC_MaxRC )
			timeoutEnd = CRCInput::calcTimeoutEnd(g_settings.timing[SNeutrinoSettings::TIMING_FILEBROWSER]);

		if(!CRCInput::isNumeric(msg))
		{
			m_SMSKeyInput.resetOldKey();
		}

		if (msg == CRCInput::RC_yellow)
		{
			if ((Multi_Select) && (selected < filelist.size()))
			{
				if(filelist[selected].getFileName() != "..")
				{
					if( (S_ISDIR(filelist[selected].Mode) && Dirs_Selectable) || !S_ISDIR(filelist[selected].Mode) )
					{
						filelist[selected].Marked = !filelist[selected].Marked;
						paintItem(selected - liststart);
					}
				}
				msg_repeatok = CRCInput::RC_down;	// jump to next item
			}
		}

		if ((msg == CRCInput::RC_red) || msg == CRCInput::RC_page_down)
		{
			selected += listmaxshow;
			if (selected >= filelist.size()) {
				if (((filelist.size() / listmaxshow) + 1) * listmaxshow == filelist.size() + listmaxshow) // last page has full entries
					selected = 0;
				else
					selected = selected < (((filelist.size() / listmaxshow) + 1) * listmaxshow) ? (filelist.size() - 1) : 0;
			}
			liststart = (selected / listmaxshow) * listmaxshow;
			paint();
		}
		else if ((msg == CRCInput::RC_green) || (msg == CRCInput::RC_page_up) )
		{
			if ((int(selected)-int(listmaxshow))<0)
				selected=filelist.size()-1;
			else
				selected -= listmaxshow;
			liststart = (selected/listmaxshow)*listmaxshow;
			paint();
		}
		else if (msg_repeatok == CRCInput::RC_up)
		{
			int prevselected=selected;
			if(selected==0)
			{
				selected = filelist.size()-1;
			}
			else
				selected--;
			paintItem(prevselected - liststart);
			unsigned int oldliststart = liststart;
			liststart = (selected/listmaxshow)*listmaxshow;
			if(oldliststart!=liststart)
			{
				paint();
			}
			else
			{
				paintItem(selected - liststart);
			}
		}
		else if (msg_repeatok == CRCInput::RC_down)
		{
			if (!(filelist.empty()))
			{
				int prevselected=selected;
				selected = (selected + 1) % filelist.size();
				paintItem(prevselected - liststart);
				unsigned int oldliststart = liststart;
				liststart = (selected/listmaxshow)*listmaxshow;
				if(oldliststart!=liststart)
					paint();
				else
					paintItem(selected - liststart);
			}
		}
		else if ( ( msg == CRCInput::RC_timeout ) )
		{
			selected = oldselected;
			loop=false;
		}
		else if ( msg == CRCInput::RC_right )
		{
			if (!(filelist.empty()))
			{
				if (S_ISDIR(filelist[selected].Mode))
				{
#ifdef ENABLE_INTERNETRADIO
					if (m_Mode == ModeSC) {
						ChangeDir(filelist[selected].Url);
					} else
#endif
					{
	 					if (filelist[selected].getFileName() != "..") {
							selections.push_back(selected);
							ChangeDir(filelist[selected].Name);
						}
					}
				}
			}
		}
		else if ( msg == CRCInput::RC_left )
		{
#ifdef ENABLE_INTERNETRADIO
			if (m_Mode == ModeSC)
			{
				for(unsigned int i = 0; i < filelist.size();i++) {
					if (S_ISDIR(filelist[i].Mode) && filelist[i].getFileName() == "..") {
						ChangeDir(filelist[i].Url);
						break;
					}
				}
			}
			else
#endif
			if (selections.size() > 0)
			{
				ChangeDir("..",selections.back());
				selections.pop_back();
			} else
			{
				ChangeDir("..");
			}
		}
		else if ( msg == CRCInput::RC_blue )
		{
			if(Filter != NULL)
			{
				use_filter = !use_filter;
				paintFoot();
				ChangeDir(Path);
			}
		}
		else if ( msg == CRCInput::RC_home )
		{
			loop = false;
		}
		else if ( msg == CRCInput::RC_spkr && strncmp(Path.c_str(), VLC_URI, strlen(VLC_URI)) != 0) //Not in vlc mode
		{
			if(".." !=(filelist[selected].getFileName().substr(0,2))) // do not delete that
			{
				std::stringstream _msg;
				_msg << g_Locale->getText(LOCALE_FILEBROWSER_DODELETE1) << " ";
				if (filelist[selected].getFileName().length() > 25)
				{
					_msg << filelist[selected].getFileName().substr(0, 25) << "...";
				}
				else
					_msg << filelist[selected].getFileName();

				_msg << " " << g_Locale->getText(LOCALE_FILEBROWSER_DODELETE2);
				if (ShowMsgUTF(LOCALE_FILEBROWSER_DELETE, _msg.str(), CMessageBox::mbrNo, CMessageBox::mbYes|CMessageBox::mbNo)==CMessageBox::mbrYes)
				{
					recursiveDelete(filelist[selected].Name.c_str());
					if(".ts" ==(filelist[selected].getFileName().substr(filelist[selected].getFileName().length()-3,filelist[selected].getFileName().length())))//if bla.ts
					{
						recursiveDelete((filelist[selected].Name.substr(0,filelist[selected].Name.length()-7)+".xml").c_str());//remove bla.xml von bla.ts
					}
					ChangeDir(Path);

				}
			}
		}
		else if (msg == CRCInput::RC_ok)
		{
			if (!(filelist.empty()))
			{
				if (filelist[selected].getFileName() == "..")
				{
#ifdef ENABLE_INTERNETRADIO
					if (m_Mode == ModeSC)
						ChangeDir(filelist[selected].Url);
					else
#endif
					{
						if (selections.size() > 0)
						{
							ChangeDir("..",selections.back());
							selections.pop_back();
						} else
						{
							std::string::size_type pos = Path.substr(0,Path.length()-1).rfind('/');
							if (pos != std::string::npos) {
								ChangeDir("..");
							}
							else {
								loop = false;
								res = true;
								filelist[selected].Name = "/";
							}
						}
					}
				}
				else
				{
					std::string filename = filelist[selected].Name;
					if ( filename.length() > 1 )
					{
						if((!Multi_Select) && S_ISDIR(filelist[selected].Mode) && !Dir_Mode)
						{
#ifdef ENABLE_INTERNETRADIO
							if (m_Mode == ModeSC)
								ChangeDir(filelist[selected].Url);
							else
#endif
								ChangeDir(filelist[selected].Name);
						}
						else
						{
							filelist[selected].Marked = true;
							loop = false;
							res = true;
						}
					}
				}
			}
		}
		else if (msg==CRCInput::RC_help)
		{
			if (++g_settings.filebrowser_sortmethod >= FILEBROWSER_NUMBER_OF_SORT_VARIANTS)
				g_settings.filebrowser_sortmethod = 0;

			sort(filelist.begin(), filelist.end(), sortBy[g_settings.filebrowser_sortmethod]);

			paint();
			paintFoot();
		}
		else if (CRCInput::isNumeric(msg_repeatok))
		{
			if (!(filelist.empty()))
				SMSInput(msg_repeatok);
		}
		else
		{
			if ( CNeutrinoApp::getInstance()->handleMsg( msg, data ) & messages_return::cancel_all )
			{
				loop = false;
			}
		}
	}

	hide();

	selected_filelist.clear();

	if(res && Multi_Select)
	{
		CProgressWindow * progress = new CProgressWindow();
		progress->setTitle(LOCALE_FILEBROWSER_SCAN);
		progress->exec(NULL,"");
		for(unsigned int i = 0; i < filelist.size();i++)
			if(filelist[i].Marked)
			{
				if(S_ISDIR(filelist[i].Mode)) {
#ifdef ENABLE_INTERNETRADIO
					if (m_Mode == ModeSC)
						addRecursiveDir(&selected_filelist,filelist[i].Url, true, progress);
					else
#endif
						addRecursiveDir(&selected_filelist,filelist[i].Name, true, progress);
				} else
					selected_filelist.push_back(filelist[i]);
			}
		progress->hide();
		delete progress;
	}

	return res;
}

//------------------------------------------------------------------------

void CFileBrowser::addRecursiveDir(CFileList * re_filelist, std::string rpath, bool bRootCall, CProgressWindow * progress)
{
	neutrino_msg_t      msg;
	neutrino_msg_data_t data;

	int n;

	//printf("addRecursiveDir %s\n",rpath.c_str());

	if (bRootCall) bCancel=false;

	g_RCInput->getMsg_us(&msg, &data, 1);
	if (msg==CRCInput::RC_home)
	{
		// home key cancel scan
		bCancel=true;
	}
	else if (msg!=CRCInput::RC_timeout)
	{
		// other event, save to low priority queue
		g_RCInput->postMsg( msg, data, false );
	}
	if(bCancel)
		return;

	if ((m_Mode != ModeSC) && ((rpath.empty()) || ((*rpath.rbegin()) != '/')))
	{
		rpath += '/';
	}

	CFileList tmplist;
	if(!readDir(rpath, &tmplist))
	{
		perror(("Recursive scandir: "+rpath).c_str());
	}
	else
	{
		n = tmplist.size();
		if(progress)
		{
			progress->showStatusMessageUTF(FILESYSTEM_ENCODING_TO_UTF8_STRING(rpath));
		}
		for(int i = 0; i < n;i++)
		{
			if(progress)
			{
				progress->showGlobalStatus(100/n*i);
			}
			std::string basename = tmplist[i].Name.substr(tmplist[i].Name.rfind('/')+1);
			if( basename != ".." )
			{
				if(Filter != NULL && (!S_ISDIR(tmplist[i].Mode)) && use_filter)
				{
					if(!Filter->matchFilter(tmplist[i].Name))
					{
						continue;
					}
				}
				if(!S_ISDIR(tmplist[i].Mode))
					re_filelist->push_back(tmplist[i]);
				else
					addRecursiveDir(re_filelist,tmplist[i].Name, false, progress);
			}
		}
	}
}


//------------------------------------------------------------------------

void CFileBrowser::hide()
{
	frameBuffer->paintBackgroundBoxRel(x,y, width,height);
}

//------------------------------------------------------------------------

void CFileBrowser::paintItem(unsigned int pos)
{
	int colwidth1, colwidth2, colwidth3, colwidth1_dir, colwidth2_dir;
	int c_rad_small;
	uint8_t color;
	fb_pixel_t bgcolor;
	int ypos = y+ theight+0 + pos*fheight;
	CFile * actual_file = NULL;
	std::string fileicon;

	colwidth2_dir = 180;
	colwidth1_dir = width - 35 - colwidth2_dir - 10;

	if (liststart + pos == selected)
	{
		color   = COL_MENUCONTENTSELECTED;
		bgcolor = COL_MENUCONTENTSELECTED_PLUS_0;
		c_rad_small = RADIUS_SMALL;
// 		paintFoot();
	}
	else
	{
		color   = COL_MENUCONTENT;//DARK;
		bgcolor = COL_MENUCONTENT_PLUS_0;//DARK;
		c_rad_small = 0;
	}

	if( (liststart + pos) < filelist.size() )
	{
		actual_file = &filelist[liststart+pos];
		if (actual_file->Marked)
		{
			color = COL_MENUCONTENTINACTIVE; //+= 2; FIXME
			bgcolor = (liststart + pos == selected) ? COL_MENUCONTENTSELECTED_PLUS_2 : COL_MENUCONTENT_PLUS_2;
		}

		if (g_settings.filebrowser_showrights == 0 && S_ISREG(actual_file->Mode))
		{
			colwidth2 = 0;
			colwidth3 = 90;
		}
		else
		{
			colwidth2 = 90;
			colwidth3 = 90;
		}
		colwidth1 = width - 35 - colwidth2 - colwidth3 - 10;

		frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, bgcolor, c_rad_small);

		if ( actual_file->Name.length() > 0 )
		{
			if (liststart+pos==selected)
				CVFD::getInstance()->showMenuText(0, FILESYSTEM_ENCODING_TO_UTF8_STRING(actual_file->getFileName()).c_str(), -1, true); // UTF-8

			switch(actual_file->getType())
			{
			case CFile::FILE_CDR:
			case CFile::FILE_MP3:
			case CFile::FILE_OGG:
			case CFile::FILE_WAV:
#ifdef ENABLE_FLAC
			case CFile::FILE_FLAC:
#endif
				fileicon = NEUTRINO_ICON_MP3;
//				color = COL_MENUCONTENT;
				break;

			case CFile::FILE_DIR:
				fileicon = NEUTRINO_ICON_FOLDER;
				break;

			case CFile::FILE_PICTURE:
			case CFile::FILE_TEXT:
			default:
				fileicon = NEUTRINO_ICON_FILE;
			}
			frameBuffer->paintIcon(fileicon, x+5 , ypos + (fheight-16) / 2 );

			g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(x + 35, ypos + fheight, colwidth1 - 10 , FILESYSTEM_ENCODING_TO_UTF8_STRING(actual_file->getFileName()), color, 0, true); // UTF-8

			if( S_ISREG(actual_file->Mode) )
			{
				if (g_settings.filebrowser_showrights != 0)
				{
					const char * attribute = "xwr";
					char modestring[9 + 1];
					for (int m = 8; m >= 0; m--)
					{
						modestring[8 - m] = (actual_file->Mode & (1 << m)) ? attribute[m % 3] : '-';
					}
					modestring[9] = 0;

					g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(x + 35 + colwidth1 , ypos+ fheight, colwidth2 - 10, modestring, color, 0, true); // UTF-8
				}

#define GIGABYTE 1073741824LL
#define MEGABYTE 1048576LL
#define KILOBYTE 1024LL
				char tmpstr[256];
				const char *unit = "";
				int64_t factor = 0;
				if (actual_file->Size >= GIGABYTE)
				{
					factor = GIGABYTE;
					unit = "G";
				}
				else if (actual_file->Size >= MEGABYTE)
				{
					factor = MEGABYTE;
					unit = "M";
				}
				else if (actual_file->Size >= KILOBYTE)
				{
					factor = KILOBYTE;
					unit = "k";
				}
				if (factor)
				{
					int a = actual_file->Size / factor;
					int b = (actual_file->Size - a * factor) * 1000 / factor;
					snprintf(tmpstr, sizeof(tmpstr), "%d.%03d%s", a, b, unit);
				}
				else
					snprintf(tmpstr,sizeof(tmpstr),"%d", (int)actual_file->Size);

				g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(x + 35 + colwidth1 + colwidth2, ypos+ fheight, colwidth3 - 10, tmpstr, color);
			}

			if( S_ISDIR(actual_file->Mode) )
			{
				char timestring[18];
				time_t rawtime;

				rawtime = actual_file->Time;
				strftime(timestring, 18, "%d-%m-%Y %H:%M", gmtime(&rawtime));

				g_Font[SNeutrinoSettings::FONT_TYPE_FILEBROWSER_ITEM]->RenderString(x + 35 + colwidth1_dir, ypos+ fheight, colwidth2_dir - 10, timestring, color);
			}
		}
	}
	else
		frameBuffer->paintBoxRel(x,ypos, width- 15, fheight, COL_MENUCONTENT_PLUS_0/*DARK*/);
}

//------------------------------------------------------------------------

void CFileBrowser::paintHead()
{
	char l_name[100];
	frameBuffer->paintBoxRel(x,y, width,theight+0, COL_MENUHEAD_PLUS_0, RADIUS_MID, CORNER_TOP);
#ifdef ENABLE_INTERNETRADIO
	if(m_Mode == ModeSC)
		snprintf(l_name, sizeof(l_name), "%s %s", g_Locale->getText(LOCALE_AUDIOPLAYER_ADD_SC), FILESYSTEM_ENCODING_TO_UTF8_STRING(name).c_str()); // UTF-8
	else
#endif
		snprintf(l_name, sizeof(l_name), "%s %s", g_Locale->getText(LOCALE_FILEBROWSER_HEAD), FILESYSTEM_ENCODING_TO_UTF8_STRING(name).c_str()); // UTF-8

	g_Font[SNeutrinoSettings::FONT_TYPE_EVENTLIST_TITLE]->RenderString(x+10,y+theight+1, width-11, l_name, COL_MENUHEAD, 0, true); // UTF-8
}

//------------------------------------------------------------------------

const struct button_label FileBrowserButtons[3] =
{
	{ NEUTRINO_ICON_BUTTON_RED   , LOCALE_FILEBROWSER_NEXTPAGE        },
	{ NEUTRINO_ICON_BUTTON_GREEN , LOCALE_FILEBROWSER_PREVPAGE        },
	{ NEUTRINO_ICON_BUTTON_YELLOW, LOCALE_FILEBROWSER_MARK            },
};
const struct button_label FileBrowserFilterButton[2] =
{
	{ NEUTRINO_ICON_BUTTON_BLUE  , LOCALE_FILEBROWSER_FILTER_INACTIVE },
	{ NEUTRINO_ICON_BUTTON_BLUE  , LOCALE_FILEBROWSER_FILTER_ACTIVE   },
};

void CFileBrowser::paintFoot()
{
	int dx = (width-20) / 4;
	//Second Line (bottom, top)
	int by2 = y + height - (foheight - 4);
	int ty2 = by2 + g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->getHeight();

	//Background
	frameBuffer->paintBoxRel(x, y + height - (2 * foheight ), width, (2 * foheight ), COL_INFOBAR_SHADOW_PLUS_1, RADIUS_MID, CORNER_BOTTOM);

	if (!(filelist.empty()))
	{
		int by = y + height - 2 * (foheight - 4);

		::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 10, by, dx, Multi_Select ? 3 : 2, FileBrowserButtons);

		if(Filter != NULL)
			::paintButtons(frameBuffer, g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL], g_Locale, x + 10 + (3 * dx), by, dx, 1, &(FileBrowserFilterButton[use_filter?0:1]));

		//OK-Button
		if( (filelist[selected].getType() != CFile::FILE_UNKNOWN) || (S_ISDIR(filelist[selected].Mode)) )
		{
			frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_OKAY, x +3 , by2 - 3);
			g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x + 35, ty2, dx - 35, g_Locale->getText(LOCALE_FILEBROWSER_SELECT), COL_INFOBAR /*_SHADOW_PLUS_1*/, 0, true); // UTF-8

		}

		//?-Button
		frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, x + (1 * dx), by2 - 3);
		g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x + 35 + (1 * dx), ty2, dx - 35, g_Locale->getText(sortByNames[g_settings.filebrowser_sortmethod]), COL_INFOBAR /*_SHADOW_PLUS_1*/, 0, true); // UTF-8

		//Mute-Button
		if (strncmp(Path.c_str(), VLC_URI, strlen(VLC_URI)) != 0) { //Not in vlc mode
		    frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_MUTE_SMALL, x + (2 * dx), by2 - 3);
			g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x + 35 + (2 * dx), ty2, dx - 35, g_Locale->getText(LOCALE_FILEBROWSER_DELETE), COL_INFOBAR /*_SHADOW_PLUS_1*/, 0, true); // UTF-8
		}

		if(m_SMSKeyInput.getOldKey()!=0)
		{
			char cKey[2]={m_SMSKeyInput.getOldKey(),0};
			g_Font[SNeutrinoSettings::FONT_TYPE_INFOBAR_SMALL]->RenderString(x + width - 16, by2 , 16, cKey, COL_MENUHEAD, 0, true); // UTF-8
		}
	}
}

//------------------------------------------------------------------------

void CFileBrowser::paint()
{
	liststart = (selected/listmaxshow)*listmaxshow;

//	if (filelist[0].Name.length() != 0)
//		frameBuffer->paintIcon(NEUTRINO_ICON_BUTTON_HELP, x+ width- 30, y+ 5 );
	CVFD::getInstance()->setMode(CVFD::MODE_MENU_UTF8, g_Locale->getText(LOCALE_FILEBROWSER_HEAD));

	for(unsigned int count=0;count<listmaxshow;count++)
		paintItem(count);

	int ypos = y+ theight;
	int sb = fheight* listmaxshow;
	frameBuffer->paintBoxRel(x+ width- 15,ypos, 15, sb,  COL_MENUCONTENT_PLUS_1);

	int sbc= ((filelist.size()- 1)/ listmaxshow)+ 1;
	int sbs= (selected/listmaxshow);

	frameBuffer->paintBoxRel(x+ width- 13, ypos+ 2+ sbs*(sb-4)/sbc, 11, (sb-4)/sbc, COL_MENUCONTENT_PLUS_3, RADIUS_SMALL);
}

//------------------------------------------------------------------------

void CFileBrowser::SMSInput(const neutrino_msg_t msg)
{
	unsigned char key = m_SMSKeyInput.handleMsg(msg);

	unsigned int i;
	for(i=(selected+1) % filelist.size(); i != selected ; i= (i+1) % filelist.size())
	{
		if(tolower(filelist[i].getFileName()[0]) == key)
		{
			break;
		}
	}
	int prevselected=selected;
	selected=i;
	paintItem(prevselected - liststart);
	unsigned int oldliststart = liststart;
	liststart = (selected/listmaxshow)*listmaxshow;
	if(oldliststart!=liststart)
	{
		paint();
	}
	else
	{
		paintItem(selected - liststart);
	}
}

//------------------------------------------------------------------------

void CFileBrowser::recursiveDelete(const char* file)
{
	stat_struct statbuf;
	dirent_struct **namelist;
	int n;
	printf("Delete %s\n", file);
	if(my_lstat(file,&statbuf) == 0)
	{
		if(S_ISDIR(statbuf.st_mode))
		{
			n = my_scandir(file, &namelist, 0, my_alphasort);
			while(n--)
			{
				if(strcmp(namelist[n]->d_name, ".")!=0 && strcmp(namelist[n]->d_name, "..")!=0)
				{
					std::string fullname = (std::string)file + "/" + namelist[n]->d_name;
					recursiveDelete(fullname.c_str());
				}
				free(namelist[n]);
			}
			free(namelist);
			rmdir(file);
		}
		else
		{
			unlink(file);
		}
	}
	else
		perror(file);
}
