import Field from './field';
import { find, createError } from './utils';

export default class FieldBag {
  constructor () {
    this.items = [];
  }

  /**
   * @return {Number} The current collection length.
   */
  get length () {
    return this.items.length;
  }

  /**
   * Finds the first field that matches the provided matcher object.
   * @param {Object} matcher
   * @return {Field|undefined} The first matching item.
   */
  find (matcher) {
    return find(this.items, item => item.matches(matcher));
  }

  /**
   * @param {Object|Array} matcher
   * @return {Array} Array of matching field items.
   */
  filter (matcher) {
    // multiple matchers to be tried.
    if (Array.isArray(matcher)) {
      return this.items.filter(item => matcher.some(m => item.matches(m)));
    }

    return this.items.filter(item => item.matches(matcher));
  }

  /**
   * Maps the field items using the mapping function.
   *
   * @param {Function} mapper
   */
  map (mapper) {
    return this.items.map(mapper);
  }

  /**
   * Finds and removes the first field that matches the provided matcher object, returns the removed item.
   * @param {Object|Field} matcher
   * @return {Field|null}
   */
  remove (matcher) {
    let item = null;
    if (matcher instanceof Field) {
      item = matcher;
    } else {
      item = this.find(matcher);
    }

    if (!item) return null;

    const index = this.items.indexOf(item);
    this.items.splice(index, 1);

    return item;
  }

  /**
   * Adds a field item to the list.
   *
   * @param {Field} item
   */
  push (item) {
    if (! (item instanceof Field)) {
      throw createError('FieldBag only accepts instances of Field that has an id defined.');
    }

    if (!item.id) {
      throw createError('Field id must be defined.');
    }

    if (this.find({ id: item.id })) {
      throw createError(`Field with id ${item.id} is already added.`);
    }

    this.items.push(item);
  }
}

@@ -68,16 +68,26 @@
 tils';%0A%0A
+// @flow%0A%0A
 export d
@@ -110,16 +110,40 @@
 ldBag %7B%0A
+  items: Array%3CField%3E;%0A%0A
   constr
@@ -194,26 +194,14 @@
   * 
-@return %7BNumber%7D T
+Gets t
 he c
@@ -211,18 +211,13 @@
 ent 
-collection
+items
  len
@@ -227,16 +227,32 @@
 .%0A   */%0A
+  // $FlowFixMe%0A
   get le
@@ -258,16 +258,24 @@
 ength ()
+: number
  %7B%0A    r
@@ -387,111 +387,42 @@
    *
- @param %7BObject%7D matcher%0A   * @return %7BField%7Cundefined%7D The first matching item.%0A   */%0A  find (matcher)
+/%0A  find (matcher: Object): ?Field
  %7B%0A 
@@ -500,87 +500,51 @@
   * 
-@param %7BObject%7CArray%7D matcher%0A   * @return %7BArray%7D Array of
+Filters the items down to the
  match
-ing
+ed
  field
- item
 s.%0A 
@@ -561,25 +561,60 @@
 ter (matcher
-)
+: Object %7C Array%3Cany%3E): Array%3CField%3E
  %7B%0A    // mu
@@ -893,59 +893,57 @@
    *
+/
 %0A  
- * @param %7BFunction%7D mapper%0A   */%0A  map (mapper)
+map (mapper: (f: Field) =%3E any): Array%3CField%3E
  %7B%0A 
@@ -1102,89 +1102,58 @@
    *
- @param %7B
+/%0A  remove (matcher: 
 Object
-%7C
+ %7C 
 Field
-%7D matcher%0A   * @return %7B
+): 
 Field
-%7C
+ %7C 
 null
-%7D%0A   */%0A  remove (matcher)
  %7B%0A 
@@ -1458,38 +1458,8 @@
 st.%0A
-   *%0A   * @param %7BField%7D item%0A
    *
@@ -1472,16 +1472,24 @@
 sh (item
+: ?Field
 ) %7B%0A    

add flow to fieldBag