/* Behold.  The CNU Namespace */
//var CNU = {};

/* * * CNU config * * */
//CNU.config = {};

//CNU.config.cluster = '';
//CNU.config.brand = '';
//CNU.config.country = '';
//CNU.config.language = '';

/* Assistant Debug Switch */
//CNU.config.DEBUG_ASSISTANT = false;

/* General Console Debug Switch */
//CNU.config.DEBUG = false;

/* ON/OFF switch for Form Submit Validation */
//CNU.config.VALIDATE_FORMS = true;

/* ON/OFF switch for entire Validator Assistant */
//CNU.config.VALIDATE = true;

/* ON/OFF switch for ClickTale Page Events */
//CNU.config.CLICK_TALE_ENABLED = false;

/* regex's */
//CNU.config.regex = {};
//CNU.config.regex.email_address = /^[A-Z0-9._%+\-]+@[A-Z0-9.\-]+\.[A-Z]{2,4}$/i;

/* extra validations */
//CNU.config.x_validations = {};

/* Up here to get timestamp as early as possible */
/* Fun math since Unix timestamp is in seconds, not milliseconds */
CNU.local_timestamp = Math.round(new Date().getTime() / 1000);

/* Utility Functions */
CNU.util = {};
CNU.ev = {};
CNU.dom = {};


CNU.ev.addDomEvent = function (func) {
  $(document).ready(func);
};

/* Chains event functions to window.onload */
CNU.ev.addLoadEvent = function (func) {
  var oldonload = window.onload;
  if (typeof window.onload !== 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      /* REFACTOR 4036: this if () is always true, due to typeof check above */
      if (typeof oldonload == 'function') { oldonload(); }
      if (typeof func == 'function') { func(); }
    };
  }
};
CNU.ev.prepend_event = function (id, ev, func) { 
  var el = document.getElementById(id);
  var oldev = el[ev];
  var result = false;
  if (typeof el[ev] != 'function') {
    el[ev] = func;
  } else {
    el[ev] = function () { return (func() && oldev()); };
  }
};

CNU.ev.add_click_tale_event = function (ev) { 
  if ((CNU.config.CLICK_TALE_ENABLED === true) && (typeof ClickTaleTag == 'function')) { ClickTaleTag(ev); }
  return true;
};
CNU.util.is_active = function () { document.getElementsByTagName('body')[0].addClass('js'); };


/* addEvent attachment */
CNU.ev.addEvent = function ( obj, type, fn ) {
  if (obj.addEventListener) {
    obj.addEventListener( type, fn, false );
    CNU.ev.EventCache.add(obj, type, fn);
  } else if (obj.attachEvent) {
    obj["e"+type+fn] = fn;
    obj[type+fn] = function() { obj["e"+type+fn]( window.event ); };
    obj.attachEvent( "on"+type, obj[type+fn] );
    CNU.ev.EventCache.add(obj, type, fn);
  } else {
    obj["on"+type] = obj["e"+type+fn];
  }
};

CNU.ev.EventCache = function () {
  var listEvents = [];
  return {
    listEvents : listEvents,
    add : function(node, sEventName, fHandler){
      listEvents.push(arguments);
    },
    flush : function(){
      var i, item;
      for(i = listEvents.length - 1; i >= 0; i = i - 1){
        item = listEvents[i];
        if(item[0].removeEventListener){
          item[0].removeEventListener(item[1], item[2], item[3]);
        }
        if(item[1].substring(0, 2) != "on"){
          item[1] = "on" + item[1];
        }
        if(item[0].detachEvent){
          item[0].detachEvent(item[1], item[2]);
        }
        item[0][item[1]] = null;
      }
    }
  };
}();
CNU.ev.addEvent(window,'unload',CNU.ev.EventCache.flush);

/* thank you, quirksmode */
CNU.ev.getTarget = function (e) { 
  var targ;
  if (!e) { e = window.event; }
  if (e.target) { targ = e.target; }
  else if (e.srcElement) { targ = e.srcElement; }
  if (targ.nodeType == 3) { targ = targ.parentNode; }
  return targ;
};







CNU.dom.is_visible = function (element) {
  var parent_visible = true;
  var element_visible = true;
  
  // check visibility of element
  if ( !$(element).is(':visible') || $(element).css('visibility') == 'hidden' ) { element_visible = false; } 
  
  // check visibility of element parents
  if (element_visible) {
    $(element).parents().each(function() {
      if ($(this).css('visibility') == 'hidden' || !$(this).is(':visible')) { parent_visible = false; }
     });
  }
  return element_visible && parent_visible;
};

CNU.dom.hideByClass = function (searchClass,node,tag) {  
  CNU.dom.getElementsByClass(searchClass, node, tag).hide();
};



// returns first form element found of a specific class
// this is useful because it stays within the given form
// not the whole document.
CNU.dom.getChildElementByClass = function (class_name, form) {
  var el = $(form);
  el.children().each(function(){
    if ($(this).hasClass(class_name)) {
      el = $(this);
      return false;
    }
  });
  return el;
};

// returns first form element found of a specific class
// this is useful because it stays within the given form
// not the whole document.
CNU.dom.getDescendantElementByClass = function (class_name, form) {
  return $(form).find('.' + class_name).eq(0);
};

/* grab Elements from the DOM by className */
CNU.dom.getElementsByClass = function (searchClass,node,tag) {
  
  var node = node || document;
  var tag = tag + ' ' || '';
  
  return $(node).find(tag + '.' + searchClass);
};


CNU.dom.insertAfter = function (parent, node, referenceNode) { parent.insertBefore(node, referenceNode.nextSibling); };

/* utilities for returning all form tags from the document */
CNU.dom.get_forms = function () { return document.getElementsByTagName('form'); };
CNU.dom.get_inputs = function (form) { return form.getElementsByTagName('input'); };
CNU.dom.get_selects = function (form) { return form.getElementsByTagName('select'); };
CNU.dom.get_textareas = function (form) { return form.getElementsByTagName('textarea'); };

/* Extend certain portions of the built-in dom */
CNU.dom.extend_string = function () {

  if (!String.prototype.contains) {
    String.prototype.contains = function (t) { return this.indexOf(t) >= 0 ? true : false; };
  }
  if (!String.prototype.trim) {
    String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); };
  }

};


