// Must. Have. Data.
var feedURL = "http://ipv6.he.net/exhaustionFeed.php?platform=json";
var skew = 0; //86400 / 3 * 2.65;

// Queries go where?
var xmlObject = null;

// Current tab
var currentTab = 'stats';

// Current data. This is default "loading" data
var currentData = {
	startDate: -1,
	exhaustionDate: -1,
	unallocatedv4Blocks: -1,
	totalTLDs: -1,
	v6TLDs: -1,
	v6ASNs: -1,
	totalASNs: -1,
	v6NS: -1,
	v6Domains: -1,
	v6DomainsPerDay: -1,
	totalv4Blocks: -1,
	addrsPerBlock: -1,
	afrinic24s: -1,
	afrinicPercent: -1,
	apnic24s: -1,
	apnicPercent: -1,
	arin24s: -1,
	arinPercent: -1,
	lacnic24s: -1,
	lacnicPercent: -1,
	ripe24s: -1,
	ripePercent: -1
};

// Display update timer
var updateInterval = 100;
var timerUpdateID = -1;
var updateProcess = true;

// Data reload timer
var reloadInterval = 60 * 60 * 4 * 1000;
var timerReloadID = -1;

function startup () {
	// Set the field labels
	if (useShort == true) {
		setContent ("stats_title", locale.stats_title_short);
		setLabel ("stats_ipv4_remaining", locale.stats_ipv4_remaining_short);
		setLabel ("stats_ipv4_8s_left", locale.stats_ipv4_8s_left_short);
		setLabel ("stats_ipv6_asns", locale.stats_ipv6_asns_short);
		setLabel ("stats_ipv6_tlds", locale.stats_ipv6_tlds_short);
		setLabel ("stats_ipv6_glues", locale.stats_ipv6_glues_short);
		setLabel ("stats_ipv6_domains", locale.stats_ipv6_domains_short);
		setLabel ("stats_days_remaining", locale.stats_days_remaining_short);
		
		setContent ("rirs_title", locale.rirs_title_short);
		
		setContent ("exhausted_title", locale.exhausted_title_short);
		setContent ("exhausted_rirs_title", locale.exhausted_rirs_title_short);
		setLabel ("exhausted_stats_ipv6_asns", locale.stats_ipv6_asns_short);
		setLabel ("exhausted_stats_ipv6_tlds", locale.stats_ipv6_tlds_short);
		setLabel ("exhausted_stats_ipv6_glues", locale.stats_ipv6_glues_short);
		setLabel ("exhausted_stats_ipv6_domains", locale.stats_ipv6_domains_short);
		setLabel ("exhausted_for", locale.exhausted_for_short);
		setLabel ("exhausted_days", locale.exhausted_days);
		setLabel ("exhausted_days_remaining", locale.exhausted_days_remaining_short);
		setLabel ("exhausted_iana", locale.exhausted_iana_short);
		
		setLabel ("info_ipv4_addr", locale.info_ipv4_addr_short);
		setLabel ("info_ipv6_addr", locale.info_ipv6_addr_short);
		setLabel ("info_have_ipv6", locale.info_have_ipv6_short);
		setLabel ("info_get_ipv6", locale.info_get_ipv6_short);
		
		try {
			if (remoteIP) {
				setValue ("info_ip_addr", remoteIP);
				if (isIPv6) {
					setLabel ("info_ip_addr", locale.info_ipv6_addr_short + ":");
					setContent ("info_ip_note", locale.info_have_ipv6_short);
				} else {
					setLabel ("info_ip_addr", locale.info_ipv4_addr_short + ":");
					setContent ("info_ip_note", '<a target="_blank" href="http://tunnelbroker.net/">' + locale.info_get_ipv6_short + '</a>');
				}
			}
		}
		catch (err) {
			// Nothing here
		}
	} else {
		setContent ("stats_title", locale.stats_title);
		setLabel ("stats_ipv4_remaining", locale.stats_ipv4_remaining);
		setLabel ("stats_ipv4_8s_left", locale.stats_ipv4_8s_left);
		setLabel ("stats_ipv6_asns", locale.stats_ipv6_asns);
		setLabel ("stats_ipv6_tlds", locale.stats_ipv6_tlds);
		setLabel ("stats_ipv6_glues", locale.stats_ipv6_glues);
		setLabel ("stats_ipv6_domains", locale.stats_ipv6_domains);
		setLabel ("stats_days_remaining", locale.stats_days_remaining);
		
		setContent ("rirs_title", locale.rirs_title);
		
		setContent ("exhausted_title", locale.exhausted_title);
		setContent ("exhausted_rirs_title", locale.exhausted_rirs_title);
		setLabel ("exhausted_stats_ipv6_asns", locale.stats_ipv6_asns);
		setLabel ("exhausted_stats_ipv6_tlds", locale.stats_ipv6_tlds);
		setLabel ("exhausted_stats_ipv6_glues", locale.stats_ipv6_glues);
		setLabel ("exhausted_stats_ipv6_domains", locale.stats_ipv6_domains);
		setLabel ("exhausted_for", locale.exhausted_for);
		setLabel ("exhausted_days", locale.exhausted_days);
		setLabel ("exhausted_days_remaining", locale.exhausted_days_remaining);
		setLabel ("exhausted_iana", locale.exhausted_iana);
		
		setLabel ("info_ipv4_addr", locale.info_ipv4_addr);
		setLabel ("info_ipv6_addr", locale.info_ipv6_addr);
		setLabel ("info_have_ipv6", locale.info_have_ipv6);
		setLabel ("info_get_ipv6", locale.info_get_ipv6);
		
		try {
			if (remoteIP) {
				setValue ("info_ip_addr", remoteIP);
				if (isIPv6) {
					setLabel ("info_ip_addr", locale.info_ipv6_addr + ":");
					setContent ("info_ip_note", locale.info_have_ipv6);
				} else {
					setLabel ("info_ip_addr", locale.info_ipv4_addr + ":");
					setContent ("info_ip_note", '<a target="_blank" href="http://tunnelbroker.net/">' + locale.info_get_ipv6 + '</a>');
				}
			}
		}
		catch (err) {
			// Nothing here
		}
	}
	
	// Set the fields to "loading" values
	setValue ("stats_ipv4_remaining", "<i>?</i>");
	setValue ("stats_ipv4_8s_left", "<i>?</i>");
	setValue ("stats_ipv4_8s_left_i", "(<i>?</i>)");
	setValue ("stats_ipv6_asns", "<i>?</i>");
	setValue ("stats_ipv6_asns_i", "(<i>?</i>)");
	setValue ("stats_ipv6_tlds", "<i>?</i>");
	setValue ("stats_ipv6_tlds_i", "(<i>?</i>)");
	setValue ("stats_ipv6_glues", "<i>?</i>");
	setValue ("stats_ipv6_domains", "<i>?</i>");
	setValue ("stats_days_remaining", "<i>?</i>");
	
	// Look for an overlay. Make it visible if we're not in a sidebar
	try {
		if (System) {
			setDisplay ('link_overlay', 'none');
		}
	}
	catch (err) {
		setDisplay ('link_overlay', 'block');
	}
	
	// Get the first data set
	getFile (feedURL, updateData);
}

