YUI.add('aui-autosize-iframe', function (A, NAME) {

/**
 * The Autosize Iframe Utility
 *
 * @module aui-autosize-iframe
 */

var getClassName = A.getClassName,

    CSS_AUTOSIZE_IFRAME_MONITORED_HEIGHT = getClassName('autosizeiframe', 'monitored', 'height');

/**
 * A base class for `A.AutosizeIframe`.
 *
 * @class A.AutosizeIframe
 * @extends Plugin.Base
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 */
var AutosizeIframe = A.Component.create({

    /**
     * Static property provides a string to identify the class.
     *
     * @property NAME
     * @type {String}
     * @static
     */
    NAME: 'autosizeiframe',

    /**
     * Static property provides a string to identify the namespace.
     *
     * @property NS
     * @type {String}
     * @static
     */
    NS: 'autosizeiframe',

    /**
     * Static property used to define which component it extends.
     *
     * @property EXTENDS
     * @type {String}
     * @static
     */
    EXTENDS: A.Plugin.Base,

    /**
     * Static property used to define the default attribute
     * configuration for the `A.AutosizeIframe`.
     *
     * @property ATTRS
     * @type {Object}
     * @static
     */
    ATTRS: {

        /**
         * The height of the iframe.
         *
         * @attribute height
         * @default 0
         * @type {Number}
         */
        height: {
            value: 0
        },

        /**
         * Indicates if the height should be monitored.
         *
         * @attribute monitorHeight
         * @default true
         * @type {Boolean}
         */
        monitorHeight: {
            value: true
        },

        /**
         * The width of the iframe.
         *
         * @attribute width
         * @default null
         * @type {Number}
         */
        width: {
            value: null
        }
    },

    prototype: {

        /**
         * Construction logic executed during `A.AutosizeIframe` instantiation.
         * Lifecycle.
         *
         * @method initializer
         * @param config
         * @protected
         */
        initializer: function(config) {
            var instance = this;

            var frame = instance.get('host');

            instance.node = frame;
            instance._iframeEl = frame.getDOM();

            instance._defaultHeight = config.height;

            instance.bindUI();
            instance.syncUI();
        },

        /**
         * Binds the events on the `A.AutosizeIframe` UI. Lifecycle.
         *
         * @method bindUI
         * @protected
         */
        bindUI: function() {
            var instance = this;

            instance.after('heightChange', instance._afterHeightChange);
            instance.after('widthChange', instance._afterWidthChange);
            instance.after('monitorHeightChange', instance._afterMonitorHeightChange);
        },

        /**
         * Syncs the `A.AutosizeIframe` UI. Lifecycle.
         *
         * @method syncUI
         * @protected
         */
        syncUI: function() {
            var instance = this;

            instance._uiSetMonitorHeight(instance.get('monitorHeight'));
        },

        /**
         * Destructor lifecycle implementation for the `A.AutosizeIframe` class.
         *
         * @method destructor
         * @protected
         */
        destructor: function() {
            var instance = this;

            instance._uiSetMonitorHeight(false);
        },

        /**
         * Stops to monitor the height.
         *
         * @method pauseMonitor
         */
        pauseMonitor: function() {
            var instance = this;

            instance._clearInterval();
        },

        /**
         * Restarts to monitor the height.
         *
         * @method restartMonitor
         */
        restartMonitor: function() {
            var instance = this;

            if (instance.get('monitorHeight')) {
                instance._setInterval();
            }
        },

        /**
         * Fires after `height` attribute changes.
         *
         * @method _afterHeightChange
         * @param event
         * @protected
         */
        _afterHeightChange: function(event) {
            var instance = this;

            instance._uiSetHeight(event.newVal);
        },

        /**
         * Fires after `monitorHeight` attribute changes.
         *
         * @method _afterMonitorHeightChange
         * @param event
         * @protected
         */
        _afterMonitorHeightChange: function(event) {
            var instance = this;

            instance._uiSetMonitorHeight(event.newVal);
        },

        /**
         * Fires after `width` attribute changes.
         *
         * @method _afterWidthChange
         * @param event
         * @protected
         */
        _afterWidthChange: function(event) {
            var instance = this;

            instance._uiSetWidth(event.newVal);
        },

        /**
         * Cancels repeated action which was set up using `setInterval`.
         *
         * @method _clearInterval
         * @protected
         */
        _clearInterval: function() {
            var instance = this,
                iframeDoc = instance._iframeDoc;

            if (iframeDoc) {
                var docEl = iframeDoc.documentElement;

                if (docEl) {
                    docEl.style.overflowY = '';
                }
            }

            if (instance._intervalId) {
                A.clearInterval(instance._intervalId);

                instance._intervalId = null;
            }
        },

        /**
         * Fires when a window resize happens.
         *
         * @method _onResize
         * @protected
         */
        _onResize: function() {
            var instance = this;

            instance._iframeDoc = null;

            var newHeight = instance._iframeHeight;

            var iframeDoc;
            var iframeWin;

            try {
                iframeWin = instance._iframeEl.contentWindow;

                iframeDoc = iframeWin.document;

                instance._iframeDoc = iframeDoc;
            }
            catch (e) {}

            if (iframeDoc && iframeWin) {
                newHeight = AutosizeIframe._getContentHeight(iframeWin, iframeDoc, instance._iframeHeight);

                instance._uiSetHeight(newHeight);
            }
            else if (!iframeDoc) {
                instance._clearInterval();

                instance._uiSetHeight(instance._defaultHeight);
            }
        },

        /**
         * Calls a function repeatedly, with a fixed time delay between each
         * call to that function.
         *
         * @method _setInterval
         * @param event
         * @protected
         */
        _setInterval: function() {
            var instance = this;

            if (!instance._intervalId) {
                instance._onResize();

                instance._intervalId = A.setInterval(instance._onResize, 100, instance);
            }
        },

        /**
         * Sets the iframe height in the UI.
         *
         * @method _uiSetHeight
         * @param value
         * @protected
         */
        _uiSetHeight: function(value) {
            var instance = this;

            if (instance._iframeHeight !== value) {
                instance._iframeHeight = value;

                instance.node.setStyle('height', value);
            }
        },

        /**
         * Sets the monitor height in the UI.
         *
         * @method _uiSetMonitorHeight
         * @param monitorHeight
         * @protected
         */
        _uiSetMonitorHeight: function(monitorHeight) {
            var instance = this;

            var iframe = instance.node;

            if (monitorHeight) {
                instance._setInterval();

                instance._loadHandle = iframe.on('load', instance._setInterval, instance);

                iframe.addClass(CSS_AUTOSIZE_IFRAME_MONITORED_HEIGHT);
            }
            else {
                instance._clearInterval();

                if (instance._loadHandle) {
                    instance._loadHandle.detach();
                }

                iframe.removeClass(CSS_AUTOSIZE_IFRAME_MONITORED_HEIGHT);
            }
        },

        /**
         * Sets the iframe width in the UI.
         *
         * @method _uiSetWidth
         * @param value
         * @protected
         */
        _uiSetWidth: function(value) {
            var instance = this;

            instance.node.setStyle('width', value);
        },

        _iframeHeight: 0
    }
});

A.mix(AutosizeIframe, {

    /**
     * Returns the content height of a window.
     *
     * @method getContentHeight
     * @param iframeWin
     * @return {Number | null}
     */
    getContentHeight: function(iframeWin) {
        var contentHeight = null;

        try {
            var iframeDoc;

            if (iframeWin.nodeName && iframeWin.nodeName.toLowerCase() === 'iframe') {
                iframeWin = iframeWin.contentWindow;
            }
            else if (A.instanceOf(iframeWin, A.Node)) {
                iframeWin = iframeWin.getDOM().contentWindow;
            }

            iframeDoc = iframeWin.document;

            contentHeight = AutosizeIframe._getContentHeight(iframeWin, iframeDoc);
        }
        catch (e) {}

        return contentHeight;
    },

    /**
     * Returns the content height of a window.
     *
     * @method _getContentHeight
     * @param iframeWin, iframeDoc, fallbackHeight
     * @protected
     * @return {Number | null}
     */
    _getContentHeight: function(iframeWin, iframeDoc, fallbackHeight) {
        var contentHeight = null;

        if (iframeDoc && iframeWin.location.href !== 'about:blank') {
            var docEl = iframeDoc.documentElement;

            var docOffsetHeight = (docEl && Math.max(docEl.offsetHeight, docEl.scrollHeight)) || 0;

            var standardsMode = (iframeDoc.compatMode === 'CSS1Compat');

            if (standardsMode && docOffsetHeight) {
                contentHeight = docOffsetHeight;
            }
            else {
                contentHeight = AutosizeIframe._getQuirksHeight(iframeWin) || fallbackHeight;
            }
        }

        return contentHeight;
    },

    /**
     * Returns the quirks content height of a window.
     *
     * @method _getQuirksHeight
     * @param iframeWin
     * @protected
     * @return {Number}
     */
    _getQuirksHeight: function(iframeWin) {
        var contentHeight = 0;

        var iframeDoc = iframeWin.document;
        var docEl = iframeDoc && iframeDoc.documentElement;
        var iframeBody = iframeDoc && iframeDoc.body;

        var viewPortHeight = 0;

        if (iframeWin.innerHeight) {
            viewPortHeight = iframeWin.innerHeight;
        }
        else if (docEl && docEl.clientHeight) {
            viewPortHeight = docEl.clientHeight;
        }
        else if (iframeBody) {
            viewPortHeight = iframeBody.clientHeight;
        }

        if (iframeDoc) {
            var docClientHeight;
            var docScrollHeight;
            var docOffsetHeight = (iframeBody && iframeBody.offsetHeight);

            if (docEl) {
                docClientHeight = docEl.clientHeight;
                docScrollHeight = docEl.scrollHeight;
                docOffsetHeight = docEl.offsetHeight;
            }

            if (docClientHeight !== docOffsetHeight && iframeBody) {
                docOffsetHeight = iframeBody.offsetHeight;
                docScrollHeight = iframeBody.scrollHeight;
            }

            var compareNum;

            if (docScrollHeight > viewPortHeight) {
                compareNum = Math.max;
            }
            else {
                compareNum = Math.min;
            }

            contentHeight = compareNum(docScrollHeight, docOffsetHeight);
        }

        return contentHeight;
    }
});

A.Plugin.AutosizeIframe = AutosizeIframe;


}, '3.1.0-deprecated.102', {"requires": ["plugin", "aui-component", "aui-timer", "aui-node-base"]});
