text: /*
  *  utilite is a cross-platform library with
  *  useful utilities for fast and small developing.
  *  Copyright (C) 2010  Mathieu Labbe
  *
  *  utilite is free library: you can redistribute it and/or modify
  *  it under the terms of the GNU Lesser General Public License as published by
  *  the Free Software Foundation, either version 3 of the License, or
  *  (at your option) any later version.
  *
  *  utilite 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 Lesser General Public License for more details.
  *
  *  You should have received a copy of the GNU Lesser General Public License
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  
  #include "rtabmap/utilite/UDirectory.h"
  
  #ifdef _WIN32
    #include <Windows.h>
    #include <direct.h>
    #include <algorithm>
    #include <conio.h>
  #else
    #include <dirent.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/param.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
  #endif
  
  #include "rtabmap/utilite/UStl.h"
  #include "rtabmap/utilite/UFile.h"
  #include "rtabmap/utilite/UDirectory.h"
  #include "rtabmap/utilite/UConversion.h"
  
  #include "rtabmap/utilite/ULogger.h"
  
  #ifdef _WIN32
  
  bool sortCallback(const std::string & a, const std::string & b)
  {
  	return uStrNumCmp(a,b) < 0;
  }
  #elif __APPLE__
  int sortCallback(const struct dirent ** a, const struct dirent ** b)
  {
  	return uStrNumCmp((*a)->d_name, (*b)->d_name);
  }
  #else
  int sortCallback( const dirent ** a,  const dirent ** b)
  {
  	return uStrNumCmp((*a)->d_name, (*b)->d_name);
  }
  #endif
  
  UDirectory::UDirectory(const std::string & path, const std::string & extensions)
  {
  	extensions_ = uListToVector(uSplit(extensions, ' '));
  	path_ = path;
  	iFileName_ = fileNames_.begin();
  	this->update();
  }
  
  UDirectory::UDirectory(const UDirectory & dir)
  {
  	*this = dir;
  }
  
  UDirectory & UDirectory::operator=(const UDirectory & dir)
  {
  	extensions_ = dir.extensions_;
  	path_ = dir.path_;
  	fileNames_ = dir.fileNames_;
  	for(iFileName_=fileNames_.begin(); iFileName_!=fileNames_.end(); ++iFileName_)
  	{
  		if(iFileName_->compare(*dir.iFileName_) == 0)
  		{
  			break;
  		}
  	}
  	return *this;
  }
  
  UDirectory::~UDirectory()
  {
  }
  
  void UDirectory::setPath(const std::string & path, const std::string & extensions)
  {
  	extensions_ = uListToVector(uSplit(extensions, ' '));
  	path_ = path;
  	fileNames_.clear();
  	iFileName_ = fileNames_.begin();
  	this->update();
  }
  
  void UDirectory::update()
  {
  	if(exists(path_))
  	{
  		std::string lastName;
  		bool endOfDir = false;
  		if(iFileName_ != fileNames_.end())
  		{
  			//Record the last file name
  			lastName = *iFileName_;
  		}
  		else if(fileNames_.size())
  		{
  			lastName = *fileNames_.rbegin();
  			endOfDir = true;
  		}
  		fileNames_.clear();
  #ifdef _WIN32
  		WIN32_FIND_DATA fileInformation;
  	#ifdef UNICODE
  		wchar_t * pathAll = createWCharFromChar((path_+"\\*").c_str());
  		HANDLE hFile  = ::FindFirstFile(pathAll, &fileInformation);
  		delete [] pathAll;
  	#else
  		HANDLE hFile  = ::FindFirstFile((path_+"\\*").c_str(), &fileInformation);
  	#endif
  		if(hFile != INVALID_HANDLE_VALUE)
  		{
  			do
  			{
  	#ifdef UNICODE
  				char * fileName = createCharFromWChar(fileInformation.cFileName);
  				fileNames_.push_back(fileName);
  				delete [] fileName;
  	#else
  				fileNames_.push_back(fileInformation.cFileName);
  	#endif
  			} while(::FindNextFile(hFile, &fileInformation) == TRUE);
  			::FindClose(hFile);
  			std::vector<std::string> vFileNames = uListToVector(fileNames_);
  			std::sort(vFileNames.begin(), vFileNames.end(), sortCallback);
  			fileNames_ = uVectorToList(vFileNames);
  		}
  #else
  		int nameListSize;
  		struct dirent ** nameList = 0;
  		nameListSize =	scandir(path_.c_str(), &nameList, 0, sortCallback);
  		if(nameList && nameListSize>0)
  		{
  			for (int i=0;i<nameListSize;++i)
  			{
  				fileNames_.push_back(nameList[i]->d_name);
  				free(nameList[i]);
  			}
  			free(nameList);
  		}
  #endif
  
  		//filter extensions...
  		std::list<std::string>::iterator iter = fileNames_.begin();
  		bool valid;
  		while(iter!=fileNames_.end())
  		{
  			valid = false;
  			if(extensions_.size() == 0 &&
  			   iter->compare(".") != 0 &&
  			   iter->compare("..") != 0)
  			{
  				valid = true;
  			}
  			for(unsigned int i=0; i<extensions_.size(); ++i)
  			{
  				if(UFile::getExtension(*iter).compare(extensions_[i]) == 0)
  				{
  					valid = true;
  					break;
  				}
  			}
  			if(!valid)
  			{
  				iter = fileNames_.erase(iter);
  			}
  			else
  			{
  				++iter;
  			}
  		}
  		iFileName_ = fileNames_.begin();
  		if(!lastName.empty())
  		{
  			bool found = false;
  			for(std::list<std::string>::iterator iter=fileNames_.begin(); iter!=fileNames_.end(); ++iter)
  			{
  				if(lastName.compare(*iter) == 0)
  				{
  					found = true;
  					iFileName_ = iter;
  					break;
  				}
  			}
  			if(endOfDir && found)
  			{
  				++iFileName_;
  			}
  			else if(endOfDir && fileNames_.size())
  			{
  				iFileName_ = --fileNames_.end();
  			}
  		}
  	}
  }
  
  bool UDirectory::isValid()
  {
  	return exists(path_);
  }
  
  std::string UDirectory::getNextFileName()
  {
  	std::string fileName;
  	if(iFileName_ != fileNames_.end())
  	{
  		fileName = *iFileName_;
  		++iFileName_;
  	}
  	return fileName;
  }
  
  std::string UDirectory::getNextFilePath()
  {
  	std::string filePath;
  	if(iFileName_ != fileNames_.end())
  	{
  		filePath = path_+separator()+*iFileName_;
  		++iFileName_;
  	}
  	return filePath;
  }
  
  void UDirectory::rewind()
  {
  	iFileName_ = fileNames_.begin();
  }
  
  
  bool UDirectory::exists(const std::string & dirPath)
  {
  	bool r = false;
  #ifdef _WIN32
  	#ifdef UNICODE
  	wchar_t * wDirPath = createWCharFromChar(dirPath.c_str());
  	DWORD dwAttrib = GetFileAttributes(wDirPath);
  	delete [] wDirPath;
  	#else
  	DWORD dwAttrib = GetFileAttributes(dirPath.c_str());
  	#endif
  	r = (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
  #else
  	DIR *dp;
  	if((dp  = opendir(dirPath.c_str())) != NULL)
  	{
  		r = true;
  		closedir(dp);
  	}
  #endif
  	return r;
  }
  
  // return the directory path of the file
  std::string UDirectory::getDir(const std::string & filePath)
  {
  	std::string dir = filePath;
  	int i=(int)dir.size()-1;
  	for(; i>=0; --i)
  	{
  		if(dir[i] == '/' || dir[i] == '\\')
  		{
  			//remove separators...
  			dir[i] = 0;
  			--i;
  			while(i>=0 && (dir[i] == '/' || dir[i] == '\\'))
  			{
  				dir[i] = 0;
  				--i;
  			}
  			break;
  		}
  		else
  		{
  			dir[i] = 0;
  		}
  	}
  
  	if(i<0)
  	{
  		dir = ".";
  	}
  	else
  	{
  		dir.resize(i+1);
  	}
  
  	return dir;
  }
  
  std::string UDirectory::currentDir(bool trailingSeparator)
  {
  	std::string dir;
  	char * buffer;
  
  #ifdef _WIN32
  	buffer = _getcwd(NULL, 0);
  #else
  	buffer = getcwd(NULL, MAXPATHLEN);
  #endif
  
  	if( buffer != NULL )
  	{
  		dir = buffer;
  		free(buffer);
  		if(trailingSeparator)
  		{
  			dir += separator();
  		}
  	}
  
  	return dir;
  }
  
  bool UDirectory::makeDir(const std::string & dirPath)
  {
  	int status;
  #ifdef _WIN32
  	status = _mkdir(dirPath.c_str());
  #else
  	status = mkdir(dirPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
  #endif
  	return status==0;
  }
  
  bool UDirectory::removeDir(const std::string & dirPath)
  {
  	int status;
  #ifdef _WIN32
  	status = _rmdir(dirPath.c_str());
  #else
  	status = rmdir(dirPath.c_str());
  #endif
  	return status==0;
  }
  
  std::string UDirectory::homeDir()
  {
  	std::string path;
  #ifdef _WIN32
  	#ifdef UNICODE
  	wchar_t wProfilePath[250];
  	ExpandEnvironmentStrings(L"%userprofile%",wProfilePath,250);
  	char * profilePath = createCharFromWChar(wProfilePath);
  	path = profilePath;
  	delete [] profilePath;
  	#else
  	char profilePath[250];
  	ExpandEnvironmentStrings("%userprofile%",profilePath,250);
  	path = profilePath;
  	#endif
  #else
  	path = getenv("HOME");
  #endif
  	return path;
  }
  
  std::string UDirectory::separator()
  {
  #ifdef _WIN32
  	return "\\";
  #else
  	return "/";
  #endif
  }
  