function updateDisplay () {
	if (! updateProcess) {
		return;
	}
	
	setValue ("stats_ipv4_remaining", commaize (getIPsRemaining ()));
	setValue ("stats_days_remaining", commaize (getDaysRemaining ()));
	
	if (! isExhausted ()) {
		setDisplay ('view_exhausted', 'none');
		setDisplay ('view_normal', 'block');
	} else {	
		setDisplay ('view_normal', 'none');
		setDisplay ('view_exhausted', 'block');
		
		setValue ("exhausted", commaize (getDaysPast ()));
	}
	setValue ("stats_ipv6_domains", commaize (Math.floor (currentData.v6Domains + ((currentData.v6DomainsPerDay / 86400) * (now () - currentData.midnight)))));
	setValue ("exhausted_stats_ipv6_domains", commaize (Math.floor (currentData.v6Domains + ((currentData.v6DomainsPerDay / 86400) * (now () - currentData.midnight)))));
}

function getDaysRemaining () {
	var temp;
	
	temp = Math.floor ((currentData.exhaustionDate + skew - now ()) / 86400);
	//temp = Math.round (((currentData.exhaustionDate + skew - now ()) / 86400) * 10) / 10;
	if (temp < 0) {
		return (0);
	}
	return (temp);
}

function getDaysPast () {
	temp = Math.floor ((now () - currentData.exhaustionDate) / 86400);
	if (temp < 0) {
		return (0);
	}
	return (temp);
}

