/*
Array.prototype.binSearch = function(needle, case_insensitive) {
    if (!this.length) return -1;

    var high = this.length - 1;
    var low = 0;
    case_insensitive = (typeof (case_insensitive) !== 'undefined' && case_insensitive) ? true : false;
    needle = (case_insensitive) ? needle.toLowerCase() : needle;

    while (low <= high) {
        mid = parseInt((low + high) / 2)
        element = (case_insensitive) ? this[mid].toLowerCase() : this[mid];
        if (element > needle) {
            high = mid - 1;
        } else if (element < needle) {
            low = mid + 1;
        } else {
            return mid;
        }
    }

    return -1;
};
*/

YAHOO.namespace("UserForm");
YAHOO.UserForm.IsTextbox = function(el)
{
  var myType = el.getAttribute("type");
  
  return (myType == "text") || (myType == "password");
};

YAHOO.UserForm.AllowFocus = function(el)
{
  var myType = el.getAttribute("type");
  
  return (myType == "text") || (myType == "password") || (myType == "radio") || (myType == "checkbox");
};

YAHOO.UserForm.IsTrue = function(el)
{
  return true;
};

YAHOO.UserForm.IsVisible = function(el)
{
  var myDisplay = YAHOO.util.Dom.getStyle(el,"display");
  
  return myDisplay != "none"
};

// Set focus on first input control of form
YAHOO.UserForm.FocusOnFirst = function()
{
  //Old code failed with root="userForm"
  //new code failed with root=div#content
  //only need first element rather than iterating thru all
  var colInputs = YAHOO.util.Dom.getElementsBy(YAHOO.UserForm.AllowFocus, "input");
  
  if (colInputs.length > 0)
  {
    colInputs[0].focus();
    return;
  }
  
  var colTextAreas = YAHOO.util.Dom.getElementsBy(YAHOO.UserForm.IsVisible, "textarea");
  
  if (colTextAreas.length > 0)
  {
    colTextAreas[0].focus();
  }
};

// Modify text and textarea controls to select all existing text
YAHOO.UserForm.SelectText = function()
{
  var colInputs = YAHOO.util.Dom.getElementsBy(YAHOO.UserForm.IsTextbox, "input");
  
  for (var i = 0; i < colInputs.length; i++)
  {
    colInputs[i].onfocus = function() { YAHOO.util.Dom.addClass(this,"selected");this.select(); };
    colInputs[i].onblur = function() { YAHOO.util.Dom.removeClass(this,"selected"); };
  }
  
  var colTextAreas = YAHOO.util.Dom.getElementsBy(YAHOO.UserForm.IsVisible, "textarea");
  
  for (var ii = 0; i < colTextAreas.length; i++){
    colTextAreas[ii].onfocus = function() { YAHOO.util.Dom.addClass(this,"selected");this.select(); };
    colTextAreas[ii].onblur = function() { YAHOO.util.Dom.removeClass(this,"selected"); };
  }
};

// Submit only once--can't because it messes with ASP.NET submission javascript
// Confirm submission
YAHOO.UserForm.ConfirmSubmit = function()
{
  var colInputs = document.getElementsByTagName("input");
  
  for (var i = 0; i < colInputs.length; i++)
  {
    if (colInputs[i].type == "submit")
    {
      if (colInputs[i].onclick != null)
      {
        var ctl = colInputs[i];
        
        colInputs[i].onclick = function()
        {
          var result = true;
          
          if (typeof(Page_ClientValidate) == 'function')
          {
            result = Page_ClientValidate();
          }
          return result && confirm(" _confirmMessage + ");
        };
      }
    }
  }
};

YAHOO.UserForm.IsTimezone = function(el)
{
  var myType = el.getAttribute("type");
  
  return (myType == "hidden") && (el.id.indexOf("Metadata/TimezoneA") > -1);
};

