(function ($) {

/**
 * Enhancements to states.js.
 */

/**
 * Handle array values.
 * @see http://drupal.org/node/1149078
 */
Drupal.states.Dependent.comparisons['Array'] = function (reference, value) {
  // Make sure value is an array.
  if (!(typeof(value) === 'object' && (value instanceof Array))) {
    return false;
  }
  // We iterate through each value provided in the reference. If all of them
  // exist in value array, we return true. Otherwise return false.
  for (var key in reference) {
    if (reference.hasOwnProperty(key) && $.inArray(reference[key], value) < 0) {
      return false;
    }
  }
  return true;
};

/**
 * Handle Object values.
 */
Drupal.states.Dependent.comparisons['Object'] = function (reference, value) {
  /* Regular expressions are objects with a RegExp property. */
  if (reference.hasOwnProperty('RegExp')) {
    reference = new RegExp(reference.RegExp);
    return this.RegExp(reference, value);
  }
  else {
    return compare(reference, value);
  }
};

/**
 * Focused condition.
 */
Drupal.states.Trigger.states.focused = function(element) {
  element.bind('focus', function () {
    element.trigger({ type: 'state:focused', value: true });
  })
  .bind('blur', function () {
    element.trigger({ type: 'state:focused', value: false });
  });

  Drupal.states.postponed.push($.proxy(function () {
    element.trigger({ type: 'state:focused', value: element.is(':focus') });
  }, window));
};

/**
 * Touched condition.
 */
Drupal.states.Trigger.states.touched = {
  'focus': function(e) {
    return (typeof e === 'undefined' && !this.is(':focus')) ? false : true;
  }
};

/**
 * New and existing states enhanced with configurable options.
 * Event names of states with effects have the following structure:
 * state:stateName-effectName.
 */

// Visible/Invisible.
$(document).bind('state:visible-fade', function(e) {
  if (e.trigger) {
    $(e.target).closest('.form-item, .form-submit, .form-wrapper')[e.value ? 'fadeIn' : 'fadeOut'](e.effect.speed);
  }
})
.bind('state:visible-slide', function(e) {
  if (e.trigger) {
    $(e.target).closest('.form-item, .form-submit, .form-wrapper')[e.value ? 'slideDown' : 'slideUp'](e.effect.speed);
  }
})
// Empty/Filled.
.bind('state:empty-empty', function(e) {
  if (e.trigger) {
    var field = $(e.target).find('input, select, textarea');
    if (e.effect.reset) {
      if (typeof oldValue == 'undefined' || field.val() !== e.effect.value) {
        oldValue = field.val();
      }
      field.val(e.value ? e.effect.value : oldValue);
    }
    else if (e.value) {
      field.val(e.effect.value);
    }
  }
})
.bind('state:empty-fill', function(e) {
  if (e.trigger) {
    var field = $(e.target).find('input, select, textarea');
    if (e.effect.reset) {
      if (typeof oldValue === 'undefined' || field.val() !== e.effect.value) {
        oldValue = field.val();
      }
      field.val(!e.value ? e.effect.value : oldValue);
    }
    else if (!e.value) {
      field.val(e.effect.value);
    }
  }
})
// Unchanged state. Do nothing.
.bind('state:unchanged', function() {});

Drupal.behaviors.conditionalFields = {
  attach: function (context, settings) {
    // AJAX is not updating settings.conditionalFields correctly.
    var conditionalFields = settings.conditionalFields || Drupal.settings.conditionalFields;
    if (typeof conditionalFields === 'undefined' || typeof conditionalFields.effects === 'undefined') {
      return;
    }
    // Override state change handlers for dependents with special effects.
    var eventsData = $.hasOwnProperty('_data') ? $._data(document, 'events') : $(document).data('events');
    $.each(eventsData, function(i, events) {
      if (i.substring(0, 6) === 'state:') {
        var originalHandler = events[0].handler;
        events[0].handler = function(e) {
          var effect = conditionalFields.effects['#' + e.target.id];
          if (typeof effect !== 'undefined') {
            var effectEvent = i + '-' + effect.effect;
            if (typeof eventsData[effectEvent] !== 'undefined') {
              $(e.target).trigger({ type : effectEvent, trigger : e.trigger, value : e.value, effect : effect.options });
              return;
            }
          }
          originalHandler(e);
        }
      }
    });
  }
};

})(jQuery);
