var EmailCorrector = {
	address:  '',
	username: '',
	domain:   '',

	// regex rules:
	// most common domains
	domain_names : {
		'gmail'   : '^(gmal+|ga?mil|gmai|gail|gm.il|gma.l|gmai.|gmial|gmail.+)$',
		'yahoo'   : '^(yaho|yaoo|.ahoo|ya.oo|y.hoo|yhoo|yaoho|yahoo.+)$',
		'hotmail' : '^(hotmai|hotmal|hotmil|hotail|homail|htmail|otmail|.otmail|h.tmail|ho.mail|hot.ail|hotm.il|hotma.l|hotmai.|hotmail.+)$',
		'aol'     : '^(oal|alo|aoll|zol|sol|qol|ol|al|ao)$',
		'mail'    : '^(mali|mai)$'
	},
	// most common tlds
	tld_names 	: {
		'com' 	: '(\\.co|c\\.om|\\.moc|\\.cmo)$',
		'net' 	: '(\\.ne|\\.tne|\\.nte|\\.ten|\\.ent)$',
		'org' 	: '(\\.or|\\.ogr|o\\.rg)$',
		'edu' 	: '(\\.ed|\\.eud|e\\.du)$',
		'co.uk'	: '(\\.couk)$'
	},
	// missing dot at the end of domain name
	missing_dot : '([^\\.+]+)(com|net|org|edu|co\\.uk)$',

   /**
    * Email address validation process
    *
    * @param  string $address
    * @return mixed (bool|string)
    */
	processEmailAddress: function(address)
	{
		if (!this.setAddress(address))
		{
		    return 0;
		}
		if (!this.validEmailFormat())
		{
		    this.fixCommonErrors();
		}
		if (!this.setParts())
		{
			// unable to set parts - log user input and leave
			this.saveLog(address);
			return 0;
		}
		//first off all we will check and fix 1st domain level (.com, .net, .org, etc.)
		this.fixTLDName();

		//now we need to fix popular email domains such gmail, aol, yahoo
		this.fixDomainName();

		// this.gmailFixAfterPlus();

		this.buildAddress();

		this.saveLog(address);

		return this.validEmailFormat();
	},

    /**
     * Set address, username, domain and tld name
     *
     * @param mixed address
     */
	setAddress: function(address)
	{
		// if param passed is empty, return false
		if (!address)
		{
		    return 0;
		}
		this.clear();
		this.address = address.toLowerCase();

		return this.address ? 1 : 0;
	},

    /**
     * Clear|reset static values
     */
	clear: function()
	{
		this.address = '';
		this.username = '';
		this.domain = '';
	},

    /**
     * Rebuild email address from parts
     */
	buildAddress: function()
	{
		this.address = (this.username && this.domain) ? this.username + '@' + this.domain : '';
		return this.address ? 1 : 0;
	},

    /**
     * Set email parts: username [@] domain.tld
     */
	setParts: function()
	{
		// check if @ sign exists, if not - try to fix address
        var pos = this.address.indexOf('@');
        if (pos == -1)
        {
            if (!this.fixAtSign())
            {
                return 0
            }
            else
            {
                var pos = this.address.indexOf('@');
                if (pos == -1)
                {
                    return 0;
                }
            }
        }
        this.username = this.address.substr(0, pos);
        this.domain =  this.address.substr(pos + 1);
		return (this.username && this.domain) ? 1 : 0;
	},

	saveLog: function(address)
	{
		if (!address)
		{
		    return 0;
		}
	},

    /**
     * Fix common problems, before we can explode email address to parts
     * - remove spaces, change commas into dots, remove repeated dots, etc...
     * - add missing dot before most common tlds
     */
	fixCommonErrors: function()
	{
		// remove spaces, change commas into dots, change multiplied dots
		this.address = this.address.replace(/\s+/gi, '');
		this.address = this.address.replace(/,+/gi, '.');
		this.address = this.address.replace(/\.{2,}/gi, '.');
		if (this.address.match(this.missing_dot))
		{
		    regex = new RegExp(this.missing_dot, "i");
			this.address = this.address.replace(regex, '$1.$2');
		}
	},

    /**
     * Fix extensions for most common top level domains
     */
	fixTLDName: function()
	{
		if (!this.tld_names)
		{
		    return 0;
		}

		for (replace in this.tld_names)
		{
		    regex = this.tld_names[replace];
			if (this.domain.match(regex))
			{
			    regex = new RegExp(regex, "i");
				this.domain = this.domain.replace(regex, '.' + replace);
				return 1;
			}
		}
		return 1;
	},

    /**
     * Fix domain name for most common domain names
     */
	fixDomainName: function()
	{
		// fix leading www in domain name
		this.domain = this.domain.replace(/^www./i, '');
		var pieces = this.domain.toString().split('.');

        if (!pieces.length || !this.domain_names)
        {
            return 0;
        }
        for (replace in this.domain_names)
        {
            regex = this.domain_names[replace];
            if (pieces[0].match(regex))
			{
			    regex = new RegExp(regex, "i");
				pieces[0] = pieces[0].replace(regex, replace);
				this.domain = pieces.join('.');
				return 1;
			}
		}
		return 1;
	},

    /**
     * Fix @ sign
     */
	fixAtSign: function()
	{
		// if we have more than one '2' character, return false
		var ats = this.address.match(/2/gi);
		if (ats && ats.length == 1)
		{
		    this.address = this.address.replace(/2/i, '@');
		}
		return 1;
	},

    /**
     * Email Validation
     */
	validEmailFormat: function()
	{
		matches = this.address.match(/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/);
		if (!matches)
		{
		    return 0;
		}
		return matches[0];
	},

	/**
     * Validate gmail address:
     * - PLUS SIGN and all that comes after it, in the local part of an email
     * @example some.username+wldating@gmail.com is the same email address as some.username@gmail.com (when +wldating is removed)
     */
	gmailFixAfterPlus: function ()
	{
	    if ((this.domain == 'gmail.com') || (this.domain == 'googlemail.com'))
	    {
	        var pos = this.username.indexOf('+');
	        if (pos > 0)
	        {
	            this.username = this.username.substr(0, pos);
	        }
	    }
	    return 1;
	},

	selfTest: function()
	{
	    var emails_in = new Array(
            'drtest@drtest.nEt',
            'drtest2@drtest.net',
            'test@inbox.lv',
            'spam.test@drtest.net',
            'spam.test@drtest,net',
            'drtest@drtestnet',
            'drtest@drtest.nte',
            'drtest@www.drtest.net',
            'drtest@gmai.com',
            'drtest@gmaicom',
            'drtest@gmai.cmo',
            'drtest2gmailcom',
            'drtest2gmail.com'
            // 'drtest+test1@gmail.com'
        );
        var emails_out = new Array(
            'drtest@drtest.net',
            'drtest2@drtest.net',
            'test@inbox.lv',
            'spam.test@drtest.net',
            'spam.test@drtest.net',
            'drtest@drtest.net',
            'drtest@drtest.net',
            'drtest@drtest.net',
            'drtest@gmail.com',
            'drtest@gmail.com',
            'drtest@gmail.com',
            'drtest@gmail.com',
            'drtest@gmail.com'
            // 'drtest@gmail.com'
        );
        var output = '';
        for (i = 0; i < emails_in.length; ++i)
        {
            new_mail = EmailCorrector.processEmailAddress(emails_in[i]);
            if (new_mail != emails_out[i])
            {
                // output += emails_in[i] + ' -> ' + new_mail + ' : ' + emails_out[i] + "<br/>\n";
            }
            else
            {
                output += emails_in[i] + ' OK' + "<br/>\n";
            }
        }
        if (output == '')
        {
            output += ' TEST PASSED!' + "<br/>\n";
        }
        document.write(output);
	}
};
