// the email address hasn't been checked to start with and is blank
var finalVersion = false;
var warningText = "";
var emailAddress = "";

// Function to check the email - this is what we call from the page when the button is pressed...
function checkEmail(emailBoxID)
{
	// Get the text in the box, lowercase it and trim it (of leading and trailing whitespace)
    var e1 = document.getElementById(emailBoxID).value.toLowerCase().replace(/^\s\s*/, '').replace(/\s\s*$/, '');
	// If the syntax is bad, always return
    if (!goodEmailSyntax(e1)){
		return {good: false, message: warningText};
	}
	// If it's not been checked already & spelling is bad, return
    if (!sameEmail(e1) && !goodEmailSpelling(e1, emailBoxID)) {
		return {good: false, message: warningText};
	}
	// Return true
	return {good: true, message: warningText};
}

// If the email has been flagged but is the same this time around allow it!
function sameEmail(e1){
	if (finalVersion){
		if (e1 == emailAddress){
			return true;
		} else {
			finalVersion = false;
		}
	}
	// If it has changed, go through the checking again on the new email
	return false;
}

// Is the email sytax good?
function goodEmailSyntax(e1) {
    // Fairly comprehensive valid email regex! (not perfect but...)
    var regex = new RegExp("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*"+						"@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?");
    // If we don't get a match, the address is bad and we write that to the warning text and return false
    if (!e1.match(regex)){
        return false;
    }
	// Else, syntax is ok - return true
	return true;
}

