#include "AVersion.h"

// constuctors
AVersion::AVersion()
{
	Clear();
}

AVersion::AVersion(AVersion const &v)
{
	major	= v.major;
	minor	= v.minor;
	release	= v.release;
}

AVersion::AVersion(int maj, int min, int rel)
{
	major	= maj;
	minor	= min;
	release	= rel;
}

AVersion::AVersion(String const &s)
{
	operator=(s);
}

// clear
AVersion &AVersion::Clear(void)
{
	major = minor = release = 0;
	return *this;
}

// assignment
AVersion const &AVersion::operator=(AVersion const &v)
{
	major	= v.major;
	minor	= v.minor;
	release	= v.release;
	return *this;
}

AVersion const &AVersion::operator=(String const &s)
{
	Clear();
	const char *c = ~s;
	while(*c && IsSpace(*c))
		c++;
	while(IsDigit(*c))
		major = 10 * major + *c++ - '0';
	if(*c != '.')
		return *this;
	c++;
	while(IsDigit(*c))
		minor = 10 * minor + *c++ - '0';
	if(*c != '.')
		return *this;
	c++;
	while(IsDigit(*c))
		release = 10 * release + *c++ - '0';
	return *this;
}

// comparaisons
bool AVersion::operator==(AVersion const &v) const
{
	return
		major	== v.major &&
		minor	== v.minor &&
		release	== v.release
	;
}

bool AVersion::operator<(AVersion const &v) const
{
	if(major < v.major)
		return true;
	if(major > v.major)
		return false;
	if(minor < v.minor)
		return true;
	if(minor > v.minor)
		return false;
	return release < v.release;
}

bool AVersion::operator>(AVersion const &v) const
{
	if(major > v.major)
		return true;
	if(major < v.major)
		return false;
	if(minor > v.minor)
		return true;
	if(minor < v.minor)
		return false;
	return release > v.release;
}

bool AVersion::IsNull(void) const
{
	return
		major == 0 &&
		minor == 0 &&
		release == 0
	;
}

// to string
String AVersion::ToString(void) const
{
	return Format("%d.%d.%d", major, minor, release);
}

String AVersion::ToStringUndotted(void) const
{
	return Format("%d%02d%02d", major, minor, release);
}

// store to xml
void AVersion::Xmlize(XmlIO &xml)
{
	String s;
	if(xml.IsLoading())
	{
		::Xmlize(xml, s);
		operator=(s);
	}
	else
	{
		s = ToString();
		::Xmlize(xml, s);
	}
}

// parse a string in format AVersion(maintainer)
MaintainerVersion::MaintainerVersion(String const &mv)
{
	int idx = mv.Find("(");
	if(idx < 0)
	{
		version = AVersion(mv);
		maintainer = "";
		return;
	}
	String sv = TrimBoth(mv.Left(idx));
	String sm = mv.Mid(idx + 1);
	idx = sm.ReverseFind(")");
	if(idx >= 0)
		sm = sm.Left(idx);
	sm = TrimBoth(sm);
	version = AVersion(sv);
	maintainer = sm;
}

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

// helper
String ExtractMaintainer(String const &m, String const &auth)
{
	// trim leading and trailing spaces
	// and put all lowercase
	String s = ToLower(TrimBoth(m));
	
	// if maintainer contains <...> text, that one
	// is probably an e-mail, so strip it and return
	// stripped name
	int i1 = s.Find("<");
	int i2 = s.Find(">");
	if(i1 >= 1 && i2 > i1)
	{
		s = s.Mid(0, i1 - 1);
		return TrimBoth(s);
	}
	// should not happen, but it may start with <...>, so an e-mail
	// in that case, we strip domain name
	if(i1 == 0 && i2 > i1 + 2)
	{
		s = s.Mid(i1 + 1, i2 - i1 - 1);
		s = TrimBoth(s);
		i1 = s.Find("@");
		if(i1 >= 0)
			s = s.Left(i1);
		return s;
	}
	// another possibility, the string contains just a link
	// (https://.....); in that case we check if string
	// contains author name, which becomes maintainer
	if(s.StartsWith("http:") || s.StartsWith("https:"))
	{
		String a = ToLower(TrimBoth(auth));
		if(s.Find(a) >= 0)
			return a;
	}
	// none of the above, just use whole maintainer field
	return s;
}

