#include "Package.h"

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

// constructor
Package::Package()
{
}

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

// find a platform by name
Platform const *Package::FindPlatform(String const &name) const
{
	for(int iPlatform = 0; iPlatform < _platforms.GetCount(); iPlatform++)
		if(_platforms[iPlatform]._name == name)
			return &_platforms[iPlatform];
	return NULL;
}

Platform *Package::FindPlatform(String const &name)
{
	for(int iPlatform = 0; iPlatform < _platforms.GetCount(); iPlatform++)
		if(_platforms[iPlatform]._name == name)
			return &_platforms[iPlatform];
	return NULL;
}

// find a tool by name
Tool const *Package::FindTool(String const &name, String const &version) const
{
	for(int iTool = 0; iTool < _tools.GetCount(); iTool++)
	{
		Tool const &tool = _tools[iTool];
		if(tool._name == name && tool._version == version)
			return &tool;
	}
	return NULL;
}

Tool *Package::FindTool(String const &name, String const &version)
{
	for(int iTool = 0; iTool < _tools.GetCount(); iTool++)
	{
		Tool &tool = _tools[iTool];
		if(tool._name == name && tool._version == version)
			return &tool;
	}
	return NULL;
}

// find a platform by architecture
Platform *Package::FindPlatformByArchitecture(String const &arch)
{
	for(int iPlatform = 0; iPlatform < _platforms.GetCount(); iPlatform++)
		if(_platforms[iPlatform]._architecture == arch)
			return &_platforms[iPlatform];
	return NULL;
}

Platform const *Package::FindPlatformByArchitecture(String const &arch) const
{
	for(int iPlatform = 0; iPlatform < _platforms.GetCount(); iPlatform++)
		if(_platforms[iPlatform]._architecture == arch)
			return &_platforms[iPlatform];
	return NULL;
}

// parse package data contained in a Value object
bool Package::ParseJSON(Value const &json)
{
	_name			= json["name"];
	_maintainer		= json["maintainer"];
	_websiteURL		= json["websiteURL"];
	_email			= json["email"];
	
	// read help URLs
	Value helps 	= json["help"];
	if(IsValueMap(helps))
	{
		ValueMap map(helps);
		for(int iHelp = 0; iHelp < map.GetCount(); iHelp++)
			_helpURLs.Add(map.GetKey(iHelp), map.GetValue(iHelp));
	}
	
	// read provided platforms
	Value platformsData = json["platforms"];
	for(int iPlatform = 0; iPlatform < platformsData.GetCount(); iPlatform++)
	{
		Value platformData = platformsData[iPlatform];
		
		// look for another version already got
		Platform *platform = FindPlatform(platformData["name"]);
		if(!platform)
			platform = &_platforms.Add(new Platform(this));
		if(!platform->ParseJSON(platformData))
			return false;
	}
	
	// read provided tools
	Value toolsData = json["tools"];
	for(int iTool = 0; iTool < toolsData.GetCount(); iTool++)
	{
		Value toolData = toolsData[iTool];
		if(!_tools.Add(new Tool(this)).ParseJSON(toolData))
			return false;
	}
	
	return true;
}
		

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

// constructor
PackagesClass::PackagesClass()
{
}

// destructor
PackagesClass::~PackagesClass()
{
}
		
// clear
PackagesClass &PackagesClass::Clear(void)
{
	Array<Package>::Clear();
	return *this;
}

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

// parse package json data
bool PackagesClass::ParseJSON(String const &s)
{
	Value v = ::ParseJSON(s);
	
	Value packagesData = v["packages"];
	if(IsValueArray(packagesData))
	{
		for(int iPackage = 0; iPackage < packagesData.GetCount(); iPackage++)
		{
			Value packageData = packagesData[iPackage];
			Add().ParseJSON(packageData);
		}
	}
	
	return false;
}

// find a package by name
Package const *PackagesClass::FindPackage(String const &name) const
{
	for(int iPackage = 0; iPackage < GetCount(); iPackage++)
	{
		if(operator[](iPackage)._name == name)
			return &operator[](iPackage);
	}
	return NULL;
}

Package *PackagesClass::FindPackage(String const &name)
{
	for(int iPackage = 0; iPackage < GetCount(); iPackage++)
	{
		if(operator[](iPackage)._name == name)
			return &operator[](iPackage);
	}
	return NULL;
}


// cleanup unused tools
bool PackagesClass::CleanupTools(void)
{
	// gather all used tools
	ArrayMap<String, String> usedTools;
	for(int iPackage = 0; iPackage < GetCount(); iPackage++)
	{
		Package &package = At(iPackage);
		Array<Platform> &platforms = package.GetPlatforms();
		for(int iPlatform = 0; iPlatform < platforms.GetCount(); iPlatform++)
		{
			Platform &platform = platforms[iPlatform];
			if(platform.IsInstalled())
			{
				PlatformVersion &version = platform.GetVersions().Get(platform.GetInstalledVersion());
				Vector<PlatformVersion::ToolDep> const &deps = version.GetToolsDeps();
				for(int iDep = 0; iDep < deps.GetCount(); iDep++)
				{
					PlatformVersion::ToolDep const &dep = deps[iDep];
					bool found = false;
					for(int iUsed = 0; iUsed < usedTools.GetCount(); iUsed++)
					{
						if(usedTools.GetKey(iUsed) == dep._name && usedTools[iUsed] == dep._version)
						{
							found = true;
							break;
						}
					}
					if(!found)
						usedTools.Add(dep._name, dep._version);
				}
			}
		}
	}

	// now we shall scan all tools and, if not used, remove it
	for(int iPackage = 0; iPackage < GetCount(); iPackage++)
	{
		Package &package = At(iPackage);
		Array<Tool> &tools = package.GetTools();
		for(int iTool = 0; iTool < tools.GetCount(); iTool++)
		{
			Tool &tool = tools[iTool];
			if(tool.IsInstalled())
			{
				bool found = false;
				for(int iUsed = 0; iUsed < usedTools.GetCount(); iUsed++)
				{
					if(usedTools.GetKey(iUsed) == tool.GetName() && usedTools[iUsed] == tool.GetVersion())
					{
						found = true;
						break;
					}
				}
				if(!found)
					tool.Remove();
			}
		}
	}
	
	return true;
}

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

PackagesClass &__GetPackages(void)
{
	static PackagesClass pack;
	return pack;
}

