﻿/**
*   Requires: 
*   - global.js
*/

// TODO: Remove this polyfill!!
// If native trim doesn't exist
if (!String.prototype["trim"]) {
    String.prototype["trim"] = function () {
        return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
    };
}

// Cache document object for performance
if (!_document) { var _document = document; }

/**
* DecorateFields - Static Obj
* Contains functionality to create masks for checkboxes and drop-downs.
*/

// Base Decorate Vars
var DecorateFields = {
    selectsCnt: 0, checkboxesCnt: 0, radioCnt: 0,
    chkBxFrag: '<span class="field_chkbx" />',
    radioFrag: '<span class="field_radio" />',
    selectFrag: '<span class="selected_index">&nbsp;</span><ul class="select_options"></ul>',
    optionDocFrag: null,
    selectPre: "obj",
    liPre: "_li_"
};
// Decorate Checkboxes & Selects
DecorateFields.decorateFormFields = function (obj, onHidden) {
    var container = obj || _document;
    var hiddenFlag = (onHidden != null) ? onHidden : true;
    //console.time("timing form fields");
    this.decorateCheckboxes(container, hiddenFlag);
    this.decorateRadioBtns(container, hiddenFlag);
    //this.decorateSelects(container, hiddenFlag);
    //console.timeEnd("timing form fields");
};
// Decorate Checkboxes with HTML 
DecorateFields.decorateCheckboxes = function (obj, onHidden) {
    var container = obj || document;
    var hiddenFlag = (onHidden != null) ? onHidden : true;
    var inputCnt = 0;
    var spanFrag = this.chkBxFrag;
    var selectPre = "chkbx_";
    var inputs = container.getElementsByTagName("input");
    for (var i = inputs.length; i--; ) {
        var target = inputs[i];
        var $this = $(target);
        if ($this.attr("ismask") == null && target.type == "checkbox" && (hiddenFlag || (!hiddenFlag && $this.is(":visible")))) {
            var $clone = $this.clone();
            $clone.remove();
            var $parent = $(spanFrag);
            $parent.attr("id", selectPre + $this.attr('id'));
            $parent.addClass($this.prop("class"));
            $clone.attr("ismask", "true");
            $parent.append($clone);
            $this.replaceWith($parent);
            inputCnt++;
            this.checkboxesCnt++;
        }
    }
};
// Decorate Radio with HTML 
DecorateFields.decorateRadioBtns = function (obj, onHidden) {
    var container = obj || document;
    var hiddenFlag = (onHidden != null) ? onHidden : true;
    var inputCnt = 0;
    var spanFrag = this.radioFrag;
    var selectPre = "radio_";
    var inputs = container.getElementsByTagName("input");
    for (var i = inputs.length; i--; ) {
        var target = inputs[i];
        var $this = $(target);
        if ($this.attr("ismask") == null && target.type == "radio" && (hiddenFlag || (!hiddenFlag && $this.is(":visible")))) {
            var $clone = $this.clone();
            $clone.remove();
            var $parent = $(spanFrag);
            $parent.attr("id", selectPre + $this.attr('id'));
            $parent.addClass($this.prop("class"));
            $clone.attr("ismask", "true");
            $parent.append($clone);
            $this.replaceWith($parent);
            inputCnt++;
            this.radioCnt++;
        }
    }
};
// Iterate over options, creating <li>s in preparation to populate <ul>
DecorateFields.copyOptionsToListFragment = function (optList, prefix, listTag) {
    var optionFragment = _document.createDocumentFragment();
    var optLen = optList.length;
    //console.log('option count: '+optLen);
    var lenDsp = 0;
    while (optLen--) {
        var option = optList[optLen]; // Done for performance
        if (option.value && option.value != "") {
            var text = option.innerHTML;
            //var listEle = listTag.cloneNode(true);
            var listEle = _document.createElement('li');
            listEle.id = prefix + lenDsp;
            listEle.className = lenDsp;
            listEle.innerHTML = (text != "" ? text : "&nbsp;");
            optionFragment.appendChild(listEle);
        }
        lenDsp++;
    }
    return optionFragment;
};
// Decorate Selects with HTML
DecorateFields.decorateSelects = function (obj, onHidden) {
    var container = obj || _document;
    var selects = container.getElementsByTagName("select");
    var selectsCnt = selects.length;
    if (selectsCnt > 0) {
        var hiddenFlag = (onHidden != null) ? onHidden : true;
        var selectCnt = 0;
        // Create Select Mask template for cloning
        var selectTemplate = _document.createElement("span");
        selectTemplate.className = "field_select";
        selectTemplate.innerHTML = this.selectFrag;
        var listTag = _document.createElement("li");
        var selectPre = this.selectPre, liPre = this.liPre;
        for (var i = selectsCnt; i--; ) {
            var target = ($.browser.msie) ? selects[i] : selects.item(i); // Done for performance
            var $target = $(target);
            if ($target.attr("ismask") == null && !$target.attr("multiple") && (hiddenFlag || (!hiddenFlag && $target.is(":visible")))) {
                //console.log(target.name);
                var $this = $target.clone();
                //$this.children('[value="' + $target.val() + '"]').first().prop('selected', true);
                $this.prop('selectedIndex', $target.prop('selectedIndex'));
                var wrapper = $(selectTemplate).clone();

                // Prep IDs
                var ulId = $this.attr('id') + "_" + selectPre;
                var selectIndx = $this.children(":selected").first().text();
                //console.info($this.children(":selected").first());
                if (selectIndx == "") { selectIndx = "&nbsp;"; }
                wrapper.children('.selected_index:first').attr("id", ulId + "_value").html(selectIndx);
                wrapper.attr("id", ulId).addClass($this.prop("class"));

                // Populate <ul>
                /*
                var optList = $this.children("option").toArray().reverse();
                var optionFragment = this.copyOptionsToListFragment(optList, String(ulId + liPre), listTag);
                wrapper.children('ul').first().append(optionFragment);
                */
                wrapper.append($this);

                selectCnt++;
                this.selectsCnt++;
                $this.attr("ismask", "true");
                //$target.replaceWith(wrapper);
                $target.before(wrapper);
                $target.remove();
            }
        }
    }
};
// Replicate select options into UL
DecorateFields.populateSelectMask = function (maskEle) {
    //console.log('populateSelectMask() called');
    var $mask = $(maskEle),
        $target = $mask.children('ul').first(),
        $src = $mask.children('select').first();

    var selectIndx = $src.children(":selected").first().text();
    if (selectIndx == "") { selectIndx = "&nbsp;"; }
    var $indexTxt = $mask.children('.selected_index:first');

    //console.log("re-populate");
    $target.html("");
    var liPrefix = $mask.attr("id") + this.liPre;

    // Populate <ul>
    var optList = jQuery.makeArray($src.children("option")).reverse();
    var optionFragment = this.copyOptionsToListFragment(optList, liPrefix);
    $target.append(optionFragment);

    $indexTxt.html(selectIndx);
    $mask.attr('populated', 1);
};
// Backwards Compatibility
function decorateFormFields(obj, onHidden) {
    DecorateFields.decorateFormFields(obj, onHidden);
};