// Is the spelling good?
function goodEmailSpelling(e1, boxID){

	// Get the front and back part of the email address
    var name = e1.split("@")[0];
    var domain = e1.split("@")[1];
	// Break the domain into parts (e.g. "hotmail","co","uk")
	var domainParts = new Array();
	domainParts = domain.split(".");
	// Get the list of common domains (e.g. hotmail, yahoo, live, gmail...)
	var commonDomains = new Array();
	commonDomains = getCommonDomains();
	// Set exact domain match to false
	var exactDomainMatch = false;
	var domainErrors = new Array();
	// Check for an exact domain match (assume domain is first part - not yet implemented subdomain checking!)
	for (var x = 0; x < commonDomains.length; x++){
		if (domainParts[0] == commonDomains[x]){ 
			exactDomainMatch = true;
			break;
		}
	}
	// If we haven't got an exact domain match, we'll check for errors
	if (exactDomainMatch == false){
		// Test for possible swaps on the main domain part
		domainErrors = possibleSwaps(domainParts[0],commonDomains);
		// If no possible swaps, test for misspellings
		if (domainErrors.length == 0){
			domainErrors = possibleMispellings(domainParts[0], commonDomains);
		}
	}
	// Test for possible swaps on the suffix part 
	var commonSuffixes = new Array();
	var suffixErrors = new Array();
	var suffix = "";
	var exactSuffixMatch = false;
	// First deal with ones with only two parts e.g. @hotmail.com
	if (domainParts.length == 2){
		suffix = domainParts[1];
		commonSuffixes = getCommonSingleSuffix();
		// Check for an exact match
		for (var x = 0; x < commonSuffixes.length; x++){
			if (suffix == commonSuffixes[x]){ 
				exactSuffixMatch = true;
				break;
			}
		}
		// If we didn't get an exact match on the suffix, check for spelling mistakes
		if (exactSuffixMatch == false){
			suffixErrors = possibleSwaps(suffix,commonSuffixes);
			if (suffixErrors.length == 0){
				suffixErrors = possibleMispellings(suffix,commonSuffixes);
			}
		}
		// Next deal with longer suffixes e.g. hotmail.co.uk
	} else if (domainParts.length > 2) {
		// We assume that the 'suffix' part comes at the end and is 2 in length (e.g. .co.uk, .uk.com)
		commonSuffixes = getCommonDoubleSuffix();
		len = domainParts.length;
		suffix = domainParts[len-2]+"."+domainParts[len-1];
		// Check for an exact match
		for (var x = 0; x < commonSuffixes.length; x++){
			if (suffix == commonSuffixes[x]){ 
				exactSuffixMatch = true;
				break;
			}
		}
		// If we didn't get an exact match on the suffix, check for spelling mistakes
		if (exactSuffixMatch == false){
			suffixErrors = possibleSwaps(suffix,commonSuffixes);
			if (suffixErrors.length == 0){
				suffixErrors = possibleMispellings(suffix,commonSuffixes);
			}
			// If we've found an error and the number of 'back' parts is longer than 3, we need to add in the rest of the address (we'll add to the suffixes) 
			// e.g. abc.def.ghi.co.uk
			if (suffixErrors.length > 0 && domainParts.length > 3){
				var recombinedAddress = "";
				for (var x = 1; x < domainParts.length - 2; x++){
					recombinedAddress += domainParts[x] + '.'; 
				}
				for (var i = 0; i < suffixErrors.length; i++){
					suffixErrors[i] = recombinedAddress + suffixErrors[i];
				}
			}
		}
	}
	
	// If we've got some kind of possible error, write it out and return false
	if (domainErrors.length > 0 || suffixErrors.length > 0){
		var outstring = "Did you mean?";
		if (domainErrors.length == 0){
			for (var x = 0; x < suffixErrors.length; x++){
				var n = name + "@" + domainParts[0] + "." + suffixErrors[x];
				outstring = outstring + "<br/><a href='#' onclick='finalVersion=true;document.getElementById(\"" + boxID + "\").value=\"" + n + "\";document.body.removeChild(this.parentNode);try {document.body.removeChild(document.getElementById(\"" + boxID + "Arrow\"))} catch (err) {};return false;'>" + n + "</a>";
			}
		} else if (suffixErrors.length == 0){
			for (var x = 0; x < domainErrors.length; x++){
				var n = name + "@" + domainErrors[x] + "." + suffix;
				outstring = outstring + "<br/><a href='#' onclick='finalVersion=true;document.getElementById(\"" + boxID + "\").value=\"" + n + "\";document.body.removeChild(this.parentNode);try {document.body.removeChild(document.getElementById(\"" + boxID + "Arrow\"))} catch (err) {};return false;'>" + n + "</a>";
			}
		} else {
			for (var x = 0; x < domainErrors.length; x++){
				for (var y = 0; y < suffixErrors.length; y++) {
					var n = name + "@" + domainErrors[x] + "." + suffixErrors[y];
					outstring = outstring + "<br/><a href='#' onclick='finalVersion=true;document.getElementById(\"" + boxID + "\").value=\"" + n + "\";document.body.removeChild(this.parentNode);try {document.body.removeChild(document.getElementById(\"" + boxID + "Arrow\"))} catch (err) {};return false;'>" + n + "</a>";
				}
			}
		}
		outstring = outstring + "<br/><a href='#' onclick='finalVersion=true;document.body.removeChild(this.parentNode);try {document.body.removeChild(document.getElementById(\"" + boxID + "Arrow\"))} catch (err) {}; return false;'>No, my email is correct</a>";
		emailAddress = e1;
		warningText = outstring;
		return false;
	}
	// If all is 'ok' return true;
	return true;
}


// Check for a match with swapped letters
function possibleSwaps(strng,arry){

    // First part deals with swapped letters (e.g. htomail.com) - strings must be the same length
    var possibleMatch = false;
    var stringlength = strng.length;
    for ( var i=0, len=arry.length; i < len; ++i ){
        if (stringlength == arry[i].length) {
            var counter = 0;
            for (var k = 0; k < stringlength - 1; k++) {
                if (strng.charAt(k) != arry[i].charAt(k)) {
                    if (strng.charAt(k) == arry[i].charAt(k + 1) &&
                        strng.charAt(k + 1) == arry[i].charAt(k)) {
                        counter++;
                        k++;
                        possibleMatch = true;
                    } else {
                        possibleMatch = false;
                        break;
                    }
                }
            }
            if ((counter <= 2) && (possibleMatch == true)) {
				// If we've got up to two sets of swaps but an otherwise good match, return the correct string
				return new Array(arry[i]);
            }
        }
    }
	// Return empty array if we didn't find a 'swap' match
	return new Array();
}