YAHOO.UserForm.SetTimezones = function()
{
  var date = new Date();
  var tzo = date.getTimezoneOffset() * -1;
  
  var els = YAHOO.util.Dom.getElementsBy(YAHOO.UserForm.IsTimezone, "input");

  for (var i = 0; i < els.length; i++)
  {
    els[i].value = tzo;
  }

  var el = YAHOO.util.Dom.get("x-VisitorTimeZoneOffset");
  
  if (el)
  {
    el.value = tzo;
  }
}

YAHOO.UserForm.AddHelpModules = function() {
    var idPrefix;

    this.HasID = function(el) {
        var myId = el.id;

        return (myId == null) ? false : myId.toLowerCase().indexOf(idPrefix) == 0;
    }

    this.IsAnchor = function(el, prefix) {
        idPrefix = prefix;
        var els = YAHOO.util.Dom.getElementsBy(this.HasID, "a", el);

        return els.length > 0 ? els[0] : null;
    }

    this.AddHelp = function(el) {
        idPrefix = "help";
        var els = YAHOO.util.Dom.getElementsBy(this.HasID, "div", el);

        for (var i = 0; i < els.length; i++) {
            var module = new YAHOO.widget.Module(els[i], { visible: false });

            if (module != null) {
                module.render();

                var showA = IsAnchor(el, "show");
                var hideA = IsAnchor(el, "hide");

                if (showA != null && hideA != null) {
                    var show = new YAHOO.widget.Module(showA);
                    var hide = new YAHOO.widget.Module(hideA);

                    if (show != null && hide != null) {
                        YAHOO.util.Event.addListener(showA, "click", module.show, module, true);
                        YAHOO.util.Event.addListener(showA, "click", hide.show, hide, true);
                        YAHOO.util.Event.addListener(showA, "click", show.hide, show, true);

                        YAHOO.util.Event.addListener(hideA, "click", module.hide, module, true);
                        YAHOO.util.Event.addListener(hideA, "click", show.show, show, true);
                        YAHOO.util.Event.addListener(hideA, "click", hide.hide, hide, true);
                    }
                }
            }
        }
    }

    // Find all containers that might contain help
    var els = YAHOO.util.Dom.getElementsByClassName("container", "div");

    for (var i = 0; i < els.length; i++) {
        AddHelp(els[i]);
    }
}

YAHOO.util.Event.addListener(window, 'load', YAHOO.UserForm.AddHelpModules);

YAHOO.UserForm.getCellIndex = function(aCell) {
    if (!aCell) return -1;

    var aTD = aCell.parentNode;
    if (!aTD) return -1;

    var aRow = aTD.parentNode;
    if (!aRow) return -1;

    for (var i = 0; i != aRow.cells.length; i++) {
        if (aRow.cells[i] == aTD) return i;
    }
    return -1;
}

YAHOO.UserForm.DateTimeRequiredValidator = function(ctl, args) {
    this.IsInput = function(el) {
        switch (el.nodeName.toLowerCase()) {
            case 'select':
                return true;
        }
        return false;
    }

    this.StyleControl = function(ctl, isValid) {
        var styleID = ctl.getAttribute("controltostyle");

        if (typeof (styleID) != "undefined" && styleID != "") {
            var styleCtl = document.getElementById(styleID);

            if (typeof (styleCtl) != "undefined" && styleCtl) {
                var cssClass = ctl.getAttribute("class") || ctl.className;

                if (typeof (cssClass) != "undefined" && cssClass != "") {
                    if (isValid) {
                        YAHOO.util.Dom.removeClass(styleCtl, cssClass);
                    } else {
                        YAHOO.util.Dom.addClass(styleCtl, cssClass);
                    }
                }
            }
        }
    }

    try {
        if (ctl && ctl.controltovalidate) {
            var dt = document.getElementById(ctl.controltovalidate);

            if (dt) {
                var inputs = YAHOO.util.Dom.getElementsBy(this.IsInput, null, dt);

                for (var i = 0; i < inputs.length; i++) {
                    var inp = inputs[i];
                    var typ = inp.type != "undefined" && inp.type.toLowerCase();
                    var ans;

                    switch (typ) {
                        case "select-one":
                            // N.B. IE6 does not use value if not explicitly coded
                            ans = inp.selectedIndex == 0 ? inp.options[inp.selectedIndex].value : inp.options[inp.selectedIndex].text;
                            if (typeof (ans) == "undefined" || ans == "") {
                                args.IsValid = false;
                            }
                            break;
                    }
                    if (!args.IsValid) {
                        break;
                    }
                }
                this.StyleControl(ctl, args.IsValid);
            }
        }
    } catch (e) {
        args.IsValid = false;
    }

}

