// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

/**
 * Holds a number of child views.  As you switch between views, the old
 * view is pushed off to the side and the new view slides in from the other
 * side.
 */
class ConveyorView extends CompositeView {
  // TODO(jmesserly): some places use this property to know when the slide
  // transition is finished. It would be better to have an event that fires
  // when we're done sliding
  static final ANIMATE_SECONDS = 0.5;

  View targetView;
  // TODO(rnystrom): Should not be settable.
  View selectedView;
  // TODO(rnystrom): Hackish. Should use a real multicast event-like class.
  // Or just have it depend on an Observable to select a view and indicate
  // which view is selected? (e.g. the MVVM pattern)
  Function viewSelected;

  int animationTimeoutId;

  ConveyorView()
  : super('conveyor-view', true),
    animationTimeoutId = null {
  }

  Element render() {
    final result = super.render();
    // TODO(rnystrom): Have to do this in render() because container doesn't
    // exist before then. Hack. Should find a cleaner solution. One of:
    // - Add a ctor param to CompositeView for container class name.
    // - Make ConveyorView contain a CompositeView instead of subclass.
    // - Add method to CompositeView to set class name.
    container.attributes['class'] = 'conveyor-view-container';
    return result;
  }

  void selectView(View targetView, [bool animate = true]) {
    selectedView = targetView;

    // Only animate if we're actually in the document now.
    if (isRendered) {
      adjustOffset(animate);
    }
  }

  void adjustOffset(bool animate) {
    int index = getIndexOfSelectedView();
    final durationSeconds = animate ? ANIMATE_SECONDS : 0.0;

    final style = container.style;
    // TODO(jacobr): modify setTransitionDuration so the input is always
    // specified in miliseconds rather than accepting a string.
    Css.setTransitionDuration(style, '${durationSeconds}s');
    final xTranslationPercent = -index * 100;
    Css.setTransform(style, 'translate3d(${xTranslationPercent}%, 0px, 0px)');

    if (animationTimeoutId != null) {
      window.clearTimeout(animationTimeoutId);
    }

    if (animate) {
      animationTimeoutId = window.setTimeout(
          () { _onAnimationEnd(); }, (durationSeconds * 1000).toInt());
    }
    // TODO(mattsh), we should set the visibility to hide everything but the
    // selected view.
  }

  int getIndexOfSelectedView() {
    for (int i = 0; i < childViews.length; i++) {
      if (childViews[i] == selectedView) {
        return i;
      }
    }
    throw "view not found";
  }

  /**
   * Adds a child view to the ConveyorView.  The views are stacked horizontally
   * in the order they are added.
   */
  View addChild(View view) {
    view.addClass('conveyor-item');
    view.transform = 'translate3d(' + (childViews.length * 100) + '%, 0, 0)';
    return super.addChild(view);
  }

  void _onAnimationEnd() {
    if (viewSelected != null) {
      viewSelected(selectedView);
    }
  }
}
