// Copyright 2016 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.

/**
 * @fileoverview |GlobalScrollTargetBehavior| allows an element to be aware of
 * the global scroll target.
 *
 * |scrollTarget| will be populated async by |setGlobalScrollTarget|.
 *
 * |subpageScrollTarget| will be equal to the |scrollTarget|, but will only be
 * populated when the current route is the |subpageRoute|.
 *
 * |setGlobalScrollTarget| should only be called once.
 */

cr.define('settings', function() {
  const scrollTargetResolver = new PromiseResolver();

  /** @polymerBehavior */
  const GlobalScrollTargetBehaviorImpl = {
    properties: {
      /**
       * Read only property for the scroll target.
       * @type {HTMLElement}
       */
      scrollTarget: {
        type: Object,
        readOnly: true,
      },

      /**
       * Read only property for the scroll target that a subpage should use.
       * It will be set/cleared based on the current route.
       * @type {HTMLElement}
       */
      subpageScrollTarget: {
        type: Object,
        computed: 'getActiveTarget_(scrollTarget, active_)',
      },

      /**
       * The |subpageScrollTarget| should only be set for this route.
       * @type {settings.Route}
       * @private
       */
      subpageRoute: Object,

      /** Whether the |subpageRoute| is active or not. */
      active_: Boolean,
    },

    /** @override */
    attached: function() {
      this.active_ = settings.getCurrentRoute() == this.subpageRoute;
      scrollTargetResolver.promise.then(this._setScrollTarget.bind(this));
    },

    /** @param {!settings.Route} route */
    currentRouteChanged: function(route) {
      // Immediately set the scroll target to active when this page is
      // activated, but wait a task to remove the scroll target when the page is
      // deactivated. This gives scroll handlers like iron-list a chance to
      // handle scroll events that are fired as a result of the route changing.
      // TODO(https://crbug.com/859794): Having this timeout can result some
      // jumpy behaviour in the scroll handlers. |this.active_| can be set
      // immediately when this bug is fixed.
      if (route == this.subpageRoute) {
        this.active_ = true;
      } else {
        setTimeout(() => {
          this.active_ = false;
        });
      }
    },

    /**
     * Returns the target only when the route is active.
     * @param {HTMLElement} target
     * @param {boolean} active
     * @return {?HTMLElement}
     * @private
     */
    getActiveTarget_: function(target, active) {
      return active ? target : null;
    },
  };

  /**
   * This should only be called once.
   * @param {HTMLElement} scrollTarget
   */
  const setGlobalScrollTarget = function(scrollTarget) {
    scrollTargetResolver.resolve(scrollTarget);
  };

  return {
    GlobalScrollTargetBehaviorImpl: GlobalScrollTargetBehaviorImpl,
    setGlobalScrollTarget: setGlobalScrollTarget,
    scrollTargetResolver: scrollTargetResolver,
  };
});

// This is done to make the closure compiler happy: it needs fully qualified
// names when specifying an array of behaviors.
/** @polymerBehavior */
settings.GlobalScrollTargetBehavior =
    [settings.RouteObserverBehavior, settings.GlobalScrollTargetBehaviorImpl];
