import { EMPTY_BASE, NON_DIMENSION_PROPS } from './constants';


/** Copy own-properties from `props` onto `obj`.
 *	@returns obj
 *	@private
 */
export function extend(obj, props) {
	if (props) {
		for (let i in props) {
			if (props[i]!==undefined) {
				obj[i] = props[i];
			}
		}
	}
	return obj;
}


/** Fast clone. Note: does not filter out non-own properties.
 *	@see https://esbench.com/bench/56baa34f45df6895002e03b6
 */
export function clone(obj) {
	return extend({}, obj);
}


/** Create a caching wrapper for the given function.
 *	Note: As this method is only used for memoizing string operations, it does not safeguard against Object.prototype manipulation.
 *	@private
 */
export function memoize(fn) {
	let mem = {};
	return k => mem[k] || (mem[k] = fn(k));
}


/** Get a deep property value from the given object, expressed in dot-notation.
 *	@private
 */
export function delve(obj, key) {
	for (let p=key.split('.'), i=0; i<p.length && obj; i++) {
		obj = obj[p[i]];
	}
	return obj;
}


/** Convert an Array-like object to an Array
 *	@private
 */
export function toArray(obj, offset) {
	return [].slice.call(obj, offset);
}


/** @private is the given object a Function? */
export function isFunction(obj) {
	return 'function'===typeof obj;
}


/** @private is the given object a String? */
export function isString(obj) {
	return 'string'===typeof obj;
}


/** Check if a value is `null` or `undefined`.
 *	@private
 */
export function empty(x) {
	return x===undefined || x===null;
}


/** Check if a value is `null`, `undefined`, or explicitly `false`. */
export function falsey(value) {
	return value===false || empty(value);
}


/** Convert a hashmap of styles to CSSText
 *	@private
 */
export function styleObjToCss(s) {
	let str = '';
	for (let prop in s) {
		let val = s[prop];
		if (!empty(val)) {
			if (str) str += ' ';
			str += jsToCss(prop);
			str += ': ';
			str += val;
			if (typeof val==='number' && !NON_DIMENSION_PROPS[prop]) {
				str += 'px';
			}
			str += ';';
		}
	}
	return str;
}



/** Convert a hashmap of CSS classes to a space-delimited className string
 *	@private
 */
export function hashToClassName(c) {
	let str = '';
	for (let prop in c) {
		if (c[prop]) {
			if (str) str += ' ';
			str += prop;
		}
	}
	return str;
}



/** Convert a JavaScript camel-case CSS property name to a CSS property name
 *	@private
 *	@function
 */
export const jsToCss = memoize( s => toLowerCase(s.replace(/([A-Z])/g,'-$1')) );


/** Just a memoized String.prototype.toLowerCase */
export const toLowerCase = memoize( s => s.toLowerCase() );


// For animations, rAF is vastly superior. However, it scores poorly on benchmarks :(
// export const setImmediate = typeof requestAnimationFrame==='function' ? requestAnimationFrame : setTimeout;

let ch;
try { ch = new MessageChannel(); } catch (e) {}

/** Call a function asynchronously, as soon as possible.
 *	@param {Function} callback
 */
export const setImmediate = ch ? ( f => {
	ch.port1.onmessage = f;
	ch.port2.postMessage(EMPTY_BASE);
}) : setTimeout;

@@ -5,20 +5,8 @@
 rt %7B
- EMPTY_BASE,
  NON
@@ -2765,65 +2765,8 @@
 t;%0A%0A
-let ch;%0Atry %7B ch = new MessageChannel(); %7D catch (e) %7B%7D%0A%0A
 /** 
@@ -2848,24 +2848,90 @@
 allback%0A */%0A
+let resolved = typeof Promise!=='undefined' && Promise.resolve();%0A
 export const
@@ -2950,82 +2950,45 @@
 e = 
-ch
+resolved
  ? (
- 
 f =%3E %7B
-%0A%09ch.port1.onmessage = f;%0A%09ch.port2.postMessage(EMPTY_BASE);%0A
+ resolved.then(f); 
 %7D) :

Switch `setImmediate` implementation from using `MessageChannel` as an async deferral to `Promise.resolve().then()`. This is [much faster](https://esbench.com/bench/55d4d44e2efbca1100bf7251), *however* it comes with the caveat of being unusable for animation. While this matches the use-case for `setImmediate()` within Preact, which is simply to debounce rendering, it means that componentDidUpdate() and setState() callbacks should no longer be used as a means of animation. This is only true when using the built-in debounce mechanism, overriding to requestAnimationFrame is still sufficient for all other cases.