/**
 * @fileoverview added by tsickle
 * @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
 */
import * as tslib_1 from "tslib";
/*
 The MIT License (MIT)

 Copyright (c) 2017-2018 Stefano Cappa (Ks89)

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 */
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { AccessibleComponent } from '../accessible.component';
import { Action } from '../../model/action.enum';
import { DescriptionStrategy } from '../../model/description.interface';
import { ImageModalEvent } from '../../model/image.class';
import { InternalLibImage } from '../../model/image-internal.class';
import { Keyboard } from '../../model/keyboard.enum';
import { LoadingType } from '../../model/loading-config.interface';
import { NEXT, PREV } from '../../utils/user-input.util';
import { getIndex } from '../../utils/image.util';
/**
 * Interface to describe the Load Event, used to
 * emit an event when the image is finally loaded and the spinner has gone.
 * @record
 */
export function ImageLoadEvent() { }
if (false) {
    /** @type {?} */
    ImageLoadEvent.prototype.status;
    /** @type {?} */
    ImageLoadEvent.prototype.index;
    /** @type {?} */
    ImageLoadEvent.prototype.id;
}
/**
 * Component with the current image with some additional elements like arrows and side previews.
 */
var CurrentImageComponent = /** @class */ (function (_super) {
    tslib_1.__extends(CurrentImageComponent, _super);
    /**
     * Component with the current image with some additional elements like arrows and side previews.
     */
    function CurrentImageComponent() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        /**
         * Output to emit an event when images are loaded. The payload contains an `ImageLoadEvent`.
         */
        _this.loadImage = new EventEmitter();
        /**
         * Output to emit any changes of the current image. The payload contains an `ImageModalEvent`.
         */
        _this.changeImage = new EventEmitter();
        /**
         * Output to emit an event when the modal gallery is closed. The payload contains an `ImageModalEvent`.
         */
        _this.close = new EventEmitter();
        /**
         * Enum of type `Action` that represents a mouse click on a button.
         * Declared here to be used inside the template.
         */
        _this.clickAction = Action.CLICK;
        /**
         * Enum of type `Action` that represents a keyboard action.
         * Declared here to be used inside the template.
         */
        _this.keyboardAction = Action.KEYBOARD;
        /**
         * Boolean that it's true when you are watching the first image (currently visible).
         * False by default
         */
        _this.isFirstImage = false;
        /**
         * Boolean that it's true when you are watching the last image (currently visible).
         * False by default
         */
        _this.isLastImage = false;
        /**
         * Boolean that it's true if an image of the modal gallery is still loading.
         * True by default
         */
        _this.loading = true;
        /**
         * Private object without type to define all swipe actions used by hammerjs.
         */
        _this.SWIPE_ACTION = {
            LEFT: 'swipeleft',
            RIGHT: 'swiperight',
            UP: 'swipeup',
            DOWN: 'swipedown'
        };
        return _this;
    }
    /**
     * Method ´ngOnInit´ to build `configCurrentImage` applying default values.
     * This is an Angular's lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     */
    /**
     * Method ´ngOnInit´ to build `configCurrentImage` applying default values.
     * This is an Angular's lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     * @return {?}
     */
    CurrentImageComponent.prototype.ngOnInit = /**
     * Method ´ngOnInit´ to build `configCurrentImage` applying default values.
     * This is an Angular's lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called only one time!!!
     * @return {?}
     */
    function () {
        /** @type {?} */
        var defaultLoading = { enable: true, type: LoadingType.STANDARD };
        /** @type {?} */
        var defaultDescriptionStyle = {
            bgColor: 'rgba(0, 0, 0, .5)',
            textColor: 'white',
            marginTop: '0px',
            marginBottom: '0px',
            marginLeft: '0px',
            marginRight: '0px'
        };
        /** @type {?} */
        var defaultDescription = {
            strategy: DescriptionStrategy.ALWAYS_VISIBLE,
            imageText: 'Image ',
            numberSeparator: '/',
            beforeTextDescription: ' - ',
            style: defaultDescriptionStyle
        };
        /** @type {?} */
        var defaultCurrentImageConfig = {
            navigateOnClick: true,
            loadingConfig: defaultLoading,
            description: defaultDescription,
            downloadable: false,
            invertSwipe: false
        };
        this.configCurrentImage = Object.assign({}, defaultCurrentImageConfig, this.currentImageConfig);
        this.configCurrentImage.description = Object.assign({}, defaultDescription, this.configCurrentImage.description);
    };
    /**
     * Method ´ngOnChanges´ to update `loading` status and emit events.
     * If the gallery is open, then it will also manage boundary arrows and sliding.
     * This is an Angular's lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     */
    /**
     * Method ´ngOnChanges´ to update `loading` status and emit events.
     * If the gallery is open, then it will also manage boundary arrows and sliding.
     * This is an Angular's lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     * @param {?} changes
     * @return {?}
     */
    CurrentImageComponent.prototype.ngOnChanges = /**
     * Method ´ngOnChanges´ to update `loading` status and emit events.
     * If the gallery is open, then it will also manage boundary arrows and sliding.
     * This is an Angular's lifecycle hook, so its called automatically by Angular itself.
     * In particular, it's called when any data-bound property of a directive changes!!!
     * @param {?} changes
     * @return {?}
     */
    function (changes) {
        /** @type {?} */
        var images = changes.images;
        /** @type {?} */
        var currentImage = changes.currentImage;
        if (currentImage && currentImage.previousValue !== currentImage.currentValue) {
            this.updateIndexes();
        }
        else if (images && images.previousValue !== images.currentValue) {
            this.updateIndexes();
        }
    };
    /**
     * Method to handle keypress based on the `keyboardConfig` input. It gets the keyCode of
     * the key that triggered the keypress event to navigate between images or to close the modal gallery.
     * @param number keyCode of the key that triggered the keypress event
     */
    /**
     * Method to handle keypress based on the `keyboardConfig` input. It gets the keyCode of
     * the key that triggered the keypress event to navigate between images or to close the modal gallery.
     * @param {?} keyCode
     * @return {?}
     */
    CurrentImageComponent.prototype.onKeyPress = /**
     * Method to handle keypress based on the `keyboardConfig` input. It gets the keyCode of
     * the key that triggered the keypress event to navigate between images or to close the modal gallery.
     * @param {?} keyCode
     * @return {?}
     */
    function (keyCode) {
        /** @type {?} */
        var esc = this.keyboardConfig && this.keyboardConfig.esc ? this.keyboardConfig.esc : Keyboard.ESC;
        /** @type {?} */
        var right = this.keyboardConfig && this.keyboardConfig.right ? this.keyboardConfig.right : Keyboard.RIGHT_ARROW;
        /** @type {?} */
        var left = this.keyboardConfig && this.keyboardConfig.left ? this.keyboardConfig.left : Keyboard.LEFT_ARROW;
        switch (keyCode) {
            case esc:
                this.close.emit(new ImageModalEvent(Action.KEYBOARD, true));
                break;
            case right:
                this.nextImage(Action.KEYBOARD);
                break;
            case left:
                this.prevImage(Action.KEYBOARD);
                break;
        }
    };
    /**
     * Method to get the image description based on input params.
     * If you provide a full description this will be the visible description, otherwise,
     * it will be built using the `Description` object, concatenating its fields.
     * @param Image image to get its description. If not provided it will be the current image
     * @returns String description of the image (or the current image if not provided)
     * @throws an Error if description isn't available
     */
    /**
     * Method to get the image description based on input params.
     * If you provide a full description this will be the visible description, otherwise,
     * it will be built using the `Description` object, concatenating its fields.
     * @throws an Error if description isn't available
     * @param {?=} image
     * @return {?} String description of the image (or the current image if not provided)
     */
    CurrentImageComponent.prototype.getDescriptionToDisplay = /**
     * Method to get the image description based on input params.
     * If you provide a full description this will be the visible description, otherwise,
     * it will be built using the `Description` object, concatenating its fields.
     * @throws an Error if description isn't available
     * @param {?=} image
     * @return {?} String description of the image (or the current image if not provided)
     */
    function (image) {
        if (image === void 0) { image = this.currentImage; }
        if (!this.configCurrentImage || !this.configCurrentImage.description) {
            throw new Error('Description input must be a valid object implementing the Description interface');
        }
        /** @type {?} */
        var imageWithoutDescription = !image.modal || !image.modal.description || image.modal.description === '';
        switch (this.configCurrentImage.description.strategy) {
            case DescriptionStrategy.HIDE_IF_EMPTY:
                return imageWithoutDescription ? '' : image.modal.description + '';
            case DescriptionStrategy.ALWAYS_HIDDEN:
                return '';
            default:
                // ----------- DescriptionStrategy.ALWAYS_VISIBLE -----------------
                return this.buildTextDescription(image, imageWithoutDescription);
        }
    };
    /**
     * Method to get `alt attribute`.
     * `alt` specifies an alternate text for an image, if the image cannot be displayed.
     * @param Image image to get its alt description. If not provided it will be the current image
     * @returns String alt description of the image (or the current image if not provided)
     */
    /**
     * Method to get `alt attribute`.
     * `alt` specifies an alternate text for an image, if the image cannot be displayed.
     * @param {?=} image
     * @return {?} String alt description of the image (or the current image if not provided)
     */
    CurrentImageComponent.prototype.getAltDescriptionByImage = /**
     * Method to get `alt attribute`.
     * `alt` specifies an alternate text for an image, if the image cannot be displayed.
     * @param {?=} image
     * @return {?} String alt description of the image (or the current image if not provided)
     */
    function (image) {
        if (image === void 0) { image = this.currentImage; }
        if (!image) {
            return '';
        }
        return image.modal && image.modal.description ? image.modal.description : "Image " + (getIndex(image, this.images) + 1);
    };
    /**
     * Method to get the title attributes based on descriptions.
     * This is useful to prevent accessibility issues, because if DescriptionStrategy is ALWAYS_HIDDEN,
     * it prevents an empty string as title.
     * @param Image image to get its description. If not provided it will be the current image
     * @returns String title of the image based on descriptions
     * @throws an Error if description isn't available
     */
    /**
     * Method to get the title attributes based on descriptions.
     * This is useful to prevent accessibility issues, because if DescriptionStrategy is ALWAYS_HIDDEN,
     * it prevents an empty string as title.
     * @throws an Error if description isn't available
     * @param {?=} image
     * @return {?} String title of the image based on descriptions
     */
    CurrentImageComponent.prototype.getTitleToDisplay = /**
     * Method to get the title attributes based on descriptions.
     * This is useful to prevent accessibility issues, because if DescriptionStrategy is ALWAYS_HIDDEN,
     * it prevents an empty string as title.
     * @throws an Error if description isn't available
     * @param {?=} image
     * @return {?} String title of the image based on descriptions
     */
    function (image) {
        if (image === void 0) { image = this.currentImage; }
        if (!this.configCurrentImage || !this.configCurrentImage.description) {
            throw new Error('Description input must be a valid object implementing the Description interface');
        }
        /** @type {?} */
        var imageWithoutDescription = !image.modal || !image.modal.description || image.modal.description === '';
        /** @type {?} */
        var description = this.buildTextDescription(image, imageWithoutDescription);
        return description;
    };
    /**
     * Method to get the left side preview image.
     * @returns Image the image to show as size preview on the left
     */
    /**
     * Method to get the left side preview image.
     * @return {?} Image the image to show as size preview on the left
     */
    CurrentImageComponent.prototype.getLeftPreviewImage = /**
     * Method to get the left side preview image.
     * @return {?} Image the image to show as size preview on the left
     */
    function () {
        /** @type {?} */
        var currentIndex = getIndex(this.currentImage, this.images);
        if (currentIndex === 0 && this.slideConfig.infinite) {
            // the current image is the first one,
            // so the previous one is the last image
            // because infinite is true
            return this.images[this.images.length - 1];
        }
        this.handleBoundaries(currentIndex);
        return this.images[Math.max(currentIndex - 1, 0)];
    };
    /**
     * Method to get the right side preview image.
     * @returns Image the image to show as size preview on the right
     */
    /**
     * Method to get the right side preview image.
     * @return {?} Image the image to show as size preview on the right
     */
    CurrentImageComponent.prototype.getRightPreviewImage = /**
     * Method to get the right side preview image.
     * @return {?} Image the image to show as size preview on the right
     */
    function () {
        /** @type {?} */
        var currentIndex = getIndex(this.currentImage, this.images);
        if (currentIndex === this.images.length - 1 && this.slideConfig.infinite) {
            // the current image is the last one,
            // so the next one is the first image
            // because infinite is true
            return this.images[0];
        }
        this.handleBoundaries(currentIndex);
        return this.images[Math.min(currentIndex + 1, this.images.length - 1)];
    };
    /**
     * Method called by events from both keyboard and mouse on an image.
     * This will invoke the nextImage method.
     * @param KeyboardEvent | MouseEvent event payload
     * @param Action action that triggered the event or `Action.NORMAL` if not provided
     */
    /**
     * Method called by events from both keyboard and mouse on an image.
     * This will invoke the nextImage method.
     * @param {?} event
     * @param {?=} action
     * @return {?}
     */
    CurrentImageComponent.prototype.onImageEvent = /**
     * Method called by events from both keyboard and mouse on an image.
     * This will invoke the nextImage method.
     * @param {?} event
     * @param {?=} action
     * @return {?}
     */
    function (event, action) {
        if (action === void 0) { action = Action.NORMAL; }
        // check if triggered by a mouse click
        // If yes, It should block navigation when navigateOnClick is false
        if (action === Action.CLICK && !this.configCurrentImage.navigateOnClick) {
            // a user has requested to block navigation via configCurrentImage.navigateOnClick property
            return;
        }
        /** @type {?} */
        var result = _super.prototype.handleImageEvent.call(this, event);
        if (result === NEXT) {
            this.nextImage(action);
        }
    };
    /**
     * Method called by events from both keyboard and mouse on a navigation arrow.
     * @param string direction of the navigation that can be either 'next' or 'prev'
     * @param KeyboardEvent | MouseEvent event payload
     * @param Action action that triggered the event or `Action.NORMAL` if not provided
     */
    /**
     * Method called by events from both keyboard and mouse on a navigation arrow.
     * @param {?} direction
     * @param {?} event
     * @param {?=} action
     * @return {?}
     */
    CurrentImageComponent.prototype.onNavigationEvent = /**
     * Method called by events from both keyboard and mouse on a navigation arrow.
     * @param {?} direction
     * @param {?} event
     * @param {?=} action
     * @return {?}
     */
    function (direction, event, action) {
        if (action === void 0) { action = Action.NORMAL; }
        /** @type {?} */
        var result = _super.prototype.handleNavigationEvent.call(this, direction, event);
        if (result === NEXT) {
            this.nextImage(action);
        }
        else if (result === PREV) {
            this.prevImage(action);
        }
    };
    /**
     * Method to go back to the previous image.
     * @param action Enum of type `Action` that represents the source
     *  action that moved back to the previous image. `Action.NORMAL` by default.
     */
    /**
     * Method to go back to the previous image.
     * @param {?=} action Enum of type `Action` that represents the source
     *  action that moved back to the previous image. `Action.NORMAL` by default.
     * @return {?}
     */
    CurrentImageComponent.prototype.prevImage = /**
     * Method to go back to the previous image.
     * @param {?=} action Enum of type `Action` that represents the source
     *  action that moved back to the previous image. `Action.NORMAL` by default.
     * @return {?}
     */
    function (action) {
        if (action === void 0) { action = Action.NORMAL; }
        // check if prevImage should be blocked
        if (this.isPreventSliding(0)) {
            return;
        }
        /** @type {?} */
        var prevImage = this.getPrevImage();
        this.loading = !prevImage.previouslyLoaded;
        this.changeImage.emit(new ImageModalEvent(action, getIndex(prevImage, this.images)));
    };
    /**
     * Method to go back to the previous image.
     * @param action Enum of type `Action` that represents the source
     *  action that moved to the next image. `Action.NORMAL` by default.
     */
    /**
     * Method to go back to the previous image.
     * @param {?=} action Enum of type `Action` that represents the source
     *  action that moved to the next image. `Action.NORMAL` by default.
     * @return {?}
     */
    CurrentImageComponent.prototype.nextImage = /**
     * Method to go back to the previous image.
     * @param {?=} action Enum of type `Action` that represents the source
     *  action that moved to the next image. `Action.NORMAL` by default.
     * @return {?}
     */
    function (action) {
        if (action === void 0) { action = Action.NORMAL; }
        // check if nextImage should be blocked
        if (this.isPreventSliding(this.images.length - 1)) {
            return;
        }
        /** @type {?} */
        var nextImage = this.getNextImage();
        this.loading = !nextImage.previouslyLoaded;
        this.changeImage.emit(new ImageModalEvent(action, getIndex(nextImage, this.images)));
    };
    /**
     * Method to emit an event as loadImage output to say that the requested image if loaded.
     * This method is invoked by the javascript's 'load' event on an img tag.
     * @param Event event that triggered the load
     */
    /**
     * Method to emit an event as loadImage output to say that the requested image if loaded.
     * This method is invoked by the javascript's 'load' event on an img tag.
     * @param {?} event
     * @return {?}
     */
    CurrentImageComponent.prototype.onImageLoad = /**
     * Method to emit an event as loadImage output to say that the requested image if loaded.
     * This method is invoked by the javascript's 'load' event on an img tag.
     * @param {?} event
     * @return {?}
     */
    function (event) {
        /** @type {?} */
        var loadImageData = {
            status: true,
            index: getIndex(this.currentImage, this.images),
            id: this.currentImage.id
        };
        this.loadImage.emit(loadImageData);
        this.loading = false;
    };
    /**
     * Method used by Hammerjs to support touch gestures (you can also invert the swipe direction with configCurrentImage.invertSwipe).
     * @param action String that represent the direction of the swipe action. 'swiperight' by default.
     */
    /**
     * Method used by Hammerjs to support touch gestures (you can also invert the swipe direction with configCurrentImage.invertSwipe).
     * @param {?=} action String that represent the direction of the swipe action. 'swiperight' by default.
     * @return {?}
     */
    CurrentImageComponent.prototype.swipe = /**
     * Method used by Hammerjs to support touch gestures (you can also invert the swipe direction with configCurrentImage.invertSwipe).
     * @param {?=} action String that represent the direction of the swipe action. 'swiperight' by default.
     * @return {?}
     */
    function (action) {
        if (action === void 0) { action = this.SWIPE_ACTION.RIGHT; }
        switch (action) {
            case this.SWIPE_ACTION.RIGHT:
                if (this.configCurrentImage.invertSwipe) {
                    this.prevImage(Action.SWIPE);
                }
                else {
                    this.nextImage(Action.SWIPE);
                }
                break;
            case this.SWIPE_ACTION.LEFT:
                if (this.configCurrentImage.invertSwipe) {
                    this.nextImage(Action.SWIPE);
                }
                else {
                    this.prevImage(Action.SWIPE);
                }
                break;
            // case this.SWIPE_ACTION.UP:
            //   break;
            // case this.SWIPE_ACTION.DOWN:
            //   break;
        }
    };
    /**
     * Method used in `modal-gallery.component` to get the index of an image to delete.
     * @param Image image to get the index, or the visible image, if not passed
     * @returns number the index of the image
     */
    /**
     * Method used in `modal-gallery.component` to get the index of an image to delete.
     * @param {?=} image
     * @return {?} number the index of the image
     */
    CurrentImageComponent.prototype.getIndexToDelete = /**
     * Method used in `modal-gallery.component` to get the index of an image to delete.
     * @param {?=} image
     * @return {?} number the index of the image
     */
    function (image) {
        if (image === void 0) { image = this.currentImage; }
        return getIndex(image, this.images);
    };
    /**
     * Private method to update both `isFirstImage` and `isLastImage` based on
     * the index of the current image.
     * @param number currentIndex is the index of the current image
     */
    /**
     * Private method to update both `isFirstImage` and `isLastImage` based on
     * the index of the current image.
     * @param {?} currentIndex
     * @return {?}
     */
    CurrentImageComponent.prototype.handleBoundaries = /**
     * Private method to update both `isFirstImage` and `isLastImage` based on
     * the index of the current image.
     * @param {?} currentIndex
     * @return {?}
     */
    function (currentIndex) {
        if (this.images.length === 1) {
            this.isFirstImage = true;
            this.isLastImage = true;
            return;
        }
        if (!this.slideConfig || this.slideConfig.infinite === true) {
            // infinite sliding enabled
            this.isFirstImage = false;
            this.isLastImage = false;
        }
        else {
            switch (currentIndex) {
                case 0:
                    // execute this only if infinite sliding is disabled
                    this.isFirstImage = true;
                    this.isLastImage = false;
                    break;
                case this.images.length - 1:
                    // execute this only if infinite sliding is disabled
                    this.isFirstImage = false;
                    this.isLastImage = true;
                    break;
                default:
                    this.isFirstImage = false;
                    this.isLastImage = false;
                    break;
            }
        }
    };
    /**
     * Private method to check if next/prev actions should be blocked.
     * It checks if slideConfig.infinite === false and if the image index is equals to the input parameter.
     * If yes, it returns true to say that sliding should be blocked, otherwise not.
     * @param number boundaryIndex that could be either the beginning index (0) or the last index
     *  of images (this.images.length - 1).
     * @returns boolean true if slideConfig.infinite === false and the current index is
     *  either the first or the last one.
     */
    /**
     * Private method to check if next/prev actions should be blocked.
     * It checks if slideConfig.infinite === false and if the image index is equals to the input parameter.
     * If yes, it returns true to say that sliding should be blocked, otherwise not.
     * @param {?} boundaryIndex
     * @return {?} boolean true if slideConfig.infinite === false and the current index is
     *  either the first or the last one.
     */
    CurrentImageComponent.prototype.isPreventSliding = /**
     * Private method to check if next/prev actions should be blocked.
     * It checks if slideConfig.infinite === false and if the image index is equals to the input parameter.
     * If yes, it returns true to say that sliding should be blocked, otherwise not.
     * @param {?} boundaryIndex
     * @return {?} boolean true if slideConfig.infinite === false and the current index is
     *  either the first or the last one.
     */
    function (boundaryIndex) {
        return !!this.slideConfig && this.slideConfig.infinite === false && getIndex(this.currentImage, this.images) === boundaryIndex;
    };
    /**
     * Private method to get the next index.
     * This is necessary because at the end, when you call next again, you'll go to the first image.
     * That happens because all modal images are shown like in a circle.
     */
    /**
     * Private method to get the next index.
     * This is necessary because at the end, when you call next again, you'll go to the first image.
     * That happens because all modal images are shown like in a circle.
     * @return {?}
     */
    CurrentImageComponent.prototype.getNextImage = /**
     * Private method to get the next index.
     * This is necessary because at the end, when you call next again, you'll go to the first image.
     * That happens because all modal images are shown like in a circle.
     * @return {?}
     */
    function () {
        /** @type {?} */
        var currentIndex = getIndex(this.currentImage, this.images);
        /** @type {?} */
        var newIndex = 0;
        if (currentIndex >= 0 && currentIndex < this.images.length - 1) {
            newIndex = currentIndex + 1;
        }
        else {
            newIndex = 0; // start from the first index
        }
        return this.images[newIndex];
    };
    /**
     * Private method to get the previous index.
     * This is necessary because at index 0, when you call prev again, you'll go to the last image.
     * That happens because all modal images are shown like in a circle.
     */
    /**
     * Private method to get the previous index.
     * This is necessary because at index 0, when you call prev again, you'll go to the last image.
     * That happens because all modal images are shown like in a circle.
     * @return {?}
     */
    CurrentImageComponent.prototype.getPrevImage = /**
     * Private method to get the previous index.
     * This is necessary because at index 0, when you call prev again, you'll go to the last image.
     * That happens because all modal images are shown like in a circle.
     * @return {?}
     */
    function () {
        /** @type {?} */
        var currentIndex = getIndex(this.currentImage, this.images);
        /** @type {?} */
        var newIndex = 0;
        if (currentIndex > 0 && currentIndex <= this.images.length - 1) {
            newIndex = currentIndex - 1;
        }
        else {
            newIndex = this.images.length - 1; // start from the last index
        }
        return this.images[newIndex];
    };
    /**
     * Private method to build a text description.
     * This is used also to create titles.
     * @param Image image to get its description. If not provided it will be the current image.
     * @param boolean imageWithoutDescription is a boolean that it's true if the image hasn't a 'modal' description.
     * @returns String description built concatenating image fields with a specific logic.
     */
    /**
     * Private method to build a text description.
     * This is used also to create titles.
     * @param {?} image
     * @param {?} imageWithoutDescription
     * @return {?} String description built concatenating image fields with a specific logic.
     */
    CurrentImageComponent.prototype.buildTextDescription = /**
     * Private method to build a text description.
     * This is used also to create titles.
     * @param {?} image
     * @param {?} imageWithoutDescription
     * @return {?} String description built concatenating image fields with a specific logic.
     */
    function (image, imageWithoutDescription) {
        if (!this.configCurrentImage || !this.configCurrentImage.description) {
            throw new Error('Description input must be a valid object implementing the Description interface');
        }
        // If customFullDescription use it, otherwise proceed to build a description
        if (this.configCurrentImage.description.customFullDescription && this.configCurrentImage.description.customFullDescription !== '') {
            return this.configCurrentImage.description.customFullDescription;
        }
        /** @type {?} */
        var currentIndex = getIndex(image, this.images);
        // If the current image hasn't a description,
        // prevent to write the ' - ' (or this.description.beforeTextDescription)
        /** @type {?} */
        var prevDescription = this.configCurrentImage.description.imageText ? this.configCurrentImage.description.imageText : '';
        /** @type {?} */
        var midSeparator = this.configCurrentImage.description.numberSeparator ? this.configCurrentImage.description.numberSeparator : '';
        /** @type {?} */
        var middleDescription = currentIndex + 1 + midSeparator + this.images.length;
        if (imageWithoutDescription) {
            return prevDescription + middleDescription;
        }
        /** @type {?} */
        var currImgDescription = image.modal && image.modal.description ? image.modal.description : '';
        /** @type {?} */
        var endDescription = this.configCurrentImage.description.beforeTextDescription + currImgDescription;
        return prevDescription + middleDescription + endDescription;
    };
    /**
     * Private method to call handleBoundaries when ngOnChanges is called.
     */
    /**
     * Private method to call handleBoundaries when ngOnChanges is called.
     * @return {?}
     */
    CurrentImageComponent.prototype.updateIndexes = /**
     * Private method to call handleBoundaries when ngOnChanges is called.
     * @return {?}
     */
    function () {
        /** @type {?} */
        var index;
        try {
            index = getIndex(this.currentImage, this.images);
        }
        catch (err) {
            console.error('Cannot get the current image index in current-image');
            throw err;
        }
        if (this.isOpen) {
            this.handleBoundaries(index);
        }
    };
    CurrentImageComponent.decorators = [
        { type: Component, args: [{
                    selector: 'ks-current-image',
                    template: "<main class=\"main-image-container\"\n      ksKeyboardNavigation [isOpen]=\"isOpen\" (keyPress)=\"onKeyPress($event)\"\n      [attr.aria-label]=\"accessibilityConfig.mainContainerAriaLabel\"\n      [title]=\"accessibilityConfig.mainContainerTitle\">\n\n  <div class=\"left-sub-container\">\n    <a class=\"nav-left\"\n       [attr.aria-label]=\"accessibilityConfig.mainPrevImageAriaLabel\"\n       [tabindex]=\"isFirstImage ? -1 : 0\" role=\"button\"\n       (click)=\"onNavigationEvent('left', $event)\" (keyup)=\"onNavigationEvent('left', $event)\">\n      <div class=\"inside {{isFirstImage ? 'empty-arrow-image' : 'left-arrow-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"accessibilityConfig.mainPrevImageTitle\"></div>\n    </a>\n\n    <ng-container *ngIf=\"slideConfig?.sidePreviews?.show\">\n      <ng-container *ngIf=\"getLeftPreviewImage() as leftPreview\">\n        <img *ngIf=\"!isFirstImage; else firstImage\"\n             class=\"inside current-image-previous\"\n             [src]=\"leftPreview.plain?.img ? leftPreview.plain.img : leftPreview.modal.img\"\n             [hidden]=\"loading\"\n             ksSize [sizeConfig]=\"{width: slideConfig.sidePreviews?.size.width, height: slideConfig.sidePreviews?.size.height}\"\n             [attr.aria-label]=\"leftPreview.modal.ariaLabel\"\n             [title]=\"leftPreview.modal.title ? leftPreview.modal.title : getDescriptionToDisplay(leftPreview)\"\n             alt=\"{{leftPreview.modal.alt ? leftPreview.modal.alt : getAltDescriptionByImage(leftPreview)}}\"\n             [tabindex]=\"0\" role=\"img\"\n             (click)=\"onNavigationEvent('left', $event, clickAction)\" (keyup)=\"onNavigationEvent('left', $event, keyboardAction)\"/>\n        <ng-template #firstImage>\n          <div class=\"current-image-previous hidden\"\n               ksSize [sizeConfig]=\"{width: slideConfig.sidePreviews?.size.width, height: slideConfig.sidePreviews?.size.height}\"></div>\n        </ng-template>\n      </ng-container>\n    </ng-container>\n  </div>\n\n\n  <figure id=\"current-figure\" [style.display]=\"loading ? 'none' : ''\">\n    <img id=\"current-image\"\n         class=\"inside\"\n         [ngClass]=\"'rotate' + (currentImage.modal && currentImage.modal.angle ? currentImage.modal.angle : '0')\"\n         [src]=\"currentImage.modal.img\"\n         [attr.aria-label]=\"currentImage.modal.ariaLabel\"\n         [title]=\"currentImage.modal.title ? currentImage.modal.title : getTitleToDisplay()\"\n         alt=\"{{currentImage.modal.alt ? currentImage.modal.alt : getAltDescriptionByImage()}}\"\n         [tabindex]=\"0\" role=\"img\"\n         (load)=\"onImageLoad($event)\"\n         (click)=\"onImageEvent($event, clickAction)\" (keyup)=\"onImageEvent($event, keyboardAction)\"\n         (swipeleft)=\"swipe($event.type)\"\n         (swiperight)=\"swipe($event.type)\"/>\n    <figcaption *ngIf=\"getDescriptionToDisplay() !== ''\"\n                class=\"inside description\"\n                ksDescription [description]=\"configCurrentImage?.description\"\n                [innerHTML]=\"getDescriptionToDisplay()\">\n    </figcaption>\n  </figure>\n\n  <div class=\"right-sub-container\">\n    <ng-container *ngIf=\"slideConfig?.sidePreviews?.show\">\n      <ng-container *ngIf=\"getRightPreviewImage() as rightPreview\">\n        <img *ngIf=\"!isLastImage; else lastImage\"\n             class=\"inside current-image-next\"\n             [src]=\"rightPreview.plain?.img ? rightPreview.plain.img : rightPreview.modal.img\"\n             [hidden]=\"loading\"\n             ksSize [sizeConfig]=\"{width: slideConfig.sidePreviews?.size.width, height: slideConfig.sidePreviews?.size.height}\"\n             [attr.aria-label]=\"rightPreview.modal.ariaLabel\"\n             [title]=\"rightPreview.modal.title ? rightPreview.modal.title : getDescriptionToDisplay(rightPreview)\"\n             alt=\"{{rightPreview.modal.alt ? rightPreview.modal.alt : getAltDescriptionByImage(rightPreview)}}\"\n             [tabindex]=\"0\" role=\"img\"\n             (click)=\"onNavigationEvent('right', $event, clickAction)\" (keyup)=\"onNavigationEvent('right', $event, keyboardAction)\"/>\n        <ng-template #lastImage>\n          <div class=\"current-image-next hidden\"\n               ksSize [sizeConfig]=\"{width: slideConfig.sidePreviews?.size.width, height: slideConfig.sidePreviews?.size.height}\">\n          </div>\n        </ng-template>\n      </ng-container>\n    </ng-container>\n\n    <ng-container *ngIf=\"loading && configCurrentImage?.loadingConfig?.enable\">\n      <ks-loading-spinner [loadingConfig]=\"configCurrentImage?.loadingConfig\"\n                          [accessibilityConfig]=\"accessibilityConfig\"></ks-loading-spinner>\n    </ng-container>\n\n    <a class=\"nav-right\"\n       [attr.aria-label]=\"accessibilityConfig.mainNextImageAriaLabel\"\n       [tabindex]=\"isLastImage ? -1 : 0\" role=\"button\"\n       (click)=\"onNavigationEvent('right', $event)\" (keyup)=\"onNavigationEvent('right', $event)\">\n      <div class=\"inside {{isLastImage ? 'empty-arrow-image' : 'right-arrow-image'}}\"\n           aria-hidden=\"true\"\n           [title]=\"accessibilityConfig.mainNextImageTitle\"></div>\n    </a>\n  </div>\n</main>\n",
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    styles: [":host{display:flex;flex-direction:column;justify-content:center}.main-image-container{display:flex;flex-direction:row;align-items:center;justify-content:space-between}.main-image-container .nav,.main-image-container>.left-sub-container>.nav-left,.main-image-container>.right-sub-container>.nav-right{-webkit-animation:1s animatezoom;animation:1s animatezoom;cursor:pointer;transition:.5s}.main-image-container .nav:hover,.main-image-container>.left-sub-container>.nav-left:hover,.main-image-container>.right-sub-container>.nav-right:hover{-webkit-transform:scale(1.1);transform:scale(1.1)}.main-image-container>.left-sub-container{display:flex;flex-direction:row;justify-content:space-around;align-items:center}.main-image-container>.left-sub-container>.nav-left{margin-right:5px;margin-left:15px}.main-image-container>.right-sub-container{display:flex;flex-direction:row;justify-content:space-around;align-items:center}.main-image-container>.right-sub-container>.nav-right{margin-right:15px;margin-left:5px}.main-image-container #current-figure{-webkit-animation:.8s fadein-visible;animation:.8s fadein-visible;text-align:center;margin:0;position:relative}.main-image-container #current-figure>#current-image{max-width:100%;height:auto;display:block}.main-image-container #current-figure figcaption{padding:10px;position:absolute;bottom:0;left:0;right:0}.main-image-container #current-figure figcaption .description{font-weight:700;text-align:center}#current-image{height:auto;max-width:80vw;max-height:60vh;cursor:pointer}@media screen and (min-width:70vw){#current-image{max-width:70vw}}#current-image.rotate0,#current-image.rotate360{-webkit-transform-origin:top left;transform-origin:top left}#current-image.rotate90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}#current-image.rotate180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}#current-image.rotate270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}@-webkit-keyframes fadein-visible{from{opacity:0}to{opacity:1}}@keyframes fadein-visible{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadein-semi-visible05{from{opacity:0}to{opacity:.5}}@keyframes fadein-semi-visible05{from{opacity:0}to{opacity:.5}}@-webkit-keyframes fadein-semi-visible08{from{opacity:0}to{opacity:.8}}@keyframes fadein-semi-visible08{from{opacity:0}to{opacity:.8}}@-webkit-keyframes fadein-semi-visible09{from{opacity:0}to{opacity:.9}}@keyframes fadein-semi-visible09{from{opacity:0}to{opacity:.9}}", ".arrow-image,.empty-arrow-image,.left-arrow-image,.right-arrow-image{width:30px;height:30px;background-size:30px}.empty-arrow-image{background:#000;opacity:0}.left-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMTQ1LjE4OCwyMzguNTc1bDIxNS41LTIxNS41YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xcy0xMy44LTUuMy0xOS4xLDBsLTIyNS4xLDIyNS4xYy01LjMsNS4zLTUuMywxMy44LDAsMTkuMWwyMjUuMSwyMjUgICBjMi42LDIuNiw2LjEsNCw5LjUsNHM2LjktMS4zLDkuNS00YzUuMy01LjMsNS4zLTEzLjgsMC0xOS4xTDE0NS4xODgsMjM4LjU3NXoiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:.5s}.left-arrow-image:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.right-arrow-image{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQ3Ny4xNzUgNDc3LjE3NSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDc3LjE3NSA0NzcuMTc1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjUxMnB4IiBoZWlnaHQ9IjUxMnB4Ij48Zz48cGF0aCBkPSJNMzYwLjczMSwyMjkuMDc1bC0yMjUuMS0yMjUuMWMtNS4zLTUuMy0xMy44LTUuMy0xOS4xLDBzLTUuMywxMy44LDAsMTkuMWwyMTUuNSwyMTUuNWwtMjE1LjUsMjE1LjUgICBjLTUuMyw1LjMtNS4zLDEzLjgsMCwxOS4xYzIuNiwyLjYsNi4xLDQsOS41LDRjMy40LDAsNi45LTEuMyw5LjUtNGwyMjUuMS0yMjUuMUMzNjUuOTMxLDI0Mi44NzUsMzY1LjkzMSwyMzQuMjc1LDM2MC43MzEsMjI5LjA3NXogICAiIGZpbGw9IiNGRkZGRkYiLz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PC9zdmc+);opacity:.8;transition:.5s}.right-arrow-image:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}", "@media only screen and (max-width:1024px),only screen and (max-device-width:1024px){.current-image-next,.current-image-previous{display:none}}@media only screen and (min-device-width:1025px){.current-image-next,.current-image-preview,.current-image-previous{height:auto;cursor:pointer;opacity:.5;-webkit-animation:.8s fadein-semi-visible05;animation:.8s fadein-semi-visible05}.current-image-next:hover,.current-image-preview:hover,.current-image-previous:hover{opacity:1;transition:.5s}.current-image-previous{margin-left:10px;margin-right:5px}.current-image-next{margin-right:10px;margin-left:5px}}@-webkit-keyframes fadein-semi-visible05{from{opacity:0}to{opacity:.5}}@keyframes fadein-semi-visible05{from{opacity:0}to{opacity:.5}}"]
                }] }
    ];
    CurrentImageComponent.propDecorators = {
        currentImage: [{ type: Input }],
        images: [{ type: Input }],
        isOpen: [{ type: Input }],
        currentImageConfig: [{ type: Input }],
        slideConfig: [{ type: Input }],
        accessibilityConfig: [{ type: Input }],
        keyboardConfig: [{ type: Input }],
        loadImage: [{ type: Output }],
        changeImage: [{ type: Output }],
        close: [{ type: Output }]
    };
    return CurrentImageComponent;
}(AccessibleComponent));
export { CurrentImageComponent };
if (false) {
    /**
     * Object of type `InternalLibImage` that represent the visible image.
     * @type {?}
     */
    CurrentImageComponent.prototype.currentImage;
    /**
     * Array of `InternalLibImage` that represent the model of this library with all images,
     * thumbs and so on.
     * @type {?}
     */
    CurrentImageComponent.prototype.images;
    /**
     * Boolean that it is true if the modal gallery is visible.
     * If yes, also this component should be visible.
     * @type {?}
     */
    CurrentImageComponent.prototype.isOpen;
    /**
     * Interface to configure current image in modal-gallery.
     * For instance you can disable navigation on click on current image (enabled by default).
     * @type {?}
     */
    CurrentImageComponent.prototype.currentImageConfig;
    /**
     * Object of type `SlideConfig` to get `infinite sliding`.
     * @type {?}
     */
    CurrentImageComponent.prototype.slideConfig;
    /**
     * Object of type `AccessibilityConfig` to init custom accessibility features.
     * For instance, it contains titles, alt texts, aria-labels and so on.
     * @type {?}
     */
    CurrentImageComponent.prototype.accessibilityConfig;
    /**
     * Object of type `KeyboardConfig` to assign custom keys to both ESC, RIGHT and LEFT keyboard's actions.
     * @type {?}
     */
    CurrentImageComponent.prototype.keyboardConfig;
    /**
     * Output to emit an event when images are loaded. The payload contains an `ImageLoadEvent`.
     * @type {?}
     */
    CurrentImageComponent.prototype.loadImage;
    /**
     * Output to emit any changes of the current image. The payload contains an `ImageModalEvent`.
     * @type {?}
     */
    CurrentImageComponent.prototype.changeImage;
    /**
     * Output to emit an event when the modal gallery is closed. The payload contains an `ImageModalEvent`.
     * @type {?}
     */
    CurrentImageComponent.prototype.close;
    /**
     * Enum of type `Action` that represents a mouse click on a button.
     * Declared here to be used inside the template.
     * @type {?}
     */
    CurrentImageComponent.prototype.clickAction;
    /**
     * Enum of type `Action` that represents a keyboard action.
     * Declared here to be used inside the template.
     * @type {?}
     */
    CurrentImageComponent.prototype.keyboardAction;
    /**
     * Boolean that it's true when you are watching the first image (currently visible).
     * False by default
     * @type {?}
     */
    CurrentImageComponent.prototype.isFirstImage;
    /**
     * Boolean that it's true when you are watching the last image (currently visible).
     * False by default
     * @type {?}
     */
    CurrentImageComponent.prototype.isLastImage;
    /**
     * Boolean that it's true if an image of the modal gallery is still loading.
     * True by default
     * @type {?}
     */
    CurrentImageComponent.prototype.loading;
    /**
     * Object of type `CurrentImageConfig` exposed to the template. This field is initialized
     * applying transformations, default values and so on to the input of the same type.
     * @type {?}
     */
    CurrentImageComponent.prototype.configCurrentImage;
    /**
     * Private object without type to define all swipe actions used by hammerjs.
     * @type {?}
     */
    CurrentImageComponent.prototype.SWIPE_ACTION;
}
//# sourceMappingURL=data:application/json;base64, 