function isExhausted () {
	if (now () >= currentData.exhaustionDate + skew) {
		return (true);
	}
	return (false);
}

function getIPsRemaining () {
	var temp;
	
	temp = Math.floor (currentData.startAddrs * ((currentData.exhaustionDate + skew - now ()) / (currentData.exhaustionDate - currentData.startDate)));
	if (temp < 0) {
		return (locale.stats_ipv4_remaining_none);
	}
	return (temp);
}

function setLabel (id, content) {
	setContent (id + '_label', content);
}

function setValue (id, content) {
	setContent (id + '_value', content);
}

function setContent (id, content) {
	var element = document.getElementById (id);
	if (element) {
		element.innerHTML = content;
	}
}

function setDisplay (id, value) {
	var element = document.getElementById (id);
	if (element) {
		element.style.display = value;
	}
}

function setClass (id, value) {
	var element = document.getElementById (id);
	if (element) {
		element.className = value;
	}
}

function setTab (tab) {
	setDisplay ('tab_' + currentTab, 'none');
	setClass ('tabs_' + currentTab, '');
	setDisplay ('tab_' + tab, 'block');
	setClass ('tabs_' + tab, 'active');
	currentTab = tab;
}

function dateToEpoch (string, year, month, day) {
	var str = String (string);
	var parts = str.split ('-');
	var date = new Date (parts [year], parts [month] - 1, parts [day]);
	return (date.getTime () / 1000);
}

function now () {
	var date = new Date;
	//return ((date.getTime () / 1000) + (86400 * 100));
	return (date.getTime () / 1000);
}

function todayMidnight () {
	var date = new Date;
	var midnight = new Date (date.getFullYear (), date.getMonth (), date.getDate (), 0, 0, 0);
	return (midnight.getTime () / 1000);
}

function commaize (number) {
	var numberstring = String (number);
	var x = numberstring.split (".");
	var x1 = x [0];
	var x2 = x.length > 1 ? "." + x [1] : "";
	var regex = /(\d+)(\d{3})/;
	while (regex.test (x1)) {
		x1 = x1.replace (regex, "$1" + "," + "$2");
	}
	return (x1 + x2);
}

function createRequest (callback) {
	var XMLObj = null;
	try {
		XMLObj = new XMLHttpRequest ();
	} catch (e) {
		try {
			XMLObj = new ActiveXObject ("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				XMLObj = new ActiveXObject ("Microsoft.XMLHTTP");
			} catch (e) {
				return null;
			}
		}
	}
	if (XMLObj) {
		XMLObj.onreadystatechange = callback;
	}
	return (XMLObj);
}

function getFile (url, callback) {
	xmlObject = createRequest (callback);
	if (xmlObject) {
		xmlObject.open ("GET", url, true);
		xmlObject.send (null);
	}
	timerReloadID = setTimeout ("getFile(feedURL,updateData)", reloadInterval);
}

