'use strict';

const util = require('util');

const isPromise = require('../utilities').isPromise;
const isArray = thingy => Array.isArray(thingy);
const isArrayIsh = thingy => (Symbol.iterator in thingy ||
  ('length' in thingy && typeof thingy.length === 'number' &&
  '0' in thingy && (thingy.length === 0 || (thingy.length - 1) in thingy)));
const isObject = thingy => (thingy instanceof Object &&
  Object.prototype.toString === thingy.toString());

const fromPromise = (thingy, func) => thingy.then(res => listish(res, func));
const fromArray = (thingy, func) => func(thingy);
const fromArrayIsh = (thingy, func) => func(Array.from(thingy));
const fromObject = (thingy, func) => {
  const keys = Object.keys(thingy);
  const values = keys.map(key => thingy[key]);
  const reducer = (obj, item, index) => {
    obj[keys[index]] = item;
    return obj;
  };

  return action(values).then(results => results.reduce(reducer, {}));
};

const transforms = [
  [isArray, fromArray],
  [isArrayIsh, fromArrayIsh],
  [isPromise, fromPromise],
  [isObject, fromObject],
];

function complain(thingy, action) {
  const whateverThisThingIs = util.inspect(thingy);
  const iDontEvenWantToKnow = util.inspect(action);
  const complaint = ('listish expects arguments (thingy, func) ' +
    `but received (${whateverThisThingIs}, ${iDontEvenWantToKnow})`);
  return new Error(complaint);
}

function listish(thingy, action) {
  if (!thingy || typeof action !== 'function') {
    throw complain(thingy, action);
  }

  // if it matches any of our transforms, use the transform
  for (let t of transforms) {
    const test = t[0];
    const transform = t[1];
    if (test(thingy)) return transform(thingy, action);
  }

  throw complain(thingy, action);
}

module.exports = listish;

@@ -1,9 +1,9 @@
-'
+%22
 use stri
@@ -4,17 +4,17 @@
 e strict
-'
+%22
 ;%0A%0Aconst
@@ -33,14 +33,14 @@
 ire(
-'
+%22
 util
-'
+%22
 );%0A%0A
@@ -65,17 +65,17 @@
 require(
-'
+%22
 ../utili
@@ -78,17 +78,17 @@
 tilities
-'
+%22
 ).isProm
@@ -169,18 +169,19 @@
 hingy =%3E
+%0A 
  
-(
 Symbol.i
@@ -208,16 +208,16 @@
 %0A  (
-'
+%22
 length
-'
+%22
  in 
@@ -225,16 +225,20 @@
 hingy &&
+%0A   
  typeof 
@@ -259,25 +259,27 @@
 === 
-'
+%22
 number
-'
+%22
  &&%0A  
-'0'
+  %220%22
  in 
@@ -287,16 +287,20 @@
 hingy &&
+%0A   
  (thingy
@@ -316,17 +316,16 @@
 == 0 %7C%7C 
-(
 thingy.l
@@ -333,17 +333,16 @@
 ngth - 1
-)
  in thin
@@ -345,17 +345,16 @@
 thingy))
-)
 ;%0Aconst 
@@ -374,17 +374,16 @@
 ingy =%3E 
-(
 thingy i
@@ -401,18 +401,16 @@
 bject &&
-%0A 
  Object.
@@ -427,16 +427,18 @@
 toString
+()
  === thi
@@ -451,17 +451,16 @@
 String()
-)
 ;%0A%0Aconst
@@ -871,22 +871,20 @@
  return 
-action
+func
 (values)
@@ -954,19 +954,16 @@
 orms = %5B
-%0A  
 %5BisArray
@@ -975,18 +975,16 @@
 mArray%5D,
-%0A 
  %5BisArra
@@ -1003,18 +1003,16 @@
 rayIsh%5D,
-%0A 
  %5BisProm
@@ -1029,18 +1029,16 @@
 romise%5D,
-%0A 
  %5BisObje
@@ -1056,10 +1056,8 @@
 ect%5D
-,%0A
 %5D;%0A%0A
@@ -1219,11 +1219,14 @@
 nt =
- ('
+%0A    %22
 list
@@ -1266,15 +1266,11 @@
 nc) 
-'
+%22
  +
-%0A   
  %60bu
@@ -1329,17 +1329,16 @@
 oKnow%7D)%60
-)
 ;%0A  retu
@@ -1439,17 +1439,17 @@
 !== 
-'
+%22
 function
 ') %7B
@@ -1448,9 +1448,9 @@
 tion
-'
+%22
 ) %7B%0A

fix object mode of listish