import $ from '-jquery';

import {
  click,
  triggerEvent,
  keyEvent
} from 'ember-native-dom-helpers';

import {
  guardMultiple,
  buildSelector,
  findClosestValue
} from '../helpers';
import {
  fillElement
} from './helpers';
import {
  ELEMENT_NOT_FOUND,
  throwBetterError
} from '../better-errors';

const KEYBOARD_EVENT_TYPES = ['keydown', 'keypress', 'keyup'];

export default function ExecutionContext(pageObjectNode, testContext) {
  this.pageObjectNode = pageObjectNode;
  this.testContext = testContext;
}

ExecutionContext.prototype = {
  run(cb) {
    return cb(this);
  },

  runAsync() {
    throw new Error('not implemented');
  },

  click(selector, container) {
    const el = this.$(selector, container)[0];
    click(el);
  },

  fillIn(selector, container, options, content) {
    let el = this.$(selector, container)[0];

    fillElement(el, content, {
      selector,
      pageObjectNode: this.pageObjectNode,
      pageObjectKey: options.pageObjectKey
    });

    triggerEvent(el, 'input');
    triggerEvent(el, 'change');
  },

  $(selector, container) {
    if (container) {
      return $(selector, container);
    } else {
      // @todo: we should fixed usage of private `_element`
      // after https://github.com/emberjs/ember-test-helpers/issues/184 is resolved
      let testsContainer = this.testContext ?
        this.testContext._element :
        '#ember-testing';

      return $(selector, testsContainer);
    }
  },

  triggerEvent(selector, container, eventName, eventOptions) {
    const element = this.$(selector, container)[0];

    // `keyCode` is a deprecated property.
    // @see: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
    // Due to this deprecation `ember-native-dom-helpers` doesn't accept `keyCode` as a `KeyboardEvent` option.
    if (typeof eventOptions.key === 'undefined' && typeof eventOptions.keyCode !== 'undefined') {
      eventOptions.key = eventOptions.keyCode.toString();
      delete eventOptions.keyCode;
    }

    if (KEYBOARD_EVENT_TYPES.indexOf(eventName) > -1) {
      keyEvent(element, eventName, eventOptions.key, eventOptions);
    } else {
      triggerEvent(element, eventName, eventOptions);
    }
  },

  assertElementExists(selector, options) {
    let container = options.testContainer || findClosestValue(this.pageObjectNode, 'testContainer');

    let result = this.$(selector, container);

    if (result.length === 0) {
      throwBetterError(
        this.pageObjectNode,
        options.pageObjectKey,
        ELEMENT_NOT_FOUND,
        { selector }
      );
    }
  },

  find(selector, options) {
    let container = options.testContainer || findClosestValue(this.pageObjectNode, 'testContainer');

    selector = buildSelector(this.pageObjectNode, selector, options);

    let result = this.$(selector, container);

    guardMultiple(result, selector, options.multiple);

    return result;
  },

  findWithAssert(selector, options) {
    let container = options.testContainer || findClosestValue(this.pageObjectNode, 'testContainer');

    selector = buildSelector(this.pageObjectNode, selector, options);

    let result = this.$(selector, container);

    if (result.length === 0) {
      throwBetterError(
        this.pageObjectNode,
        options.pageObjectKey,
        ELEMENT_NOT_FOUND,
        { selector }
      );
    }

    guardMultiple(result, selector, options.multiple);

    return result;
  }
};


@@ -802,24 +802,30 @@
 %7B%0A    let el
+ements
  = this.$(se
@@ -838,30 +838,70 @@
 , container)
-%5B0%5D;%0A%0A
+.toArray();%0A%0A    elements.forEach((el) =%3E %7B%0A  
     fillElem
@@ -919,16 +919,18 @@
 tent, %7B%0A
+  
       se
@@ -935,32 +935,34 @@
 selector,%0A      
+  
 pageObjectNode: 
@@ -978,24 +978,26 @@
 ObjectNode,%0A
+  
       pageOb
@@ -1035,13 +1035,17 @@
     
+ 
+ 
 %7D);%0A%0A
+  
     
@@ -1071,24 +1071,26 @@
 nput');%0A    
+ 
+ 
 triggerEvent
@@ -1101,24 +1101,32 @@
  'change');%0A
+    %7D);%0A
   %7D,%0A%0A  $(se

Add support for multiple fillIn