/* Build Assistant */
CNU.Assistant = function () {

  // Validator takes an object.
  // Validator validates that object
  function Validator (element, initialize) {
    this.initialize = initialize || true;
    this.o = element;
    
    /* Validator can be called on document and document has no parents... */
    this.p = (this.o.nodeName != '#document') ? this.parent_container() : null;
    
    
    this.value = null;
    this.name = this.o.name;
    this.id = this.o.id;
    this.classes = this.o.className;
    this.result = true;
    this.message = this.MESSAGES['default_'+CNU.config.language];
    this.msgElement = this.get_error_element();
    
    if (this.initialize) { this.init(); }

  }
 
  Validator.prototype.init = function () {
    if (this.needs_validator(this.o)) { 
      switch (this.o.nodeName) {

        // find all class names, validate against classnames
        case 'TEXTAREA':  this.value = this.o.value;
                          this.result = this.is_valid();
                          break;
  
        // find all class names, validate against classnames
        case 'INPUT':     if (this.o.getAttribute('type') != 'hidden') {
                            this.value = this.o.value;
                            this.result = this.is_valid();
                          }
                          break;
  
        // find all class names, validate against classnames
        case 'SELECT':    this.value = this.o.options[this.o.selectedIndex].value;
                          this.result = this.is_valid();
                          break;
        
        // find all forms, validate each form
        case '#document': this.forms();
                          break;
  
        // find all form elements, validate each element
        case 'FORM':      this.inputs(this.o);
                          break;
  
      
        // can't do jack anything
        default:          break;
      }
    }
  };

  Validator.prototype.MESSAGES = { 
    'is_required_en' : "This field is required.", 
    'matches_syntax_en' : "Improper Format.", 
    'default_en' : "There is an error in this field",
    'form_en' : "There is an error in this form",

    'is_required_es' : "Este campo es obligatorio",
    'matches_syntax_es' : "Formato inadecuado.",
    'default_es' : "There is an error in this field",
    'form_es' : "Hay un error en este formulario"
  };

  Validator.prototype.empty_message_container = function () {
    var container = document.createElement('div');
    container.className = 'error_message';
    container.setAttribute('id', 'error_message_'+this.id);
    return container;
  };

  Validator.prototype.HASCALENDAR_STRING = 'hasCalendar';
  Validator.prototype.DATE_STRING = 'date';
  Validator.prototype.CALENDAR_STRING = 'calendar';
  Validator.prototype.REQUIRED_STRING = 'required';
  Validator.prototype.ERROR_STRING = 'error';
  Validator.prototype.MARITAL_STATUS_STRING = 'marital_status_cd';

  Validator.prototype.is_checkbox = function () { 
    var r = false;
    try { r = (this.o.getAttribute('type') == 'checkbox'); }
    catch (err) { /* do nothing -- object doesn't support this method, which is no big deal.  */ }
    return r;
  };

  Validator.prototype.is_checked = function () {
    var r = false;
    try { r = (this.o.checked); }
    catch (err) { /* do nothing -- object doesn't support this method, which is no big deal.  */ }
    return r;
  };
    
  Validator.prototype.is_required = function () { return this.classes.contains(this.REQUIRED_STRING); };
 
  Validator.prototype.is_present = function () { 
    if (this.is_checkbox()) { return this.is_checked(); }
    if (this.o.nodeName == 'SELECT') { 
      // start with the current select tag's value
      var result = (($(this).val() !== null) && ($(this).val() !== ''));
      // loop through the rest of the selects, if there are any.
      var selects = this.parent_container().find('select').each(function() {
        var select_value = $(this).val();
        result = result && ((select_value !== null) && (select_value !== ''));
      });
      return result;
    }
    return (($(this).val() !== null) && ($(this).val().trim() !== '')); 
  };

  Validator.prototype.has_syntax_rules = function () {
    var r = this.get_syntax_name();
    return (r !== false);
  };

  Validator.prototype.is_valid = function () { 
    var r = true;
    if (this.is_required()) {
      if (! this.has_syntax_rules()) { 
        r = this.is_present();
        if (! r) {
          this.message = this.MESSAGES['is_required_'+CNU.config.language];
        }
      } else {
        r = this.is_present();
        if (! r) {
          this.message = this.MESSAGES['is_required_'+CNU.config.language];
        } else {
          r = this.matches_syntax();
          if (! r) { this.message = this.MESSAGES['matches_syntax_'+CNU.config.language]; }
        }
      }
    } else {
      if (this.has_syntax_rules() && this.is_present()) {
        r = this.matches_syntax();
        if (! r) { this.message = this.MESSAGES['matches_syntax_'+CNU.config.language]; }
      }
    }
    
    if (r && this.is_present()) {
      r = this.x_validate();
    }    
    return r;
  };
  
  Validator.prototype.x_validate = function () {
    var val = this.prepare_value(), r = true, msg = false;
    if (typeof CNU.config.x_validations[this.o.id] == 'object') {
      
      $.each(CNU.config.x_validations[this.o.id],function (index, validation) {
      
        switch (validation.type) {
        case 'min' :
          r = (val < validation.val) ? false : true;
          break;
        case 'max' :
          r = (val > validation.val) ? false : true;
          break;
        }
        
        if (!r) {
          msg = validation.err;
          return false;
        }
      });
    }
    
    if (msg) { this.message = msg; }
    return r;
  }
  
  Validator.prototype.prepare_value = function () {
    var str = this.o.value;
    str = str.replace(/(^\s+|\s+$)/g, '');
    str = str.replace(/\s\s+/g, ' ');
    return str;
  };

  Validator.prototype.matches_syntax = function () {
    var v = this.prepare_value(), s, syntax, validation_case;
    this.MESSAGES.matches_syntax = 'Improper Format';
    syntax = this.get_syntax(); // Here we got collection of validation cases
    if (syntax) {
      for (validation_case in syntax.validation_cases){ // for each validation case
        if(syntax.validation_cases[validation_case]){ // If validation case is defined
          s = syntax.validation_cases[validation_case]; // get validation case
          if (s.mask instanceof RegExp) { // If validation case is regular expression
            // All previous checks should be valid AND this check should be valid
            if(!s.mask.test(v)){ // If not then
              if(s.error_message){ // If custom error message is defined
                this.MESSAGES.matches_syntax=s.error_message; // Set up Error message for this validator
              }
              return false; // And return false (Input is not valid)
            }
          }
        }
      }
    }
    return true; // By default input is valid
  };

  Validator.prototype.get_syntax = function () { 
    var s_name = this.get_syntax_name();
    var r = CNU.config.regex[s_name]; 
    return r;
  };

  Validator.prototype.get_syntax_name = function () {
    var syntax_name = this.classes;
    var reserved_words = [  new RegExp(this.CALENDAR_STRING), 
                            new RegExp(this.DATE_STRING), 
                            new RegExp(this.HASCALENDAR_STRING),
                            new RegExp(this.REQUIRED_STRING), 
                            new RegExp(this.ERROR_STRING) ];
                            
    $.each(reserved_words,function (index, reserved_word) { syntax_name = syntax_name.replace(reserved_word, ''); });
    
    
    
    syntax_name = $.trim(syntax_name);
    return syntax_name || false;
  };

  Validator.prototype.needs_validator = function (element) { 
    if (element.nodeName == '#document') { element = document.getElementsByTagName('body')[0]; }
    if (element.id.match('customer___person___ssn')) { return true; }
    if (element.id.match('last4')) { return false; }
    if (element.id.match('ssn')) { return false; }
    if (! CNU.dom.is_visible(element)) { return false; }
    return (! $(element).hasClass('valid')); 
  };
  
  Validator.prototype.button_click = function () { var validation = new Validator(this); return validation.result; };
  Validator.prototype.add_button_click = function () {
    var validation = new Validator(this.form);
    if (validation.result === true) {
      if (this.oldonclick) { this.oldonclick(); }
    }
  };

  Validator.prototype.disable_validations = function () { 
    this.form.force_valid = true;
  }

  Validator.prototype.form_submit = function () { 
    if (typeof CNU.config.submit == 'function') { CNU.config.submit(); }
    
    var validation = new Validator(this);    
    if (CNU.config.VALIDATE_FORMS === true && !this.force_valid) { 
      
      if (typeof CNU.extended_form_validation == 'function') {
        var extended_validation = CNU.extended_form_validation();
        validation.result = validation.result && extended_validation;
      }
      
      if (validation.result) {
        validation.unset_form_error(this);
      } else { 
        validation.set_form_error(this); 
        validation.scroll_to_first_error(this);
      }
      
      if (validation.needs_click_tale()) { CNU.ev.add_click_tale_event(this.id+"_submit_"+validation.result); }

      return validation.result;
    } else {
      if (validation.needs_click_tale()) { CNU.ev.add_click_tale_event(this.id+"_submit_no_js_validation"); }
      return true; 
    }
  };

  Validator.prototype.needs_click_tale = function () { return (!$(this.o).hasClass("no_click_tale") && (CNU.config.CLICK_TALE_ENABLED === true)); };

  Validator.prototype.forms = function () {
    var f = null, all_forms = CNU.dom.get_forms(), i, btn;
    for (i = 0; i < all_forms.length; i++) {
      f = all_forms.item(i);
      if (this.needs_validator(f)) {
        if (this.has_submit_once(f)) {
          btn = this.get_submit_once(f);
          btn.oldonclick = btn.onclick || "";
          btn.onclick = this.add_button_click;
        }
        var self = this;
        $(f).find('.force-validate').each(function(i,e) {
          $(e).click(function() { self.disable_validations; });
        });
        f.onsubmit = this.form_submit;

        this.enable_form_events(f);
      }
    }
  };
  
  Validator.prototype.unset_form_error = function (f) {
    // get all 'form_message' className
    var form_error = CNU.dom.getDescendantElementByClass('form_error', f);
    if (form_error.length > 0) { $(form_error).remove(); }
  };
  
  Validator.prototype.set_form_error = function (f) { 
    this.unset_form_error(f);
    
    this.show_submit_once(f);
    
    // generate message
    var msgNode = document.createElement('div');
    msgNode.innerHTML = this.MESSAGES['form_'+CNU.config.language]; 
    $(msgNode).addClass('form_error');

    // append the messages
    CNU.dom.getChildElementByClass('actions', f).append(msgNode);
    $(f).addClass('f_error');
  };

  Validator.prototype.scroll_to_first_error = function (f) {
    $('html,body').animate({ scrollTop: $(f).find('.error').first().offset().top }, { duration: 'fast', easing: 'swing' });
  };
  
  Validator.prototype.has_submit_once = function (form) {
    return $(form).find('input.submit_once').length > 0;
  };

  Validator.prototype.get_submit_once = function (form) { return $(form).find('input.submit_once').eq(0); };
  
  Validator.prototype.show_submit_once = function (form) {
    $(form).find('input.submit_once').show().next('img').hide();
  };

  Validator.prototype.inputs = function (form) {
    var inputs = CNU.dom.get_inputs(form);
    this.check_elements(inputs);

    var selects = CNU.dom.get_selects(form);
    this.check_elements(selects);

    var textareas = CNU.dom.get_textareas(form);
    this.check_elements(textareas);
    
  };

  Validator.prototype.check_elements = function (elements) {
    var type = null;
    for (var i = 0; i < elements.length; i++) {
      try { type = elements.item(i).getAttribute('type'); }
      catch (err) { type = 'generic' }
      if ((type != 'hidden') && (type != 'button') && (type != 'image') && (type != 'reset') && (type != 'submit')) { 
          var element = new Validator(elements.item(i));
          if (element.result === true) { element.unset_error(); }
          else { element.set_error(); }
          this.result = this.result && element.result;
      }
    }
  };

  Validator.prototype.enable_form_events = function (form) {
    var inputs = CNU.dom.get_inputs(form);
    this.enable_element_events(inputs);

    var selects = CNU.dom.get_selects(form);
    this.enable_element_events(selects);

    var textareas = CNU.dom.get_textareas(form);
    this.enable_element_events(textareas);
  };

  Validator.prototype.enable_focus = function () { 
    CNU.Assistant.blurred_input = false;
    var validate = new Validator(this);
    if (validate.has_error()) {
      validate.unset_error();
    }
    validate.set_focus();
  };

  Validator.prototype.enable_keydown = function (evt) { 
    var keyCode = false;

    if ("which" in evt) {
      keyCode=evt.which;
    } else if ("keyCode" in evt) {
      keyCode=evt.keyCode;
    } else if ("keyCode" in window.event) {
      keyCode=window.event.keyCode;
    } else if ("which" in window.event) {
      keyCode=evt.which;
    } else { 
    }

    if (keyCode == 9) { CNU.Assistant.tabbed = true; }
    else { CNU.Assistant.tabbed = false; }
  };

  Validator.prototype.enable_button_focus = function (e) { 
    if (! CNU.Assistant.tabbed) {
      var target = CNU.ev.getTarget(e);
      if (CNU.Assistant.blurred_input) { $(target).trigger('click'); }
      CNU.Assistant.blurred_input = false;
    }
  };

  Validator.prototype.enable_blur = function (e) {
    var validate = new Validator(this);
    validate.unset_focus();
    if (validate.result) { validate.unset_error(); }
    else { validate.set_error(); }

    CNU.Assistant.blurred_input = CNU.ev.getTarget(e);
  };

  Validator.prototype.enable_element_events = function (elements) {

    var type = null;
    for (var i = 0; i < elements.length; i++) {
      try { type = elements.item(i).getAttribute('type'); }
      catch (err) { type = 'generic' }

      if ((type != 'submit') && (type != 'hidden') && (type != 'reset')) {
        CNU.ev.addEvent(elements.item(i), 'blur', this.enable_blur);
        CNU.ev.addEvent(elements.item(i), 'focus', this.enable_focus);
        CNU.ev.addEvent(elements.item(i), 'keydown', this.enable_keydown);
      }

      /* special case: submit_once tags need click invoked after blurs. */
      if ((type == 'submit') || (type == 'reset') || (type == 'button')) {
        //if ($(elements.item(i)).hasClass('submit_once')) { 
          CNU.ev.addEvent(elements.item(i), 'focus', this.enable_button_focus);
        //}
      }
    }

  };
  
  Validator.prototype.parent_container = function () {
    var p = $(this.o).parents('.field');
    if (p.length < 1) { p = $(this.o).parent(); }
    return p;
  };
  
  
  
  Validator.prototype.has_class = function (class_name) { 

    if (this.p) {
      return $(this.p).hasClass(class_name);
    } else {
      return $(this.o).hasClass(class_name);
    }

  };

  Validator.prototype.set_class = function (class_name) {

    if (this.p) {
      $(this.p).addClass(class_name);
    }

    if (class_name == 'error') { 
      $(this.o).addClass(class_name); 
      if (this.o.nodeName == 'SELECT') { 
        $(this.o).parents('.field').find('select').addClass(class_name);
      }
    }
  };

  Validator.prototype.unset_class = function (class_name) {


    if (this.p) {
      $(this.p).removeClass(class_name);
    }

    if (class_name == 'error') { 
      $(this.o).removeClass(class_name);
      if ((this.o.nodeName == 'SELECT') || ($(this.o).hasClass('hasDatepicker'))) { 
        $(this.o).parents('.field').find('select').removeClass(class_name);
      }
    }
  };
  
  
  Validator.prototype.has_error_message = function () { return (this.message !== null); };

  Validator.prototype.set_error_message = function () {
    this.msgElement.innerHTML = this.message;
    this.parent_container().append(this.msgElement);
  };

  Validator.prototype.has_error_element = function () {
    if (this.o.nodeName == '#document') { return false; }    
    var has_error_element = this.parent_container().find('.error_message').length > 0;
    return has_error_element;
  };

  Validator.prototype.get_error_element = function () {
    var r = false;
    if (this.has_error_element()) {
      r = this.parent_container().find('.error_message')[0];
      if (! r) { r = $('#error_message_'+this.id+'___hidden')[0]; }
    }
    return r;
  };
  
  Validator.prototype.unset_error_message = function () { 
    var errNode = this.get_error_element();
    try {
      $(errNode).remove();
    } catch (err) {
      try {
        $('#error_message_'+this.id).remove();
      } catch (err2) {
      }
    }
  };
  
  Validator.prototype.set_error = function () {
    if (! this.message) { this.message = this.MESSAGES['default_'+CNU.config.language]; }
    if (! this.msgElement) { this.msgElement = this.empty_message_container(); }
    if (! this.has_class('error')) {
      this.set_class('error');
      this.set_error_message();
    }
  };

  Validator.prototype.unset_error = function () {
    if (this.message !== null) { this.message = null; }
    if (this.has_class('error')) {
      this.unset_class('error');
      this.unset_error_message();
    }      
  };

  Validator.prototype.has_error = function () { return this.has_class('error'); };
  Validator.prototype.has_focus = function () { return this.has_class('focus'); };

  Validator.prototype.set_focus = function () {
    if (! this.has_class('focus')) {
      this.set_class('focus');
    }
    this.show_tip();
  };
  Validator.prototype.unset_focus = function () {
    this.unset_class('focus');
    this.hide_tip();
  };

  Validator.prototype.get_tip = function () { 
    return CNU.dom.getElementsByClass('tooltip', this.parent_container()).eq(0);
  };
  Validator.prototype.show_tip = function () { 
    var tip = this.get_tip(); 
    if (tip) {
      if (this.needs_tip_moved()) { this.move_tip(tip); }
      tip.show(); 
    }
  };
  Validator.prototype.hide_tip = function () { 
    var tip = this.get_tip(); 
    if (tip) { tip.hide(); }
  };

  Validator.prototype.needs_tip_moved = function () {
    if (this.o.nodeName == 'SELECT') { return true; }
    // if ($(this.o).hasClass('date')) return true;
    return false;
  };

  Validator.prototype.move_tip = function (tip) { 
    var label = this.parent_container().find('label').eq(0);
    if (label) { $(tip).insertBefore(label); }
  };

  
  // public hash
  return {

    // a public method for initializing the Assistant
    init: function () {
      var validations;
      if (CNU.config.VALIDATE === true) {
        CNU.dom.extend_string();
        CNU.dom.hideByClass('tooltip', document);
        CNU.Assistant.setup_errors();
        validations = new Validator(document);
      }
    },

    validate: function (element) {
      var validation = new Validator(element);
      if (validation.result) { validation.unset_error(); }
      else { validation.set_error(); }
      return validation.result;
    },

    enable: function (element) {
      var validation = new Validator(element);  
      validation.enable_form_events(element);
    },

    set_focus: function (element) {
      var validation = new Validator(element);  
      validation.set_focus();
    },

    unset_focus: function (element) {
      var validation = new Validator(element);
      validation.unset_focus();
    },

    unset_errors: function (element) {
      var error_elements = $(".error", element);
      error_elements.each(function() {
        var name = $(this)[0].nodeName;
        var tags = ['INPUT','SELECT','TEXTAREA'];
        if ($.inArray(name, tags) > -1 && $(this).parents('.field').hasClass('error')) {
          validation = new Validator($(this)[0]);
          validation.unset_error();
        }
      });
    },

    setup_errors: function () {
      var error_elements = CNU.dom.getElementsByClass('error');
      error_elements.each(function() {
        var name = $(this)[0].nodeName;
        var tags = ['INPUT','SELECT','TEXTAREA'];
        if ($.inArray(name, tags) > -1 && !$(this).parent().hasClass('error')) {
          $(this).parent().addClass('error');
        }
      });
    },

    blurred_input: false,
    tabbed: null,
    
    validate_form : function (form_el) {
      var validation = new Validator(form_el);
      if (validation.result) { validation.unset_form_error(form_el); }
      else { validation.set_form_error(form_el); }
      return validation.result;
    }

  }; // Assistant return public hash

}(); // Assistant
CNU.ev.addLoadEvent(CNU.Assistant.init);



