/*
 *  Copyright 2009 Genius.com, Inc
 *  
 *  Licensed under the Apache License, Version 2.0 (the "License"); 
 *  you may not use this file except in compliance with the License. 
 *  You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *      
 *  Unless required by applicable law or agreed to in writing, software 
 *  distributed under the License is distributed on an "AS IS" BASIS, 
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 *  See the License for the specific language governing permissions and 
 *  limitations under the License. 
 */

// Set up namespace.
if (typeof(GeniusScript) != 'undefined')
{
    GeniusScript.validator = {};
    
    //CSS class-name to be applied to an invalid field
    GeniusScript.validator.INVALID_FIELD_CSS = 'genius_com_w2l_form_field_invalid';
    //CSS class-name to be applied to an invalid field's label element
    GeniusScript.validator.INVALID_LABEL_CSS = 'genius_com_w2l_form_label_invalid';

    GeniusScript.validator.validateEmail = function(value)
    {
        var ipPattern = /^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}$/;
        var ipInBracketsPattern = /^\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]$/;
        var labelPattern = /^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$/;
        var topLevelDomainPattern = /[A-Za-z]/;
        
        var rfc2822Atom = "([A-Za-z0-9!#$%&'*+/=?^_`{|}~-]{1,64})";
        var rfc2822QuotedString = "(\"(?:(?:[^\"])|(?:\\\\\")){0,62}\")";
        var rfc2822Word = "(" + rfc2822Atom + "|" + rfc2822QuotedString + ")";
        var rfc2822ObsLocalPart = rfc2822Word + "(\\." + rfc2822Word + ")*";
        var localPartDotAtomPattern = new RegExp("^" + rfc2822Atom + "(\\." + rfc2822Atom + ")*$");
        var quotedStringPat = new RegExp(rfc2822QuotedString);
        var localPartQuotedStringPat = new RegExp("^" + rfc2822QuotedString + "$");
        var obsLocalPartPat = new RegExp("^" + rfc2822ObsLocalPart + "$");
        var controlCharPattern = new RegExp("[\\x00-\\x1F\\x7F-\\xFF]");
        var dotPattern = new RegExp("\\.");
        
        if (controlCharPattern.test(value)) {
            return false;
        }

        if (value.length < 3 || value.length > 256) {
            return false;
        }
        
        var atPosition = value.lastIndexOf("@");

        if (atPosition == -1) {
            // no @ found
            return false;
        }

        var local = value.substring(0, atPosition);
        var domain = value.substring(atPosition + 1);

        // remove all dots
        var strippedLocalPart = local.replace(dotPattern, "");
        // remove quoted strings
        strippedLocalPart = strippedLocalPart.replace(quotedStringPat, "");

        // there should now not be any @'s in the full string
        if ((strippedLocalPart + domain).lastIndexOf("@") != -1) {
            return false;
        }

        var checkLocalPortion = function(local)
        {
            if (local.length < 1 || local.length > 64)
            {
                return false;
            }
            
            if (localPartQuotedStringPat.test(local)) {
                return true;
            }

            if (localPartDotAtomPattern.test(local)) {
                return true;
            }

            if (obsLocalPartPat.test(local)) {
                return true;
            }
            
            return false;
        }
        
        if (!checkLocalPortion(local))
        {
            return false;
        }

        var checkDomainPortion = function(domain) {
            if (domain.length < 1 || domain.length > 255) {
                return false;
            }
            
            if (ipPattern.test(domain) || ipInBracketsPattern.test(domain)) {
                return true;
            }

            // split the domain, including trailing empty strings
            var chunks = domain.split(".");

            if (chunks.length < 2) {
                // not enough parts
                return false;
            }

            for (var i = 0; i < chunks.length; i++) {
                var chunk = chunks[i];

                if (chunk.length < 1 || chunk.length > 63) {
                    return false;
                }

                if (!labelPattern.test(chunk)) {
                    return false;
                }

                // if this is the last chunk, additional restriction: TLD cannot be only numbers
                if (i == chunks.length - 1) {
                    if (!topLevelDomainPattern.test(chunk)) {
                        return false;
                    }
                }
            }

            return true;
        }

        if (!checkDomainPortion(domain)) {
            return false;
        }
        
        return true;
    };
    
    GeniusScript.validator.generateMessage = function(config)
    {
        var message = GeniusScript.messages[config.errorMessage];
        var field_label = null;
        var labelElem = document.getElementById(config.labelID)
        if (!labelElem && typeof(labelElem.innerHTML) == 'string')
        {
            field_label = config.fieldID;
        }
        else
        {
            field_label = labelElem.innerHTML;
        }
        message = message.replace("{FIELD_LABEL}", field_label);
        
        return message;
    };
    
    GeniusScript.validator.validateForm = function(eventObj)
    {
        var validForm = true;
        var invalidMessages = [];
        
        var config = GeniusScript.Configuration.validation;
        var configLength = config.length;
        
        for (var iter = 0; iter < configLength; iter++)
        {
            var curConfig = config[iter];
            
            if ((typeof(curConfig.validator) == 'string') &&
                (typeof(curConfig.fieldID) == 'string') &&
                (typeof(curConfig.labelID) == 'string'))
            {
                var inputField = document.getElementById(curConfig.fieldID);
                if (inputField && (typeof(inputField.value) == 'string'))
                {
                    if (!GeniusScript.validator[curConfig.validator](inputField.value))
                    {
                        validForm = false;
                        invalidMessages.push(GeniusScript.validator.generateMessage(curConfig));
                        GeniusScript.$(inputField).addClass(GeniusScript.validator.INVALID_FIELD_CSS);
                        var labelForField = document.getElementById(curConfig.labelID);
                        if (labelForField)
                        {
                            GeniusScript.$(labelForField).addClass(GeniusScript.validator.INVALID_LABEL_CSS);
                        }
                    }
                    else
                    {
                        GeniusScript.$(inputField).removeClass(GeniusScript.validator.INVALID_FIELD_CSS);
                        var labelForField = document.getElementById(curConfig.labelID);
                        if (labelForField)
                        {
                            GeniusScript.$(labelForField).removeClass(GeniusScript.validator.INVALID_LABEL_CSS);
                        }
                    }
                }
            }
        }
        
        if (invalidMessages.length > 0)
        {
            var message = GeniusScript.messages.BEGIN_INVALID_FORM + '\n' + 
                            invalidMessages.join('\n') + '\n' +
                            GeniusScript.messages.END_INVALID_FORM;
            alert(message);
        }
        
        // return for prevention, or allowing of, form submission
        if (!validForm)
        {
            eventObj.stopPropagation();
        }
        return validForm;
    };
    
    GeniusScript.validator.initialize = function()
    {
        var formEl = GeniusScript.$('#genius_com_w2l_form');
        if (formEl)
        {
            formEl.bind('submit', GeniusScript.validator.validateForm);
        }
    };
}
