/**
 * @namespace
 */
brand.forms = {
    init: function() {
        brand.forms.form.init();
        brand.forms.input.init();
    }
}

/**
 * @namespace
 */
brand.forms.form = {
    init: function() {
        // apply form submission behavior for specified forms
        $$("FORM.no-submit").each(function($_) { 
            $_.observe("submit", function(e) {
                Event.stop(e);
            }) 
        })
    } 
}

/**
 * @namespace
 */
brand.forms.input = {
    init: function() { 
        // apply inline label behavior for specified input fields
        $$("INPUT.inline-label-field").each(function($_) { 
            var fieldlabel = new brand.forms.inlineLabelField({ field: $_ });         
        });
    }
}


/**
 * This function tests a string against the expected pattern for an email address
 * @return {Boolean}
 * @param {String} Email address string to validate
 * @methodOf brand.forms
 */
brand.forms.isEmailAddress = function(s) {
    var filter  = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
    return (filter.test(s)); 
}

/* USED?
brand.forms.limitTextLength = function(args) {
    var field = args.field;
    var max_length = args.max_length;
    var display_element = args.display_element;
    
    if (field.value.length > max_length) {
        field.value = field.value.slice(0, max_length);
    }   
    if (!display_element) return;
    
    var remaining_chars = max_length - field.value.length; 
    if (remaining_chars < max_length) {
        // TODO: need RB/language solution here
        (remaining_chars != 1) ? plural = 's' : plural = '';
        display_element.innerHTML =  remaining_chars + ' character' + plural + ' left.';
    } else {
        display_element.innerHTML = '';
    }
}
*/


/**
 * brand.forms.inlineLabelField 
 * This class attaches behavior to a text or password input field where the label
 * is displayed inside the field and toggles on and off in response to focus/blur
 * @memberOf brand.forms
 */
brand.forms.inlineLabelField = Class.create({
    // summary:
    //      Handles toggling of label display for fields that show label
    //      in the field itself (via value attribute)

    // field: DOM node
    field: null,
    
    // fieldPswdDisplay: DOM node
    // field which displays password label
    // (workaround for IE's inability to toggle field's "type" attribute)
    fieldPswdDisplay: null,
    
    // label: String
    // field label
    label: "",
    
    // ftype: String
    // field type attribute (text, password)
    ftype: "text",
    
    // hasValue: Boolean
    // flag is true when user has entered a value in field
    hasValue: false,

    // _hasMaxlengthDisplay: Boolean
    // item's label char count exceeds field maxlength property
    _hasMaxlengthDisplay: false,
    
    // _maxlength: Object
    // if hasMaxlengthDisplay, _maxlength.data = maxlength property of input data, _maxlength.display = maxlength count for label
    _maxlength: null,

    /**
     * Creates an instance of brand.forms.inlineLabelField
     * @example
        var fieldlabel = new brand.forms.inlineLabelField({ field: fieldNode });

     * @param {Object} args.field  Input field node object   
     * @param {String} *Optional* args.label  Label string
     * @methodOf brand.forms
     */    
    initialize: function(/* Object */args) {
        this.field = args.field;
        
        // optional label arg
        if (args.label) {
            this.label = args.label;
        } else if (this.field.title && this.field.title.length > 0) {
            this.label = this.field.title;
        } else {
            this.label = "";
        }
        
        var displayField = this.field;
        this.ftype = this.field.getAttribute("type");
        
        if (this.ftype === "password") {
            this.fieldPswdDisplay = $(this.field.id+".label");
            if (!this.fieldPswdDisplay) { return };
            displayField = this.fieldPswdDisplay;
        }
        
        // check for maxlength restrictions
        var flength = this.field.maxLength;
        var labelLength = this.label.length;
        if ((flength > 0) && (flength < labelLength)) {
            this._maxlength = {};
            this._hasMaxlengthDisplay = true;
            this._maxlength.data = flength;
            this._maxlength.display = labelLength;
        }
        var self = this;
        this.handlers = [
            displayField.observe("focus", self._onFocus.bind(self)),
            this.field.observe("blur",self._onBlur.bind(self))
        ];
        
        this.setLabelState();
    },

    setLabelState: function() {
        this.checkHasValue();
        // only clear field if there is no user-set value in field
        if (!this.hasValue) {
            this.showLabel();
        }
    },

    checkHasValue: function() {
        var val = this.field.value;
        // field has user-set value
        if ((val.length > 0) && (val !== " ") && (val !== this.label)) {
            this.hasValue = true;
        } else {
            this.hasValue = false;
        }
    },
    
    beforeSubmit: function() {
        // if value is still populated by label rather than user input, clear it out before form submission
        if (!this.hasValue) {
            this.checkHasValue();
            if (!this.hasValue) {
                this.field.value = "";
            }
        }
    },
    
    _onFocus: function() {
        // display label if there is no user-set value in field
        if (!this.hasValue) {
            this.clearField();
        }
    },
    
    _onBlur: function() {
        this.setLabelState();
    },
    
    showLabel: function() {
        if (this.ftype === "password") {
            this.field.style.display = "none";
            this.fieldPswdDisplay.style.display = "block";
        } else {
            // set maxlength to accomodate label
            if (this._hasMaxlengthDisplay) {
                this.field.maxLength = this._maxlength.display;
            }
            // show label as value
            this.field.value = this.label;
        }
    },
    
    clearField: function() {
        if (this.ftype === "password") {
            this.field.style.display = "block";
            this.field.focus(); // set focus before currently focused field is hidden to avoid FF cursor disappearance
            this.fieldPswdDisplay.style.display = "none";
        } else {
            // clear field
            this.field.value = "";
            // set maxlength for expected data
            if (this._hasMaxlengthDisplay) {
                this.field.maxLength = this._maxlength.data;
            }
        }
    }
});