// hide all faq's
// add navigation to page
CNU.faq = {};

CNU.faq.CLOSED = "closed";
CNU.faq.OPEN = "open";

CNU.faq.init = function (nav) {
  nav = nav || true;

  /* Does not use "CNU.faq.hide_all()" because we want it instantly collapsed */
  $('dd.faq, ul.questions dl.faq').each(CNU.faq.hide_immediately_unless_body);

  $('.faq_category, .faq_question').each(CNU.faq.add_events);

  if (nav !== false) { CNU.faq.init_nav(); }

  if (CNU.config.SHOW_DISCLAIMERS_BY_DEFAULT === true) { 
    CNU.faq.show_disclaimers();
  }

};

CNU.faq.show_disclaimers = function () {
  $('#disclaimers')
    .removeClass(CNU.faq.CLOSED)
    .show()
    .prev()
      .removeClass(CNU.faq.CLOSED)
      .addClass(CNU.faq.OPEN);
};

CNU.faq.hide_immediately_unless_body = function (i,e) { if (e.tagName != 'BODY') { $(e).hide(); } };

CNU.faq.init_no_nav = function () { CNU.faq.init(false); };

// activate behaviors for categories and questions
// add close/open navigation to each question as
// well as the entire page.
CNU.faq.init_nav = function () {

  if (! CNU.config.is_mobile) { 
    $('.faq_answer').each(CNU.faq.add_nav);
    $('.questions').each(CNU.faq.add_global_nav); 
  }
  
};

