// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: directory.iC,v 1.17 2005/12/23 17:02:06 amoll Exp $
//

BALL_INLINE
String Directory::getcwd_()
{
	char* buffer;
	
	#ifdef BALL_COMPILER_MSVC
		buffer = ::_getcwd(NULL, MAX_PATH_LENGTH);
	#else
		buffer = ::getcwd(NULL, MAX_PATH_LENGTH);
	#endif

	String result(buffer);
	free (buffer);

	return result;
}

BALL_INLINE
int Directory::chdir_(const String& new_dir)
{
	#ifdef BALL_COMPILER_MSVC
		return ::_chdir(new_dir.c_str());
	#else
		return ::chdir(new_dir.c_str());
	#endif
}

BALL_INLINE
void Directory::synchronize_()
{
	String cwd = getcwd_();
	String canonical_path(directory_path_);

	// We need to ensure that trailing slashes are handled correctly!
	cwd+=FileSystem::PATH_SEPARATOR;
	canonical_path+=FileSystem::PATH_SEPARATOR;

	FileSystem::canonizePath(cwd);
	FileSystem::canonizePath(canonical_path);

	if (cwd != canonical_path)
	{
		backup_path_ = cwd;
		chdir_(directory_path_);
	}
}

BALL_INLINE
bool Directory::desynchronize_(bool result1)
{
  if (backup_path_ == "") 
	{
		return result1;
	}
	bool result2 = (chdir_(backup_path_) == 0);
  backup_path_ = "";

  return (result1 && result2);
}

BALL_INLINE 
void Directory::clear()
{
	#ifdef BALL_OS_WINDOWS
	if (dirent_ != INVALID_HANDLE_VALUE) FindClose(dirent_);
	if (dir_ != INVALID_HANDLE_VALUE) CloseHandle(dir_);
	#else
		if (dir_ != 0)
		{
			::closedir(dir_);
		}
	#endif
	dir_ = INVALID_HANDLE_VALUE;
	dirent_ = INVALID_HANDLE_VALUE;
  directory_path_ = "";
}

BALL_INLINE 
void Directory::destroy()
{
	clear();
}

BALL_INLINE
void Directory::set(const Directory& directory)
{
	clear();
  directory_path_ = directory.directory_path_;
  backup_path_ = "";
}

BALL_INLINE 
Directory& Directory::operator = (const Directory& directory)
{
  set(directory);
  return *this;
}

BALL_INLINE 
void Directory::get(Directory& directory) const
{
  directory.set(*this);
}

BALL_INLINE 
const String& Directory::getPath() const
{
  return directory_path_;
}

BALL_INLINE 
bool Directory::rename(String old_path, String new_path)
{ 
	synchronize_();	
	FileSystem::canonizePath(old_path);
	FileSystem::canonizePath(new_path);
	return desynchronize_((::rename(old_path.c_str(), new_path.c_str()) == 0));
}

BALL_INLINE 
bool Directory::setCurrent(String directory_path)
{
  FileSystem::canonizePath(directory_path);
	#ifdef BALL_OS_WINDOWS
		return (::_chdir(directory_path.c_str()) == 0);
	#else
		return (::chdir(directory_path.c_str()) == 0);
	#endif
}

BALL_INLINE 
bool Directory::setCurrent()
{
  return Directory::setCurrent(directory_path_);
}

BALL_INLINE 
bool Directory::create(String directory_path, const mode_t& mode)
{
	#ifdef BALL_COMPILER_MSVC
		if(!isValid()) return false;
		FileSystem::canonizePath(directory_path);
		if ((directory_path[0] == FileSystem::PATH_SEPARATOR) || (directory_path[1] == ':' && directory_path[2] == FileSystem::PATH_SEPARATOR))
		{
			return (::_mkdir(directory_path.c_str()) ==0);
		}
		synchronize_();			
		return desynchronize_(::_mkdir(directory_path.c_str()) ==0);
	#else
		FileSystem::canonizePath(directory_path);
		if (directory_path[0] == FileSystem::PATH_SEPARATOR)
		{
			return (::mkdir(directory_path.c_str(), mode) == 0);
		}
		synchronize_();	
		return desynchronize_((::mkdir(directory_path.c_str(), mode) == 0));
	#endif
}

BALL_INLINE 
bool Directory::remove(String directory_path)
{
	synchronize_();	
  FileSystem::canonizePath(directory_path);
	#ifdef BALL_COMPILER_MSVC

		// get alsolute path
		char* buffer = ::_getcwd(NULL, MAX_PATH_LENGTH);
		String old_dir(buffer);
		free(buffer);
		if(::_chdir(directory_path.c_str()) == 0)
		{	// determine absolute path
			buffer = ::_getcwd(NULL,MAX_PATH_LENGTH);
			directory_path = buffer;
			free(buffer);
			::_chdir(old_dir.c_str());
		}
		else
		{
			// cannot change to dir...return 
			return desynchronize_(false);
		}
			
		bool ok = desynchronize_((::_rmdir(directory_path.c_str()) == 0));
	#else
		bool ok = desynchronize_((::rmdir(directory_path.c_str()) == 0));
	#endif

		if (directory_path == directory_path_) 
		{
			clear();
		}

		return ok;
}

BALL_INLINE 
bool Directory::isEmpty()
{
  return (countItems() == 0);
}

BALL_INLINE 
bool Directory::operator == (const Directory& directory) const
{
  return (directory_path_ == directory.directory_path_);
}

BALL_INLINE 
bool Directory::operator != (const Directory& directory) const
{
  return (directory_path_ != directory.directory_path_);
}


