"use strict";
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 __());
};
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
var core_1 = require('angular2/core');
var common_1 = require('angular2/common');
var ion_1 = require('../ion');
var animation_1 = require('../../animations/animation');
var gesture_1 = require('../../gestures/gesture');
var util_1 = require('../../util');
var dom_1 = require('../../util/dom');
var util_2 = require('../../util/util');
var swiper_widget_1 = require('./swiper-widget');
/**
 * @name Slides
 * @description
 * The Slides component is a multi-section container. Each section can be swiped
 * or dragged between. It contains any number of [Slide](../Slide) components.
 *
 *
 * ### Creating
 * You should use a template to create slides and listen to slide events. The template
 * should contain the slide container, an `<ion-slides>` element, and any number of
 * [Slide](../Slide) components, written as `<ion-slide>`. Any configuration of the
 * slides should be passed in the `options` property of the `<ion-slides>` element.
 * You can listen to events such as the slide changing by placing the event on the
 * `<ion-slides>` element. See [Usage](#usage) below for more information on
 * creating slides.
 *
 *
 * ### Configuring
 * There are several configuration options that can be passed to Slides. These should
 * be passed in the `options` property of the `<ion-slides>` element upon creation.
 * You can allow the slides to loop around from the last to the first, set autoplay
 * on the slides so it will automatically switch between them, and more.
 *
 * Properties to pass in options:
 *
 * | Property              | Type      | Default        | Description                                                                                |
 * |-----------------------|-----------|----------------|--------------------------------------------------------------------------------------------|
 * | autoplay              | `number`  | -              | Delay between transitions (in ms). If this parameter is not passed, autoplay is disabled.  |
 * | direction             | `string`  | 'horizontal'   | Swipe direction: 'horizontal' or 'vertical'.                                               |
 * | initialSlide          | `number`  | 0              | Index number of initial slide                                                              |
 * | loop                  | `boolean` | false          | Whether to continuously loop from the last slide to the first slide.                       |
 * | speed                 | `number`  | 300            | Duration of transition between slides (in ms).                                             |
 *
 * See [Usage](#usage) below for more information on configuring slides.
 *
 *
 * ### Navigating
 * After creating and configuring the slides, you can navigate between them
 * by swiping or calling methods on the `Slides` instance. You can call `slideTo()` to
 * navigate to a specific slide, or `slideNext()` to change to the slide that follows
 * the active slide. All of the [methods](#instance-methods) provided by the `Slides`
 * instance are listed below. See [Usage](#usage) below for more information on
 * navigating between slides.
 *
 *
 * ### Limitations
 * The Slides component wraps the [Swiper](http://www.idangero.us/swiper/) component
 * built by iDangero.us. This means that all of the Swiper API isn't exposed on the
 * Slides component. See the [`getSlider()`](#getSlider) method for information on
 * getting the `Swiper` instance and using its methods directly.
 *
 *
 * @usage
 * ```html
 * <ion-slides>
 *   <ion-slide>
 *     <p>Slide 1</p>
 *     <button (click)="goToSlide(3)">Navigate</button>
 *   </ion-slide>
 *   <ion-slide>
 *     <p>Slide 2</p>
 *   </ion-slide>
 *   <ion-slide>
 *     <p>Slide 3</p>
 *   </ion-slide>
 * </ion-slides>
 * ```
 *
 * ```ts
 * import {ViewChild} from 'angular2/core';
 * import {App, Slides} from 'ionic-angular';
 *
 *
 * @App({
 *   templateUrl: 'main.html'
 * })
 * class MyApp {
 *   @ViewChild(Slides) slider: Slides;
 *
 *   goToSlide(index) {
 *     this.slider.slideTo(index, 500);
 *   }
 * }
 * ```
 *
 * @demo /docs/v2/demos/slides/
 * @see {@link /docs/v2/components#slides Slides Component Docs}
 *
 * Swiper.js:
 * The most modern mobile touch slider and framework with hardware accelerated transitions
 *
 * http://www.idangero.us/swiper/
 *
 * Copyright 2015, Vladimir Kharlampidi
 * The iDangero.us
 * http://www.idangero.us/
 *
 * Licensed under MIT
 */