// Basic show and hide functionality
CNU.faq.hide = function (el) { el.hide( 'blind', {}, 300 ); }
CNU.faq.show = function (el) { el.show( 'blind', {}, 300 ); }

// Global show and hide functionality
CNU.faq.hide_all = function () { $('.faq').each(CNU.faq.hide_unless_body); };
CNU.faq.show_all = function () { $('.faq').each(CNU.faq.show_unless_body); };

CNU.faq.hide_unless_body = function () { if (!$(this).is('body')) { CNU.faq.hide($(this)); } }
CNU.faq.show_unless_body = function () { if (!$(this).is('body')) { CNU.faq.show($(this)); } };

// adds onclick event to element
// to show next sibling that has className "faq"
CNU.faq.add_events = function (i, e) { 
  $(e.parentNode).addClass('closed');
  $(e).click(CNU.faq.click_event);
  $(e).mouseover(CNU.faq.mouseover_styles);
};

CNU.faq.click_event = function () {

  $(this.parentNode).toggleClass(CNU.faq.CLOSED);
  $(this.parentNode).toggleClass(CNU.faq.OPEN);
  $(this).toggleClass(CNU.faq.OPEN);

  CNU.faq.toggle_sibling(this);

};

CNU.faq.mouseover_styles = function () { $(this).css('cursor','pointer'); };

// Toggle the appropriate sibling, if it exists.
CNU.faq.toggle_sibling = function (e) {
  var sibling = $(e).next('.faq');
  if (sibling.length > 0) { CNU.faq.toggle(sibling.eq(0)); }
};

// Toggle the CSS classes.
CNU.faq.toggle_classes = function (e) {
  var el = $(e);
  if(el.hasClass(CNU.faq.OPEN)) {
    el.removeClass(CNU.faq.OPEN);
    el.addClass(CNU.faq.CLOSED);
  } else {
    el.addClass(CNU.faq.OPEN);
    el.removeClass(CNU.faq.CLOSED);
  }
};

// Toggle the given element
CNU.faq.toggle = function (el) {  el.toggle( 'blind', {}, 300 ); };

CNU.faq.add_nav = function () { 

  var nav = document.createElement('div');
  var close = document.createElement('a');

  close.setAttribute('href', '#');

  $(close).click(CNU.faq.close_click);
  
  $(close).mouseover(CNU.faq.mouseover_styles);

  close.appendChild(document.createTextNode('Close'));
  
  $(nav).addClass('nav');
  nav.appendChild(close);

  this.appendChild(nav);

};

CNU.faq.close_click = function () {
  CNU.faq.toggle($(this).parents('.faq.faq_answer'));
  var title = $(this).parent('.faq.faq_answer').prev('.faq_question');
  if (title.hasClass(CNU.faq.OPEN)) { 
    title.removeClass(CNU.faq.OPEN);
  } else {
    title.addClass(CNU.faq.OPEN);
  }
  return false;
}


CNU.faq.add_global_nav = function () { 

  var nav = document.createElement('p');
  var close = document.createElement('a');
  var open = document.createElement('a');

  close.setAttribute('href', '#');
  $(close).addClass('close');
  close.onclick = function () { CNU.faq.hide_all(); return false; };
  close.onmouseover = function () { close.style.cursor = 'pointer'; };
  close.appendChild(document.createTextNode('Collapse All'));

  $(open).addClass('open');
  $(open).click(function() { CNU.faq.show_all(); return false; });
  $(open).mouseover(function() { $(this).css('cursor','pointer'); });
  open.appendChild(document.createTextNode('Expand All'));

  $(nav).addClass('nav');
  nav.appendChild(open);
  nav.appendChild(document.createTextNode(" | "));
  nav.appendChild(close);
  
  this.parentNode.insertBefore(nav, this);
};


CNU.sms = function () {
  var account_sms_flg = $('#customer___sms_preference___account_sms_flg')[0];
  var terms_sms_flg = $('#customer___sms_preference___terms_sms_flg')[0];
  var promotional_sms_flg = $('#customer___sms_preference___promotional_sms_flg')[0];
  var mobile_phone = $('#customer___person___mobile_phone')[0];

  /* Whenever account_sms_flg is checked
      - mobile phone should be given a 'required' class
      - promotional_sms_flg should be enabled 
  */
  function toggle_sms_checkbox_conditions () {
    var requireNode, mobile_label;

    if (terms_sms_flg.checked) {
      $(account_sms_flg)
        .attr('disabled', '')
        .parents().first().show();
    } else {
      account_sms_flg.checked = false;
      $(account_sms_flg)
        .attr('disabled', 'disabled')
        .parents().first().hide();
    }
    
    if (account_sms_flg.checked) {
      $(promotional_sms_flg)
        .attr('disabled', '')
        .parents().first().show();
  
      $(mobile_phone).addClass('required');

      requiredNode = document.createElement('span');
      $(requiredNode)
        .html('*')
        .addClass('required')
        .attr('id', 'mobile_required');

      mobile_label = mobile_phone.parentNode.firstChild;
      mobile_phone.parentNode.insertBefore(requiredNode, mobile_label.nextSibling);
  
    } else {
      promotional_sms_flg.checked = false;

      $(promotional_sms_flg)
        .attr('disabled', 'disabled')
        .parents().first().hide();

      $(mobile_phone)
        .removeClass('required')
        .removeClass('error');
  
      CNU.Assistant.validate(mobile_phone);
      if ($('#mobile_required')) { $('#mobile_required').remove(); }
    }
  }

  /* disable the promotional_sms_flg checkbox 
      if the account_sms_flg checkbox is not checked 
  */

  return {
    init: function () {
      CNU.ev.addEvent(account_sms_flg, 'click', toggle_sms_checkbox_conditions);
      CNU.ev.addEvent(terms_sms_flg, 'click', toggle_sms_checkbox_conditions);
      toggle_sms_checkbox_conditions();
    }
  }

}();

CNU.selectExtend = { 
  init: function() { 
    $('select').each(function() { 
      var e = $(this)[0];
      CNU.ev.addEvent(e, 'mousedown', function() { $(e).addClass('dynamic'); }); 
      CNU.ev.addEvent(e, 'blur', function() { $(e).removeClass('dynamic'); }); 
      CNU.ev.addEvent(e, 'change', function() { $(e).removeClass('dynamic'); }); 
    });
  } 
};  
CNU.ev.addLoadEvent(CNU.selectExtend.init);

// Code for Read More functionality provided on index.html
CNU.more_information = {};
CNU.more_information.init = function (node_name) {
  
  // The div block concerned 
  var id = '#more_information';

  // We essentially do two things:
  // Create the link for 'Read More' and Hide the Content by default
  CNU.more_information.create_link(id, node_name);
  CNU.more_information.hide_content(id);
   
};

CNU.more_information.create_link = function (id, node_name) {
  var ele = document.createElement('a');
  ele.setAttribute('href', '#');
  ele.setAttribute('style', 'font-weight: bold; font-size: 1.5em;');
  ele.onclick = function () { CNU.more_information.hide_show(id); return false; };
  ele.onmouseover = function () { ele.style.cursor = 'pointer'; };
  ele.appendChild(document.createTextNode(node_name));
  $('.more_information_c').each(function(rl) {
    var rl = $(this)[0];
    rl.parentNode.insertBefore(ele, rl);
  });
};

CNU.more_information.hide_show = function (id) {
  $(id).toggle(400);
};

CNU.more_information.hide_content = function (id) {
  // Do a quick hide
  $(id).hide();  
};

CNU.ev.addLoadEvent(function () {
  $('.dynamic_label').each(function() {
    var wrapper = $(this);
    var target = wrapper.find('input').eq(0)[0];

    CNU.ev.addEvent(target, 'focus', function() { wrapper.addClass('active'); });
    CNU.ev.addEvent(target, 'change', function() { wrapper.addClass('active'); });

    function checkInput() {
      if(target.value == '') {
        wrapper.removeClass('nonempty');
      } else {
        wrapper.addClass('nonempty');
      }
    }

    CNU.ev.addEvent(target, 'blur', function() {
      wrapper.removeClass('active');
      checkInput();
    });

    checkInput();
  });
});

CNU.inline_editing = function () { 

  function enable_inline_edit(field) { 
    var enabled = false;
    var fields = field.find("*[name]");
    
    fields.each(function() { 
      if ($(this).attr('type') != "hidden") { $(this).css('display','inline'); }
      enabled = true;
    });
    
    fields.eq(0)[0].focus();

    if (enabled == true) {
      field.find("span.value").each(function() { $(this).hide(); });
      field.find(".ui-datepicker-trigger").css('display','inline');
    }
  }

  /* When the document is ready, find and enable all inline edit fields. */
  CNU.ev.addLoadEvent(function () { 
    $(".field.inline").each(function() {
      var el = $(this)[0];
      /* event delegation */
      el.onclick = function (ev) { 

        /* find what was clicked */
        var target = $(CNU.ev.getTarget(ev))[0];
        
        /* only do what we want to do based on the target */
        switch (target.nodeName) {
          case 'SPAN':  if ($(target).hasClass("value")) { enable_inline_edit(el); }
                        break;
        }
        
        /* stop the default action */
        return false;
      };
    });

    $(".field.inline *[name]").hide();
  });

  /* public */
  return { enable: function (field) { enable_inline_edit($(field)); } }
  
}();