/**
* Functions and event bindings for checkbox and drop-down masks.
*/

// Click Events on Form Elements
function toggleCheckBox(obj) {
    var $this = $(obj),
		$input = $this.find("input");
    if ($this.hasClass("active")) {
        $this.removeClass("active");
        $input.prop("checked", false);
    } else {
        $this.addClass("active");
        $input.prop("checked", true);
    }
    $input.trigger('change');
};
function closeSelects(obj) {
    var $fieldSelects = $(".field_select");
    if (obj) {
        $fieldSelects.not(obj).removeClass('active');
    } else {
        $fieldSelects.removeClass('active');
    }
}
function toggleSelect(obj) {
    var $this = $(obj);
    if ($this.hasClass("active")) {
        $this.removeClass("active");
    } else {
        $this.addClass("active");
    }
};
function updateSelect(obj) {
    var $this = $(obj),
        $parent = $(obj).closest(".field_select"),
        $select = $parent.children("select").first();
    $select.prop('selectedIndex', $this.prop('class')).trigger('change');
    var text = $select.find("option:selected").text();
    if (text == "") { text = "&nbsp;"; }
    $parent.find(".selected_index").html(text);
};
function fieldCheckBoxEvent() {
    if ($(this).hasClass("disabled") == false) {
        closeSelects(); toggleCheckBox(this);
    }
};
function fieldRadioBtnEvent() {
    if ($(this).hasClass("disabled") == false) {
        closeSelects(); toggleRadioBtn(this);
    }
};

