import { ElementRef, Component, Directive, EventEmitter, Optional } from '@angular/core';
import { Host, Output, Input, ChangeDetectionStrategy } from '@angular/core';
import { NgControl } from '@angular/forms';
import { BehaviorSubject, Observable } from 'rxjs/Rx';
import * as _ from 'lodash';
import { KeyCode } from '../../../services/util/key-util';
import { LoggerService } from 'dotcms-js/dotcms-js';
/**
 * Angular 2 wrapper around Semantic UI Dropdown Module.
 * @see http://semantic-ui.com/modules/dropdown.html#/usage
 * Comments for event handlers, etc, copied directly from semantic-ui documentation.
 *
 * @todo ggranum: Extract semantic UI components into a separate github repo and include them via npm.
 */
var DO_NOT_SEARCH_ON_THESE_KEY_EVENTS = {
    13: 'enter',
    33: 'pageUp',
    34: 'pageDown',
    37: 'leftArrow',
    38: 'upArrow',
    39: 'rightArrow',
    40: 'downArrow'
};
var Dropdown = (function () {
    function Dropdown(elementRef, control, loggerService) {
        this.loggerService = loggerService;
        this.onDropDownChange = new EventEmitter();
        this.touch = new EventEmitter();
        this.enter = new EventEmitter(false);
        this._optionsAry = [];
        this.onChange = function () { };
        this.onTouched = function () { };
        if (control && !control.valueAccessor) {
            control.valueAccessor = this;
        }
        this.placeholder = '';
        this.allowAdditions = false;
        this.minSelections = 0;
        this.maxSelections = 1;
        this._options = new BehaviorSubject(this._optionsAry);
        this.elementRef = elementRef;
    }
    Object.defineProperty(Dropdown.prototype, "value", {
        set: function (value) {
            this._modelValue = value;
        },
        enumerable: true,
        configurable: true
    });
    Dropdown.prototype.focus = function () {
        try {
            this._$dropdown.children('input.search')[0].focus();
        }
        catch (e) {
            this.loggerService.info('Dropdown', 'could not focus search element');
        }
    };
    Dropdown.prototype.writeValue = function (value) {
        this._modelValue = _.isEmpty(value) ? '' : value;
        this.applyValue(this._modelValue);
    };
    Dropdown.prototype.registerOnChange = function (fn) {
        this.onChange = fn;
    };
    Dropdown.prototype.registerOnTouched = function (fn) {
        this.onTouched = fn;
    };
    Dropdown.prototype.fireChange = function ($event) {
        if (this.onDropDownChange) {
            this.onDropDownChange.emit($event);
            this.onChange($event);
        }
    };
    Dropdown.prototype.fireTouch = function ($event) {
        this.touch.emit($event);
        this.onTouched($event);
    };
    Dropdown.prototype.hasOption = function (option) {
        var x = this._optionsAry.filter(function (opt) {
            return option.value === opt.value;
        });
        return x.length !== 0;
    };
    Dropdown.prototype.addOption = function (option) {
        this._optionsAry = this._optionsAry.concat(option);
        this._options.next(this._optionsAry);
        if (option.value === this._modelValue) {
            this.refreshDisplayText(option.label);
        }
    };
    Dropdown.prototype.updateOption = function (option) {
        this._optionsAry = this._optionsAry.filter(function (opt) {
            return opt.value !== option.value;
        });
        this.addOption(option);
    };
    Dropdown.prototype.ngAfterViewInit = function () {
        this.initDropdown();
    };
    Dropdown.prototype.ngOnDestroy = function () {
        // remove the change emitter so that we don't fire changes when we clear the dropdown.
        this.onDropDownChange = null;
        this._$dropdown.dropdown('clear');
    };
    Dropdown.prototype.refreshDisplayText = function (label) {
        if (this._$dropdown) {
            this._$dropdown.dropdown('set text', label);
        }
    };
    Dropdown.prototype.initDropdown = function () {
        var _this = this;
        var self = this;
        var badSearch = null;
        var config = {
            allowAdditions: this.allowAdditions,
            allowTab: true,
            onAdd: function (addedValue, addedText, $addedChoice) {
                return _this.onAdd(addedValue, addedText, $addedChoice);
            },
            onChange: function (value, text, $choice) {
                badSearch = null;
                return _this.onChangeSemantic(value, text, $choice);
            },
            onHide: function () {
                if (badSearch !== null) {
                    badSearch = null;
                    _this._$dropdown.children('input.search')[0].value = '';
                    if (!_this._modelValue || (_this._modelValue && _this._modelValue.length === 0)) {
                        _this._$dropdown.dropdown('set text', _this.placeholder);
                    }
                    else {
                        _this._$dropdown.dropdown('set selected', _this._modelValue);
                    }
                }
                return _this.onHide();
            },
            // tslint:disable-next-line:only-arrow-functions
            onLabelCreate: function (value, text) {
                var $label = this;
                return self.onLabelCreate($label, value, text);
            },
            onLabelSelect: function ($selectedLabels) {
                return _this.onLabelSelect($selectedLabels);
            },
            // tslint:disable-next-line:only-arrow-functions
            onNoResults: function (searchValue) {
                if (!this.allowAdditions) {
                    badSearch = searchValue;
                }
                return this.onNoResults(searchValue);
            },
            onRemove: function (removedValue, removedText, $removedChoice) {
                return _this.onRemove(removedValue, removedText, $removedChoice);
            },
            onShow: function () {
                return _this.onShow();
            },
            placeholder: 'auto'
        };
        if (this.maxSelections > 1) {
            config.maxSelections = this.maxSelections;
        }
        var el = this.elementRef.nativeElement;
        this._$dropdown = $(el).children('.ui.dropdown');
        this._$dropdown.dropdown(config);
        this._applyArrowNavFix(this._$dropdown);
    };
    /**
   * Is called after a dropdown value changes. Receives the name and value of selection and the active menu element
   * @param value
   * @param text
   * @param $choice
   */
    Dropdown.prototype.onChangeSemantic = function (value, text, $choice) {
        this._modelValue = value;
        this.fireChange(value);
    };
    /**
   * Is called after a dropdown selection is added using a multiple select dropdown, only receives the added value
   * @param addedValue
   * @param addedText
   * @param $addedChoice
   */
    Dropdown.prototype.onAdd = function (addedValue, addedText, $addedChoice) { };
    /**
   * Is called after a dropdown selection is removed using a multiple select dropdown, only receives the removed value
   * @param removedValue
   * @param removedText
   * @param $removedChoice
   */
    Dropdown.prototype.onRemove = function (removedValue, removedText, $removedChoice) { };
    /**
   * Allows you to modify a label before it is added. Expects $label to be returned.
   * @param $label
   * @param value
   * @param text
   */
    Dropdown.prototype.onLabelCreate = function ($label, value, text) {
        return $label;
    };
    /**
   * Is called after a label is selected by a user
   * @param $selectedLabels
   */
    Dropdown.prototype.onLabelSelect = function ($selectedLabels) { };
    /**
   * Is called after a dropdown is searched with no matching values
   * @param searchValue
   */
    Dropdown.prototype.onNoResults = function (searchValue) { };
    /**
   * Is called before a dropdown is shown. If false is returned, dropdown will not be shown.
   */
    Dropdown.prototype.onShow = function () { };
    /**
   * Is called before a dropdown is hidden. If false is returned, dropdown will not be hidden.
   */
    Dropdown.prototype.onHide = function () {
        this.touch.emit(this._modelValue);
        this.onTouched();
    };
    Dropdown.prototype.applyValue = function (value) {
        var _this = this;
        var count = 0;
        Observable.interval(10)
            .takeWhile(function () {
            count++;
            if (count > 100) {
                throw new Error('Dropdown element not found.');
            }
            return _this._$dropdown == null;
        })
            .subscribe(function () {
            // still null!
        }, function (e) {
            _this.loggerService.info('Dropdown', 'Error', e);
        }, function () {
            _this.loggerService.info('Dropdown', 'onComplete');
            _this._$dropdown.dropdown('set selected', value);
        });
    };
    /**
   * Fixes an issue with up and down arrows triggering a search in the dropdown, which auto selects the first result
   * after a short buffering period.
   * @param $dropdown The JQuery dropdown element, after calling #.dropdown(config).
   * @private
   */
    Dropdown.prototype._applyArrowNavFix = function ($dropdown) {
        var $searchField = $dropdown.children('input.search');
        var enterEvent = this.enter;
        $searchField.on('keyup', function (event) {
            if (DO_NOT_SEARCH_ON_THESE_KEY_EVENTS[event.keyCode]) {
                if (event.keyCode === KeyCode.ENTER && enterEvent) {
                    enterEvent.emit(true);
                }
                event.stopPropagation();
            }
        });
    };
    return Dropdown;
}());
export { Dropdown };
Dropdown.decorators = [
    { type: Component, args: [{
                changeDetection: ChangeDetectionStrategy.OnPush,
                selector: 'cw-input-dropdown',
                template: "<div class=\"ui fluid selection dropdown search ng-valid\"\n     [class.required]=\"minSelections > 0\"\n     [class.multiple]=\"maxSelections > 1\"\n     tabindex=\"0\"\n     (change)=\"$event.stopPropagation()\"\n     (blur)=\"$event.stopPropagation()\">\n  <input type=\"hidden\" [name]=\"name\" [value]=\"_modelValue\" />\n  <i class=\"dropdown icon\"></i>\n  <div class=\"default text\">{{placeholder}}</div>\n  <div class=\"menu\" tabindex=\"-1\">\n    <div *ngFor=\"let opt of _options | async\" class=\"item\" [attr.data-value]=\"opt.value\" [attr.data-text]=\"opt.label\">\n      <i [ngClass]=\"opt.icon\" ></i>\n      {{opt.label}}\n    </div>\n  </div>\n</div>\n  "
            },] },
];
/** @nocollapse */
Dropdown.ctorParameters = function () { return [
    { type: ElementRef, },
    { type: NgControl, decorators: [{ type: Optional },] },
    { type: LoggerService, },
]; };
Dropdown.propDecorators = {
    'name': [{ type: Input },],
    'placeholder': [{ type: Input },],
    'allowAdditions': [{ type: Input },],
    'minSelections': [{ type: Input },],
    'maxSelections': [{ type: Input },],
    'onDropDownChange': [{ type: Output },],
    'touch': [{ type: Output },],
    'enter': [{ type: Output },],
    'value': [{ type: Input },],
};
var InputOption = (function () {
    function InputOption(dropdown) {
        this._dropdown = dropdown;
    }
    InputOption.prototype.ngOnChanges = function (change) {
        if (!this._isRegistered) {
            if (this._dropdown.hasOption(this)) {
                this._dropdown.updateOption(this);
            }
            else {
                this._dropdown.addOption(this);
            }
            this._isRegistered = true;
        }
        else {
            if (!this.label) {
                this.label = this.value;
            }
            this._dropdown.updateOption(this);
        }
    };
    return InputOption;
}());
export { InputOption };
InputOption.decorators = [
    { type: Directive, args: [{
                selector: 'cw-input-option'
            },] },
];
/** @nocollapse */
InputOption.ctorParameters = function () { return [
    { type: Dropdown, decorators: [{ type: Host },] },
]; };
InputOption.propDecorators = {
    'value': [{ type: Input },],
    'label': [{ type: Input },],
    'icon': [{ type: Input },],
};
//# sourceMappingURL=dropdown.js.map