(function(angular){
    'use strict';
    function _setTranslation(string){
        if (angular.isDefined(string)) {
            if (angular.isString(string)) {
                return {
                    translationId: string
                }
            } else if (angular.isObject(string)) {
                return string;
            }
        }
    }
    let BaseCtrlInject = ['$uibModalInstance', 'data', 'texts', 'classes', 'btnText'];
    class BaseCtrl {
        static get $inject(){
            return BaseCtrlInject;
        }
        constructor(...injectables){
            injectNg(injectables, BaseCtrlInject, this);
        }
        close(){
            this.$uibModalInstance.close();
        }
        $onInit(){
            this.msg = this.texts.msg;
            let { icon } = this.classes;
            this.classes.icon = angular.isDefined(icon) && angular.isString(icon) ? icon : 'fas fa-exclamation-triangle';
            this.header = _setTranslation(this.texts.header);
        }
    }
    let WaitCtrlInject = ['$uibModalInstance', '$timeout', 'texts', 'classes', 'progressInfo'];
    class WaitCtrl {
        static get $inject(){
            return WaitCtrlInject;
        }
        constructor(...injectables){
            injectNg(injectables, WaitCtrlInject, this);
        }
        close(){
            this.$uibModalInstance.close();
        }
        get getProgress(){
            let progress = this.progressInfo.progress / this.progressInfo.total * 100;
            if (progress === this.progressInfo.total) this.$timeout(() => this.close(), 250);
            return {
                width: `${progress}%`
            }
        }
        $onInit(){
            this.msg = this.texts.msg;
            let { total, progress } = this.progressInfo;
            this.progressInfo.total = angular.isDefined(total) ? total : 200;
            this.progressInfo.progress = angular.isDefined(progress) ? progress : 0;
            let { icon } = this.classes;
            this.classes.icon = angular.isDefined(icon) && angular.isString(icon) ? icon : 'fas fa-clock';
            this.header = _setTranslation(this.texts.header);
        }
    }
    let ConfirmCtrlInject = ['$uibModalInstance', 'texts', 'data', 'classes'];
    class ConfirmCtrl {
        static get $inject(){
            return ConfirmCtrlInject;
        }
        constructor(...injectables){
            injectNg(injectables, ConfirmCtrlInject, this);
        }
        $onInit(){
            this.msg = this.texts.msg;
            let { icon } = this.classes;
            this.classes.icon = angular.isDefined(icon) && angular.isString(icon) ? icon : 'fas fa-question-circle';
            this.header = _setTranslation(this.texts.header);
        }
        no(){
            this.$uibModalInstance.dismiss('no');
        }
        yes(){
            this.$uibModalInstance.close('yes');
        }
    }
    let ConfirmDeletionCtrlInject = ['$uibModalInstance', 'data', 'config'];
    class ConfirmDeletionCtrl {
        static get $inject(){
            return ConfirmDeletionCtrlInject;
        }
        constructor(...injectables){
            injectNg(injectables, ConfirmDeletionCtrlInject, this);
        }
        remove(row){
            removeFromArray(this.data, '$$hashKey', row.$$hashKey);
            if (isNU0(this.data)) this.$uibModalInstance.dismiss('no-data');
        }
        _get(row, value){
            return getSafe(row, value);
        }
        get hasRemovables(){
            return this.data.some(o => !o.notRemovable) && !this.config.loading;
        }
        no(){
            this.$uibModalInstance.dismiss('no');
        }
        yes(){
            this.$uibModalInstance.close(this.data.filter(o => !o.notRemovable));
        }
    }
    let StDialogsConfigInject = ['StDialogsDefaults'];
    class StDialogsConfig {
        static get $inject(){
            return StDialogsConfigInject;
        }
        constructor(...injectables){
            injectNg(injectables, StDialogsConfigInject, this);
        }
        set all(all){
            if (!angular.isObject(all)) return;
            angular.merge(this.StDialogsDefaults, all);
        }
        $get(){
            return this;
        }
    }
    let StDialogsServiceInject = ['StDialogsDefaults', '$uibModal', '$templateCache', '$uibModalStack', '$window', '$timeout'];
    class StDialogsService {
        static get $inject(){
            return StDialogsServiceInject;
        }
        constructor(...injectables){
            injectNg(injectables, StDialogsServiceInject, this);
        }
        mergeConfig(config, type){
            if (!type) type = 'dialogs';
            if (!isPlainObject(config)) config = {};
            return angular.merge({}, this.StDialogsDefaults[type], config);
        }
        getBaseConfig(config, templateUrl, controller, data){
            let resolve = {};
            if (angular.isObject(data)) {
                angular.forEach(data, (value, key) => {
                    resolve[key] = () => value;
                });
            } else {
                resolve = {
                    data: () => data
                }
            }
            return Object.assign({}, config, {
                templateUrl,
                controller,
                controllerAs: '$ctrl',
                resolve
            })
        }
        _applyRendered(modal, config){
            if (config.rendered) {
                if (angular.isFunction(config.rendered)) {
                    config.rendered.apply(config.rendered.this, config.rendered.values);
                } else if (isPlainObject(config.rendered)) {
                    let { rendered } = config;
                    modal.rendered.then(() => {
                        let el = this.$uibModalStack.getTop().value.modalDomEl,
                        selected = angular.element(el[0].querySelectorAll(rendered.selector));
                        if (rendered.apply in selected) {
                            selected[rendered.apply].apply(selected, rendered.values);
                        }
                    })
                }
            };
            return modal;
        }
        error(header, msg, config, data = {}){
            config = this.mergeConfig(config);
            let resolve = {
                texts: {
                    header: angular.copy(header),
                    msg: angular.copy(msg),
                },
                data: config.copy ? angular.copy(data) : data,
                classes: {
                    header: 'dialog-header-error',
                    text: 'danger',
                    icon: config.icon || 'fas fa-exclamation-triangle',
                    btnClose: 'btn-danger'
                },
                btnText: {
                    close: 'DIALOGS_CLOSE'
                }
            }
            return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, '/stDialogs/base.html', BaseCtrl, resolve)), config);
        }
        wait(header, msg, progressInfo, config){
            config = this.mergeConfig(config);
            let resolve = {
                texts: {
                    header: angular.copy(header),
                    msg: angular.copy(msg),
                },
                progressInfo,
                classes: {
                    header: 'dialog-header-wait',
                    icon: config.icon || 'fas fa-clock'
                }
            }
            return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, '/stDialogs/wait.html', WaitCtrl, resolve)), config);
        }
        notify(header, msg, config, data = {}){
            config = this.mergeConfig(config);
            let resolve = {
                texts: {
                    header: angular.copy(header),
                    msg: angular.copy(msg),
                },
                data: config.copy ? angular.copy(data) : data,
                classes: {
                    header: 'dialog-header-notify',
                    text: 'info',
                    icon: config.icon || 'fas fa-info-circle',
                    btnClose: 'btn-primary'
                },
                btnText: {
                    close: 'DIALOGS_OK'
                }
            }
            return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, '/stDialogs/base.html', BaseCtrl, resolve)), config);
        }
        success(header, msg, config, data = {}){
            config = this.mergeConfig(config);
            let resolve = {
                texts: {
                    header: angular.copy(header),
                    msg: angular.copy(msg),
                },
                data: config.copy ? angular.copy(data) : data,
                classes: {
                    header: 'dialog-header-success',
                    text: 'success',
                    icon: config.icon || 'fas fa-check-circle',
                    btnClose: 'btn-success'
                },
                btnText: {
                    close: 'DIALOGS_CLOSE'
                }
            }
            return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, '/stDialogs/base.html', BaseCtrl, resolve)), config);
        }
        infoModule(header, msg, config, data = {}){
            config = this.mergeConfig(config);
            let resolve = {
                texts: {
                    header: angular.copy(header),
                    msg: angular.copy(msg),
                },
                data: config.copy ? angular.copy(data) : data,
                classes: {
                    header: 'dialog-header-notify',
                    text: 'dark',
                    icon: config.icon || 'fas fa-info-circle',
                    btnClose: 'btn-primary'
                },
                btnText: {
                    close: 'DIALOGS_CLOSE'
                }
            }
            return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, '/stDialogs/base.html', BaseCtrl, resolve)), config);
        }
        confirm(header, msg, config, data = {}){
            config = this.mergeConfig(config);
            let resolve = {
                texts: {
                    header: angular.copy(header),
                    msg: angular.copy(msg),
                },
                data: config.copy ? angular.copy(data) : data,
                classes: {
                    header: 'dialog-header-confirm',
                    icon: config.icon || 'fas fa-question-circle',
                    btnClose: 'btn-default',
                    btnAccept: 'btn-primary'
                },
                btnText: {
                    accept: 'DIALOGS_YES',
                    close: 'DIALOGS_NO'
                }
            }
            return this._applyRendered(this.$uibModal.open(this.getBaseConfig(config, '/stDialogs/confirm.html', ConfirmCtrl, resolve)), config);
        }
        confirmDeletion(data, config = {}, options = {}){
            options = this.mergeConfig(options);
            if (!isPlainObject(config)) config = {};
            let resolve = {data, config};
            let base = this.getBaseConfig(options, config.templateUrl, ConfirmDeletionCtrl, resolve);
            return this._applyRendered(this.$uibModal.open(base), config);
        }
        create(config, data, options){
            options = this.mergeConfig(options);
            if (angular.isString(config)) {
                config = {
                    component: config
                }
            } else if (!isPlainObject(config)) throw new Error('Needs to be an Object | string');
            else if (!(config.template || config.templateUrl || config.controller || config.component)) throw new Error('Needs a component or controller/template');
            let modalOptions = Object.assign({}, options, config, {
                resolve: {
                    data: () => config.copy ? angular.copy(data) : data
                }
            });
            return this._applyRendered(this.$uibModal.open(modalOptions), config);
        }
    }
    RunTemplateCache.$inject = ['$templateCache']
    function RunTemplateCache($templateCache){
        $templateCache.put('/stDialogs/base.html', `
            <div class="modal-header" ng-class="$ctrl.classes.header">
                <button type="button" class="close" ng-click="$ctrl.close()">&times;</button>
                <h4 class="modal-title">
                    <span ng-class="$ctrl.classes.icon"></span> 
                    <span translate="{{$ctrl.header.translationId}}" translate-values="{{$ctrl.header.values}}"></span>
                </h4>
            </div>
            <div class="modal-body text-{{$ctrl.classes.text}}" bind-html-compile="$ctrl.msg"></div>
            <div class="modal-footer">
                <button type="button" class="btn" ng-class="$ctrl.classes.btnClose" ng-click="$ctrl.close()" translate="{{$ctrl.btnText.close}}"></button>
            </div>
        `);
        $templateCache.put('/stDialogs/wait.html', `
            <div class="modal-header" ng-class="$ctrl.classes.header">
                <h4 class="modal-title">
                    <span ng-class="$ctrl.classes.icon"></span> 
                    <span translate="{{$ctrl.header.translationId}}" translate-values="{{$ctrl.header.values}}"></span>
                </h4>
            </div>
            <div class="modal-body">
                <span bind-html-compile="$ctrl.msg"></span>
                <div class="active progress progress-striped">
                    <div class="progress-bar progress-bar-info" ng-style="$ctrl.getProgress"></div>
                    <span class="sr-only">
                        <span ng-bind="$ctrl.progress"></span> 
                        <span translate="DIALOGS_PERCENT_COMPLETE"></span>
                    </span>
                </div>
            </div>
        `);
        $templateCache.put('/stDialogs/confirm.html', `
            <div class="modal-header" ng-class="$ctrl.classes.header">
                <button class="close" ng-click="$ctrl.no()" type="button">&times;</button>
                <h4 class="modal-title">
                    <span ng-class="$ctrl.classes.icon"></span> 
                    <span translate="{{$ctrl.header.translationId}}" translate-values="{{$ctrl.header.values}}"></span>
                </h4>
            </div>
            <div class="modal-body" bind-html-compile="$ctrl.msg"></div>
            <div class="modal-footer">
                <button class="btn" ng-class="$ctrl.classes.btnAccept" ng-click="$ctrl.yes()" type="button" translate="{{$ctrl.btnText.accept}}"></button>
                <button class="btn" ng-class="$ctrl.classes.btnClose" ng-click="$ctrl.no()" type="button" translate="{{$ctrl.btnText.close}}"></button>
            </div>
        `);
        $templateCache.put('/stDialogs/confirmDeletion.html', `
            <div class="dialog-header-confirm modal-header">
                <button class="close" ng-click="$ctrl.no()" type=button>&times;</button>
                <h4 class="modal-title">
                    <span class="fas fa-question-circle"></span> 
                    <span translate="ui-grid-st-confirm-deletion" translate-values="{{$ctrl.header.values}}"></span>
                </h4>
            </div>
            <div class="modal-body">
                <ul class="list-group">
                    <li class="list-group-item list-group-item-action ui-grid-st-deletion-animation" 
                        ng-repeat="row in $ctrl.data"
                        ng-class="{'not-removable': row.notRemovable}"
                        tooltip-enable="row.notRemovable" 
                        tooltip-popup-delay="378" 
                        uib-tooltip="{{$ctrl.config.verify.msg | translate}}">

                        <span ng-if="!$ctrl.config.noLabel" translate="{{$ctrl.config.label || $ctrl.config.confirmDeletion}}"></span>: 
                        <span ng-bind="$ctrl._get(row, $ctrl.config.confirmDeletion)"></span>
                        <div class="loading-bar-spinner-list pull-right" ng-if="$ctrl.config.loading">
                            <div class="spinner-icon"></div>
                        </div>
                        <a class="badge badge-danger" ng-if="$ctrl.config.deleteFromList">
                            <span class="fas fa-times" ng-click="$ctrl.remove(row)"></span>
                        </a>
                    </ul>
            </div>
            <div class="modal-footer">
                <button class="btn btn-primary" ng-click="$ctrl.yes()" type="button" ng-disabled="!$ctrl.hasRemovables" translate="DIALOGS_YES"></button>
                <button class="btn btn-default" ng-click="$ctrl.no()" type="button" translate="DIALOGS_NO"></button>
            </div>
        `);
    }
    angular.module('st.dialogs', ['ui.bootstrap.modal', 'pascalprecht.translate', 'ngAnimate'])
        .constant('StDialogsDefaults', {
            backdrop: true,
            keyboard: true,
            windowClass: 'dialogs-default',
            backdropClass: 'dialogs-backdrop-default',
            copy: true,
            windowTemplate: null,
            size: 'lg',
            animation: true
        })
        .provider('StDialogsConfig', StDialogsConfig)
        .service('StDialogs', StDialogsService)
        .run(RunTemplateCache)
}(window.angular))