function toggleRadioBtn(obj) {
    var $this = $(obj),
		$input = $this.find("input"),
		$current = $this.parents('.radio_btns').find('.active');
		$current.removeClass('active');
		$current.removeAttr('checked');
		
		$this.addClass("active");
		$input.attr("checked", "checked");
		
		//alert( $('.radio_btns input:checked').val() );
};
function fieldSelectEvent() {
    //console.log('fieldSelectEvent() called');
    //if ($(this).prop('populated') != 1) {
    DecorateFields.populateSelectMask(this);
    //}
    if ($(this).hasClass("disabled") == false) {
        closeSelects(this); toggleSelect(this);
    }
};
function updateSelectEvent() {
    updateSelect(this);
};
// Basic bind Events for Selects and Checkboxes
$(":input").live('focus', function () { closeSelects(); });
$(".field_chkbx").live('click', fieldCheckBoxEvent);
$(".field_radio").live('click', fieldRadioBtnEvent);
$(".field_select").live('click', fieldSelectEvent);
//$(".field_select").live('mouseleave', function () { setTimeout('closeSelects()', 200); });
$(".select_options li").live('click', updateSelectEvent);


// Country / State bindings
function updateStateFromMask(obj) {
    //console.log("updateStateFromMask() called");
    var $select = $(obj).closest(".field_select").children("select").first();
    //console.log($select.val());
    updateStateWith($select);
    //console.log($select.attr("stateDDL"));
    var $target = $($select.attr("stateDDL"));
    DecorateFields.populateSelectMask($target.closest(".field_select"));

    var $stateTxt = $($select.attr('stateTXT'));
    if ($stateTxt.val() == selectedState) {
        $stateTxt.val('');
    }
};
function updateStateFromMaskEvent() {
    updateStateFromMask(this);
};
$(".field_select.country .select_options li").live('click', updateStateFromMaskEvent);


