// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @constructor
 * @extends {WebInspector.SidebarPane}
 * @param {string} title
 */
WebInspector.ElementsSidebarPane = function(title)
{
    WebInspector.SidebarPane.call(this, title);
    this._node = null;
    this._updateController = new WebInspector.ElementsSidebarPane._UpdateController(this, this.doUpdate.bind(this));
    WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, this._nodeChanged, this);
}

WebInspector.ElementsSidebarPane.prototype = {
    /**
     * @return {?WebInspector.DOMNode}
     */
    node: function()
    {
        return this._node;
    },

    /**
     * @return {?WebInspector.CSSModel}
     */
    cssModel: function()
    {
        return this._cssModel && this._cssModel.isEnabled() ? this._cssModel : null;
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _nodeChanged: function(event)
    {
        this.setNode(/** @type {?WebInspector.DOMNode} */ (event.data));
    },

    /**
     * @param {?WebInspector.DOMNode} node
     */
    setNode: function(node)
    {
        this._node = node;
        this._updateTarget(node ? node.target() : null);
        this.update();
    },

    /**
     * @protected
     * @return {!Promise.<?>}
     */
    doUpdate: function()
    {
        return Promise.resolve();
    },

    update: function()
    {
        this._updateController.update();
    },

    wasShown: function()
    {
        WebInspector.SidebarPane.prototype.wasShown.call(this);
        this._updateController.viewWasShown();
    },

    /**
     * @param {?WebInspector.Target} target
     */
    _updateTarget: function(target)
    {
        if (this._target === target)
            return;
        if (this._targetEvents) {
            WebInspector.EventTarget.removeEventListeners(this._targetEvents);
            this._targetEvents = null;
        }
        this._target = target;

        var domModel = null;
        var resourceTreeModel = null;
        if (target) {
            this._cssModel = WebInspector.CSSModel.fromTarget(target);
            domModel = WebInspector.DOMModel.fromTarget(target);
            resourceTreeModel = target.resourceTreeModel;
        }

        if (this._cssModel && domModel && resourceTreeModel) {
            this._targetEvents = [
                this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this.onCSSModelChanged, this),
                this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this.onCSSModelChanged, this),
                this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, this.onCSSModelChanged, this),
                this._cssModel.addEventListener(WebInspector.CSSModel.Events.MediaQueryResultChanged, this.onCSSModelChanged, this),
                this._cssModel.addEventListener(WebInspector.CSSModel.Events.PseudoStateForced, this.onCSSModelChanged, this),
                this._cssModel.addEventListener(WebInspector.CSSModel.Events.ModelWasEnabled, this.onCSSModelChanged, this),
                domModel.addEventListener(WebInspector.DOMModel.Events.DOMMutated, this._domModelChanged, this),
                resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameResized, this._onFrameResized, this),
            ];
        }
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _onFrameResized: function(event)
    {
        /**
         * @this {WebInspector.ElementsSidebarPane}
         */
        function refreshContents()
        {
            this.onFrameResizedThrottled();
            delete this._frameResizedTimer;
        }

        if (this._frameResizedTimer)
            clearTimeout(this._frameResizedTimer);

        this._frameResizedTimer = setTimeout(refreshContents.bind(this), 100);
    },

    /**
     * @param {!WebInspector.Event} event
     */
    _domModelChanged: function(event)
    {
        var node = /** @type {!WebInspector.DOMNode} */ (event.data);
        this.onDOMModelChanged(node)
    },

    /**
     * @param {!WebInspector.DOMNode} node
     */
    onDOMModelChanged: function(node) { },

    /**
     * @param {!WebInspector.Event} event
     */
    onCSSModelChanged: function(event) { },

    onFrameResizedThrottled: function() { },

    __proto__: WebInspector.SidebarPane.prototype
}

/**
 * @constructor
 * @param {!WebInspector.Widget} view
 * @param {function():!Promise.<?>} doUpdate
 */
WebInspector.ElementsSidebarPane._UpdateController = function(view, doUpdate)
{
    this._view = view;
    this._updateThrottler = new WebInspector.Throttler(100);
    this._updateWhenVisible = false;
    this._doUpdate = doUpdate;
}

WebInspector.ElementsSidebarPane._UpdateController.prototype = {
    update: function()
    {
        this._updateWhenVisible = !this._view.isShowing();
        if (this._updateWhenVisible)
            return;
        this._updateThrottler.schedule(innerUpdate.bind(this));

        /**
         * @this {WebInspector.ElementsSidebarPane._UpdateController}
         * @return {!Promise.<?>}
         */
        function innerUpdate()
        {
            return this._view.isShowing() ? this._doUpdate.call(null) : Promise.resolve();
        }
    },

    viewWasShown: function()
    {
        if (this._updateWhenVisible)
            this.update();
    }
}
