// 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',
      },
      /**
       * @type (?Object)
       */
      target: {
        type: Object,
        notify: true,
        observer: '_scrollToTarget',
      },
      /**
       * The height of content intended to be included with the target.
       * @type (?number)
       */
      _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.
       * TODO (beckysiegel) figure out why it can be undefined
       * @type (string|undefined)
       */
      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 {!HTMLElement} 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];
      }

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

      if (!this.target) { return; }

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

      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);
    },
  });
})();