/**
 * brand.forms.contextualOptions 
 * This class attaches behavior to 2 select menus where the contents of the 2nd menu
 * are contextual based on the selected value of the 1st menu
 * @memberOf brand.forms
 */
brand.forms.contextualOptions = Class.create({ 
    srcSelect: null,
    targetSelect: null, 
    valueKey: null,
    labelKey: null, 
    targetSelectOptions: {}, 
    _selectsAreWidgets: false,

    /**
     * Creates an instance of brand.forms.contextualOptions
     * @example
        var contextualStoreSelect = new brand.forms.contextualOptions({
            srcSelectId: "select-menu-state",
            targetSelectId: "select-menu-stores",
            targetSelectOptions: {
               "AL" : [
                  {
                     "DOOR_NAME" : "The Summit",
                     "DOOR_ID" : "77790"
                  }
               ],
               "AK" : [
                  {
                     "DOOR_NAME" : "Lakeside",
                     "DOOR_ID" : "77771"
                  }
               ]
            }
            valueKey: "DOOR_ID",
            labelKey: "DOOR_NAME"
        });

     * @param {String} args.srcSelectId  ID of source select menu where initial selection will be made   
     * @param {String} args.targetSelectId  ID of target select menu whose options will be populated based on the selected value of args.srcSelectId 
     * @param {Object} args.targetSelectOptions  A JSON list of options for targetSelectId, keyed by the values listed the source select menu
     * @param {String} args.valueKey  Key ID for the option value in each item in the args.targetSelectOptions data
     * @param {String} args.labelKey  Key ID for the option label in each item in the args.targetSelectOptions data 
     * @memberOf brand.forms
     */     
    initialize: function(/* Object */args) {
        srcSelect = $(args.srcSelectId);
        targetSelect = $(args.targetSelectId);
        if (srcSelect && targetSelect) {
            srcSelect.observe("change", this.onChange.bind(this));
        } else {
            console.log("brand.form.contextualOptions: select element not found");
            return false;
        } 
        this.srcSelect = srcSelect;
        this.targetSelect = targetSelect;
        this.targetSelectOptions = args.targetSelectOptions; 
        if (args.valueKey) { this.valueKey = args.valueKey; }
        if (args.labelKey) { this.labelKey = args.labelKey; }
        if(this.srcSelect.selectedIndex) {
            this.onChange();
        }
    },
    
    onChange: function() {
        var srcval = this.srcSelect.value;
        var targetSelect = this.targetSelect;
        if (srcval === "" || srcval === null) { return false; } 
        this.removeOptions(targetSelect);
        this.addOptions(targetSelect);
    },
    
    getNewOptions: function() {
        // summary:
        // 
        // Defines default path to list of new options
        // Redefined to pass list from different array/object heirarchy
        var selected = this.srcSelect.value;
        return this.targetSelectOptions[selected];
    },

    addOptions: function(targetSelect) {
        var isWidget = this._selectsAreWidgets;
        var options = this.getNewOptions();
        
        // expect value, label pair stored in data, either as object (key id'ed) or in array (first 2 positions)        
        var labelKey = (this.labelKey ? this.labelKey : 0);
        var valueKey = (this.valueKey ? this.valueKey : 1);

        options.each(function(option, ix) {
            targetSelect.options[ix] = new Option(option[labelKey], option[valueKey]); 
        });

    },
    
    removeOptions: function(targetSelect) {
        var l = (targetSelect.options.length - 1);
        var i;
        for (i = l; i >= 0; i--) {
            if (targetSelect.options[i].value !== "") {
                targetSelect.options[i] = null;         
            }
        }    
    }
    
});