CNU.paydates = {};
CNU.paydates.original_values = {};
CNU.paydates.dialog = {};
CNU.paydates.ajax_url = CNU.paydates.ajax_url || "/secure/customer_paydates/edit";
CNU.paydates.init = function () { 

  $("ul.paydates *[name]").each(function () { CNU.paydates.original_values[this.name] = this.value; });

  $("#edit_paydates").click(function(ev) { 
    ev.preventDefault();
    $("#dialog").dialog("open");
  });

};

CNU.paydates.dialog.open = function () { 
  $('.ui-dialog-titlebar-close').hide();
  $this = $(this);
  $.ajax({
    url: CNU.paydates.ajax_url, 
    success: function (data) { 
      var holder = document.createElement("div");
      holder.innerHTML = data;
      $("#dialog").html($(holder).find("#content_main form")).prepend(CNU.paydates.flash_message);
      $.each( $(".flash_notice"), function(index, value) {
        $('#dialog').prepend(value);
        });
      CNU.Assistant.enable($("#dialog form").get(0));
      CNU.Assistant.unset_errors($("#dialog form").get(0));
      CNU.calendar.init("#dialog input.calendar");
      $("#customer_paydates_save_paydates_submit").click(function (ev) { 
        ev.preventDefault(); 
        CNU.paydates.validate();
      });
      $("#dialog form .actions").append("<img src='/images/spin.gif' id='customer_paydates_save_paydates_spinner' alt='submit' style='display:none;' />")
    }
  });
};

CNU.paydates.dialog.close = function () { 
  $this = $(this);
  $this.html("<img src='/images/ajax-loader.gif' alt='Loading...' />");
  $this.trigger('update_totals');
};

CNU.paydates.stop_loading = function () { 
  $("#customer_paydates_save_paydates_spinner").hide();
  $("#customer_paydates_save_paydates_submit").show();
};

CNU.paydates.start_loading = function () { 
  $("#customer_paydates_save_paydates_spinner").show();
  $("#customer_paydates_save_paydates_submit").hide();
};

/* compare_values, deprecated -- not needed */
CNU.paydates.compare_values = function () { 
  var result = true;
  $("#dialog fieldset.paydates *[name]").each(function () { 
    if ((CNU.paydates.original_values[this.name]) && (this.value != CNU.paydates.original_values[this.name])) { 
      result = false;
      CNU.paydates.validate();
      return false;
    }
  });
  return result;
};

CNU.paydates.validate = function () {
  var valid = true;
  CNU.paydates.start_loading();
  $("#dialog fieldset.paydates select").each(function () { 
    valid = valid && CNU.Assistant.validate(this);
  });

  if (valid) { CNU.paydates.verify(); }
  else CNU.paydates.stop_loading();
};

CNU.paydates.verify = function () { 
  var new_paydates = { response: "json" };
  $("#dialog fieldset.paydates *[name]").each(function () { new_paydates[this.name] = this.value; });

  $.ajax({ 
    url: CNU.paydates.ajax_url,
    dataType: 'json',
    type: 'post',
    data: new_paydates, 
    error: CNU.paydates.error,
    success: CNU.paydates.success,
    complete: CNU.paydates.stop_loading
  });

}; /* END verify */

CNU.paydates.success = function (data, status) {

  if (data.valid != true) {
    CNU.paydates.populate_error_messages(data.errors);
  } else {

    /* done editing paydates */
    $("#dialog").dialog("close");
    CNU.paydates.populate_success_values(data.values);

    /* Populate additional returned values into fields */
    $.each(data.values, function (key, value) { 
      if (key == 'loans') CNU.extension.populate_values(value);
    });
  }

}

CNU.paydates.populate_error_messages = function (errors) { 
  $.each(errors, function (key, value) { 
    $("#dialog fieldset.paydates *[name="+key+"]").each(function () { CNU.shared.populate_error_message(this, value); });
  });
};

CNU.paydates.populate_success_message = function (success_message) { /* console.log("success_message", success_message); */ };

CNU.paydates.populate_success_values = function (paydates) { 
  $.each(paydates, function (key, value) { 
    $("#create_extension fieldset.paydates #customer___customer_paydate___"+key+"_value").html(value);
  });
};

CNU.paydates.populate_values = function (paydates) { 
  $.each(paydates, function (key, value) { 
    $("#dialog fieldset.paydates *[name=customer___customer_paydate\["+key+"\]]").val(value);
  });
};
CNU.paydates.error = function () { /* console.log("error"); */ };



CNU.extension = {};
CNU.extension.ajax_url = CNU.extension.ajax_url || location.pathname;
CNU.extension.init = function () { 

  $("body").addClass("js");

  $('<span class="partial_payment_link"><a href="#">Add a partial payment</a><span class="tip-trigger partial_payment_tip">?</span></span>').insertAfter(".has_hidden_partial_payment div.total");
  $('<span class="partial_payment_close"><a href="#">X</a></span>').insertAfter(".partial_payment dd .loading-spinner");

  CNU.extension.hide_partial_payments();
  CNU.extension.reattach_events();
  if (CNU.shared.collapse_payments == true) { CNU.extension.hide_partial_payment_step(); }

  $("body").bind('update_totals', function () { CNU.extension.update_totals(this); });
  $("body").bind('update_loans', function () { CNU.extension.populate_values(CNU.shared.loans); });
  $("body").bind('attach_events', function () { CNU.extension.reattach_events(); });

  if (CNU.shared.mobile !== true) { 
    CNU.end_action_cd.init(); 
    $("body").addClass("end_action_cd");
  }

};
CNU.extension.hide_partial_payment_step = function () { 
  $('h4.number.four').addClass('three').removeClass('four');
  $('.partial_payment_information')
    .removeClass('separator')
    .addClass('toggle-content')
    .hide();
  $('.partial_payment_information>h4').removeClass('number three');
  $a = $("<div class='toggle-trigger'><a href='#'>"+CNU.shared.collapse_trigger_msg+"</a></div>")
  $a
    .click(function (ev) { 
      ev.preventDefault();
      if (ev.target.nodeName == 'A') {
        $this = $(this);
        $('.partial_payment_information').toggle(); 
        if ($this.hasClass('open')) $this.removeClass('open');
        else $this.addClass('open');
      }
    })
    .insertBefore(".partial_payment_information");
};
CNU.extension.reattach_events = function () { 
  $('.partial_payment_link').unbind('click');
  $('.partial_payment_link').click(function (ev) {
    if ($(ev.target).hasClass("tip-trigger")) { 
      ev.stopPropagation();
      if ((CNU.shared.tip_msg != "") && (CNU.shared.showing_tip != true)) {
        $("<div class='tip'><span class='tip-close'>X</span>"+CNU.shared.tip_msg+"</div>").appendTo(this);
        CNU.shared.showing_tip = true;
        $('.tip-close').unbind("click");
        $('.tip-close').click(function (ev, el) { 
          ev.stopPropagation();
          $this = $(this);
          $this.parent().remove();
          CNU.shared.showing_tip = false;
        });
      }
    }
    if (ev.target.tagName == "A") { 
      var $this = $(this);
      $this.parent().children(".partial_payment").css("display", "block");
      $this.hide();
    }
    ev.preventDefault();
  });

  $('.partial_payment_close').unbind('click');
  $('.partial_payment_close').click(function (ev) { 
    ev.preventDefault();
    var original_value = $(this).siblings('.field').children('select').val();
    $(this).siblings('.field').children('select').val('0');
    if (original_value != 0) { $(this).trigger("update_totals"); }
    $(this).parent().parent().hide();
    $(this).parent().parent().parent().children('.partial_payment_link').show();
  });
  
  $('.partial_payment .field *[name]').unbind('change');
  $('.partial_payment .field *[name]').change(function (ev) {
    $(this).trigger("update_totals");
  });
};

CNU.extension.update_totals = function (el) { 
  var data = { response: "json", update: { partial_payment: "Update total" } };

  $('form#create_extension *[name]').each(function () {
    data[this.name] = this.value;
  });
  
  $.ajax({
    url: CNU.extension.ajax_url,
    dataType: 'json',
    type: 'post',
    data: data,
    beforeSend: CNU.extension.before_send,
    error: CNU.extension.error,
    success: CNU.extension.success,
    complete: CNU.extension.complete
  });
};

CNU.extension.before_send = function () { $(".partial_payment span.loading-spinner").show(); $(".partial_payment_close").hide(); };
CNU.extension.complete = function () { $(".partial_payment span.loading-spinner").hide(); $(".partial_payment_close").show(); };

CNU.extension.populate_values = function (loans) { 
  var options = "";
  $.each(loans, function (key, value) { 
    $.each(value, function (field_name, amount) { 
      if (field_name == 'partial_payment_amounts') {
        $(amount).each(function (k, v) {
          options += "<option value='"+v[0]+"'>"+v[0]+"</option>";
        });
        $("#"+key+"___end_partial_payment_amount")
          .html(options)
          .val(value["end_partial_payment_amount"])
          .each(function () { CNU.shared.clear_error_message(this); });
        options = "";
      }
      CNU.shared.loans[key][field_name] = amount;
      $("."+key+" ."+field_name).html(amount);
    });
  });
};

