// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

part of mdv;

abstract class _InputBinding extends NodeBinding {
  StreamSubscription _eventSub;

  _InputBinding(node, name, model, path): super(node, name, model, path) {
    _eventSub = _getStreamForInputType(node).listen(nodeValueChanged);
  }

  void boundValueChanged(newValue);

  void nodeValueChanged(e);

  void close() {
    if (closed) return;
    _eventSub.cancel();
    super.close();
  }

  static EventStreamProvider<Event> _checkboxEventType = () {
    // Attempt to feature-detect which event (change or click) is fired first
    // for checkboxes.
    var div = new DivElement();
    var checkbox = div.append(new InputElement());
    checkbox.type = 'checkbox';
    var fired = [];
    checkbox.onClick.listen((e) {
      fired.add(Element.clickEvent);
    });
    checkbox.onChange.listen((e) {
      fired.add(Element.changeEvent);
    });
    checkbox.dispatchEvent(new MouseEvent('click', view: window));
    // WebKit/Blink don't fire the change event if the element is outside the
    // document, so assume 'change' for that case.
    return fired.length == 1 ? Element.changeEvent : fired.first;
  }();

  static Stream<Event> _getStreamForInputType(element) {
    switch (element.type) {
      case 'checkbox':
        return _checkboxEventType.forTarget(element);
      case 'radio':
      case 'select-multiple':
      case 'select-one':
        return element.onChange;
      default:
        return element.onInput;
    }
  }
}

class _ValueBinding extends _InputBinding {
  _ValueBinding(node, model, path) : super(node, 'value', model, path);

  get node => super.node;

  void boundValueChanged(newValue) {
    // Note: node can be an InputElement or TextAreaElement. Both have "value".
    (node as dynamic).value = sanitizeBoundValue(newValue);
  }

  void nodeValueChanged(e) {
    value = (node as dynamic).value;
  }
}

class _CheckedBinding extends _InputBinding {
  _CheckedBinding(node, model, path) : super(node, 'checked', model, path);

  InputElement get node => super.node;

  void boundValueChanged(newValue) {
    node.checked = _toBoolean(newValue);
  }

  void nodeValueChanged(e) {
    value = node.checked;

    // Only the radio button that is getting checked gets an event. We
    // therefore find all the associated radio buttons and update their
    // CheckedBinding manually.
    if (node is InputElement && node.type == 'radio') {
      for (var r in _getAssociatedRadioButtons(node)) {
        var checkedBinding = r.bindings['checked'];
        if (checkedBinding != null) {
          // Set the value directly to avoid an infinite call stack.
          checkedBinding.value = false;
        }
      }
    }
  }

  // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
  // Returns an array containing all radio buttons other than |element| that
  // have the same |name|, either in the form that |element| belongs to or,
  // if no form, in the document tree to which |element| belongs.
  //
  // This implementation is based upon the HTML spec definition of a
  // "radio button group":
  //   http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#radio-button-group
  //
  static Iterable _getAssociatedRadioButtons(element) {
    if (!_isNodeInDocument(element)) return [];
    if (element.form != null) {
      return element.form.nodes.where((el) {
        return el != element &&
            el is InputElement &&
            el.type == 'radio' &&
            el.name == element.name;
      });
    } else {
      var radios = element.document.queryAll(
          'input[type="radio"][name="${element.name}"]');
      return radios.where((el) => el != element && el.form == null);
    }
  }

  // TODO(jmesserly): polyfill document.contains API instead of doing it here
  static bool _isNodeInDocument(Node node) {
    // On non-IE this works:
    // return node.ownerDocument.contains(node);
    var document = node.document;
    if (node == document || node.parentNode == document) return true;
    return document.documentElement.contains(node);
  }
}

class _SelectedIndexBinding extends _InputBinding {
  _SelectedIndexBinding(node, model, path)
      : super(node, 'selectedIndex', model, path);

  SelectElement get node => super.node;

  void boundValueChanged(value) {
    var newValue = _toInt(value);
    if (newValue <= node.length) {
      node.selectedIndex = newValue;
      return;
    }

    // The binding may wish to bind to an <option> which has not yet been
    // produced by a child <template>. Furthermore, we may need to wait for
    // <optgroup> iterating and then for <option>.
    //
    // Unlike the JavaScript MDV, we don't have a special "Object.observe" event
    // loop to schedule on. (See the the "ensureScheduled" function:
    // https://github.com/Polymer/mdv/commit/9a51ad7ed74a292bf71662cea28acbd151ff65c8)
    //
    // Instead we use scheduleMicrotask. Each <template repeat> needs a delay of
    // 2:
    //   * once to happen after the child _TemplateIterator is created
    //   * once to be after _TemplateIterator.inputs CompoundBinding resolve
    // And then we need to do this delay sequence twice:
    //   * once for OPTGROUP
    //   * once for OPTION.
    // The resulting 2 * 2 is our maxRetries.
    var maxRetries = 4;
    delaySetSelectedIndex() {
      if (newValue > node.length && --maxRetries >= 0) {
        scheduleMicrotask(delaySetSelectedIndex);
      } else {
        node.selectedIndex = newValue;
      }
    }

    scheduleMicrotask(delaySetSelectedIndex);
  }

  void nodeValueChanged(e) {
    value = node.selectedIndex;
  }

  // TODO(jmesserly,sigmund): I wonder how many bindings typically convert from
  // one type to another (e.g. value-as-number) and whether it is useful to
  // have something like a int/num binding converter (either as a base class or
  // a wrapper).
  static int _toInt(value) {
    if (value is String) return int.parse(value, onError: (_) => null);
    return value is int ? value : null;
  }
}
