/*
 * Copyright (C) 2022 StApps
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */

import {SHARED_AXIS_DIRECTIONS} from './material-motion';

/**
 * /**
 * Choreograph a shared axis animation based on a row of values so that changing state
 * results in the correct, expected behavior of reverting the previous animation etc.
 *
 * The Choreographer manages motion of an element that changes value. This can be used in a variety of ways,
 * for example multi-view choreographing can be achieved as such
 *
 * ```html
 * <div [ngSwitch]='choreographer.state'
 * [@animation]='choreographer.animationState'
 * [@animation.done]='choreographer.done()'>
 * <div *ngSwitchCase='"a"'/>
 * <div *ngSwitchCase='"b"'/>
 * </div>
 * ```
 * @see {@link https://material.io/design/motion/the-motion-system.html#shared-axis}
 */
export class SharedAxisChoreographer<T> {
  /**
   * Expected next value
   */
  private expectedValue: T;

  /**
   * Animation State
   */
  animationState: string;

  /**
   * Current value to read from
   */
  currentValue: T;

  constructor(
    initialValue: T,
    readonly pages?: T[],
  ) {
    this.currentValue = initialValue;
    this.expectedValue = initialValue;
  }

  /**
   * Must be linked to the animation callback
   */
  animationDone() {
    this.animationState = 'in';
    this.currentValue = this.expectedValue;
  }

  /**
   * Change view for a new state that the current active view should receive
   */
  changeViewForState(newValue: T, direction?: -1 | 0 | 1) {
    if (direction === 0) {
      this.currentValue = this.expectedValue = newValue;
      return;
    }

    this.expectedValue = newValue;

    // pre-place animation state
    // new element comes in from the right and pushes the old one to the left
    this.animationState = SHARED_AXIS_DIRECTIONS[direction ?? this.getDirection(this.currentValue, newValue)];
  }

  /**
   * Get direction from to
   */
  getDirection(from: T, to: T) {
    const element = this.pages?.find(it => it === from || it === to);

    return element === from ? 1 : element === to ? -1 : 0;
  }
}