YAHOO.UserForm.MatrixSingleValueColumnValidator = function(ctl, args) {
    this.IsInput = function(el) {
        switch (el.nodeName.toLowerCase()) {
            case 'input':
            case 'select':
                return true;
        }
        return false;
    }

    this.FindValidator = function(searchID) {
        for (var v = 0; v < Page_Validators.length; v++) {
            var targetID = Page_Validators[v].getAttribute("controltostyle");

            if ((typeof (targetID) != "undefined") && (searchID == targetID)) {
                return Page_Validators[v];
            }
        }
        return null;
    }

    // If js running, then only 0 or 1 response per column
    // Therefore, if all cols have 1 response, disable row validators with no responses
    try {
        if (ctl && ctl.controltovalidate) {
            var matrix = document.getElementById(ctl.controltovalidate);

            if (matrix) {
                var tbody = matrix && matrix.getElementsByTagName("tbody");
                var trs = tbody && tbody.length > 0 && tbody[0].getElementsByTagName("tr");
                var colCounts = [];

                for (var row = 0; row < trs.length; row++) {
                    var cols = YAHOO.util.Dom.getElementsBy(this.IsInput, null, trs[row]);

                    while (colCounts.length < cols.length) {
                        colCounts.push(0);
                    }
                    for (var col = 0; col < cols.length; col++) {
                        var inp = cols[col];
                        var typ = inp.type != "undefined" && inp.type.toLowerCase();
                        switch (typ) {
                            case "radio":
                            case "checkbox":
                                if (inp.checked) {
                                    colCounts[col]++;
                                }
                                break;
                        }
                    }
                }

                var allColResponses = colCounts.length > 0;

                for (var i = 0; i < colCounts.length; i++) {
                    if (colCounts[i] == 0) {
                        allColResponses = false;
                        break;
                    }
                }
                for (var r = 0; r < trs.length; r++) {
                    var validator = this.FindValidator(trs[r].id);

                    if (validator) {
                        if (allColResponses) {
                            validator.isvalid = true;
                        }
                        ValidatorUpdateDisplay(validator);
                        validator.enabled = !allColResponses;
                        SstStyleValidationControl(validator, validator.isvalid)
                    }
                }
            }
        }
    } catch (e) {
        args.IsValid = false;
    }
}

YAHOO.UserForm.Matrix = function() {

    this.onWatchChanged = function(el, col, table) {
        this.isCol = function(el) {
            return el && YAHOO.UserForm.getCellIndex(el) == col;
        }

        var els = YAHOO.util.Dom.getElementsBy(this.isCol, "input", table);

        for (var i = 0; i < els.length; i++) {
            if (els[i].id != el.id) {
                els[i].checked = false;
            }
        }
    }

    var tables = YAHOO.util.Dom.getElementsByClassName("oneValueCol", "table");

    for (var i = 0; i < tables.length; i++) {
        var inps = tables[i].getElementsByTagName("input");

        for (var j = 0; j < inps.length; j++) {
            var type = inps[j].type.toLowerCase();

            if (type == "radio" || type == "checkbox") {
                YAHOO.util.Event.addListener(inps[j], "click", (function(el, col, table) {
                    return function() {
                        this.onWatchChanged(el, col, table);
                    };
                })(inps[j], YAHOO.UserForm.getCellIndex(inps[j]), tables[i]), this, true);
            }
        }
    }
}