// jQuery Interface to Drop-Down Masks
(function ($) {
    var methods = {
        init: function (options) {
            var req = options || {};
        },
        lock: function (bool) {
            var lockMask = Boolean(bool);
            return this.each(function () {
                var $this = $(this);
                if ($this.hasClass('.field_select') == false) {
                    $this = $this.closest(".field_select");
                }
                if (lockMask) {
                    $this.addClass("disabled");
                } else {
                    $this.removeClass("disabled");
                }
            });
        },
        disable: function (bool) {
            var disableMask = Boolean(bool);
            return this.each(function () {
                var $this = $(this);
                var $select;
                if ($this.hasClass('.field_select') == false) {
                    $select = $this;
                    $this = $this.closest('.field_select');
                } else {
                    $select = $this.children('select').first();
                }
                if (disableMask) {
                    $select.prop('disabled', true);
                    $this.selectMask('lock', true);
                } else {
                    $select.prop('disabled', false);
                    $this.selectMask('lock', false);
                }
            });
        },
        setIndex: function (strVal) { //sets selectedIndex
            return this.each(function () {
                var $this = $(this);
                var $select;
                if ($this.hasClass('.field_select') == false) {
                    $select = $this;
                    $this = $this.closest('.field_select');
                } else {
                    $select = $this.children('select').first();
                }
            });
        },
        getIndex: function () { //gets selectedIndex
            return this.each(function () {
                var $this = $(this);
                var $select;
                if ($this.hasClass('.field_select') == false) {
                    $select = $this;
                    $this = $this.closest('.field_select');
                } else {
                    $select = $this.children('select').first();
                }
            });
        },
        setValue: function (strVal) { //sets selectedIndex from value
            return this.each(function () {
                var $this = $(this);
                var $select;
                if ($this.hasClass('.field_select') == false) {
                    $select = $this;
                    $this = $this.closest('.field_select');
                } else {
                    $select = $this.children('select').first();
                }
            });
        },
        getValue: function () { //gets value
            return this.each(function () {
                var $this = $(this);
                var $select;
                if ($this.hasClass('.field_select') == false) {
                    $select = $this;
                    $this = $this.closest('.field_select');
                } else {
                    $select = $this.children('select').first();
                }
                var selector = "option[value='" + val + "']";
                //console.log("selector: "+selector+"  - pos: "+$select.children(selector).index());
                $select.prop('selectedIndex', $select.children(selector).index());
                var text = $select.find("option:selected").first().text();
                if ($.trim(text) == "") { text = "&nbsp;"; }
                $this.find(".selected_index").html(text);
            });
        },
        setText: function (strVal) { //sets selectedIndex from text
            return this.each(function () {
                var $this = $(this);
                var $select;
                if ($this.hasClass('.field_select') == false) {
                    $select = $this;
                    $this = $this.closest('.field_select');
                } else {
                    $select = $this.children('select').first();
                }
            });
        },
        getText: function () { //gets text
            return this.each(function () {
                var $this = $(this);
                var $select;
                if ($this.hasClass('.field_select') == false) {
                    $select = $this;
                    $this = $this.closest('.field_select');
                } else {
                    $select = $this.children('select').first();
                }
            });
        }
    };
    $.fn.selectMask = function (method) {
        // Method calling logic
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.selectMask');
        }
    };
    $.fn.lockSelect = function () {
        $(this).selectMask('lock', true);
    };
    $.fn.unLockSelect = function () {
        $(this).selectMask('lock', false);
    };
    $.fn.disableSelect = function () {
        $(this).selectMask('disable', true);
    };
    $.fn.enableSelect = function () {
        $(this).selectMask('disable', false);
    };
    $.fn.setSelectByValue = function (strVal) {
        var val = strVal;
        return this.each(function () {
            var $this = $(this);
            var $select;
            //console.log("value: "+val);
            if ($this.hasClass('.field_select') == false) {
                $select = $this;
                $this = $this.closest('.field_select');
            } else {
                $select = $this.children('select').first();
            }
            var selector = "option[value='" + val + "']";
            //console.log("selector: "+selector+"  - pos: "+$select.children(selector).index());
            $select.prop('selectedIndex', $select.children(selector).index());
            var text = $select.find("option:selected").first().text();
            if ($.trim(text) == "") { text = "&nbsp;"; }
            $this.find(".selected_index").html(text);
        });
    };
    $.fn.setSelectByIndex = function (strVal) {
        var val = parseInt(strVal);
        return this.each(function () {
            var $this = $(this);
            var $select;
            //console.log("selected index: "+val);
            if ($this.hasClass('.field_select') == false) {
                $select = $this;
                $this = $this.closest('.field_select');
            } else {
                $select = $this.children('select').first();
            }
            $select.prop('selectedIndex', val);
            var text = $select.find("option:selected").first().text();
            if ($.trim(text) == "") { text = "&nbsp;"; }
            $this.find(".selected_index").html(text);
        });
    };
    $.fn.setSelectCountry = function (strVal) {
        var val = strVal;
        return this.each(function () {
            var $this = $(this);
            var $select;
            //console.log("country: "+val);
            if ($this.hasClass('.field_select') == false) {
                $select = $this;
                $this = $this.closest('.field_select');
            } else {
                $select = $this.children('select').first();
            }
            $this.setSelectByValue(val);
            updateStateFromMask($select);
        });
    };
})(jQuery);

function disableSelectMask(obj) {
    $(obj).lockSelect();
};