// Check for a mistyped letter, a missing letter or an added letter
function possibleMispellings(strng,arry){

    var actualDist = 0;
	var returnArray = [];
    for (var i = 0, len = arry.length; i < len; i++) {
        actualDist = getDistance(strng, arry[i]);
        if (actualDist == 1) {
			returnArray.push(arry[i]);
        }
    }
	return returnArray;
}


// Get the edit distance (Levenshtein distance) between the two strings
function getDistance(a, b){

    var min = Math.min, len1=0, len2=0, I=0, i=0, d=[], c='', j=0, J=0;
    var split = false;
    try{
        split=!('0')[0];
    } catch(i){
        split=true; 
    }
    if (a == b) {
        return 0;
    }
    if (!a.length || !b.length) {
        return b.length || a.length;
    }
    if (split){
        a = a.split('');
        b = b.split('');
    }
    len1 = a.length + 1;
    len2 = b.length + 1;
    d = [[0]];
    while (++i < len2) {
        d[0][i] = i;
    }
    i = 0;
    while (++i < len1) {
        J = j = 0;
        c = a[I];
        d[i] = [i];
        while (++j < len2) {
            d[i][j] = min(d[I][j] + 1, d[i][J] + 1, d[I][J] + (c != b[J]));
            ++J;
        }
        ++I;
    }  
    return d[len1 - 1][len2 - 1];
}

// Get the array containing our common domains
function getCommonDomains(){
    var commonDomains = new Array(
            "3mail",
            "aim",
            "aol",
            "bloomberg",
            "blueyonder",
            "btclick",
            "btconnect",
            "btinternet",
            "btopenworld",
            "clara",
            "dishmail",
            "earthlink",
            "easy",
            "email",
            "excite",
            "fastmail",
            "freenet",
            "freeserve",
            "fsmail",
            "gmail",
            "gmx",
            "googlemail",
            "gotadsl",
            "hotmail",
            "iafrica",
            "juno",
            "libero",
            "lineone",
            "lineone",
            "live",
            "lycos",
            "mac",
            "macunlimited",
            "madasafish",
            "mail",
            "mindspring",
            "msn",
            "nildram",
            "ntlworld",
            "o2",
            "onetel",
            "online",
            "orange",
            "rocketmail",
            "sky",
            "sprintpcs",
            "supanet",
            "talk21",
            "talktalk",
            "telefonica",
            "telia",
            "tesco",
            "tiscali",
            "ukonline",
            "verizon",
            "versatel",
            "virgin",
            "vodafone",
            "wanadoo",
            "windowslive",
            "yahoo",
            "yahoo-inc",
            "ymail",
            "zoom"
	);
	return commonDomains;
}

// Get the array containing our common domains
function getCommonSingleSuffix(){
    var singleSuffixes = new Array(
            "ae",
            "ag",
            "at",
            "be",
            "bg",
            "biz",
            "br",
            "ca",
            "cc",
            "ch",
            "cn",
            "com",
            "cz",
            "de",
            "dk",
            "dm",
            "edu",
            "es",
            "eu",
            "fm",
            "fr",
            "gov",
            "gr",
            "gr",
            "hr",
            "hu",
            "ie",
            "in",
            "in",
            "info",
            "int",
            "is",
            "is",
            "it",
            "lc",
            "lu",
            "me",
            "mil",
            "mobi",
            "mu",
            "name",
            "net",
            "nl",
            "no",
            "nu",
            "org",
            "pl",
            "pt",
            "pt",
            "ro",
            "ru",
            "se",
            "se",
            "us",
            "ws",
            "ws"
	);
	return singleSuffixes;
}

function getCommonDoubleSuffix(){
    var doubleSuffixes = new Array(
            "ac.uk",
            "cg.yu",
            "co.il",
            "co.id",
            "co.in",
            "co.jp",
            "co.nz",
            "co.uk",
            "co.za",
            "com.ar",
            "com.au",
            "com.br",
            "com.cn",
            "com.cy",
            "com.gr",
            "com.hk",
            "com.mt",
            "com.mx",
            "com.pa",
            "com.ph",
            "com.pt",
            "com.sg",
            "com.tr",
            "gov.uk",
            "me.uk",
            "net.ae",
            "net.au",
            "net.il",
            "net.in",
            "org.uk",
            "sch.uk",
            "uk.com"
	);
	return doubleSuffixes;
}