YAHOO.UserForm.Init = function() {
    YAHOO.UserForm.Matrix();
    YAHOO.UserForm.SetTimezones();
    YAHOO.UserForm.SelectText();
    YAHOO.UserForm.FocusOnFirst();
};

YAHOO.util.Event.onDOMReady(YAHOO.UserForm.Init);

UserFormOnInitButtons = function(ids) {
    var nIds = ids.length;

    for (var i = 0; i < nIds; i++) {
        var oButton = new YAHOO.widget.Button(ids[i]);
    }
}

UserFormConditionalLogic = function(watches, predicates, rules) {
    this.hideClass = "hideC";
    this.watches = watches;
    this.predicates = predicates;
    this.predicateValues = [];
    this.rules = rules;
    this.lastError;
    this.lookupTable = {};

    function typeOf(value) {
        // Determine if object is an array
        var s = typeof value;

        if (s === 'object') {
            if (value) {
                if (typeof value.length === 'number' &&
                    !(value.propertyIsEnumerable('length')) &&
                    typeof value.splice === 'function') {
                    s = 'array';
                }
            } else {
                s = 'null';
            }
        }
        return s;
    }

    this.IsInput = function(el) {
        switch (el.nodeName.toLowerCase()) {
            case 'input':
            case 'select':
                return true;
        }

        return false;
    }

    this.UpdateValidators = function(el, enableValidator) {
        //console.log("UpdateValidators[" + el.id + "]=" + enableValidator);
        if (typeof (Page_Validators) != "undefined") {
            var stack = [];
            var YUDhasClass = YAHOO.util.Dom.hasClass;
            var hasHiddenAncestor = YAHOO.util.Dom.getAncestorByClassName(el, this.hideClass) != null;

            stack.push(el);
            while (stack.length > 0) {
                var current = stack.pop();

                if (current != null) {
                    var skipChildren = false;

                    // 1. Visit current node
                    if (typeof (current.id) != "undefined" && current.id.length > 0) {
                        skipChildren = enableValidator &&
                        (YUDhasClass(current, this.hideClass) || hasHiddenAncestor);
                        if (!skipChildren) {
                            this.UpdateValidatorState(current.id, enableValidator);
                        }
                    }

                    // 2. Traverse children
                    if (!skipChildren) {
                        var children = YAHOO.util.Dom.getChildren(current);
                        var nChildren = children.length - 1;

                        for (var c = nChildren; c >= 0; c--) {
                            // Push backwards so we pop left-to-right
                            stack.push(children[c]);
                        }
                    }
                }
            }
        }
    }

    this.UpdateValidatorState = function(childID, enableValidator) {
        var v = this.lookupTable[childID];

        if (v) {
            //YAHOO.log("Validator[" + childID + "]=" + enableValidator);
            //console.log("  Validator[" + childID + "]=" + enableValidator);
            var nV = v.length;

            for (var i = 0; i < nV; i++) {
                //YAHOO.log("  Page[" + Page_Validators[v[i]].id + "]");
                //console.log("    Page[" + Page_Validators[v[i]].id + "]");
                Page_Validators[v[i]].enabled = enableValidator;
            }
        }
    }

    this.hideFields = function(el) {
        YAHOO.util.Dom.addClass(el, this.hideClass);
        this.UpdateValidators(el, false);
    }

    this.showFields = function(el) {
        YAHOO.util.Dom.removeClass(el, this.hideClass); // 2010-07-22 this was after UpdateValidators for ?
        this.UpdateValidators(el, true);
    }

    this.runCode = function(code) {
        var stack = [];

        try {
            var nCode = code.length;

            for (var c = 0; c < nCode; c++) {
                switch (code[c].op) {
                    case "push":
                        stack.push(this.predicateValues[code[c].arg]);
                        break;

                    case "and":
                        stack.push(stack.pop() && stack.pop());
                        break;

                    case "or":
                        stack.push(stack.pop() || stack.pop());
                        break;

                    case "show":
                        if (stack.pop()) {
                            return 'show';
                        }
                        return 'hide';

                    case "hide":
                        if (stack.pop()) {
                            return 'hide';
                        }
                        return 'show';

                    case "pop":
                        stack.pop();
                        break;

                    default:
                        this.lastError = "Unknown op=" + code[c].op;
                }
            }
        }
        catch (e) {
            this.lastError = e;
            //debugger;
        }
        if (stack.length > 0) {
            return stack.pop();
        }
    }

    this.evalRule = function(rule) {
        var el = document.getElementById(rule.id);

        if (el) {
            var result = this.runCode(rule.code);

            if (result == 'show') {
                this.showFields(el);
            } else if (result == 'hide') {
                this.hideFields(el);
            }
        }
    }

    this.ifRuleChanged = function(changedPredicates, code) {
        var nCode = code.length;

        for (var c = 0; c < nCode; c++) {
            if (typeof (code[c].arg) != 'undefined') {
                var nPredicates = changedPredicates.length;

                for (var p = 0; p < nPredicates; p++) {
                    if (code[c].arg == changedPredicates[p]) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    this.evalRules = function(changedPredicates) {
        if (changedPredicates.length > 0) {
            var nRules = this.rules.length;

            for (var r = 0; r < nRules; r++) {
                if (this.ifRuleChanged(changedPredicates, this.rules[r].code)) {
                    this.evalRule(this.rules[r]);
                }
            }
        }
    }

    this.evalNumericPredicate = function(watchValue, op, ans) {
        if (typeof (watchValue) == 'undefined' || typeof (ans) == 'undefined') {
            return false;
        }

        var rhs;
        var lhs;

        if (typeOf(watchValue) == 'array') {
            if (watchValue.length == 0 || watchValue.length > 1) {
                return false;
            }
            lhs = watchValue[0];
        } else {
            lhs = watchValue;
        }
        rhs = ans;

        if (lhs == null || rhs == null || lhs == "" || rhs == "") {
            return false;
        }
        try {
            lhs = Number(lhs);
            rhs = Number(rhs);
            switch (op) {
                case "gt":
                    return lhs > rhs;
                case "ge":
                    return lhs >= rhs;
                case "le":
                    return lhs <= rhs;
                case "lt":
                    return lhs < rhs;
            }
        } catch (e) {
            return false;
        }
        return false;
    }

    this.evalPredicate = function(watchValue, predicateIndex) {
        switch (this.predicates[predicateIndex].op) {
            case "==":
                if (typeOf(watchValue) == 'array') {
                    return this.evalPredicateMultiselect(watchValue, predicateIndex, true);
                } else {
                    return typeof (watchValue) != 'undefined' && watchValue == this.predicates[predicateIndex].ans;
                }

            case "!=":
                if (typeOf(watchValue) == 'array') {
                    return this.evalPredicateMultiselect(watchValue, predicateIndex, false);
                } else {
                    return typeof (watchValue) == 'undefined' || watchValue != this.predicates[predicateIndex].ans;
                }
            case "gt":
            case "ge":
            case "le":
            case "lt":
                return this.evalNumericPredicate(watchValue, this.predicates[predicateIndex].op, this.predicates[predicateIndex].ans);
        }
    }

    this.evalPredicateMultiselect = function(watchValue, predicateIndex, ifFound) {
        var limit = watchValue.length;

        for (var i = 0; i < limit; i++) {
            if (watchValue[i] == this.predicates[predicateIndex].ans) {
                return ifFound;
            }
        }
        return !ifFound;
    }

    this.ifPredicateChanged = function(watchValue, predicateIndex) {
        var newVal = this.evalPredicate(watchValue, predicateIndex);
        var oldVal = this.predicateValues[predicateIndex];
        var changed = (typeof (oldVal) == 'undefined') || oldVal != newVal;

        if (changed) {
            this.predicateValues[predicateIndex] = newVal;
        }
        return changed;
    }

    this.evalPredicateValues = function(watchValue, watchIndex) {
        var changedPredicates = [];
        var nPredicates = this.predicates.length;

        for (var i = 0; i < nPredicates; i++) {
            if (this.predicates[i].id == watchIndex) {
                if (this.ifPredicateChanged(watchValue, i)) {
                    changedPredicates.push(i);
                }
            }
        }
        if (changedPredicates.length > 0) {
            this.evalRules(changedPredicates);
        }
    }

    this.onWatchChanged = function(id, watchIndex) {
        var el = document.getElementById(id);

        if (el) {
            var els = YAHOO.util.Dom.getElementsBy(this.IsInput, null, el);
            var watchValue = [];
            var nEls = els.length;

            for (var j = 0; j < nEls; j++) {
                var inp = els[j];
                var typ = inp.type.toLowerCase();

                switch (typ) {
                    case "radio":
                    case "checkbox":
                        // Use array for radio and checkbox lists
                        if (inp.checked) {
                            watchValue.push(inp.value);
                        } /* else {
                            watchValue.push(undefined);
                        }*/
                        break;

                    case "text":
                        watchValue.push(inp.value);
                        break;

                    case "select-one":
                        watchValue.push(inp.options[inp.selectedIndex].value);
                        break;

                    case "select-multiple":
                        for (var k = 0; k < inp.options.length; k++) {
                            var sel = inp.options[k];

                            if (sel.selected) {
                                watchValue.push(sel.value);
                            }
                        }
                        break;

                    //                    case "button":                                                                               
                    //                    case "file":                                                                               
                    //                    case "hidden":                                                                               
                    //                    case "image":                                                                               
                    //                    case "password":                                                                               
                    //                    case "reset":                                                                               
                    //                    case "submit":                                                                               
                    //                        break;                                                                               
                }
            }
            // Change type of watchValue if not multiple results
            switch (watchValue.length) {
                case 0:
                    watchValue = undefined;
                    break;
                case 1:
                    watchValue = watchValue[0];
                    break;
            }
            this.evalPredicateValues(watchValue, watchIndex);
        }
    }

    //YAHOO.widget.Logger.enableBrowserConsole();

    // Initialize hash table to lookup controls with validators
    var nValidators = Page_Validators.length;

    for (var v = 0; v < nValidators; v++) {
        var controlID = Page_Validators[v].getAttribute("controltostyle");

        if (typeof (controlID) != "undefined") {
            // One control may have multiple validators
            if (controlID in this.lookupTable) {
                this.lookupTable[controlID].push(v);
            } else {
                this.lookupTable[controlID] = [v];
            }
        }
    }

    // Add listeners to watch fields
    var nWatches = this.watches.length;

    for (var i = 0; i < nWatches; i++) {
        var id = this.watches[i];
        var el = document.getElementById(id);

        if (el) {
            var els = YAHOO.util.Dom.getElementsBy(this.IsInput, null, el);

            if (els) {
                for (var j = 0; j < els.length; j++) {
                    var inp = els[j];
                    var typ = inp.type.toLowerCase();
                    var evt;

                    switch (typ) {
                        case "radio":
                        case "checkbox":
                            evt = "click";
                            break;

                        case "text":
                            evt = "blur";
                            break;

                        default:
                            evt = "change";
                            break;
                    }

                    YAHOO.util.Event.addListener(inp, evt, (function(id, i) {
                        return function() {
                            this.onWatchChanged(id, i);
                        };
                    })(id, i), this, true);
                }
                this.onWatchChanged(id, i);
            }
        }
    }

}
