// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
(function() {
  'use strict';

  const ScrollBehavior = {
    NEVER: 'never',
    KEEP_VISIBLE: 'keep-visible',
  };

  Polymer({
    is: 'gr-cursor-manager',

    properties: {
      stops: {
        type: Array,
        value() {
          return [];
        },
        observer: '_updateIndex',
      },
      target: {
        type: Object,
        notify: true,
        observer: '_scrollToTarget',
      },
      /**
       * The height of content intended to be included with the target.
       */
      _targetHeight: Number,

      /**
       * The index of the current target (if any). -1 otherwise.
       */
      index: {
        type: Number,
        value: -1,
        notify: true,
      },

      /**
       * The class to apply to the current target. Use null for no class.
       */
      cursorTargetClass: {
        type: String,
        value: null,
      },

      /**
       * The scroll behavior for the cursor. Values are 'never' and
       * 'keep-visible'. 'keep-visible' will only scroll if the cursor is beyond
       * the viewport.
       */
      scrollBehavior: {
        type: String,
        value: ScrollBehavior.NEVER,
      },

      /**
       * When true, will call element.focus() during scrolling.
       */
      focusOnMove: {
        type: Boolean,
        value: false,
      },
    },

    detached() {
      this.unsetCursor();
    },

    next(opt_condition, opt_getTargetHeight) {
      this._moveCursor(1, opt_condition, opt_getTargetHeight);
    },

    previous(opt_condition) {
      this._moveCursor(-1, opt_condition);
    },

    /**
     * Set the cursor to an arbitrary element.
     * @param {DOMElement} element
     * @param {boolean} opt_noScroll prevent any potential scrolling in response
     *   setting the cursor.
     */
    setCursor(element, opt_noScroll) {
      let behavior;
      if (opt_noScroll) {
        behavior = this.scrollBehavior;
        this.scrollBehavior = ScrollBehavior.NEVER;
      }

      this.unsetCursor();
      this.target = element;
      this._updateIndex();
      this._decorateTarget();

      if (opt_noScroll) { this.scrollBehavior = behavior; }
    },

    unsetCursor() {
      this._unDecorateTarget();
      this.index = -1;
      this.target = null;
      this._targetHeight = null;
    },

    isAtStart() {
      return this.index === 0;
    },

    isAtEnd() {
      return this.index === this.stops.length - 1;
    },

    moveToStart() {
      if (this.stops.length) {
        this.setCursor(this.stops[0]);
      }
    },

    setCursorAtIndex(index, opt_noScroll) {
      this.setCursor(this.stops[index], opt_noScroll);
    },

    /**
     * Move the cursor forward or backward by delta. Noop if moving past either
     * end of the stop list.
     * @param {Number} delta either -1 or 1.
     * @param {Function} opt_condition Optional stop condition. If a condition
     *    is passed the cursor will continue to move in the specified direction
     *    until the condition is met.
     * @param {Function} opt_getTargetHeight Optional function to calculate the
     *    height of the target's 'section'. The height of the target itself is
     *    sometimes different, used by the diff cursor.
     * @private
     */
    _moveCursor(delta, opt_condition, opt_getTargetHeight) {
      if (!this.stops.length) {
        this.unsetCursor();
        return;
      }

      this._unDecorateTarget();

      const newIndex = this._getNextindex(delta, opt_condition);

      let newTarget = null;
      if (newIndex != -1) {
        newTarget = this.stops[newIndex];
      }

      if (opt_getTargetHeight) {
        this._targetHeight = opt_getTargetHeight(newTarget);
      } else {
        this._targetHeight = newTarget.scrollHeight;
      }

      this.index = newIndex;
      this.target = newTarget;

      if (this.focusOnMove) { this.target.focus(); }

      this._decorateTarget();
    },

    _decorateTarget() {
      if (this.target && this.cursorTargetClass) {
        this.target.classList.add(this.cursorTargetClass);
      }
    },

    _unDecorateTarget() {
      if (this.target && this.cursorTargetClass) {
        this.target.classList.remove(this.cursorTargetClass);
      }
    },

    /**
     * Get the next stop index indicated by the delta direction.
     * @param {Number} delta either -1 or 1.
     * @param {Function} opt_condition Optional stop condition.
     * @return {Number} the new index.
     * @private
     */
    _getNextindex(delta, opt_condition) {
      if (!this.stops.length || this.index === -1) {
        return -1;
      }

      let newIndex = this.index;
      do {
        newIndex = newIndex + delta;
      } while (newIndex > 0 &&
               newIndex < this.stops.length - 1 &&
               opt_condition && !opt_condition(this.stops[newIndex]));

      newIndex = Math.max(0, Math.min(this.stops.length - 1, newIndex));

      // If we failed to satisfy the condition:
      if (opt_condition && !opt_condition(this.stops[newIndex])) {
        if (delta > 0) {
          return this.stops.length - 1;
        } else if (delta < 0) {
          return 0;
        }
        return this.index;
      }

      return newIndex;
    },

    _updateIndex() {
      if (!this.target) {
        this.index = -1;
        return;
      }

      const newIndex = Array.prototype.indexOf.call(this.stops, this.target);
      if (newIndex === -1) {
        this.unsetCursor();
      } else {
        this.index = newIndex;
      }
    },

    /**
     * Calculate where the element is relative to the window.
     * @param {object} target Target to scroll to.
     * @return {number} Distance to top of the target.
     */
    _getTop(target) {
      let top = target.offsetTop;
      for (let offsetParent = target.offsetParent;
           offsetParent;
           offsetParent = offsetParent.offsetParent) {
        top += offsetParent.offsetTop;
      }
      return top;
    },

    /**
     * @return {boolean}
     */
    _targetIsVisible(top) {
      return this.scrollBehavior === ScrollBehavior.KEEP_VISIBLE &&
          top > window.pageYOffset &&
          top < window.pageYOffset + window.innerHeight;
    },

    _calculateScrollToValue(top, target) {
      return top - (window.innerHeight / 3) + (target.offsetHeight / 2);
    },

    _scrollToTarget() {
      if (!this.target || this.scrollBehavior === ScrollBehavior.NEVER) {
        return;
      }

      const top = this._getTop(this.target);
      const bottomIsVisible = this._targetHeight ?
          this._targetIsVisible(top + this._targetHeight) : true;
      const scrollToValue = this._calculateScrollToValue(top, this.target);

      if (this._targetIsVisible(top)) {
        // Don't scroll if either the bottom is visible or if the position that
        // would get scrolled to is higher up than the current position. this
        // woulld cause less of the target content to be displayed than is
        // already.
        if (bottomIsVisible || scrollToValue < window.scrollY) {
          return;
        }
      }

      // Scroll the element to the middle of the window. Dividing by a third
      // instead of half the inner height feels a bit better otherwise the
      // element appears to be below the center of the window even when it
      // isn't.
      window.scrollTo(0, scrollToValue);
    },
  });
})();
