#include "IPAddress.h"

uint16_t _addr[8];

// constructors
IPV6Address::IPV6Address(uint16_t const *addr)
{
	memcpy(_addr, addr, 16);
}

IPV6Address::IPV6Address(const char *addr)
{
	String s = addr;
	
	// if there are double colons, expand them
	int idx = s.Find("::");
	int count = 0;
	if(idx >= 0)
	{
		for(int i = 0; i < s.GetCount(); i++)
			if(s[i] == ':')
				count++;
		for(int i = count; i < 7; i++)
			s.Insert(idx, ':');
		count = 7;
	}
	else
	{
		// add missing ':' on string head
		for(int i = 0; i < s.GetCount(); i++)
			if(s[i] == ':')
				count++;
		if(count < 7)
			for(int i = count; i < 7; i++)
				s.Insert(0, ':');
	}
	// now insert 0 between couples of ':'
	while( (idx = s.Find("::")) >= 0)
		s.Insert(idx + 1, '0');
	if(s.StartsWith(":"))
		s.Insert(0, "0");
	if(s.EndsWith(":"))
		s.Cat('0');
	
	// and finally we can scan the string
	s = ToLower(s);
	Vector<String> v = Split(s, ':');
	memset(_addr, 0, 16);
	for(int i = 0; i < v.GetCount(); i++)
	{
		uint16_t w = 0;
		const char *p = ~v[i];
		while(*p)
		{
			if(*p >= '0' && *p <= '9')
				w = 16 * w + *p - '0';
			else if(*p >= 'a' && *p <= 'f')
				w = 16 * w + *p - 'a' + 10;
			else
				NEVER();
			p++;
		}
		_addr[i] = w;
	}
}

IPV6Address::IPV6Address(IPV6Address const &addr)
{
	memcpy(_addr, addr._addr, 16);
}

String IPV6Address::ToString(void) const
{
	Vector<String> v;
	for(int i = 0; i < 8; i++)
		v.Add(Format("%x", _addr[i]));
	String s = Join(v, ":");
	
	// strip leading 0: i any
	if(s.StartsWith("0:"))
	{
		while(s.StartsWith("0:"))
			s = s.Mid(2);
		return s;
	}
	
	// simplify biggest sequence of 0s
	int idx;
	int r = 11;
	String f = ":0:0:0:0:0:0:";
	while(r > 2)
	{
		idx = s.Find(f);
		if(idx >= 0)
		{
			s.Remove(idx + 1, r);
			return s;
		}
		r -= 2;
		f.TrimLast(2);
	}
	return s;
}

IPV6Address &IPV6Address::operator=(IPV6Address const &a)
{
	memcpy(_addr, a._addr, 16);
	return *this;
}

bool IPV6Address::operator==(IPV6Address const &a) const
{
	return !memcmp(_addr, a._addr, 16);
}