var Slides = (function (_super) {
    __extends(Slides, _super);
    function Slides(elementRef) {
        var _this = this;
        _super.call(this, elementRef);
        /**
         * @private Deprecated
         */
        this.slideChangeStart = new core_1.EventEmitter();
        /**
         * @private Deprecated
         */
        this.change = new core_1.EventEmitter();
        /**
         * @output {any} Expression to evaluate when a slide change starts.
         */
        this.willChange = new core_1.EventEmitter();
        /**
         * @output {any} Expression to evaluate when a slide change ends.
         */
        this.didChange = new core_1.EventEmitter();
        /**
         * @output {any} Expression to evaluate when a slide moves.
         */
        this.move = new core_1.EventEmitter();
        this.rapidUpdate = util_2.debounce(function () {
            _this.update();
        }, 10);
        this.id = ++slidesId;
        this.slideId = 'slides-' + this.id;
    }
    /**
     * @private
     */
    Slides.prototype.ngOnInit = function () {
        var _this = this;
        if (!this.options) {
            this.options = {};
        }
        if (util_2.isPresent(this.pager)) {
            // beta.5 2016-04-18 deprecated warning
            // Pager should be passed as an option
            void 0;
            // Remove this with the deprecation warning
            this.showPager = util_2.isTrueProperty(this.pager);
        }
        if (util_2.isPresent(this.zoom)) {
            // beta.5 2016-04-18 deprecated warning
            // Zoom should be passed as an option
            void 0;
        }
        if (util_2.isPresent(this.change)) {
            // beta.5 2016-04-18 deprecated warning
            // change has been renamed to didChange
            void 0;
        }
        if (util_2.isPresent(this.slideChangeStart)) {
            // beta.5 2016-04-18 deprecated warning
            // slideChangeStart has been renamed to willChange
            void 0;
        }
        if (util_2.isPresent(this.options.pager)) {
            this.showPager = util_2.isTrueProperty(this.options.pager);
        }
        var paginationId = '.' + this.slideId + ' .swiper-pagination';
        var options = util_2.defaults({
            pagination: paginationId
        }, this.options);
        options.onTap = function (swiper, e) {
            _this.onTap(swiper, e);
            return _this.options.onTap && _this.options.onTap(swiper, e);
        };
        options.onClick = function (swiper, e) {
            _this.onClick(swiper, e);
            return _this.options.onClick && _this.options.onClick(swiper, e);
        };
        options.onDoubleTap = function (swiper, e) {
            _this.onDoubleTap(swiper, e);
            return _this.options.onDoubleTap && _this.options.onDoubleTap(swiper, e);
        };
        options.onTransitionStart = function (swiper, e) {
            _this.onTransitionStart(swiper, e);
            return _this.options.onTransitionStart && _this.options.onTransitionStart(swiper, e);
        };
        options.onTransitionEnd = function (swiper, e) {
            _this.onTransitionEnd(swiper, e);
            return _this.options.onTransitionEnd && _this.options.onTransitionEnd(swiper, e);
        };
        options.onSlideChangeStart = function (swiper) {
            // TODO deprecated 2016-04-18
            _this.slideChangeStart.emit(swiper);
            _this.willChange.emit(swiper);
            return _this.options.onSlideChangeStart && _this.options.onSlideChangeStart(swiper);
        };
        options.onSlideChangeEnd = function (swiper) {
            // TODO deprecated 2016-04-18
            _this.change.emit(swiper);
            _this.didChange.emit(swiper);
            return _this.options.onSlideChangeEnd && _this.options.onSlideChangeEnd(swiper);
        };
        options.onLazyImageLoad = function (swiper, slide, img) {
            return _this.options.onLazyImageLoad && _this.options.onLazyImageLoad(swiper, slide, img);
        };
        options.onLazyImageReady = function (swiper, slide, img) {
            return _this.options.onLazyImageReady && _this.options.onLazyImageReady(swiper, slide, img);
        };
        options.onSliderMove = function (swiper, e) {
            _this.move.emit(swiper);
            return _this.options.onSliderMove && _this.options.onSliderMove(swiper, e);
        };
        setTimeout(function () {
            var swiper = new swiper_widget_1.Swiper(_this.getNativeElement().children[0], options);
            _this.slider = swiper;
        });
        /*
        * TODO: Finish this
        if (isTrueProperty(this.zoom)) {
          this.enableZoom = true;
          setTimeout(() => {
            this.initZoom();
          })
        }
        */
    };
    /**
     * @private
     */
    Slides.prototype.onTap = function (swiper, e) {
    };
    /**
     * @private
     */
    Slides.prototype.onClick = function (swiper, e) {
    };
    /**
     * @private
     */
    Slides.prototype.onDoubleTap = function (swiper, e) {
        this.toggleZoom(swiper, e);
    };
    /**
     * @private
     */
    Slides.prototype.onLazyImageLoad = function (swiper, slide, img) {
    };
    /**
     * @private
     */
    Slides.prototype.onLazyImageReady = function (swiper, slide, img) {
    };
    /*
    nextButton(swiper, e) {
    }
    prevButton() {
    }
    indexButton() {
    }
    */
    /**
     * @private
     */
    Slides.prototype.initZoom = function () {
        var _this = this;
        this.zoomDuration = this.zoomDuration || 230;
        this.maxScale = this.zoomMax || 3;
        this.zoomElement = this.getNativeElement().children[0].children[0];
        this.zoomElement && this.zoomElement.classList.add('ion-scroll-zoom');
        this.zoomGesture = new gesture_1.Gesture(this.zoomElement);
        this.zoomGesture.listen();
        this.scale = 1;
        this.zoomLastPosX = 0;
        this.zoomLastPosY = 0;
        var last_scale, startX, startY, posX = 0, posY = 0, zoomRect;
        this.viewportWidth = this.getNativeElement().offsetWidth;
        this.viewportHeight = this.getNativeElement().offsetHeight;
        this.zoomElement.addEventListener('touchstart', function (e) {
            _this.onTouchStart(e);
        });
        this.zoomElement.addEventListener('touchmove', function (e) {
            _this.onTouchMove(e);
        });
        this.zoomElement.addEventListener('touchend', function (e) {
            _this.onTouchEnd(e);
        });
        this.zoomGesture.on('pinchstart', function (e) {
            last_scale = _this.scale;
            void 0;
        });
        this.zoomGesture.on('pinch', function (e) {
            _this.scale = Math.max(1, Math.min(last_scale * e.scale, 10));
            void 0;
            _this.zoomElement.style[dom_1.CSS.transform] = 'scale(' + _this.scale + ')';
            zoomRect = _this.zoomElement.getBoundingClientRect();
        });
        this.zoomGesture.on('pinchend', function () {
            // last_scale = Math.max(1, Math.min(last_scale * e.scale, 10));
            if (_this.scale > _this.maxScale) {
                var za = new animation_1.Animation(_this.zoomElement)
                    .duration(_this.zoomDuration)
                    .easing('linear')
                    .from('scale', _this.scale)
                    .to('scale', _this.maxScale);
                za.play();
                _this.scale = _this.maxScale;
            }
        });
    };
    /**
     * @private
     */
    Slides.prototype.resetZoom = function () {
        if (this.zoomElement) {
            this.zoomElement.parentElement.style[dom_1.CSS.transform] = '';
            this.zoomElement.style[dom_1.CSS.transform] = 'scale(1)';
        }
        this.scale = 1;
        this.zoomLastPosX = 0;
        this.zoomLastPosY = 0;
    };
    /**
     * @private
     */
    Slides.prototype.toggleZoom = function (swiper, e) {
        void 0;
        if (!this.enableZoom) {
            return;
        }
        void 0;
        /*
        let x = e.pointers[0].clientX;
        let y = e.pointers[0].clientY;
    
        let mx = this.viewportWidth / 2;
        let my = this.viewportHeight / 2;
    
        let tx, ty;
    
        if (x > mx) {
          // Greater than half
          tx = -x;
        } else {
          // Less than or equal to half
          tx = (this.viewportWidth - x);
        }
        if (y > my) {
          ty = -y;
        } else {
          ty = y-my;
        }
    
        console.debug(y);
        */
        var zi = new animation_1.Animation(this.touch.target.children[0])
            .duration(this.zoomDuration)
            .easing('linear');
        var zw = new animation_1.Animation(this.touch.target.children[0])
            .duration(this.zoomDuration)
            .easing('linear');
        var za = new animation_1.Animation();
        za.add(zi);
        if (this.scale > 1) {
            // zoom out
            // zw.fromTo('translateX', posX + 'px', '0px');
            // zw.fromTo('translateY', posY + 'px', '0px');
            zi.from('scale', this.scale);
            zi.to('scale', 1);
            za.play();
            // posX = 0;
            // posY = 0;
            this.scale = 1;
        }
        else {
            // zoom in
            // zw.fromTo('translateX', posX + 'px', tx + 'px');
            // zw.fromTo('translateY', posY + 'px', ty + 'px');
            zi.from('scale', this.scale);
            zi.to('scale', this.maxScale);
            za.play();
            // posX = tx;
            // posY = ty;
            this.scale = this.maxScale;
        }
    };
    /**
     * @private
     */
    Slides.prototype.onTransitionStart = function (swiper, e) {
    };
    /**
     * @private
     */
    Slides.prototype.onTransitionEnd = function (swiper, e) {
    };
    /**
     * @private
     */
    Slides.prototype.onTouchStart = function (e) {
        void 0;
        // TODO: Support mice as well
        var target = util_1.dom.closest(e.target, '.slide').children[0].children[0];
        this.touch = {
            x: null,
            y: null,
            startX: e.touches[0].clientX,
            startY: e.touches[0].clientY,
            deltaX: 0,
            deltaY: 0,
            lastX: 0,
            lastY: 0,
            target: target.parentElement,
            zoomable: target,
            zoomableWidth: target.offsetWidth,
            zoomableHeight: target.offsetHeight
        };
        void 0;
        // TODO: android prevent default
    };
    /**
     * @private
     */
    Slides.prototype.onTouchMove = function (e) {
        this.touch.deltaX = e.touches[0].clientX - this.touch.startX;
        this.touch.deltaY = e.touches[0].clientY - this.touch.startY;
        // TODO: Make sure we need to transform (image is bigger than viewport)
        var zoomableScaledWidth = this.touch.zoomableWidth * this.scale;
        var zoomableScaledHeight = this.touch.zoomableHeight * this.scale;
        var x1 = Math.min((this.viewportWidth / 2) - zoomableScaledWidth / 2, 0);
        var x2 = -x1;
        var y1 = Math.min((this.viewportHeight / 2) - zoomableScaledHeight / 2, 0);
        var y2 = -y1;
        void 0;
        if (this.scale <= 1) {
            return;
        }
        void 0;
        // move image
        this.touch.x = this.touch.deltaX + this.touch.lastX;
        this.touch.y = this.touch.deltaY + this.touch.lastY;
        if (this.touch.x < x1) {
            void 0;
        }
        if (this.touch.x > x2) {
            void 0;
        }
        if (this.touch.x > this.viewportWidth) {
        }
        else if (-this.touch.x > this.viewportWidth) {
        }
        else {
            void 0;
            // this.touch.target.style[CSS.transform] = 'translateX(' + this.touch.x + 'px) translateY(' + this.touch.y + 'px)';
            this.touch.target.style[dom_1.CSS.transform] = 'translateX(' + this.touch.x + 'px) translateY(' + this.touch.y + 'px)';
            e.preventDefault();
            e.stopPropagation();
            return false;
        }
    };
    /**
     * @private
     */
    Slides.prototype.onTouchEnd = function (e) {
        void 0;
        if (this.scale > 1) {
            if (Math.abs(this.touch.x) > this.viewportWidth) {
                // TODO what is posX?
                var posX = posX > 0 ? this.viewportWidth - 1 : -(this.viewportWidth - 1);
                void 0;
            }
            /*
            if (posY > this.viewportHeight/2) {
              let z = new Animation(this.zoomElement.parentElement);
              z.fromTo('translateY', posY + 'px', Math.min(this.viewportHeight/2 + 30, posY));
              z.play();
            } else {
              let z = new Animation(this.zoomElement.parentElement);
              z.fromTo('translateY', posY + 'px', Math.max(this.viewportHeight/2 - 30, posY));
              z.play();
            }
            */
            this.touch.lastX = this.touch.x;
            this.touch.lastY = this.touch.y;
        }
    };
    /**
     * @private
     * Update the underlying slider implementation. Call this if you've added or removed
     * child slides.
     */
    Slides.prototype.update = function () {
        var _this = this;
        setTimeout(function () {
            _this.slider.update();
            // Don't allow pager to show with > 10 slides
            if (_this.length() > 10) {
                _this.showPager = false;
            }
        });
    };
    /**
     * Transition to the specified slide.
     *
     * @param {number} index  The index number of the slide.
     * @param {number} speed  Transition duration (in ms). Optional.
     * @param {boolean} runCallbacks  Whether or not to emit the `willChange`/`didChange` events. Optional. Default true.
     */
    Slides.prototype.slideTo = function (index, speed, runCallbacks) {
        this.slider.slideTo(index, speed, runCallbacks);
    };
    /**
     * Transition to the next slide.
     *
     * @param {number} speed  Transition duration (in ms). Optional.
     * @param {boolean} runCallbacks  Whether or not to emit the `willChange`/`didChange` events. Optional. Default true.
     */
    Slides.prototype.slideNext = function (speed, runCallbacks) {
        this.slider.slideNext(runCallbacks, speed);
    };
    /**
     * Transition to the previous slide.
     *
     * @param {number} speed  Transition duration (in ms). Optional.
     * @param {boolean} runCallbacks  Whether or not to emit the `willChange`/`didChange` events. Optional. Default true.
     */
    Slides.prototype.slidePrev = function (speed, runCallbacks) {
        this.slider.slidePrev(runCallbacks, speed);
    };
    /**
     * Get the index of the active slide.
     *
     * @returns {number} The index number of the current slide.
     */
    Slides.prototype.getActiveIndex = function () {
        return this.slider.activeIndex;
    };
    /**
     * Get the total number of slides.
     *
     * @returns {number} The total number of slides.
     */
    Slides.prototype.length = function () {
        return this.slider.slides.length;
    };
    /**
     * Get whether or not the current slide is the last slide.
     *
     * @returns {boolean} If the slide is the last slide or not.
     */
    Slides.prototype.isEnd = function () {
        return this.slider.isEnd;
    };
    /**
     * Get whether or not the current slide is the first slide.
     *
     * @returns {boolean} If the slide is the first slide or not.
     */
    Slides.prototype.isBeginning = function () {
        return this.slider.isBeginning;
    };
    /**
     * Get the `Swiper` instance.
     *
     * The Slides component wraps the `Swiper` component built by iDangero.us. See the
     * [Swiper API Docs](http://idangero.us/swiper/api/) for information on using
     * the `Swiper` instance directly.
     *
     * @returns {Swiper}
     */
    Slides.prototype.getSlider = function () {
        return this.slider;
    };
    __decorate([
        core_1.Input(), 
        __metadata('design:type', Object)
    ], Slides.prototype, "options", void 0);
    __decorate([
        core_1.Input(), 
        __metadata('design:type', Object)
    ], Slides.prototype, "pager", void 0);
    __decorate([
        core_1.Input(), 
        __metadata('design:type', Object)
    ], Slides.prototype, "zoom", void 0);
    __decorate([
        core_1.Input(), 
        __metadata('design:type', Object)
    ], Slides.prototype, "zoomDuration", void 0);
    __decorate([
        core_1.Input(), 
        __metadata('design:type', Object)
    ], Slides.prototype, "zoomMax", void 0);
    __decorate([
        core_1.Output(), 
        __metadata('design:type', core_1.EventEmitter)
    ], Slides.prototype, "slideChangeStart", void 0);
    __decorate([
        core_1.Output(), 
        __metadata('design:type', core_1.EventEmitter)
    ], Slides.prototype, "change", void 0);
    __decorate([
        core_1.Output(), 
        __metadata('design:type', core_1.EventEmitter)
    ], Slides.prototype, "willChange", void 0);
    __decorate([
        core_1.Output(), 
        __metadata('design:type', core_1.EventEmitter)
    ], Slides.prototype, "didChange", void 0);
    __decorate([
        core_1.Output(), 
        __metadata('design:type', core_1.EventEmitter)
    ], Slides.prototype, "move", void 0);
    Slides = __decorate([
        core_1.Component({
            selector: 'ion-slides',
            template: '<div class="swiper-container">' +
                '<div class="swiper-wrapper">' +
                '<ng-content></ng-content>' +
                '</div>' +
                '<div [class.hide]="!showPager" class="swiper-pagination"></div>' +
                '</div>',
            directives: [common_1.NgClass],
            host: {
                '[class]': 'slideId'
            },
            changeDetection: core_1.ChangeDetectionStrategy.OnPush,
            encapsulation: core_1.ViewEncapsulation.None,
        }), 
        __metadata('design:paramtypes', [core_1.ElementRef])
    ], Slides);
    return Slides;
}(ion_1.Ion));
exports.Slides = Slides;
/**
 * @name Slide
 * @description
 * The Slide component is a child component of [Slides](../Slides). The template
 * should be written as `ion-slide`. Any slide content should be written
 * in this component and it should be used in conjunction with [Slides](../Slides).
 *
 * See the [Slides API Docs](../Slides) for more usage information.
 *
 * @demo /docs/v2/demos/slides/
 * @see {@link /docs/v2/api/components/slides/Slides/ Slides API Docs}
 */
var Slide = (function () {
    function Slide(elementRef, slides) {
        this.ele = elementRef.nativeElement;
        this.ele.classList.add('swiper-slide');
        slides.rapidUpdate();
    }
    __decorate([
        core_1.Input(), 
        __metadata('design:type', Object)
    ], Slide.prototype, "zoom", void 0);
    Slide = __decorate([
        core_1.Component({
            selector: 'ion-slide',
            template: '<div class="slide-zoom"><ng-content></ng-content></div>',
            changeDetection: core_1.ChangeDetectionStrategy.OnPush,
            encapsulation: core_1.ViewEncapsulation.None,
        }),
        __param(1, core_1.Host()), 
        __metadata('design:paramtypes', [core_1.ElementRef, Slides])
    ], Slide);
    return Slide;
}());
exports.Slide = Slide;
/**
 * @private
 */
var SlideLazy = (function () {
    function SlideLazy() {
    }
    SlideLazy = __decorate([
        core_1.Directive({
            selector: 'slide-lazy',
            host: {
                'class': 'swiper-lazy'
            }
        }), 
        __metadata('design:paramtypes', [])
    ], SlideLazy);
    return SlideLazy;
}());
exports.SlideLazy = SlideLazy;
var slidesId = -1;