function enableSelectMask(obj) {
    $(obj).unLockSelect();
};

function BubbleHelper(target) {
    var bubble = target;
    var $bubble = $(bubble);
    var lastObjMarked;

    console.log(bubble);
    console.log($bubble);

    function hideEvent() {
        hide();
    }

    function display(obj, msg) {
        if ($bubble.length == 0) {
            $bubble = $(bubble);
        }
        if (obj && msg) {
            if (lastObjMarked) {
                $(lastObjMarked).unbind('focus', hideEvent);
                lastObjMarked = null;
            }
            //console.log(obj);
            var $obj = $(obj),
                $ele = $obj;
            if (obj.nodeName == "SELECT" && $obj.attr("ismask") == "true") {
                //console.log('element is a select');
                $ele = $obj.closest('.field_select');
            } else if (obj.nodeName == "INPUT" && obj.type == "checkbox") {
                //console.log('element is a checkbox');
                $ele = $obj.closest('.field_chkbx');
            }
            var offset = $ele.offset(),
                parentOffset = $('#content').offset();
            $bubble.children('p').first().text(msg);
            $bubble.show();
            //console.log($ele);

            //console.log("Parent offset  -- top: " + parentOffset.top + ", left: " + parentOffset.left);
            //console.log("Element offset -- top: " + offset.top + ", left: " + offset.left);

            var adjustedOffsetTop = parseInt(offset.top - parentOffset.top),
                adjustedOffsetLeft = parseInt(offset.left - parentOffset.left);

            var leftPos = adjustedOffsetLeft,
                topPos = parseInt(adjustedOffsetTop - ($bubble[0].clientHeight + 30));
            if (obj.type && obj.type == "checkbox") {
                topPos = parseInt(adjustedOffsetTop - ($bubble[0].clientHeight + 13));
            }
            //console.log("Bubble offset  -- top: " + topPos + ", left: " + leftPos);
            //$bubble.offset({ top: topPos, left: leftPos });
            $bubble.css("top", topPos);
            $bubble.css("left", leftPos);
            window.scrollTo(0, topPos - 10);

            // Set bindings & state
            lastObjMarked = obj;
            $obj.bind('focus', hideEvent);
        }
    }
    this.display = display;

    function hide() {
        if ($bubble.length == 0) {
            $bubble = $(bubble);
        }
        $bubble.children('p').first().text('');
        $bubble.hide();
        if (lastObjMarked) {
            $(lastObjMarked).unbind('focus', hideEvent);
            lastObjMarked = null;
        }
    }
    this.hide = hide;
};