CNU.extension.success = function (data, status) {

  if (data.valid != true) {
    CNU.extension.populate_error_messages(data.errors);
  } else {
    CNU.extension.clear_error_messages();
  }

  if (data.values) {
    $.each(data.values, function (key, value) { 
      if (key == 'loans') CNU.extension.populate_values(value);
    });
  }

};

CNU.extension.error = function () { /* console.log("error"); */ };

CNU.extension.hide_partial_payments = function () { 
  $(".payment .partial_payment [name]").each(function () {
    $this = $(this);
    if (($this.val() != '') && ($this.val() != '0')) {
      $this.parent().parent().parent().css("display", "block");
      $this.parent().parent().parent().parent().children(".partial_payment_link").hide();
    }
  });
  $(".update_partial_payment").remove();
  $(".partial_payment span.loading-spinner").hide().html(CNU.shared.spinner_img)
};

CNU.extension.populate_error_messages = function (errors) { 
  $.each(errors, function (key, value) { 
    $(".payment *[name="+key+"]").each(function () { CNU.shared.populate_error_message(this, value); });
  });
};

CNU.extension.clear_error_messages = function () { 
  $(".payment *[name]").each(function () { CNU.shared.clear_error_message(this); });
};

CNU.shared = {};
CNU.shared.loans = {};
CNU.shared.tip_msg = "";
CNU.shared.spinner_img = "<img class='loading-spinner' src='/images/spin.gif' alt='loading...' />";
CNU.shared.num_extensions_remaining = 0;
CNU.shared.clear_error_message = function (el) { 
  $el = $(el);
  $el
    .parent().removeClass("error")
    .children().filter("*[name]").removeClass("error");

  $el.siblings(".error_message").remove();
};

CNU.shared.populate_error_message = function (el, value) { 
  $el = $(el);
  $el
    .parent().addClass("error")
    .children().filter("*[name]").addClass("error");
  
  if ($el.parent().filter(":has(.error_message)").length == 0) {
    $el.parent().append("<div class='error_message' id='error_message_"+el.id+"___hidden'>"+value+"</div>");
  } else {
    $el.filter(".error_message").html(value);
  }
};

CNU.end_action_cd = {};
CNU.end_action_cd.loans = {};
CNU.end_action_cd.saved_payment = "";
CNU.end_action_cd.init = function () {
  $(".select_end_action_information li.loading-spinner").html(CNU.shared.spinner_img).hide();
  $(".select_end_action_information ul.single li .radio_submit").remove();
  $(".select_end_action_information ul.single li."+$("input[name=loan[end_action_cd]]").val()).show();
  $(".select_end_action_information ul.single").append("<li class='slider'><div id='end_action_cd_slider'></div></li>");
  var val = CNU.end_action_cd.selected();
  $("#end_action_cd_slider").slider({
    range: "min",
    value: val,
    min: 0,
    max: 100,
    stop: CNU.end_action_cd.stop
  });
  CNU.end_action_cd.update_payments($("#end_action_cd_slider").slider("value"), true);
};
CNU.end_action_cd.selected = function () { 
  if ($("input[name=loan[end_action_cd]]").val() == "partial_payment") return 96;
  return 50;
};
CNU.end_action_cd.stop = function (event, ui) { 
  $this = $(this);
  if (ui.value <= 70) $this.slider("value", 50);
  else $this.slider("value", 96);
  $(".select_end_action_information ul.single li."+$("input[name=loan[end_action_cd]]").val()).hide();
  CNU.end_action_cd.update_payments($this.slider("value"));
  $(".select_end_action_information ul.single li."+$("input[name=loan[end_action_cd]]").val()).show();
};
CNU.end_action_cd.update_payments = function (value, force) { 
  force = force || false;
  switch (value) { 
    case 50:  CNU.end_action_cd.update("pay_in_full", force);
              break;
    case 96:  CNU.end_action_cd.update("partial_payment", force);
              break;
  }
};
CNU.end_action_cd.update = function (value, force) {
  if ((value != "partial_payment") && (value != "pay_in_full")) return false;

  $("li.loading-spinner").show();
  force = force || false;
  $end_action_cd = $("input[name=loan[end_action_cd]]");
  if (($end_action_cd.val() != value) || force) {
    $end_action_cd.val(value);

    if (value == "partial_payment") { 
      if ((CNU.shared.num_extensions_remaining > 0) && !force) CNU.shared.num_extensions_remaining = CNU.shared.num_extensions_remaining - 1;
  
      if (CNU.shared.num_extensions_remaining == 0) $(".extensions_count").html("");
      else $(".extensions_count").html(CNU.shared.extensions_messages[1]);
  
      if (CNU.end_action_cd.saved_payment != "") {
        $(".partial_payment_information .loan.info").addClass("extension").removeClass("loan")
        $('.partial_payment_information .current_loan.info').after(CNU.end_action_cd.saved_payment);
        CNU.end_action_cd.saved_payment = "";
      }
      $(".partial_payment_information .loan.info").trigger("update_loans").trigger("attach_events");
    }

    if (value == "pay_in_full") {
      if (!force) CNU.shared.num_extensions_remaining = CNU.shared.num_extensions_remaining + 1;
  
      $(".extensions_count").html(CNU.shared.extensions_messages[0]);
  
      CNU.end_action_cd.saved_payment = $(".partial_payment_information .loan.info").remove();
      $(".partial_payment_information .extension.info").addClass("loan").removeClass("extension").trigger("update_loans");
    }

    $(".num_extensions_remaining").html(CNU.shared.num_extensions_remaining);
    if (CNU.shared.num_extensions_remaining == 1) $(".num_extensions_remaining_plural").hide();
    else $(".num_extensions_remaining_plural").show();
  
  }
  $("li.loading-spinner").hide();
};

CNU.extension.replace_urls = function () {
  var new_url = "/secure/advances/request_extension";
  $("a[href$='new_extension']").attr("href", new_url)
  $("form[action$='new_extension']").attr("action", new_url)
  return true;
};
CNU.ev.addLoadEvent(CNU.extension.replace_urls);




CNU.parseClassInfo = function (el,pre) {
  //ex: class of cnuinfo-class_one-class_two becomes ['class_one','class_two']
  // whatever character directly follows "pre" becomes the delimiter of values
  var pre = pre || 'cnuinfo';
  var info = undefined;
  var class_names = el.attr('class');
  var tmp = class_names.split(' ');
  if (typeof tmp === 'object' && tmp.length > 0) {
    for (var i=0,j=tmp.length;i<j;i++) {
      var class_name = tmp[i];
      if (class_name.substr(0,pre.length) == pre) { info = class_name.substr(pre.length); }
    }
  } else if (typeof class_names === 'string' && class_names != '') {
    if (class_names.substr(0,pre.length) == pre) { info = class_name.substr(pre.length); }
  }
  if (info) {
    var split_on = info.substr(0,1);
    info = info.substr(1);
    info = (info.indexOf(split_on) > -1) ? info.split(split_on) : [info];
  }
  return info;
}
CNU.getElIndex = function (el,selector) {
  var selector = selector || el[0].tagName.toLowerCase();
  var el_index = 0;
  var pre_el = el.prev(selector);
  while (pre_el.length > 0) {
    el_index++;
    pre_el = pre_el.prev(selector);
  }
  return el_index;
}






CNU.tabs = function (cnutab_els) {
  // private
  var cnutabs = [];
  var default_options = ['cnu-tab','cnu-tab-content'];
  
  function toggleTab(el) {
    if (!el.hasClass('focus')) {
      var cnutab = getCnuTab(el);
      var selected_index = CNU.getElIndex(el);
      var current_el = $(cnutab.nav).find('li.focus').eq(0);
      var current_index = CNU.getElIndex(current_el);
      current_el.removeClass('focus');
      var tab_contents = $(cnutab.el).find('.' + cnutab.options[1]);
      tab_contents.eq(current_index).hide();
      $(cnutab.nav).find('li').eq(selected_index).addClass('focus');
      tab_contents.eq(selected_index).show();
    }
  }
  
  function isTab (el) {
    return el.parents('ul.cnu-tabs-nav').length > 0;
  }
  
  function getCnuTab (el) {
    var cnutab = false;
    var cnutab_el = el.parents('.cnu-tabs').eq(0);
    $.each(cnutabs,function(index,value) {
      if (value.el == cnutab_el[0]) { cnutab = value;return; }
    });
    return cnutab;
  }
  
  // ---------------------- handle events
  function getEventTarget (event) {
    var el = $(event.target);
    var tag = el[0].tagName.toLowerCase();
    var type = el[0].type;
    return {'el':el,'tag':tag,'type':type};
  }
  
  function clickEvent (event) {
		var target = getEventTarget(event);
		switch (target.tag) {
		case 'li' :
			if (isTab(target.el)) { toggleTab(target.el); }
			break;
		}
	}
	
	function overEvent (event) {
	  var target = getEventTarget(event);
	  if (isTab(target.el)) {
	    var tab_el = (target.tag != 'li') ? target.el.parents('li').eq(0) : target.el;
	    tab_el.addClass('hover');
	  } 
	}
	
	function outEvent (event) {
		var target = getEventTarget(event);
		var related_el = event.relatedTarget || event.toElement;
		if (related_el !== null) {
			while (related_el != target.el && related_el.nodeName != 'BODY' && related_el.nodeName != 'HTML') {
				related_el = related_el.parentNode;
			}
			if (related_el == target.el) return;
			if (isTab(target.el)) { target.el.removeClass('hover'); }
		}
	}
	
  // initialize
  function initTabs (cnutab_el) {
    var options = CNU.parseClassInfo(cnutab_el) || default_options;
    
    var tabs_html = [];
    cnutab_el.find('.' + options[0]).each(function(index,tab_el) {
      if (index > 0) {
        tabs_html.push('<li class="cnu-tab">' + this.innerHTML + '</li>');
        $(tab_el).next('.' + options[1]).addClass('cnu-tab-content').hide();
      } else {
        tabs_html.push('<li class="cnu-tab focus">' + this.innerHTML + '</li>');
        $(tab_el).next('.' + options[1]).addClass('cnu-tab-content focus');
      }
      $(tab_el).remove();
    });
    
    cnutab_el.prepend('<ul class="cnu-tabs-nav">' + tabs_html.join('') + '</ul>');
    tab_nav_el = cnutab_el.find('ul.cnu-tabs-nav').eq(0);
    cnutab_el.addClass('cnu-tabs-enabled');
    
    // bind events
    cnutab_el.bind({
      "mouseover"  : overEvent,
      "mouseout"  : outEvent,
      "click"       : clickEvent
    });
    
    cnutabs.push({'el':cnutab_el[0],'nav':tab_nav_el[0],'options':options});
  }
  
  // constructor  
  if (cnutab_els) { cnutab_els.each(function() { initTabs($(this)); }); }
  
  // return public methods
  return {}
}($('.cnu-tabs'));


