var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
define(["require", "exports", 'react', '../../utilities/css', '../../utilities/eventGroup/EventGroup', '../../utilities/array', '../../utilities/KeyCodes', './Dropdown.scss'], function (require, exports, React, css_1, EventGroup_1, array_1, KeyCodes_1) {
    "use strict";
    var _instance = 0;
    var Dropdown = (function (_super) {
        __extends(Dropdown, _super);
        function Dropdown(props) {
            _super.call(this, props);
            this._events = new EventGroup_1.EventGroup(this);
            this.state = {
                id: "Dropdown-" + _instance++,
                isOpen: false,
                selectedIndex: this._getSelectedIndex(props.options, props.selectedKey),
                isDisabled: this.props.isDisabled
            };
            this._onDropdownKeyDown = this._onDropdownKeyDown.bind(this);
            this._onDropdownClick = this._onDropdownClick.bind(this);
            this._onFocusChange = this._onFocusChange.bind(this);
        }
        Dropdown.prototype.componentWillReceiveProps = function (newProps) {
            this.setState({
                selectedIndex: this._getSelectedIndex(newProps.options, newProps.selectedKey)
            });
        };
        Dropdown.prototype.componentWillUpdate = function (nextProps, nextState) {
            if (this.state.isOpen !== nextState.isOpen) {
                if (nextState.isOpen) {
                    this._events.on(window, 'focus', this._onFocusChange, true);
                }
                else {
                    this._events.off();
                }
            }
        };
        Dropdown.prototype.componentWillUnmount = function () {
            this._events.dispose();
        };
        Dropdown.prototype.componentDidUpdate = function (prevProps, prevState) {
            if (prevState.isOpen === false && this.state.isOpen === true) {
                this._scrollOnOpen();
            }
            else if (prevState.selectedIndex !== this.state.selectedIndex) {
                this._scrollSelectedItemIntoView();
            }
        };
        Dropdown.prototype.render = function () {
            var _this = this;
            var _a = this.props, label = _a.label, options = _a.options;
            var _b = this.state, id = _b.id, isOpen = _b.isOpen, selectedIndex = _b.selectedIndex, isDisabled = _b.isDisabled;
            var selectedOption = options[selectedIndex];
            // Need to assign role application on containing div because JAWS doesnt call OnKeyDown without this role
            return (React.createElement("div", {ref: 'root'}, React.createElement("label", {id: id + '-label', className: 'ms-Label'}, label), React.createElement("div", {ref: function (c) { return _this._dropDown = c; }, id: id, className: css_1.css('ms-Dropdown', {
                'is-open': isOpen, 'is-disabled': isDisabled
            }), tabIndex: isDisabled ? -1 : 0, onKeyDown: this._onDropdownKeyDown, onClick: this._onDropdownClick, "aria-expanded": isOpen ? 'true' : 'false', role: 'application', "aria-activedescendant": selectedIndex >= 0 ? (id + '-list' + selectedIndex) : (id + '-list'), "aria-controls": id + '-list'}, React.createElement("i", {className: 'ms-Dropdown-caretDown ms-Icon ms-Icon--caretDown'}), React.createElement("span", {className: 'ms-Dropdown-title'}, selectedOption ? selectedOption.text : ''), React.createElement("ul", {ref: function (c) { return _this._optionList = c; }, id: id + '-list', className: 'ms-Dropdown-items', role: 'listbox', "aria-labelledby": id + '-label'}, options.map(function (option, index) { return (React.createElement("li", {id: id + '-list' + index.toString(), ref: Dropdown.Option + index.toString(), key: option.key, "data-index": index, className: css_1.css('ms-Dropdown-item', { 'is-selected': selectedIndex === index }), onClick: _this.setSelectedIndex.bind(_this, index), role: 'option', "aria-selected": selectedIndex === index ? 'true' : 'false', "aria-label": option.text}, option.text)); })))));
        };
        Dropdown.prototype.focus = function () {
            if (this._dropDown && this._dropDown.tabIndex !== -1) {
                this._dropDown.focus();
            }
        };
        Dropdown.prototype.setSelectedIndex = function (index) {
            var _a = this.props, onChanged = _a.onChanged, options = _a.options;
            var selectedIndex = this.state.selectedIndex;
            index = Math.max(0, Math.min(options.length - 1, index));
            if (index !== selectedIndex) {
                // Set the selected option.
                this.setState({
                    selectedIndex: index
                });
                if (onChanged) {
                    onChanged(options[index], index);
                }
            }
        };
        Dropdown.prototype._getSelectedIndex = function (options, selectedKey) {
            return array_1.findIndex(options, (function (option) { return (option.isSelected || selectedKey && option.key === selectedKey); }));
        };
        Dropdown.prototype._onDropdownKeyDown = function (ev) {
            switch (ev.which) {
                case KeyCodes_1.KeyCodes.enter:
                    this.setState({
                        isOpen: !this.state.isOpen
                    });
                    break;
                case KeyCodes_1.KeyCodes.escape:
                    this.setState({
                        isOpen: false
                    });
                    break;
                case KeyCodes_1.KeyCodes.up:
                    this.setSelectedIndex(this.state.selectedIndex - 1);
                    break;
                case KeyCodes_1.KeyCodes.down:
                    this.setSelectedIndex(this.state.selectedIndex + 1);
                    break;
                case KeyCodes_1.KeyCodes.home:
                    this.setSelectedIndex(0);
                    break;
                case KeyCodes_1.KeyCodes.end:
                    this.setSelectedIndex(this.props.options.length - 1);
                    break;
                default:
                    return;
            }
            ev.stopPropagation();
            ev.preventDefault();
        };
        Dropdown.prototype._onDropdownClick = function () {
            var _a = this.state, isDisabled = _a.isDisabled, isOpen = _a.isOpen;
            if (!isDisabled) {
                this.setState({
                    isOpen: !isOpen
                });
            }
        };
        Dropdown.prototype._onFocusChange = function (ev) {
            if (this.state.isOpen && !this.refs.root.contains(ev.target)) {
                var context_1 = this;
                context_1.setState({
                    isOpen: false
                });
            }
        };
        Dropdown.prototype._scrollSelectedItemIntoView = function () {
            var _a = this._getCurrentItemPositionDetails(), posTop = _a.posTop, posBottom = _a.posBottom;
            // if the selected item is too far down
            if (posBottom > this._optionList.offsetHeight + this._optionList.scrollTop) {
                this._optionList.scrollTop = posBottom - this._optionList.offsetHeight;
            }
            else if (posTop < this._optionList.scrollTop) {
                this._optionList.scrollTop = posTop;
            }
        };
        Dropdown.prototype._scrollOnOpen = function () {
            var _a = this._getCurrentItemPositionDetails(), currentItem = _a.currentItem, posBottom = _a.posBottom;
            // the selected item should be in the center of the dropdown if possible
            if (currentItem) {
                this._optionList.scrollTop = posBottom - (currentItem.offsetHeight + this._optionList.offsetHeight) / 2;
            }
        };
        Dropdown.prototype._getCurrentItemPositionDetails = function () {
            var currentItem = this.refs[Dropdown.Option + this.state.selectedIndex];
            var posTop = currentItem ? currentItem.offsetTop : 0;
            var posBottom = currentItem ? posTop + currentItem.offsetHeight : 0;
            return { currentItem: currentItem,
                posTop: posTop,
                posBottom: posBottom };
        };
        Dropdown.defaultProps = {
            options: [],
            isDisabled: false
        };
        Dropdown.Option = 'option';
        return Dropdown;
    }(React.Component));
    exports.Dropdown = Dropdown;
});
