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', '../eventGroup/EventGroup', './SelectionLayout', '../KeyCodes', './interfaces'], function (require, exports, React, EventGroup_1, SelectionLayout_1, KeyCodes_1, interfaces_1) {
    "use strict";
    // Selection definitions:
    //
    // Anchor index: the point from which a range selection starts.
    // Focus index: the point from which layout movement originates from.
    //
    // These two can differ. Tests:
    //
    // If you start at index 5
    // Shift click to index 10
    //    The focus is 10, the anchor is 5.
    // If you shift click at index 0
    //    The anchor remains at 5, the items between 0 and 5 are selected and everything else is cleared.
    // If you click index 8
    //    The anchor and focus are set to 8.
    var SELECTION_INDEX_ATTRIBUTE_NAME = 'data-selection-index';
    var SELECTION_TOGGLE_ATTRIBUTE_NAME = 'data-selection-toggle';
    var SELECTALL_TOGGLE_ALL_ATTRIBUTE_NAME = 'data-selection-all-toggle';
    var SelectionZone = (function (_super) {
        __extends(SelectionZone, _super);
        function SelectionZone() {
            _super.call(this);
            this._events = new EventGroup_1.EventGroup(this);
        }
        SelectionZone.prototype.componentDidMount = function () {
            var element = this.refs.root;
            this._events.onAll(element, {
                'keydown': this._onKeyDown,
                'mousedown': this._onMouseDown,
                'click': this._onClick,
                'dblclick': this._onDoubleClick
            });
            // Always know what the state of shift/ctrl/meta are.
            this._events.on(element, 'focus', this._onFocus, true);
            this._events.on(window, 'keydown', this._onKeyChangeCapture, true);
            this._events.on(window, 'keyup', this._onKeyChangeCapture, true);
        };
        SelectionZone.prototype.componentWillUnmount = function () {
            this._events.dispose();
        };
        SelectionZone.prototype.render = function () {
            return (React.createElement("div", {className: 'ms-SelectionZone', ref: 'root'}, this.props.children));
        };
        SelectionZone.prototype._onFocus = function (ev) {
            var _a = this.props, selection = _a.selection, selectionMode = _a.selectionMode;
            var index = this._getIndexFromElement(ev.target);
            if (index >= 0 && selectionMode !== interfaces_1.SelectionMode.none && !this._hasClickedOnItem) {
                selection.setChangeEvents(false);
                if (this._isShiftPressed && selectionMode === interfaces_1.SelectionMode.multiple) {
                    if (!this._isCtrlPressed && !this._isMetaPressed) {
                        selection.setAllSelected(false);
                    }
                    selection.selectToIndex(index);
                }
                else if (!this._isCtrlPressed && !this._isMetaPressed) {
                    selection.setAllSelected(false);
                    selection.setIndexSelected(index, true, true);
                }
                selection.setChangeEvents(true);
            }
            this._hasClickedOnItem = false;
        };
        SelectionZone.prototype._onMouseDown = function (ev) {
            // We need to reset the key states for ctrl/meta/etc.
            this._onKeyChangeCapture(ev);
            var target = ev.target;
            var selectionMode = this.props.selectionMode;
            var index = this._getIndexFromElement(target, true);
            if (index >= 0 && selectionMode !== interfaces_1.SelectionMode.none) {
                this._hasClickedOnItem = true;
            }
        };
        SelectionZone.prototype._onClick = function (ev) {
            var target = ev.target;
            var _a = this.props, selection = _a.selection, selectionMode = _a.selectionMode, onItemInvoked = _a.onItemInvoked;
            var isToggleElement = this._isToggleElement(target, SELECTION_TOGGLE_ATTRIBUTE_NAME) || ev.ctrlKey || ev.metaKey;
            var index = this._getIndexFromElement(target, true);
            if (index >= 0 && selectionMode !== interfaces_1.SelectionMode.none) {
                var isSelected = selection.isIndexSelected(index);
                // Disable change events.
                selection.setChangeEvents(false);
                if (ev.shiftKey && selectionMode === interfaces_1.SelectionMode.multiple) {
                    if (!ev.ctrlKey && !ev.metaKey) {
                        selection.setAllSelected(false);
                    }
                    selection.selectToIndex(index);
                }
                else {
                    if (selectionMode === interfaces_1.SelectionMode.single || !isToggleElement) {
                        selection.setAllSelected(false);
                    }
                    selection.setIndexSelected(index, isToggleElement ? !isSelected : true, !ev.shiftKey);
                }
                // Re-enabled change events.
                selection.setChangeEvents(true);
            }
            else if (onItemInvoked) {
                onItemInvoked(selection.getItems()[index], index, ev);
            }
        };
        SelectionZone.prototype._onDoubleClick = function (ev) {
            var _a = this.props, onItemInvoked = _a.onItemInvoked, selection = _a.selection;
            var index = this._getIndexFromElement(ev.target, true);
            if (onItemInvoked) {
                onItemInvoked(selection.getItems()[index], index, ev);
            }
        };
        SelectionZone.prototype._onKeyChangeCapture = function (ev) {
            this._isShiftPressed = ev.shiftKey;
            this._isCtrlPressed = ev.ctrlKey;
            this._isMetaPressed = ev.metaKey;
        };
        SelectionZone.prototype._onKeyDown = function (ev) {
            var target = ev.target;
            var _a = this.props, selection = _a.selection, selectionMode = _a.selectionMode, onItemInvoked = _a.onItemInvoked;
            var isToggleElement = this._isToggleElement(target, SELECTION_TOGGLE_ATTRIBUTE_NAME);
            var isToggleAllElement = !isToggleElement && this._isToggleElement(target, SELECTALL_TOGGLE_ALL_ATTRIBUTE_NAME);
            var index = this._getIndexFromElement(target, true);
            if (index >= 0 && !this._isInputElement(target) && selectionMode !== interfaces_1.SelectionMode.none) {
                var isSelected = selection.isIndexSelected(index);
                if (ev.which === KeyCodes_1.KeyCodes.space) {
                    if (isToggleAllElement) {
                        if (selectionMode === interfaces_1.SelectionMode.multiple) {
                            selection.toggleAllSelected();
                        }
                    }
                    else {
                        selection.setChangeEvents(false);
                        if (selectionMode === interfaces_1.SelectionMode.single) {
                            selection.setAllSelected(false);
                        }
                        selection.setIndexSelected(index, !isSelected, true);
                        selection.setChangeEvents(true);
                    }
                }
                else if (ev.which === KeyCodes_1.KeyCodes.enter) {
                    if (isToggleAllElement) {
                        selection.toggleAllSelected();
                    }
                    else if (isToggleElement) {
                        selection.setChangeEvents(false);
                        if (selectionMode === interfaces_1.SelectionMode.single) {
                            selection.setAllSelected(false);
                        }
                        selection.setIndexSelected(index, !isSelected, true);
                        selection.setChangeEvents(true);
                    }
                    else if (this._getIndexFromElement(target) >= 0 && onItemInvoked) {
                        // if the target IS the item, and not a link inside, then call the invoke method.
                        onItemInvoked(selection.getItems()[index], index, ev);
                    }
                    else {
                        return;
                    }
                }
                else if (ev.which === KeyCodes_1.KeyCodes.a && (ev.ctrlKey || ev.metaKey) && selectionMode === interfaces_1.SelectionMode.multiple) {
                    selection.setAllSelected(true);
                }
                else if (ev.which === KeyCodes_1.KeyCodes.escape) {
                    selection.setAllSelected(false);
                }
                else {
                    return;
                }
            }
            else {
                return;
            }
            ev.preventDefault();
            ev.stopPropagation();
        };
        SelectionZone.prototype._isToggleElement = function (element, attributeName) {
            var isToggle = false;
            while (!isToggle && element !== this.refs.root) {
                isToggle = element.getAttribute(attributeName) === 'true';
                element = element.parentElement;
            }
            return isToggle;
        };
        SelectionZone.prototype._isInputElement = function (element) {
            return element.tagName === 'INPUT' || element.tagName === 'TEXTAREA';
        };
        SelectionZone.prototype._getIndexFromElement = function (element, traverseParents) {
            var index = -1;
            do {
                var indexString = element.getAttribute(SELECTION_INDEX_ATTRIBUTE_NAME);
                if (indexString) {
                    index = Number(indexString);
                    break;
                }
                if (element !== this.refs.root) {
                    element = element.parentElement;
                }
            } while (traverseParents && element !== this.refs.root);
            return index;
        };
        SelectionZone.defaultProps = {
            layout: new SelectionLayout_1.SelectionLayout(interfaces_1.SelectionDirection.vertical),
            isMultiSelectEnabled: true,
            isSelectedOnFocus: true
        };
        return SelectionZone;
    }(React.Component));
    exports.SelectionZone = SelectionZone;
});