CNU.dialog = function (params) {
  // ========== private    
  var options = {};
  var content = '';
  var dialog_el;
  
  function parse_content (content) {
    // if content is a dom id then grab the elements content to use for the dialog and then remove the element from the dom
    // also check for anchors that might have linked to the element and set their click handlers accordingly
    if (content.substr(0,1) == '#') {
      $('a[href=' + content + ']').click(function (event) {
        event.preventDefault();
        open_dialog();
      });
      var new_content = '<div id="' + content.substr(1) + '">' + $(content).html() + '</div>';
      $(content).remove();
      content = new_content;
    }
    return content;
  }
  
  function close_dialog () {
    dialog_el.dialog('close');
  }
  
  function open_dialog () {
    dialog_el.dialog('open');
  }
  
  function init_form () {
    dialog_el.find('form').each(function () { CNU.Assistant.enable(this); });
  }
  
  // ========== initialize new
  function init (params) {
    options = params.options || {};
    content = params.content || '';
    dialog_el = $('<div></div>').attr('id', options.dialogContentId).addClass(options.dialogContentClass).html(parse_content(content));
    dialog_el.dialog(options);
  }
  if (params) { init(params); }
  
  // ========== return public api
  return {
    init : function (params) { init(params); },
    
    init_bookmark : function (bookmark) { 
      init_open();
      dialog_el.find('#bookmark_brand').click(function () { 
        CNU.util.bookmark(bookmark, location.href);
        close_dialog();
        return false;
      });
    },
    
    el : function () { return dialog_el.dialog('widget'); },
    
    on_open : function () {
      init_form();
      dialog_el.find('.close').click(function (event) { event.preventDefault(); close_dialog(); return false; });
    },
    
    on_close : function () {
       
    },
    
    open : function () { open_dialog(); },
    
    close : function () { close_dialog(); }
  }
};
/* Prevent links from triggering the label target because of Firefox behavior. */
CNU.ev.addLoadEvent(function() {
  $('label a').each(function(){ 
    if (!$(this).hasClass('toggler')) {
      $(this).onclick = function() {
        window.open($(this).attr('href'), $(this).attr('target'));
        return false;
      }
    }
  });
});
CNU.bookmark = {
  add: function (e) { 
    var name = document.title;
    var url = location.protocol + "//" + location.host + location.pathname;
    if (window.sidebar) {
      window.sidebar.addPanel(name, url, "");
    } else if (window.external && (typeof (window.external.AddFavorite) !== "undefined")) { 
      window.external.AddFavorite(url, name);
    } else if (window.opera && window.print) {
      window.external.AddFavorite(url, name);
    } else {
      alert('Your browser does not support this feature.  Please manually bookmark this site.');
    }
    if (window.event) { window.event.returnValue = false; }
    return false;
  },
  is_possible: function () { return (window.sidebar || (window.external && (typeof (window.external.AddFavorite) !== "undefined")) || (window.opera && window.print)); },
  setup_dogear: function () { 
    var a;
    if (CNU.bookmark.is_possible()) { 
      a = document.createElement("a");
      a.id = "js-bookmark";
      a.href = "#";
      a.innerHTML = "Bookmark This Page!";
      a.onclick = CNU.bookmark.add; 
      $("body").eq(0)[0].appendChild(a);
    }
  },
  setup: function () {
    if (CNU.bookmark.is_possible()) { 
      $('#account_home_bookmark').css('display','block');
      $('#promo_bookmark_link').click(CNU.bookmark.add);
    } else {
      $('#account_home_bookmark').remove();
    }
  }
};

// submit once tag
CNU.ev.addLoadEvent(function () {
  $('input.submit_once').each(function() {
    var spinner_id = $(this).attr('id').replace('submit','spinner');
    $(this).after('<img src="/images/spin.gif" style="display:none;" id="' + spinner_id + '" />').click(function(event) {
      $(this).hide().next('img').show();
    });
  });
});


CNU.toggler = function (toggle_links) {
  // private
  var togglers = [];
  var t_class_pre = 'toglr_';
  var t_class_el = 'element';
  var t_class_active = 'active';
  var t_class_open = 'open';
  var t_class_closed = 'closed';
  var t_class_close_link = 'close';
  var t_class_hover = 'hover';
  
  function parseClass (c_name) {
    var pre_len = t_class_pre.length;
    return (c_name.substr(0,pre_len) == t_class_pre) ? c_name.substr(pre_len) : false;
  }
  
  function initTogglerElement (t_link) {
    var t_id = false;
    var el_class_names = t_link.attr('class');
    var tmp = el_class_names.split(' ');
    if (typeof tmp === 'object' && tmp.length > 0) {
      $.each(tmp,function (index,c_name) {
        t_id = parseClass(c_name);
        if (t_id !== false) { return; }
      });
    } else if (typeof el_class_names === 'string' && el_class_names != '') {
      t_id = parseClass(el_class_names);
    }
    return (t_id !== false && $('#'+t_id).length > 0) ? $('#'+t_id).eq(0) : false;
  }
  
  function findTogglerLink (t_el) {
    var t_link;
    if (t_el.hasClass(t_class_pre + t_class_close_link)) {
      t_el = t_el.parents('.' + t_class_pre + t_class_el);
    }
    
    $.each(togglers,function(index,value) {
      if (value.t_el == t_el[0]) { t_link = $(value.t_link);return; }
    });
    
    return t_link;
  }
  
  function findTogglerElement (t_link) {
    var t_el;
    
    $.each(togglers,function(index,value) {
      if (value.t_link == t_link[0]) { t_el = $(value.t_el);return; }
    });
    
    return t_el;
  }
    
  function addCloseLink (t_el) {
    var close_link_html = '<span class="' + t_class_pre + t_class_close_link + ' ">Close<\/span>';
    if (t_el.is('ol,ul')) { close_link_html = '<li>' + close_link_html + '</li>'; }
    t_el.append(close_link_html);
    return t_el.find('span.' + t_class_pre + t_class_close_link).eq(0);
  }
  
  function closeToggler(t_link) {
    var t_el = findTogglerElement(t_link);
    t_el.hide('blind', {}, 300);
    t_link.removeClass(t_class_pre + t_class_open);
    t_link.addClass(t_class_pre + t_class_closed);
  }
  
  function openToggler(t_link) {
    var t_el = findTogglerElement(t_link);
    t_el.show('blind', {}, 300);
    t_link.removeClass(t_class_pre + t_class_closed);
    t_link.addClass(t_class_pre + t_class_open);
  }
  
  
  // ---------------------- handle events
  function getEventTarget (event) {
    var el = $(event.target);
    var tag = el[0].tagName.toLowerCase();
    var type = el[0].type;
    return {'el':el,'tag':tag,'type':type};
  }
  
  function enterEvent (event) {
    var target = getEventTarget(event);
    if (target.el.hasClass(t_class_pre + t_class_active)) { target.el.addClass(t_class_pre + t_class_hover); }
  }
  
  function leaveEvent (event) {
    var target = getEventTarget(event);
    if (target.el.hasClass(t_class_pre + t_class_active)) { target.el.removeClass(t_class_pre + t_class_hover); }
  }
  
  function clickEvent (event) {
    var target = getEventTarget(event);
    if (target.el.hasClass(t_class_pre + t_class_close_link)) {
      closeToggler(findTogglerLink(target.el));
    } else {
      if (target.el.hasClass(t_class_pre + t_class_closed)) {
        openToggler(target.el);
      } else if (target.el.hasClass(t_class_pre + t_class_open)) {
        closeToggler(target.el);
      }
    }
    return false;
  }
  
  function initToggler (t_link) {
    var t_el = initTogglerElement(t_link);
    
    if (t_el !== false) {
      // check if defaults to "open"
      if (!t_link.hasClass(t_class_pre + t_class_open)) {
        t_el.hide();
        t_link.addClass(t_class_pre + t_class_closed);
      }
      
      t_el.addClass(t_class_pre + t_class_el);
      t_link.addClass(t_class_pre + t_class_active);
    
      // set events
      t_link.bind({
        "mouseenter"  : enterEvent,
        "mouseleave"  : leaveEvent,
        "click"       : clickEvent
      });
      
      // add a close link
      // Hack: inputs cannot have additional text.
      if (!t_el.is('input')) {
        addCloseLink(t_el).click(clickEvent);
      }
      
      togglers.push({'t_link':t_link[0],'t_el':t_el[0]});
    }
  }
  
  // constructor  
  if (toggle_links) { toggle_links.each(function() { initToggler($(this)); }); }

  // public
  return {};
}($('.toggler'));


