content: import React from 'react';
  import $ from 'jquery';
  import {BaseMixin, ElementaryMixin, ContentMixin, Tools} from './../common/common.js';
  import {Span, Div, Button, Glyphicon, Backdrop} from './../bricks/bricks.js';
  
  import './select-input.less';
  
  export default React.createClass({
  
    mixins: [
      BaseMixin,
      ElementaryMixin,
      ContentMixin
    ],
  
    statics: {
      tagName: 'UU5.Forms.Select._input',
      classNames: {
        main: 'uu5-forms-select-input',
        inputGroup: 'input-group uu5-forms-text-group-with-feedback',
        inputFeedback: 'uu5-forms-text-input-feedback',
        inputBtnGroup: 'uu5-forms-select-input-btn-group input-group-btn',
        header: 'uu5-forms-select-input-header form-control',
        menu: 'uu5-forms-select-input-menu',
        innerMenu: 'uu5-forms-select-input-inner-menu list-group',
        opened: 'uu5-forms-select-input-opened',
        selectedItem: 'uu5-forms-select-input-selected-item bg-info',
        placeholder: 'uu5-forms-select-input-placeholder',
        noButton: 'uu5-forms-select-input-no-button',
        hoverItem: 'uu5-forms-select-input-hover-item',
        button: 'uu5-forms-input-button'
      }
    },
  
    propTypes: {
      isOpened: React.PropTypes.bool,
      value: React.PropTypes.number,
      placeholder: React.PropTypes.string,
      isReadOnly: React.PropTypes.bool,
      isButtonHidden: React.PropTypes.bool,
      openedGlyphicon: React.PropTypes.string,
      closedGlyphicon: React.PropTypes.string,
      onChange: React.PropTypes.func.isRequired
    },
  
    // Setting defaults
    getDefaultProps: function () {
      return {
        isOpened: false,
        value: null,
        placeholder: null,
        isReadOnly: false,
        isButtonHidden: false,
        openedGlyphicon: null,
        closedGlyphicon: null,
        onChange: null
      };
    },
  
    getInitialState: function () {
      return {
        isOpened: this.props.isOpened,
        selectedIndex: null
      };
    },
  
    // Interface
  
    isOpened: function () {
      return this.state.isOpened;
    },
  
    open: function (setStateCallback) {
      this.setState({ isOpened: true }, setStateCallback);
      return this;
    },
  
    close: function (setStateCallback) {
      this.setState({ isOpened: false }, setStateCallback);
      return this;
    },
  
    toggle: function (setStateCallback) {
      var input = this;
      this.setState(function (state) {
        return { isOpened: !state.isOpened };
      }, setStateCallback);
      return this;
    },
  
    getSelectedIndex: function () {
      return this.state.selectedIndex;
    },
  
    getSelectedOption: function () {
      var option;
      if (this.getSelectedIndex() === null) {
        option = null;
      } else {
        option = this.getRenderedChildren()[this.getSelectedIndex()];
      }
      return option;
    },
  
    getSelectedValue: function () {
      var option = this.getSelectedOption();
      return option ? option.getValue() : null;
    },
  
    // Overriding Functions
    expandChildProps_: function (child, i) {
      var props = Tools.mergeDeep({}, child.props);
      props.selected = i == this.props.value;
  
      if (this.props.value === i && this.getSelectedIndex() !== i) {
        props.className = props.className ? props.className + ' ' + this.getClassName().selectedItem : this.getClassName().selectedItem;
      }
  
      if (this.getSelectedIndex() === i) {
        props.className = props.className ? props.className + ' ' + this.getClassName().hoverItem : this.getClassName().hoverItem;
      }
  
      props.mainAttrs = props.mainAttrs || {};
      props.mainAttrs.id = this.getId() + '-item-' + i;
  
      var input = this;
      var childOnClick = props.onClick;
      props.onClick = function (opt) {
        input._onClose(opt, childOnClick);
      };
  
      return props;
    },
  
    selectUp: function (setStateCallback) {
      var input = this;
      this.setState(function (state) {
        var index = null;
        if (state.isOpened) {
          var childrenLength;
  
          if (state.selectedIndex == null || state.selectedIndex === 0) {
            childrenLength = input.getRenderedChildren().length;
            index = childrenLength - 1;
          } else {
            index = state.selectedIndex - 1;
          }
  
          childrenLength = childrenLength || input.getRenderedChildren().length;
          var offset = index > childrenLength - 3 ?
            $('#' + input.getId() + '-item-' + (childrenLength - 1))[0].offsetTop :
            index - 1 > 0 ? $('#' + input.getId() + '-item-' + (index - 1))[0].offsetTop : 0;
  
          $('#' + this.getId() + '-menu').animate({ scrollTop: offset }, 0);
        }
  
        return { selectedIndex: index };
      }, setStateCallback);
      return this;
    },
  
    selectDown: function (setStateCallback) {
      var input = this;
      this.setState(function (state) {
        var index = null;
        var newState;
        if (state.isOpened) {
          var childrenLength = input.getRenderedChildren().length;
  
          if (state.selectedIndex == null || state.selectedIndex === childrenLength - 1) {
            index = 0;
          } else {
            index = state.selectedIndex + 1;
          }
  
          var offset = index > 1 ? $('#' + input.getId() + '-item-' + (index - 1))[0].offsetTop : 0;
          $('#' + input.getId() + '-menu').animate({ scrollTop: offset }, 0);
  
          newState = { selectedIndex: index };
        } else {
          newState = { isOpened: true, selectedIndex: 0 };
        }
  
        return newState;
      }, setStateCallback);
  
      return this;
    },
  
    // Component Specific Helpers
    _onClose: function (opt, onClick) {
      var input = this;
      this.setState({ isOpened: false }, function () {
        var onClick = onClick || input.props.onChange;
        onClick(opt);
      });
      return this;
    },
  
    _getMainAttrs: function () {
      var attrs = this.getMainAttrs();
      (this.props.isButtonHidden || this.props.isReadOnly) && (attrs.className += ' ' + this.getClassName().noButton);
  
      if (this.isOpened()) {
        attrs.className += ' ' + this.getClassName().opened;
  
        var input = this;
        var customOnKeyPress = attrs.onKeyPress;
        attrs.onKeyPress = function (e) {
          // stop submit form on enter if input is alone in form
          if (e.keyCode == 13 || e.charCode == 13) {
            e.preventDefault();
            input._onClose({ component: input, event: e, value: input.getSelectedIndex() });
          }
          if (typeof customOnKeyPress === 'function') {
            customOnKeyPress(e);
          }
        };
  
        var customOnKeyDown = attrs.onKeyDown;
        attrs.onKeyDown = function (e) {
          switch (e.keyCode) {
            case 27:
              e.preventDefault();
              input.close();
              break;
            case 38:
              e.preventDefault();
              input.selectUp();
              break;
            // case 39:
            //   input.open();
            //   break;
            case 40:
              e.preventDefault();
              input.selectDown();
              break;
          }
  
          if (typeof customOnKeyDown === 'function') {
            customOnKeyDown(e);
          }
        };
      }
  
      return attrs;
    },
  
    _getBackdropProps: function () {
      var backdropId = this.getId() + "-backdrop";
  
      return {
        hidden: !this.isOpened(),
        id: backdropId,
        onClick: function (backdrop, event) {
          event.target.id === backdropId && this.close();
        }.bind(this)
      };
    },
  
    _getChildren: function () {
      return this.getChildren();
    },
  
    _getButtonProps: function () {
      var input = this;
      var props = {
        className: this.getClassName('button'),
        disabled: this.props.disabled,
        pressed: this.isOpened()
      };
  
      if (!this.props.isReadOnly && !this.props.disabled) {
        props.onClick = function () {
          input.toggle();
        };
      }
  
      return props;
    },
  
    _getHeader: function (children) {
      var result;
      if (this.props.value === null) {
        if (this.props.placeholder) {
          result = <Span className={this.getClassName().placeholder} content={this.props.placeholder} />
        }
      } else {
        var child = children[this.props.value];
        result = child.props.selectedContent || child.props.content || child.props.children || child.props.value;
      }
      return result;
    },
  
    _getMenuAttrs: function () {
      return {
        className: this.getClassName().menu
      };
    },
  
    _getHeaderProps: function (children) {
      var input = this;
      var props = {
        className: this.getClassName().header,
        content: this._getHeader(children)
      };
  
      if (!this.props.isReadOnly && !this.props.disabled) {
        props.mainAttrs = {
          onClick: function () {
            input.toggle();
          }
        };
      }
  
      return props;
    },
  
    // Render
    render: function () {
      var children = this._getChildren();
  
      return (
        <div {...this._getMainAttrs()}>
          <div className={this.getClassName().inputGroup}>
            <div className={this.getClassName().inputFeedback}>
              <Div {...this._getHeaderProps(children)} />
              {this.props.glyphicon}
            </div>
  
            {!this.props.isButtonHidden && !this.props.isReadOnly &&
            <span className={this.getClassName().inputBtnGroup}>
              <Button {...this._getButtonProps()}>
                <Glyphicon glyphicon={this.props[this.isOpened() ? 'openedGlyphicon' : 'closedGlyphicon']} />
              </Button>
            </span>
            }
          </div>
  
          <div {...this._getMenuAttrs()}>
            <div className={this.getClassName().innerMenu} id={this.getId() + '-menu'}>
              {children}
            </div>
          </div>
  
          <Backdrop {...this._getBackdropProps()} />
        </div>
      );
    }
  });