#include "LibraryInfo.h"

#include "FileTools.h"

// clear data
void LibraryInfo::ClearInfo(void)
{
	_oldStyle = true;
	_anyArchitecture = false;
	_name = "";
	_version = "";
	_author = "";
	_maintainer = "";
	_sentence = "";
	_paragraph = "";
	_category = "";
	_url = "";
	_architectures.Clear();
	_includes.Clear();

	_files.Clear();
	
	_kind = USER;
}

// read info from 'library.properties' file
void LibraryInfo::ReadPropertiesFile(void)
{
	ClearInfo();

	String infoFile = AppendFileName(_path, "library.properties");
	if(FileExists(infoFile))
	{
		_oldStyle = !DirectoryExists(AppendFileName(_path, "src"));
		FileIn f(infoFile);
		while(!f.IsEof())
		{
			String s = TrimBoth(f.GetLine());
			if(s.IsEmpty())
				continue;
			if(s.StartsWith("name="))
				_name = TrimBoth(s.Mid(5));
			else if(s.StartsWith("version="))
				_version = AVersion(TrimBoth(s.Mid(8)));
			else if(s.StartsWith("author="))
				_author = TrimBoth(s.Mid(7));
			else if(s.StartsWith("maintainer="))
				_maintainer = TrimBoth(s.Mid(11));
			else if(s.StartsWith("sentence="))
				_sentence = TrimBoth(s.Mid(9));
			else if(s.StartsWith("paragraph="))
				_paragraph = TrimBoth(s.Mid(10));
			else if(s.StartsWith("category="))
				_category = TrimBoth(s.Mid(9));
			else if(s.StartsWith("url="))
				_url = TrimBoth(s.Mid(4));
			else if(s.StartsWith("architectures="))
			{
				String archs = TrimBoth(s.Mid(14));
				if(archs == "*")
					_anyArchitecture = true;
				else
				{
					_architectures = Split(archs, ',');
					for(int i = 0; i < _architectures.GetCount(); i++)
						_architectures[i] = TrimBoth(_architectures[i]);
				}
			}
			else if(s.StartsWith("includes="))
			{
				String incs = TrimBoth(s.Mid(9));
				_includes = Split(incs, ',');
				for(int i = 0; i < _includes.GetCount(); i++)
					_includes[i] = TrimBoth(_includes[i]);
			}
		}
	}
	else
	{
		String p = UnixPath(_path);
		if(p.EndsWith("\\"))
			p.Trim(p.GetCount() - 1);
		_name = GetFileTitle(p);
		_anyArchitecture = false;
	}
}
	
// constructor
LibraryInfo::LibraryInfo(String pth)
{
	if(!DirectoryExists(pth))
	{
		_path.Clear();
	}
	else
	{
		_path = pth;
		ReadPropertiesFile();
	}
}

LibraryInfo::LibraryInfo(void)
{
	ClearInfo();
	_path.Clear();
}

// destructor
LibraryInfo::~LibraryInfo()
{
}

// check if architecture is supported by lib
bool LibraryInfo::SupportsArchitecture(String const &arc) const
{
	if(_anyArchitecture)
		return true;
	return FindIndex(_architectures, arc) >= 0;
}

// get include path
String LibraryInfo::GetIncludePath(void) const
{
	if(_oldStyle)
		return _path;
	else
		return AppendFileName(_path, "src");
}
		
// get include files
Vector<String> LibraryInfo::ScanIncludes(bool fullPath) const
{
	Vector<String> res;
	Vector<String> includesPattern = { "*.h", "*.hpp", "*.hxx" };
	
	String path;
	if(_oldStyle)
		path = _path;
	else
		path = AppendFileName(_path, "src");
	res = FileTools::ScanFolder(path, includesPattern);

	if(fullPath)
		for(int i = 0; i < res.GetCount(); i++)
			res[i] = AppendFileName(path, res[i]);

	return res;
}

// get source files
Vector<String> LibraryInfo::ScanSources(bool fullPath) const
{
	Vector<String> res;
	Vector<String> sourcesPattern = { "*.c", "*.cpp", "*.cxx", "*.S" };

	String libRoot;
	if(_oldStyle)
	{
		// old style libs -- sources in root folder and in utility folder
		// no recursive scan
		libRoot = _path;
		res = FileTools::ScanFolder(libRoot, sourcesPattern);
		Vector<String> util = FileTools::ScanFolder(AppendFileName(libRoot, "utility"), sourcesPattern);
		for(int i = 0; i < util.GetCount(); i++)
			res.Add(AppendFileName("utility", util[i]));
	}
	else
	{
		// new style libs -- all sources in src folder and its subfolders
		libRoot = AppendFileName(_path, "src");
		res = FileTools::RecurseScan(libRoot, sourcesPattern);
	}

	if(fullPath)
		for(int i = 0; i < res.GetCount(); i++)
			res[i] = AppendFileName(libRoot, res[i]);

	return res;
}

// files order management
// used when showing files on IDE
Vector<String> const &LibraryInfo::ScanFiles(Vector<String> const &files)
{
	// first, scan all library files
	Vector<String> newFiles = FileTools::RecurseScan(_path, "*");
	Vector<String> oldFiles = pick(_files);
	
	// if files argument is given, take it as sort
	Vector<String> const &sortFiles = (files.IsEmpty() ? oldFiles : files);
	
	// start with given files, just checking if they're in scanned ones
	_files.Clear();
	for(int i = 0; i < sortFiles.GetCount(); i++)
		if(FindIndex(newFiles, sortFiles[i]) >= 0)
			_files.Add(sortFiles[i]);
	
	// now append remaining available files, if any
	for(int i = 0; i < newFiles.GetCount(); i++)
		if(FindIndex(_files, newFiles[i]) < 0)
			_files.Add(newFiles[i]);
		
	// return the (sorted) files
	return _files;
}