CNU.local_date_from_server_date = function(server_date) {
  if(typeof CNU.config.server_timestamp !== 'number' ||
     typeof CNU.local_timestamp  !== 'number') {
    /* Not enough information to convert.  Best we can do is assume server date == local date. */
    return server_date;
  }

  var seconds_diff = CNU.config.server_timestamp - CNU.local_timestamp;
  var local = new Date(server_date.getTime() - seconds_diff*1000);
  return local;
}


// ============= CNU.countdown_clock
CNU.countdown_clock = function() {
  var defaults = {  'digits'        : ['seconds','minutes','hours','days','weeks'],
                    'reload'        : false, // can be true or a params object
                    'preload'       : null,
                    'utc'           : true,
                    'on_complete'   : null,
                    'target_date'   : null,
                    'separator'     : ':'
                  };
  
  
  function generate_clock_digits (params) {
    var digits = [];
    $.each(params.digits,function(i,type) { digits.push('<span class="digit ' + type + '">00</span>'); });
    return digits.join('<span class="separator">' + params.separator + '</span>');
  }  
  
  function parse_target_date (date) {
    var target_date = null;
    if (typeof date == 'string') {
      date = $.trim(date);
      eval('target_date = ' + date + ';');
      if (typeof target_date == 'function') {
        date = target_date();
      } else if (typeof target_date == 'number') {
        date = target_date * 1000; // convert timestamp to milliseconds for js use
      }
    } else if (typeof date == 'function') {
      date = date();
    }

    if(date === null) {
      return null;
    } else if(date instanceof Date) {
      return date;
    } else {
      return new Date(date);
    }
  }
  
  function parse_on_complete (countdown_clock,params) {
    var on_complete = params.on_complete;
    if (on_complete) {
      var eval_str = '';
      if (typeof on_complete == 'string') {
        eval_str = $.trim(on_complete);
        if (eval_str.substr(0,8) != 'function') {
          if (eval_str.charAt(eval_str.length - 1) != ')') { eval_str += '(countdown_clock);'; }
          eval_str = 'function(){' + eval_str + reload_action(params.reload) + '}';
        }
      } else if ($.isArray(on_complete)) {
        var function_name = on_complete.shift();
        var function_params = (on_complete.length === 1) ? on_complete[0] : on_complete;
        eval_str = 'function(){' + function_name + '(countdown_clock,function_params);' + reload_action(params.reload) + '}';
      }
    } else {
      eval_str = 'function(){' + reload_action(params.reload) + '}';
    }
    eval('on_complete = ' + eval_str + ';');
    return on_complete;
  }
  
  function parse_preload (countdown_clock,preload) {
    if (preload) {
      var eval_str = '';
      if (typeof preload == 'string') {
        eval_str = $.trim(preload);
        if (eval_str.charAt(eval_str.length - 1) != ')') { eval_str += '(countdown_clock);'; }
      } else if ($.isArray(preload)) {
        var function_name = preload.shift();
        var function_params = (preload.length === 1) ? preload[0] : preload;
        eval_str = function_name + '(countdown_clock,function_params);';
      }
      eval(eval_str);
    }
  }
  
  function reload_action (reload) {
    return (reload != false) ? 'reload_countdown(countdown_clock' + ((typeof reload == 'object') ? ',reload' : '') + ');' : '';
  }
  
  function begin_countdown (countdown_clock) {
    var params = countdown_clock.data('cnu-params');
    countdown_clock.removeClass('expired');
    // run preload function if necessary
    parse_preload(countdown_clock,params.preload);
    // insert the clock
    countdown_clock.html(generate_clock_digits(params)).show();
    // start the countdown
    countdown(countdown_clock);
  }
  
  function countdown (countdown_clock) {
    var $this = $(countdown_clock);
    var $data = $this.data('cnu-params');
    var target_date = $data.target_date;
    var now = new Date();
    var seconds_left = Math.floor((target_date.valueOf()-now.valueOf())/1000);
    var time = {};
    time.seconds = seconds_left % 60;
    time.minutes = Math.floor(seconds_left/60)%60;
    time.hours = Math.floor(seconds_left/60/60)%24;
    time.days = Math.floor(seconds_left/60/60/24)%7;  
    
    $.each($data.digits,function(i,digit) {
      var n = time[digit];
      if (n < 10) { n = '0' + n; }
      $this.find('.digit.' + digit).html(n);
    });
    
    if (seconds_left <= 0) {
      clearTimeout($data.timer);
      countdown_clock.addClass('expired');
      if (typeof $data.on_complete == 'function') {
        setTimeout(function() { $data.on_complete(); }, 1000);
      }
    } else {
      countdown_clock.data('cnu-params').timer = setTimeout(function() { CNU.countdown_clock.countdown(countdown_clock); }, 1000);
    }
  }
  
  function stop_countdown (countdown_clock) {    
    clearTimeout(countdown_clock.data('cnu-params').timer);
  }
  
  function start_countdown (countdown_clock) {
    CNU.countdown_clock.countdown(countdown_clock);
  }
  
  function reload_countdown (countdown_clock,overrides) {
    CNU.countdown_clock.init(countdown_clock,overrides);
  }
  
  // initialize
  function init (countdown_clock,overrides) {
    var cc = $(countdown_clock);
    // set the runtime parameters
    var el_data = cc.attr('data-cnu-params') || '{}';
    var params = $.extend({}, defaults, $.parseJSON(el_data));
    if (overrides) { params = $.extend(params, overrides); }
    // set the on_complete handler if needed
    params.on_complete = parse_on_complete(cc,params);
    // set the target date
    params.target_date = parse_target_date(params.target_date);
    // no target date, short circuit initialization
    if(params.target_date == null) {
      return;
    }
    // attach params to countdown element
    countdown_clock.data('cnu-params', params);
    
    begin_countdown(cc);
  }
  
  // public methods
  return {
    'init'      : function (el,params) { init(el,params); },
    'stop'      : function (el) { stop_countdown(el); },
    'start'     : function (el) { start_countdown(el); },
    'countdown' : function (el)  { countdown(el); }
  };
}();

// initial dom load of countdown clocks
$(document).ready(function() {
  $('.cnu-countdown-clock').each(function() {
    var $this = $(this);
    var clock_active = true;
    
    if ($this.attr('data-cnu-type') == 'seo-funding') {
      if (CNU.config.SEO_FUNDING_CLOCK_ENABLED) {
        $this.attr('data-cnu-params', '{"digits" : ["minutes","seconds"], "target_date" : "CNU.funding_countdown_target_date", "reload" : true, "preload" : "CNU.funding_countdown_preload"}');
      } else { clock_active = false; }
    } else if ($this.attr('data-cnu-type') == 'funding')  {
      clock_active = CNU.config.APP_FUNDING_CLOCK_ENABLED;
    }
    
    if (clock_active) {
      CNU.countdown_clock.init($this);
    }
  });
});

// ============= funding-specific countdown_clock
CNU.funding_countdown_preload = function (countdown_clock) {
  var now = new Date();
  var funding_date = CNU.funding_countdown_target_date();
  var milliseconds_diff = funding_date - now;
  // if funding date is more than an hour away do not show the countdown clock
  if ( milliseconds_diff > (60*60*1000) ) {
    countdown_clock.parent().hide();
    countdown_clock.parents().find('form#quick_application fieldset.applicant_information').css({'background-image':'hour_funding.gif','padding-top':'50px'});
    countdown_clock.parents().find('div.onehour-seal').show();
    countdown_clock.parents().find('div#cnu_advantage').show();
  } else {
    // hide other references to 1-hour funding below the countdown clock
    countdown_clock.parents().find('form#quick_application fieldset.applicant_information').css({'background-image':'none','padding-top':'0'});
    countdown_clock.parents().find('div.onehour-seal').hide();
    countdown_clock.parents().find('div#cnu_advantage').hide();
    countdown_clock.parent().show();
  }
};

CNU.funding_countdown_target_date = function () {
  var now = new Date();
  while(CNU.config.FUNDING_CUTOFF_TIMES.length > 0) {
    var next_funding = CNU.local_date_from_server_date(new Date(CNU.config.FUNDING_CUTOFF_TIMES[0]));
    if(now >= next_funding) {
      CNU.config.FUNDING_CUTOFF_TIMES.shift();
    } else {
      return next_funding;
    }
  }
  return null;
};