/**
* Validator Class
* For creating a group of form Validations to perform.
* Creates a new instance of Validator. 
*/
function Validator(bublId) {
    this.hasEvents = false; // TODO: What's this for?

    var validationQueue = {}; // This is a hash
    var bubbleId = bublId || "#error_msg_bubble"; // Create a get method (or obj?) for retreiving/using the bubble obj
    var errClass = this.errClass = "validationError";

    console.log(bubbleId);

    function addField(key, validationList) {
        validationQueue[key] = validationList; // Expecting array of objects
    };
    this.addField = addField;

    function getField(key) { // should be private
        if (validationQueue[key]) {
            return validationQueue[key];
        }
        return [];
    };
    this.getField = getField;

    var bubble = new BubbleHelper(bubbleId);

    function hideBubble() {
        bubble.hide();
    };
    this.hideBubble = hideBubble;
    function clearBubble(jqObj) {
        hideBubble();
        //console.log("clear bubble");
        var objs = $(jqObj) || $("[validatekey]");
        objs.removeClass(errClass);
    };
    this.clearBubble = clearBubble;
    function displayBubble(obj, msg) {
        bubble.display(obj, msg);
    };
    this.displayBubble = displayBubble;

    $(window).load(clearBubble);
};
Validator.prototype = {
    displayBubbleFromRef: function (obj, msgRef) { // Get the error message from an element attribute
        if (obj && msgRef) {
            //console.log("display bubble from ref");
            this.displayBubble(obj, $(obj).prop(msgRef));
        }
    },
    markError: function (objArr) {
        //console.log('markError count: ' + objArr.length);
        for (var i = 0, j = objArr.length; i < j; i++) {
            var $obj = $(objArr[i]);
            if ($obj.prop('nodeName') != "SELECT") {
                $obj.addClass(this.errClass);
            } else {
                if ($obj.attr("ismask") == "true") {
                    $obj.closest('.field_select').addClass(this.errClass);
                } else {
                    $obj.addClass(this.errClass);
                }
            }
            //console.log('marking obj: ' + $obj.prop('name') + ' - ' + $obj.prop('nodeName'));
        }
    },
    clearError: function (objArr) {
        //console.log('clearError count: ' + objArr.length);
        for (var i = 0, j = objArr.length; i < j; i++) {
            var $obj = $(objArr[i]);
            if ($obj.prop('nodeName') != "SELECT") {
                $obj.removeClass(this.errClass);
            } else {
                $obj.closest('.field_select').removeClass(this.errClass);
            }
            //console.log('clearing obj: ' + $obj.prop('name') + ' - ' + $obj.prop('nodeName'));
        }
    },
    cleanField: function (ele) {
        if ((ele.type && (ele.type == "text" || ele.type == "password")) || ele.nodeName == "TEXTAREA") {
            var valueStr = ele.value;
            valueStr = valueStr.trim();
            while (valueStr.indexOf("  ") > -1) {
                valueStr = valueStr.replace("  ", " ");
            }
            ele.value = valueStr;
        }
    },
    processField: function (ele, fromForm) { // Validate a field
        //console.log('processField called');
        this.cleanField(ele);
        var isSubmit = (fromForm != null) ? fromForm : false;
        var result = true,
            $ele = $(ele),
            key = $ele.attr('validatekey');
        if (key) {
            var validations = this.getField(key);
            for (var i = 0, j = validations.length; i < j; i++) {
                var validation = validations[i];
                if (result &&
                    (!validation.condition || (validation.condition && validation.condition() == true)) &&
                    (!validation.submitonly || (validation.submitonly && validation.submitonly == "true" && isSubmit))) {
                    if (!validation.params) {
                        //console.log("no params");
                        result = validation.fn(ele);
                    } else if ($.isArray(validation.params)) {
                        //console.log("array of params");
                        var args = [];
                        args.push(ele);
                        args = args.concat(validation.params);
                        result = validation.fn.apply(window, args);
                    } else {
                        //console.log("one param");
                        result = validation.fn(ele, validation.params);
                    }
                    //console.log(ele.value + " - " + result);
                    var eles = [];
                    eles.push(ele);
                    if (validation.dependents) {
                        eles = eles.concat(validation.dependents);
                        //console.log("added dependents, count: " + eles.length);
                    }

                    if (!result) {
                        this.clearBubble($ele);

                        this.markError(eles);

                        if (validation.msg) {
                            this.displayBubble(ele, validation.msg);
                        } else if (validation.msgRef) {
                            this.displayBubbleFromRef(ele, validation.msgRef);
                        }
                        break;
                    } else {
                        this.clearError(eles);

                        this.clearBubble($ele);
                    }
                }
            }
        }
        return result;
    },
    processForm: function (obj) { // Validate all relavent fields
        var $frm = $(obj).closest("form"),
            frm = $frm[0],
            fields = frm.elements;
        $frm
            .find(':input').removeClass(this.errClass)
            .end()
            .find('.field_select').removeClass(this.errClass);
        //console.log("field count: " + fields.length);

        for (var i = 0, j = fields.length; i < j; i++) {
            var field = fields[i];
            var key = $(field).attr('validatekey');
            if (key) {
                //console.log("field = key: " + key + ", name: " + field.name);

                var result = true;
                result = this.processField(field, true);
                if (!result) {
                    //console.log(field.name + " failed!");
                    return false;
                }
            }
        }
        //console.log("result is true");
        return true;
    }
};

