/**
 * @private
 * Android version of viewport.
 */
Ext.define('Ext.viewport.Android', {
    extend: 'Ext.viewport.Default',
 
    config: {
        translatable: {
            type: 'csstransform'
        }
    },
 
    /**
     * @property {Boolean} preventPullRefresh
     * Disables built-in pull-refresh of a page in Chrome
     */
    preventPullRefresh: true,
 
    constructor: function() {
        var me = this;
 
        me.callParent(arguments);
 
        me.on({
            orientationchange: 'hideKeyboardIfNeeded',
            scope: me,
            // run our handler before user code
            priority: 1001
        });
 
        // https://sencha.jira.com/browse/EXTJS-25292
        if (me.preventPullRefresh) {
            Ext.getBody().setStyle({ overflow: 'hidden' });
        }
    },
 
    getWindowWidth: function() {
        return this.element.getWidth();
    },
 
    getWindowHeight: function() {
        return this.element.getHeight();
    },
 
    getDummyInput: function() {
        var input = this.dummyInput,
            focusedElement = this.focusedElement,
            box = Ext.fly(focusedElement).getBox();
 
        if (!input) {
            this.dummyInput = input = document.createElement('input');
            input.style.position = 'absolute';
            input.style.opacity = '0';
            input.style.pointerEvents = 'none';
            document.body.appendChild(input);
        }
 
        input.style.left = box.left + 'px';
        input.style.top = box.top + 'px';
        input.style.display = '';
 
        return input;
    },
 
    doBlurInput: function(e) {
        var target = e.target,
            focusedElement = this.focusedElement,
            dummy;
 
        if (focusedElement && !this.isInputRegex.test(target.tagName)) {
            dummy = this.getDummyInput();
            delete this.focusedElement;
            dummy.focus();
 
            Ext.defer(function() {
                dummy.style.display = 'none';
            }, 100);
        }
    },
 
    hideKeyboardIfNeeded: function() {
        var focusedElement = this.focusedElement;
 
        if (focusedElement) {
            delete this.focusedElement;
 
            if (Ext.os.version.lt('4')) {
                focusedElement.style.display = 'none';
            }
            else {
                focusedElement.blur();
            }
 
            Ext.defer(function() {
                focusedElement.style.display = '';
            }, 1000);
        }
    },
 
    doFireOrientationChangeEvent: function() {
        this.orientationChanging = true;
 
        this.waitUntil(function() {
            return this.getWindowOuterHeight() !== this.windowOuterHeight;
        }, function() {
            this.windowOuterHeight = this.getWindowOuterHeight();
            this.updateSize();
            this.orientationChanging = false;
 
        }, function() {
            //<debug>
            Ext.Logger.error(
                "Timeout waiting for viewport's outerHeight to change " +
                "before firing orientationchange",
                this
            );
            //</debug>
        });
 
        return this;
    },
 
    getActualWindowOuterHeight: function() {
        return Math.round(this.getWindowOuterHeight() / window.devicePixelRatio);
    },
 
    maximize: function() {
        var stretchHeights = this.stretchHeights,
            orientation = this.orientation,
            isHeightMaximized, height;
 
        height = stretchHeights[orientation];
 
        if (!height) {
            stretchHeights[orientation] = height = this.getActualWindowOuterHeight();
        }
 
        if (!this.addressBarHeight) {
            this.addressBarHeight = height - this.getWindowHeight();
        }
 
        this.setHeight(height);
 
        isHeightMaximized = this.isHeightMaximized.bind(this, height);
 
        this.scrollToTop();
        this.waitUntil(isHeightMaximized, this.fireMaximizeEvent, this.fireMaximizeEvent);
    },
 
    isHeightMaximized: function(height) {
        this.scrollToTop();
 
        return this.getWindowHeight() === height;
    },
 
    doPreventZooming: function(e) {
        var target;
 
        // Don't prevent right mouse event
        if ('button' in e && e.button !== 0) {
            return;
        }
 
        target = e.target;
 
        if (
            target && target.nodeType === 1 &&
            !this.isInputRegex.test(target.tagName) && !this.focusedElement
        ) {
            e.preventDefault();
        }
    }
 
}, function() {
    var version, userAgent, isBuggy;
 
    if (!Ext.os.is.Android) {
        return;
    }
 
    version = Ext.os.version;
    userAgent = Ext.browser.userAgent;
    // These Android devices have a nasty bug which causes JavaScript timers to be completely frozen
    // when the browser's viewport is being panned.
    isBuggy = /(htc|desire|incredible|ADR6300)/i.test(userAgent) && version.lt('2.3');
 
    if (isBuggy) {
        this.override({
            constructor: function(config) {
                if (!config) {
                    config = {};
                }
 
                config.autoMaximize = false;
 
                this.watchDogTick = this.watchDogTick.bind(this);
 
                Ext.interval(this.watchDogTick, 1000);
 
                return this.callParent([config]);
            },
 
            watchDogTick: function() {
                this.watchDogLastTick = Ext.Date.now();
            },
 
            doPreventPanning: function() {
                var now = Ext.Date.now(),
                    lastTick = this.watchDogLastTick,
                    deltaTime = now - lastTick;
 
                // Timers are frozen
                if (deltaTime >= 2000) {
                    return;
                }
 
                return this.callParent(arguments);
            },
 
            doPreventZooming: function() {
                var now = Ext.Date.now(),
                    lastTick = this.watchDogLastTick,
                    deltaTime = now - lastTick;
 
                // Timers are frozen
                if (deltaTime >= 2000) {
                    return;
                }
 
                return this.callParent(arguments);
            }
        });
    }
 
    if (version.match('2')) {
        this.override({
            onReady: function() {
                this.addWindowListener('resize', this.onWindowResize.bind(this));
 
                this.callParent(arguments);
            },
 
            scrollToTop: function() {
                document.body.scrollTop = 100;
            },
 
            onWindowResize: function() {
                var oldWidth = this.windowWidth,
                    oldHeight = this.windowHeight,
                    width = this.getWindowWidth(),
                    height = this.getWindowHeight();
 
                if (this.getAutoMaximize() && !this.isMaximizing && !this.orientationChanging &&
                    window.scrollY === 0 &&
                    oldWidth === width &&
                    height < oldHeight &&
                    ((height >= oldHeight - this.addressBarHeight) || !this.focusedElement)) {
                    this.scrollToTop();
                }
            }
        });
    }
    else if (version.gtEq('3.1')) {
        this.override({
            isHeightMaximized: function(height) {
                this.scrollToTop();
 
                return this.getWindowHeight() === height - 1;
            }
        });
    }
    else if (version.match('3')) {
        this.override({
            isHeightMaximized: function() {
                this.scrollToTop();
 
                return true;
            }
        });
    }
 
    if (version.gtEq('4')) {
        this.override({
            doBlurInput: Ext.emptyFn
        });
    }
});