import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, Optional, Output, Renderer, ViewEncapsulation } from '@angular/core';
import { App } from '../app/app';
import { Config } from '../../config/config';
import { DomController } from '../../util/dom-controller';
import { Ion } from '../ion';
import { isTrueProperty, removeArrayItem } from '../../util/util';
import { Keyboard } from '../../util/keyboard';
import { ScrollView, ScrollDirection } from '../../util/scroll-view';
import { Tabs } from '../tabs/tabs';
import { transitionEnd } from '../../util/dom';
import { ViewController } from '../../navigation/view-controller';
export { ScrollDirection } from '../../util/scroll-view';
export class Content extends Ion {
    constructor(config, elementRef, renderer, _app, _keyboard, _zone, viewCtrl, _tabs, _dom) {
        super(config, elementRef, renderer, 'content');
        this._app = _app;
        this._keyboard = _keyboard;
        this._zone = _zone;
        this._tabs = _tabs;
        this._dom = _dom;
        this._scrollPadding = 0;
        this._inputPolling = false;
        this._imgs = [];
        this.scrollHeight = 0;
        this.scrollWidth = 0;
        this.ionScrollStart = new EventEmitter();
        this.ionScroll = new EventEmitter();
        this.ionScrollEnd = new EventEmitter();
        this.readReady = new EventEmitter();
        this.writeReady = new EventEmitter();
        this.statusbarPadding = config.getBoolean('statusbarPadding', false);
        if (viewCtrl) {
            viewCtrl._setIONContent(this);
            viewCtrl._setIONContentRef(elementRef);
        }
        this._scroll = new ScrollView(_dom);
    }
    get scrollTop() {
        return this._scroll.getTop();
    }
    set scrollTop(top) {
        this._scroll.setTop(top);
    }
    get scrollLeft() {
        return this._scroll.getLeft();
    }
    set scrollLeft(top) {
        this._scroll.setLeft(top);
    }
    get isScrolling() {
        return this._scroll.isScrolling;
    }
    get velocityY() {
        return this._scroll.ev.velocityY || 0;
    }
    get velocityX() {
        return this._scroll.ev.velocityX || 0;
    }
    get directionY() {
        return this._scroll.ev.directionY;
    }
    get directionX() {
        return this._scroll.ev.directionX;
    }
    ngOnInit() {
        if (this._scrollEle)
            return;
        const children = this._elementRef.nativeElement.children;
        (void 0);
        this._fixedEle = children[0];
        this._scrollEle = children[1];
        this._scroll.scrollStart.subscribe(ev => {
            this.ionScrollStart.emit(ev);
        });
        this._scroll.scroll.subscribe(ev => {
            this._app.setScrolling(ev.timeStamp);
            this.ionScroll.emit(ev);
            this.imgsUpdate();
        });
        this._scroll.scrollEnd.subscribe(ev => {
            this.ionScrollEnd.emit(ev);
            this.imgsUpdate();
        });
    }
    ngOnDestroy() {
        this._scLsn && this._scLsn();
        this._scroll && this._scroll.destroy();
        this._scrollEle = this._fixedEle = this._footerEle = this._scLsn = this._scroll = null;
    }
    getScrollElement() {
        return this._scrollEle;
    }
    onScrollElementTransitionEnd(callback) {
        transitionEnd(this._scrollEle, callback);
    }
    scrollTo(x, y, duration = 300, done) {
        (void 0);
        return this._scroll.scrollTo(x, y, duration, done);
    }
    scrollToTop(duration = 300) {
        (void 0);
        return this._scroll.scrollToTop(duration);
    }
    scrollToBottom(duration = 300) {
        (void 0);
        return this._scroll.scrollToBottom(duration);
    }
    enableJsScroll() {
        this._scroll.enableJsScroll(this.contentTop, this.contentBottom);
    }
    get fullscreen() {
        return !!this._fullscreen;
    }
    set fullscreen(val) {
        this._fullscreen = isTrueProperty(val);
    }
    addImg(img) {
        this._imgs.push(img);
    }
    removeImg(img) {
        removeArrayItem(this._imgs, img);
    }
    setScrollElementStyle(prop, val) {
        this._dom.write(() => {
            this._scrollEle.style[prop] = val;
        });
    }
    getContentDimensions() {
        const scrollEle = this._scrollEle;
        const parentElement = scrollEle.parentElement;
        return {
            contentHeight: parentElement.offsetHeight - this.contentTop - this.contentBottom,
            contentTop: this.contentTop,
            contentBottom: this.contentBottom,
            contentWidth: parentElement.offsetWidth,
            contentLeft: parentElement.offsetLeft,
            scrollHeight: scrollEle.scrollHeight,
            scrollTop: scrollEle.scrollTop,
            scrollWidth: scrollEle.scrollWidth,
            scrollLeft: scrollEle.scrollLeft,
        };
    }
    addScrollPadding(newPadding) {
        (void 0);
        if (newPadding > this._scrollPadding) {
            (void 0);
            this._scrollPadding = newPadding;
            if (this._scrollEle) {
                this._dom.write(() => {
                    if (this._scrollEle) {
                        this._scrollEle.style.paddingBottom = (newPadding > 0) ? newPadding + 'px' : '';
                    }
                });
            }
        }
    }
    clearScrollPaddingFocusOut() {
        if (!this._inputPolling) {
            (void 0);
            this._inputPolling = true;
            this._keyboard.onClose(() => {
                (void 0);
                this._inputPolling = false;
                this._scrollPadding = -1;
                this.addScrollPadding(0);
            }, 200, 3000);
        }
    }
    resize() {
        this._dom.read(this.readDimensions, this);
        this._dom.write(this.writeDimensions, this);
    }
    readDimensions() {
        let cachePaddingTop = this._pTop;
        let cachePaddingRight = this._pRight;
        let cachePaddingBottom = this._pBottom;
        let cachePaddingLeft = this._pLeft;
        let cacheHeaderHeight = this._hdrHeight;
        let cacheFooterHeight = this._ftrHeight;
        let cacheTabsPlacement = this._tabsPlacement;
        let tabsTop = 0;
        this.scrollWidth = 0;
        this.scrollHeight = 0;
        this._pTop = 0;
        this._pRight = 0;
        this._pBottom = 0;
        this._pLeft = 0;
        this._hdrHeight = 0;
        this._ftrHeight = 0;
        this._tabsPlacement = null;
        this._tTop = 0;
        this._fTop = 0;
        this._fBottom = 0;
        let ele = this._elementRef.nativeElement;
        if (!ele) {
            (void 0);
            return;
        }
        let computedStyle;
        let tagName;
        let parentEle = ele.parentElement;
        let children = parentEle.children;
        for (var i = children.length - 1; i >= 0; i--) {
            ele = children[i];
            tagName = ele.tagName;
            if (tagName === 'ION-CONTENT') {
                this.scrollWidth = ele.scrollWidth;
                this.scrollHeight = ele.scrollHeight;
                if (this._fullscreen) {
                    computedStyle = getComputedStyle(ele);
                    this._pTop = parsePxUnit(computedStyle.paddingTop);
                    this._pBottom = parsePxUnit(computedStyle.paddingBottom);
                    this._pRight = parsePxUnit(computedStyle.paddingRight);
                    this._pLeft = parsePxUnit(computedStyle.paddingLeft);
                }
            }
            else if (tagName === 'ION-HEADER') {
                this._hdrHeight = ele.clientHeight;
            }
            else if (tagName === 'ION-FOOTER') {
                this._ftrHeight = ele.clientHeight;
                this._footerEle = ele;
            }
        }
        ele = parentEle;
        let tabbarEle;
        while (ele && ele.tagName !== 'ION-MODAL' && !ele.classList.contains('tab-subpage')) {
            if (ele.tagName === 'ION-TABS') {
                tabbarEle = ele.firstElementChild;
                this._tabbarHeight = tabbarEle.clientHeight;
                if (this._tabsPlacement === null) {
                    this._tabsPlacement = ele.getAttribute('tabsplacement');
                }
            }
            ele = ele.parentElement;
        }
        if (this._tabs && this._tabsPlacement === 'top') {
            this._tTop = this._hdrHeight;
            tabsTop = this._tabs._top;
        }
        this._cTop = this._hdrHeight;
        this._cBottom = this._ftrHeight;
        if (this._tabsPlacement === 'top') {
            this._cTop += this._tabbarHeight;
        }
        else if (this._tabsPlacement === 'bottom') {
            this._cBottom += this._tabbarHeight;
        }
        this._fTop = this._cTop;
        this._fBottom = this._cBottom;
        if (this._fullscreen) {
            this._cTop += this._pTop;
            this._cBottom += this._pBottom;
        }
        this._dirty = (cachePaddingTop !== this._pTop ||
            cachePaddingBottom !== this._pBottom ||
            cachePaddingLeft !== this._pLeft ||
            cachePaddingRight !== this._pRight ||
            cacheHeaderHeight !== this._hdrHeight ||
            cacheFooterHeight !== this._ftrHeight ||
            cacheTabsPlacement !== this._tabsPlacement ||
            tabsTop !== this._tTop ||
            this._cTop !== this.contentTop ||
            this._cBottom !== this.contentBottom);
        this._scroll.init(this._scrollEle, this._cTop, this._cBottom);
        this.imgsUpdate();
        this.readReady.emit();
    }
    writeDimensions() {
        if (!this._dirty) {
            (void 0);
            return;
        }
        const scrollEle = this._scrollEle;
        if (!scrollEle) {
            (void 0);
            return;
        }
        const fixedEle = this._fixedEle;
        if (!fixedEle) {
            (void 0);
            return;
        }
        if (this._tabsPlacement === 'bottom' && this._cBottom > 0 && this._footerEle) {
            var footerPos = this._cBottom - this._ftrHeight;
            (void 0);
            this._footerEle.style.bottom = cssFormat(footerPos);
        }
        let topProperty = 'marginTop';
        let bottomProperty = 'marginBottom';
        let fixedTop = this._fTop;
        let fixedBottom = this._fBottom;
        if (this._fullscreen) {
            (void 0);
            (void 0);
            topProperty = 'paddingTop';
            bottomProperty = 'paddingBottom';
        }
        if (this._cTop !== this.contentTop) {
            (void 0);
            (void 0);
            scrollEle.style[topProperty] = cssFormat(this._cTop);
            fixedEle.style.marginTop = cssFormat(fixedTop);
            this.contentTop = this._cTop;
        }
        if (this._cBottom !== this.contentBottom) {
            (void 0);
            (void 0);
            scrollEle.style[bottomProperty] = cssFormat(this._cBottom);
            fixedEle.style.marginBottom = cssFormat(fixedBottom);
            this.contentBottom = this._cBottom;
        }
        if (this._tabsPlacement !== null && this._tabs) {
            if (this._tabsPlacement === 'top') {
                this._tabs.setTabbarPosition(this._tTop, -1);
            }
            else {
                (void 0);
                this._tabs.setTabbarPosition(-1, 0);
            }
        }
        this.writeReady.emit();
    }
    imgsUpdate() {
        if (this._imgs.length && this.isImgsUpdatable()) {
            updateImgs(this._imgs, this.scrollTop, this.scrollHeight, this.directionY, IMG_REQUESTABLE_BUFFER, IMG_RENDERABLE_BUFFER);
        }
    }
    isImgsUpdatable() {
        return Math.abs(this.velocityY) < 3;
    }
}
Content.decorators = [
    { type: Component, args: [{
                selector: 'ion-content',
                template: '<div class="fixed-content">' +
                    '<ng-content select="[ion-fixed],ion-fab"></ng-content>' +
                    '</div>' +
                    '<div class="scroll-content">' +
                    '<ng-content></ng-content>' +
                    '</div>' +
                    '<ng-content select="ion-refresher"></ng-content>',
                host: {
                    '[class.statusbar-padding]': 'statusbarPadding'
                },
                changeDetection: ChangeDetectionStrategy.OnPush,
                encapsulation: ViewEncapsulation.None
            },] },
];
Content.ctorParameters = [
    { type: Config, },
    { type: ElementRef, },
    { type: Renderer, },
    { type: App, },
    { type: Keyboard, },
    { type: NgZone, },
    { type: ViewController, decorators: [{ type: Optional },] },
    { type: Tabs, decorators: [{ type: Optional },] },
    { type: DomController, },
];
Content.propDecorators = {
    'ionScrollStart': [{ type: Output },],
    'ionScroll': [{ type: Output },],
    'ionScrollEnd': [{ type: Output },],
    'readReady': [{ type: Output },],
    'writeReady': [{ type: Output },],
    'fullscreen': [{ type: Input },],
};
export function updateImgs(imgs, scrollTop, scrollHeight, scrollDirectionY, requestableBuffer, renderableBuffer) {
    const scrollBottom = (scrollTop + scrollHeight);
    const priority1 = [];
    const priority2 = [];
    let img;
    for (var i = 0, ilen = imgs.length; i < ilen; i++) {
        img = imgs[i];
        if (scrollDirectionY === ScrollDirection.Up) {
            if (img.top < scrollBottom && img.bottom > scrollTop - renderableBuffer) {
                img.canRequest = img.canRender = true;
                priority1.push(img);
                continue;
            }
            if (img.bottom <= scrollTop && img.bottom > scrollTop - requestableBuffer) {
                img.canRequest = true;
                img.canRender = false;
                priority2.push(img);
                continue;
            }
            if (img.top >= scrollBottom && img.top < scrollBottom + renderableBuffer) {
                img.canRequest = img.canRender = false;
                continue;
            }
        }
        else {
            if (img.bottom > scrollTop && img.top < scrollBottom + renderableBuffer) {
                img.canRequest = img.canRender = true;
                priority1.push(img);
                continue;
            }
            if (img.top >= scrollBottom && img.top < scrollBottom + requestableBuffer) {
                img.canRequest = true;
                img.canRender = false;
                priority2.push(img);
                continue;
            }
            if (img.bottom <= scrollTop && img.bottom > scrollTop - renderableBuffer) {
                img.canRequest = img.canRender = false;
                continue;
            }
        }
        img.canRequest = img.canRender = false;
        img.reset();
    }
    priority1.sort(sortTopToBottom).forEach(i => i.update());
    if (scrollDirectionY === ScrollDirection.Up) {
        priority2.sort(sortTopToBottom).reverse().forEach(i => i.update());
    }
    else {
        priority2.sort(sortTopToBottom).forEach(i => i.update());
    }
}
const IMG_REQUESTABLE_BUFFER = 1200;
const IMG_RENDERABLE_BUFFER = 300;
function sortTopToBottom(a, b) {
    if (a.top < b.top) {
        return -1;
    }
    if (a.top > b.top) {
        return 1;
    }
    return 0;
}
function parsePxUnit(val) {
    return (val.indexOf('px') > 0) ? parseInt(val, 10) : 0;
}
function cssFormat(val) {
    return (val > 0 ? val + 'px' : '');
}
//# sourceMappingURL=content.js.map