// https://github.com/jquery/jquery/blob/2.1.3/src/manipulation/var/rcheckableType.js
// https://github.com/jquery/jquery/blob/2.1.3/src/serialize.js
var _ = require('lodash'),
    submittableSelector = 'input,select,textarea,keygen',
    rCRLF = /\r?\n/g,
    rcheckableType = /^(?:checkbox|radio)$/i,
    rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i;

exports.serializeArray = function() {
  // Resolve all form elements from either forms or collections of form elements
  var Cheerio = this.constructor;
  return this.map(function() {
      var elem = this;
      var $elem = Cheerio(elem);
      if (elem.name === 'form') {
        return $elem.find(submittableSelector).toArray();
      } else {
        return $elem.filter(submittableSelector).toArray();
      }
    }).filter(function() {
      var $elem = Cheerio(this);
      var type = $elem.attr('type');

      // Verify elements have a name (`attr.name`) and are not disabled (`:disabled`)
      return $elem.attr('name') && !$elem.is(':disabled') &&
        // and cannot be clicked (`[type=submit]`) or are used in `x-www-form-urlencoded` (`[type=file]`)
        !rsubmitterTypes.test(type) &&
        // and are either checked/don't have a checkable state
        ($elem.attr('checked') || !rcheckableType.test(type));
    // Convert each of the elements to its value(s)
    }).map(function(i, elem) {
      var $elem = Cheerio(elem);
      var name = $elem.attr('name');
      var val = $elem.val();

      // If there is no value set (e.g. `undefined`, `null`), then return nothing
      if (val == null) {
        return null;
      } else {
        // If we have an array of values (e.g. `<select multiple>`), return an array of key/value pairs
        if (Array.isArray(val)) {
          return _.map(val, function(val) {
            // We trim replace any line endings (e.g. `\r` or `\r\n` with `\r\n`) to guarantee consistency across platforms
            //   These can occur inside of `<textarea>'s`
            return {name: name, value: val.replace( rCRLF, '\r\n' )};
          });
        // Otherwise (e.g. `<input type="text">`, return only one key/value pair
        } else {
          return {name: name, value: val.replace( rCRLF, '\r\n' )};
        }
      }
    // Convert our result to an array
    }).get();
};
