/** 
 * jQuery validity Plugin.
 * @author mderting
 * @author yqian
 * @version 2.0.0 $Revision: 6115 $ ($Author: $)
 */
(function( $ ) {
  
  /**
   * Default Settings.
   * @see http://docs.jquery.com/Plugins/Authoring#Defaults_and_Options
   */
  var settings = {
  validateOnSubmit: true,
  validateOnBlur: true,
  focusOnError: true,
    debug: false
  };

  /**
   * jQuery validity Plugin Methods.
   * @see http://docs.jquery.com/Plugins/Authoring#Plugin_Methods
   */
  var methods = {
    init: function( options ) {

      this.each(function() {
        var data, dataId, opts,
            $this = $(this);

        $this.validity('options', options);
        data = $this.data('validity') || {};
        opts = data.options;

        // Reset hidden, disabled, and flow inputs, then force reload to handle back button.
        if ($this.attr('id') == "requester-form") {
          var submitButton = $this.find(':input[type="submit"]').first(),
            sendInput = $this.find(':input[name="send"]').first();
          $(':input.flow', $this).val('');
          if ((sendInput && sendInput.val() == "true") 
              || submitButton.attr('disabled') == "disabled") {
          sendInput.value = "";
          submitButton.removeAtt('disabled');
          debug("sendInput value is: " + sendInput.val());
          debug("submitButton.attr('disabled') is: " + submitButton.attr('disabled'));
          window.location.reload();
          return;
          }
          if (jQuery.browser.safari && $this.find(':input[name="token"]').length > 0) {
            $this.find(':input[name="token"]')[0].type = "text";
          }
        }
        // If the plugin hasn't been initialized yet
        if ( !data.validity ) {
          dataId = +new Date;

          data = {
            validity: validity,
            options: opts,
            id: dataId
          };

          $this.data('validity', data);
          
          // create element
          var validity = $('<div />', {
            'class': 'validity'
          });

          validity.data( 'validity', {target: $this, id: dataId} );

          // Loop through each input and attach data to the validity namespace.
          // Then bind the blur event within the validity namespace to methods.validate.
          // @see http://docs.jquery.com/Plugins/Authoring#Events
          // @see http://docs.jquery.com/Plugins/Authoring#Data
          $(':input', $this).each(function() {
            var $thisField = $(this),
                fieldData = $thisField.data( 'validity' ) || {};
          });
          
          $('#bday').dateinput({
            value: new Date(new Date().getFullYear()-18, new Date().getMonth(), new Date().getDate()),
            format: 'mm/dd/yyyy',           // the format displayed for the user
            selectors: true,                // whether month/year dropdowns are shown
            yearRange: [-70,50],
            max: new Date(new Date().getFullYear()-10, new Date().getMonth(), new Date().getDate()),
            min: new Date(new Date().getFullYear()-70, new Date().getMonth(), new Date().getDate()+1),
            onHide: function(event) {
              var $thisInput = event.target.getInput();
              $thisInput.trigger('blur.validity', [true]);
            }
          });

          // Bind Event Handler to validate form on submit.
          $this.bind('submit.validity', methods.validate);
          
          // Delegate Event Handler to validate inputs on blur.
          $this.delegate(':input:not(:submit)', 'blur.validity', methods.validate);
          
          // Delegate Event Handler to hide dateinput control on focus.
          $this.delegate(':input:not(:date)', 'focus.validity', methods.hideDateInputs);
          
          // Delegate Event Handler to update flow for multistep forms on change.
          $this.delegate(':input.flow', 'change.validity', methods.updateFlow);
          
          // Delegate Event Handler to show addable fields on click.
          $this.delegate(':button.add', 'click.validity', methods.showAddable);
          
        } // !data.validity

        

      });

      return this;
    },
    destroy: function( ) {

      this.each(function() {

        var $this = $(this),
            data = $this.data( 'validity' );

        // Remove created elements, unbind namespaced events, and remove data
        $(document).unbind( '.validity' );
        data.validity.remove();
        $this.unbind( '.validity' )
        .removeData( 'validity' );

      });

      return this;
    },
    options: function( options ) {

      this.each(function() {
        var $this = $(this),
            // don't use our getData() function here
            // because we want an object regardless
            data = $this.data( 'validity' ) || {},
            opts = data.options || {};

        // deep extend (merge) default settings, per-call options, and options set with:
        // html5 data-validity options JSON and $('selector').validity( 'options', {} );
        opts = $.extend( true, {}, $.fn.validity.defaults, opts, options || {} );
        data.options = opts;
        $.data( this, 'validity', data );
      });

      return this;
    },
    updateFlow: function(event) {
      var $this = $(event.target),
      $thisForm = $this.closest('form'),
      url = ($('input[name=handle]', $thisForm)) ? $('input[name=handle]', $thisForm).val() : $thisForm.attr('action'),
      dl = $this.closest('dl'),
      next = dl.next();
      
      while (dl.next().size() > 0) {
        var next = dl.next()[0];
        if($(next).hasClass("button-wrapper") && $this.val() ==""){
            break;
        }else{
            $(next).remove();
        }
      }
      
      var fieldset = $this.closest('fieldset');
      
      var data = $thisForm.serializeArray();
      data[data.length] = { "name": "format", "value": "json" };
      data[data.length] = { "name": "eventType", "value": event.type };
      data[data.length] = { "name": "next", "value": "Next" };
      if($this.val()!=""){
    	  $.post(url + ".html?",
    	          data,
    	          function(data) {
    	          // Update fieldset with response.
    	          fieldset.append(data);
    	          // init dateinputs
    	          $(':input:date', fieldset).not('#bday').each(function() {
    	            debug('initialize dateinput with id: ' + $(this).attr('id'));
    	            $(this).dateinput({
    	            value: new Date(new Date().getFullYear()-18, new Date().getMonth(), new Date().getDate()),
    	            format: 'mm/dd/yyyy',           // the format displayed for the user
    	            selectors: true,                // whether month/year dropdowns are shown
    	            yearRange: [-40,50],
    	            max: new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()),
    	            min: new Date(new Date().getFullYear()-40, new Date().getMonth(), new Date().getDate()),
    	            onHide: function(event) {
    	              var $thisInput = event.target.getInput();
    	              $thisInput.trigger('blur.validity', [true]);
    	            }
    	            });
    	            });
    	          // Call to netinsight trackFormEventQuestionServed
    	          if ($(':input#send', fieldset).size() == 0) {
    	            $(':input.flow:last', fieldset).netinsight('trackFormEventQuestionServed', '');
    	          } else {
    	            $(':input#send', fieldset).netinsight('trackFormEventQuestionServed', '');
    	          }
    	          // init hints
    	          if ($.browser.msie && $.browser.version=="6.0") {
    	            $("a.hint").click(function(){
    	              window.open($this.attr('href'), 'hintWindow','width=550,height=450,scrollbars=yes,resizable=yes');
    	              return false;
    	            });
    	            } else {
    	              $('a.hint').each(function() {
    	                $(this).overlay({
    	                  mask: '#789',
    	                  onBeforeLoad: function() {
    	                    // grab wrapper element inside content
    	                    var wrap = this.getOverlay().find(".contentWrap");
    	                    // load the page specified in the trigger
    	                    wrap.load(this.getTrigger().attr("href"));
    	                  }
    	                });
    	              });
    	            }
    	        },
         		  'string');
        }
      return true;
    },
    validate: function(event, proceed) {
      var $this = $(event.target),
          $thisForm = $this.closest('form'),
          url = ($('input[name=handle]', $thisForm)) ? $('input[name=handle]', $thisForm).val() : $thisForm.attr('action');

      debug("inside validate");
      
      /* If this is a date input, and the calendar is open, 
       * stop propagation so that using the calendar does not cause a 
       * validation message to be shown.
       */
      if ($this.is(':date') && $this.data("dateinput").isOpen() && !proceed) {
        return false;
      }
      
      var data = $thisForm.serializeArray();
      data[data.length] = { "name": "format", "value": "json" };
      data[data.length] = { "name": "eventType", "value": event.type };
      
      $.post(url + ".html?",
          data,
          function(data) { return methods.updateMessages($this, data); },
          'json');
      return false;
    },
    hideDateInputs: function(event) {
      var $this = $(event.target),
          $thisForm = $this.closest('form'),
          $dateInputs = $('input:date', $thisForm);
      
      debug("Inside hideDateInput method");
      if ($dateInputs.length > 0 
        && $dateInputs.data("dateinput") 
        && $dateInputs.data("dateinput").isOpen()) {
      $($dateInputs).data("dateinput").hide();
      }
    },
    showAddable: function(event) {
      var $this = $(event.target).closest('button'),
          $thisFieldset = $this.closest('fieldset'),
          $thisDls = $('dl.addable', $thisFieldset);
      
      debug("inside showAddable method");

      $thisDls.first().removeClass('addable');
      if ($thisDls.length == 1) {
        $this.remove();
      }
    },
    updateMessages: function(el, data) {
      debug("inside updateMessages");
      var $this = $(el),
          $thisForm = $this.closest('form'),
          json = data,
          dls = ($this.is('form')) ? $('dl.error', $this) : $this.closest('dl');
      
      debug('update messages using $this : ' + $this.attr('id'));
      
      methods.resetMessages(dls);
      
      if (data.jsonErrors) {
          json = data.jsonErrors;
      }


      // Display field error messages
      if (json.length) {
        debug('json.length is : ' + json.length);
        // If $this is a form, loop through all jsonErrors and add error messages to their corresponding fields.
        if ($this.is('form')) {
          $.each(json, function(i, item) {
            var dl = $(':input[name="' + item.field + '"]', $this).closest('dl');
            $(dl).addClass('error');
            $(dl).find('dd.message').html('<p>' + item.message + '</p>').addClass('ui-state-error');
            if($('p#'+item.field, $this).length>0){
            	$('p#'+item.field, $this).html(item.message);
                if(item.message.indexOf("success") != -1){
                	setTimeout( function() {
                		$("#send-location-link a").each(function(){$(this).overlay().close()});
                      }, 3000 );
                }else{
                	$('p#'+item.field, $this).addClass("error");
                }
              }
          });
        } else {
          var fieldset = $this.closest('fieldset');
          if ($(fieldset).hasClass('group')) {
            var inputs = $(':input', $(fieldset)),
                dls = $('dl', $(fieldset));
            methods.resetMessages(dls);
          } else {
            var inputs = $this;
          }
          inputs.each(function(n){
            $.each(json, function(i, item) {
              var $thisInput = inputs[n],
                  dl = $(':input[name="' + item.field + '"]', $thisForm).closest('dl');

              if ( $thisInput.name == item.field ) {
                $(dl).addClass('error');
                $(dl).find('dd.message').html('<p>' + item.message + '</p>').addClass('ui-state-error');
              }
            });
          });
        }
      } else if ($this.is('form')) {
        $this.unbind('submit.validity', methods.validate);
        // prevent double submissions
        $this.find(':input[type="submit"]').attr('disabled','disabled');
        if ($this.attr('id') == "requester-form") {
          $this.find(':input[name="send"]').attr('value', 'true');
        }
        $this.submit();
        debug("returning false on form submit event");
        return false;
      }
      return false;
    },
    resetMessages: function(dls) {
      $(dls).find('dd.message').html('<p>&#xA0;</p>').removeClass('ui-state-error');
      $(dls).removeClass('error');
      if($(".result-message").length>0){
          $(".result-message").html('&#xA0;')
          $(".result-message").removeClass('error');
      }
    }
    
  };

  var protoSlice = Array.prototype.slice;

  $.fn.validity = function( method ) {

    if ( methods[method] ) {
      return methods[method].apply( this, protoSlice.call( arguments, 1 ) );
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.fn.validity' );
    }

  };

  $.extend($.fn.validity, {
    defaults: settings,
    version: '2.0.0',
    jQueryVersionRequired: '1.4.3'
  });

  function getData(el) {
    var validity, opts,
        $this = $(el),
        data = $this.data( 'validity' ) || {};

    if (!data.validity) { return false; }

    return data;
  }

  /**
   * Prints to Firebug console, if available. To enable:
   *   $.fn.validity.defaults.debug = true;
   */
  function debug(message) {
    if (typeof console != 'undefined' && typeof console.debug != 'undefined' && $.fn.validity.defaults.debug) {
      console.debug(message);
    }
  };
})( jQuery );

