/*
** 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 1, 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.
*/

/*
 * Author : Alexandre Parenteau <aubonbeurre@hotmail.com> --- December 1997
 */

/*
 * MultiFiles.h --- class to store multiple files by directory
 */

#include "stdafx.h"

#include <stdlib.h>
#include <string.h>

#include "MultiFiles.h"
#include "CvsArgs.h"
#include "AppConsole.h"
#include "CPStr.h"
#include "AppGlue.h"

#include <errno.h>

#ifdef WIN32
#	ifdef _DEBUG
#	define new DEBUG_NEW
#	undef THIS_FILE
	static char THIS_FILE[] = __FILE__;
#	endif
#endif /* WIN32 */

//////////////////////////////////////////////////////////////////////////
//

FileEntry::FileEntry()
{
}

FileEntry::FileEntry(const char* filename, const UFSSpec* macspec /*= 0L*/, const char* currRevision /*= 0L*/)
{
	file = filename;

	if( currRevision != 0L )
		currRev = currRevision;

  	if( macspec != 0L )
		spec = *macspec;
}

FileEntry::FileEntry(const FileEntry& entry)
{
	*this = entry;
}

FileEntry& FileEntry::operator=(const FileEntry& entry)
{
	file = entry.file;
	currRev = entry.currRev;
	spec = entry.spec;
	return *this;
}


//////////////////////////////////////////////////////////////////////////
// MultiFilesEntry

MultiFilesEntry::MultiFilesEntry() 
{
}

MultiFilesEntry::MultiFilesEntry(const char* path)
{
	dir = path;
}

MultiFilesEntry::MultiFilesEntry(const MultiFilesEntry& entries)
{
	*this = entries;
}

MultiFilesEntry& MultiFilesEntry::operator=(const MultiFilesEntry& entries)
{
	dir = entries.dir;
	files = entries.files;
	return *this;
}

/// Set the directory
void MultiFilesEntry::setdir(const char* newdir)
{
	dir = newdir;
}

/// Add file
void MultiFilesEntry::add(const char* file, const UFSSpec* spec, const char* currRevision)
{
	FileEntry entry(file, spec, currRevision);
	files.push_back(entry);
}

//////////////////////////////////////////////////////////////////////////
// MultiFiles

MultiFiles::MultiFiles() 
	: pos(-1) 
{
}

/// Add a new directory
void MultiFiles::newdir(const char* dir)
{
	MultiFilesEntry entry(dir);
	dirs.push_back(dir);
}

/// Add a new file to the current directory
void MultiFiles::newfile(const char* file, const UFSSpec* spec, const char* currRevision)
{
	if( dirs.size() == 0 )
		return;

	MultiFilesEntry& entry = dirs[dirs.size() - 1];
	entry.add(file, spec, currRevision);
}

/// Rewind to first directory
void MultiFiles::rewind(void)
{
	pos = -1;
}

/// Move to next directory, return false if no more directories
bool MultiFiles::next(void)
{
	if( pos == -1 )
	{
		pos = 0;
	}
	else
	{
		// only the mac uses MultiFiles for now in such a fashion.
		// it also means that cvs should be finished with the last round.
		++pos;
		if( (size_t)pos < dirs.size() )
			WaitForCvs();
	}

	return (size_t)pos < dirs.size();
}

/// Add the files to a CvsArgs, return the directory
char* MultiFiles::add(CvsArgs& args)
{
	if( pos < 0 || (size_t)pos >= dirs.size() )
		return 0L;

	MultiFilesEntry & entry = dirs[pos];
	std::vector<FileEntry>::const_iterator i;
	for(i = entry.files.begin(); i != entry.files.end(); ++i)
	{
		args.addfile((*i).file, entry.dir, &(*i).spec, (*i).currRev);
	}

	return entry.dir;
}

/// Get the file in the current directory, return false if failed
bool MultiFiles::get(int index, CStr& path, CStr& fileName, CStr& currRev) const
{
	int locpos = pos;
	if( locpos == -1 )
		locpos = 0;
	
	if( (size_t)locpos >= dirs.size() )
		return false;

	const MultiFilesEntry& entry = dirs[locpos];
	if( index < 0 || (size_t)index >= entry.files.size() )
		return false;

	path = entry.dir;
	fileName = entry.files[index].file;
	currRev = entry.files[index].currRev;
	
	return true;
}

/// Get the current directory
const char* MultiFiles::getdir() const
{
	if( pos < 0 || (size_t)pos >= dirs.size() )
		return 0L;

	const MultiFilesEntry& entry = dirs[pos];

	return entry.dir;
}

/// Get the directory at the specified index, return false if failed
bool MultiFiles::getdir(int index, CStr& path) const
{
	if( index < 0 || index >= (int)dirs.size() )
		return false;

	const MultiFilesEntry& entry = dirs[index];

	path = entry.dir;

	return true;
}

/// Get the number of files in the current dir
int MultiFiles::NumFiles(void) const
{
	int locpos = pos;
	if( locpos == -1 )
		locpos = 0;
	
	if( (size_t)locpos >= dirs.size() )
		return 0;

	const MultiFilesEntry& entry = dirs[locpos];
	
	return entry.files.size();
}

/// Get the number of directories in the set
int MultiFiles::NumDirs(void) const
{
	return dirs.size();
}

/// Reset for reuse
void MultiFiles::reset()
{
	dirs.erase(dirs.begin(), dirs.end());
	pos = -1;
}