function updateData (response) {
	if ((xmlObject.readyState == 4) && (xmlObject.status == 200)) {
		// Stop updates to the display while we're loading data
		if (timerUpdateID != -1) {
			clearInterval (timerUpdateID);
			timerUpdateID = -1;
		}
		
		// JSON
		currentData = eval ("(" + xmlObject.responseText + ")");
		
		// Convert YYYY-MM-DD to epoch
		currentData.startDate = dateToEpoch (currentData.startDate, 0, 1, 2);
		currentData.exhaustionDate = dateToEpoch (currentData.exhaustionDate, 0, 1, 2);
		
		// Convert any strings to integers
		currentData.unallocatedv4Blocks = parseInt (currentData.unallocatedv4Blocks, 10);
		currentData.totalTLDs = parseInt (currentData.totalTLDs, 10);
		currentData.v6TLDs = parseInt (currentData.v6TLDs, 10);
		currentData.v6ASNs = parseInt (currentData.v6ASNs, 10);
		currentData.totalASNs = parseInt (currentData.totalASNs, 10);
		currentData.v6NS = parseInt (currentData.v6NS, 10);
		currentData.v6Domains = parseInt (currentData.v6Domains, 10);
		currentData.v6DomainsPerDay = parseInt (currentData.v6DomainsPerDay, 10);
		
		currentData.afrinic24s = parseInt (currentData.afrinic24s, 10);
		currentData.apnic24s = parseInt (currentData.apnic24s, 10);
		currentData.arin24s = parseInt (currentData.arin24s, 10);
		currentData.lacnic24s = parseInt (currentData.lacnic24s, 10);
		currentData.ripe24s = parseInt (currentData.ripe24s, 10);
		currentData.afrinicPercent = parseFloat (currentData.afrinicPercent);
		currentData.apnicPercent = parseFloat (currentData.apnicPercent);
		currentData.arinPercent = parseFloat (currentData.arinPercent);
		currentData.lacnicPercent = parseFloat (currentData.lacnicPercent);
		currentData.ripePercent = parseFloat (currentData.ripePercent);
		
		// Add extra useful data
		currentData.totalv4Blocks = 256;
		currentData.addrsPerBlock = Math.pow (2, 24);
		currentData.startAddrs = currentData.unallocatedv4Blocks * currentData.addrsPerBlock;
		currentData.midnight = todayMidnight ();
		
		// Set the "static" values
		setValue ("stats_ipv4_8s_left", Math.floor ((currentData.unallocatedv4Blocks / currentData.totalv4Blocks) * 100) + "%");
		setValue ("stats_ipv4_8s_left_i", "(" + commaize (currentData.unallocatedv4Blocks) + "/" + commaize (currentData.totalv4Blocks) + ")");
		setValue ("stats_ipv6_asns", Math.floor ((currentData.v6ASNs / currentData.totalASNs) * 100) + "%");
		setValue ("stats_ipv6_asns_i", "(" + commaize (currentData.v6ASNs) + "/" + commaize (currentData.totalASNs) + ")");
		setValue ("stats_ipv6_tlds", Math.floor ((currentData.v6TLDs / currentData.totalTLDs) * 100) + "%");
		setValue ("stats_ipv6_tlds_i", "(" + commaize (currentData.v6TLDs) + "/" + commaize (currentData.totalTLDs) + ")");
		setValue ("stats_ipv6_glues", commaize (currentData.v6NS));
		
		setValue ("exhausted_stats_ipv6_asns", Math.floor ((currentData.v6ASNs / currentData.totalASNs) * 100) + "%");
		setValue ("exhausted_stats_ipv6_asns_i", "(" + commaize (currentData.v6ASNs) + "/" + commaize (currentData.totalASNs) + ")");
		setValue ("exhausted_stats_ipv6_tlds", Math.floor ((currentData.v6TLDs / currentData.totalTLDs) * 100) + "%");
		setValue ("exhausted_stats_ipv6_tlds_i", "(" + commaize (currentData.v6TLDs) + "/" + commaize (currentData.totalTLDs) + ")");
		setValue ("exhausted_stats_ipv6_glues", commaize (currentData.v6NS));
		
		setValue ("rir_afrinic_p", currentData.afrinicPercent + "%");
		setValue ("rir_afrinic_i", commaize (currentData.afrinic24s));
		setValue ("rir_apnic_p", currentData.apnicPercent + "%");
		setValue ("rir_apnic_i", commaize (currentData.apnic24s));
		setValue ("rir_arin_p", currentData.arinPercent + "%");
		setValue ("rir_arin_i", commaize (currentData.arin24s));
		setValue ("rir_lacnic_p", currentData.lacnicPercent + "%");
		setValue ("rir_lacnic_i", commaize (currentData.lacnic24s));
		setValue ("rir_ripe_p", currentData.ripePercent + "%");
		setValue ("rir_ripe_i", commaize (currentData.ripe24s));
		
		setValue ("exhausted_rir_afrinic_p", currentData.afrinicPercent + "%");
		setValue ("exhausted_rir_afrinic_i", commaize (currentData.afrinic24s));
		setValue ("exhausted_rir_apnic_p", currentData.apnicPercent + "%");
		setValue ("exhausted_rir_apnic_i", commaize (currentData.apnic24s));
		setValue ("exhausted_rir_arin_p", currentData.arinPercent + "%");
		setValue ("exhausted_rir_arin_i", commaize (currentData.arin24s));
		setValue ("exhausted_rir_lacnic_p", currentData.lacnicPercent + "%");
		setValue ("exhausted_rir_lacnic_i", commaize (currentData.lacnic24s));
		setValue ("exhausted_rir_ripe_p", currentData.ripePercent + "%");
		setValue ("exhausted_rir_ripe_i", commaize (currentData.ripe24s));
		
		// Update the display
		updateDisplay ();
		
		// Restart the display update timer
		timerUpdateID = setInterval ("updateDisplay()", updateInterval);
	}
}

