'use strict';

var mixin = require('mixin-deep');
var defaults = require('defaults-deep');

var defaultOptions = { overwrite: true };

function regulate(anyValues, anyPromotions, anyEliminations, optionalOptions) {
	var eliminations, promotions, options, assign;

	promotions = _arrayify(anyPromotions);
	eliminations = _arrayify(anyEliminations);
	options = defaults(optionalOptions, defaultOptions);
	assign = options.overwrite ? mixin : defaults;
	return _regulate(anyValues);

	function _regulate(values) {
		if (Array.isArray(values)) {
			return values.map(_regulate);
		}
		if (isObject(values)) {
			return _eliminate(_promote(values));
		}
		return values;
	}

	function _promote(values) {
		return _each(values, __promote);

		function __promote(value, key, result) {
			if (includes(promotions, key) && isObject(value)) {
				return assign(result, _regulate(value));
			}
		}
	}

	function _eliminate(values) {
		return _each(values, __eliminate);

		function __eliminate(value, key, result) {
			if (includes(eliminations, key)) {
				return result;
			}
		}
	}

	function _each(values, fn) {
		return Object.keys(values).reduce(_property, {});

		function _property(result, key) {
			var value;

			value = values[key];
			return fn(value, key, result) || (result[key] = _regulate(value), result);
		}
	}
}

function _arrayify(value) {
	if (Array.isArray(value)) {
		return value;
	}
	if (isString(value)) {
		return [value];
	}
	return [];
}

function isString(value) {
	return typeof value === 'string';
}

function isObject(value) {
	return !!value && typeof value === 'object' && !Array.isArray(value);
}

function includes(array, value) {
	return array.indexOf(value) !== -1;
}

module.exports = regulate;

@@ -361,31 +361,26 @@
 efaults(
+_
 option
-alOptions
+s()
 , defaul
@@ -438,16 +438,16 @@
 faults;%0A
-
 %09return 
@@ -469,16 +469,242 @@
 lues);%0A%0A
+%09function _options() %7B%0A%09%09if (optionalOptions) %7B%0A%09%09%09return optionalOptions;%0A%09%09%7D%0A%09%09if (anyEliminations && typeof anyEliminations === 'object' && !Array.isArray(anyEliminations)) %7B%0A%09%09%09return anyEliminations;%0A%09%09%7D%0A%09%09return %7B%7D;%0A%09%7D%0A%0A
 %09functio

allow skip eliminations