package com.google.collide.client.code;

import com.google.collide.client.history.Place;
import com.google.collide.client.util.AnimationUtils;
import com.google.collide.client.util.ResizeController;

import elemental.css.CSSStyleDeclaration;
import elemental.dom.Element;
import elemental.events.Event;
import elemental.events.EventListener;

/**
 * Class responsible for managing resizing of the Navigation Section.
 */
class NavigatorAreaResizeController extends ResizeController
    implements NavigationAreaExpansionEvent.Handler {

  private static final double DURATION = 0.2;

  int oldNavWidth;
  int oldSplitterLeft;

  private final Element splitter;
  private final Element navigatorArea;
  private final Element contentArea;
  private final int splitterWidth;
  private final int splitterOverlap;
  private final Place currentPlace;

  public NavigatorAreaResizeController(Place currentPlace,
      CodePerspective.Resources resources,
      Element splitter,
      Element navigatorArea,
      Element contentArea,
      int splitterWidth,
      int splitterOverlap) {
    super(resources, splitter, new ElementInfo(navigatorArea, ResizeProperty.WIDTH),
        new ElementInfo(splitter, ResizeProperty.LEFT),
        new ElementInfo(contentArea, ResizeProperty.LEFT));
    this.currentPlace = currentPlace;
    this.splitter = splitter;
    this.navigatorArea = navigatorArea;
    this.contentArea = contentArea;
    this.splitterWidth = splitterWidth;
    this.splitterOverlap = splitterOverlap;
  }

  @Override
  public void onNavAreaExpansion(NavigationAreaExpansionEvent evt) {
    int targetNavWidth = oldNavWidth;
    int targetSplitterLeft = oldSplitterLeft;
    int targetContentAreaLeft = oldSplitterLeft + splitterWidth;

    // If we are asked to collapse.
    if (!evt.shouldExpand()) {

      // Remember the old sizes if we happen to be expanded.
      if (!isCollapsed(splitter)) {
        oldNavWidth = navigatorArea.getClientWidth();
        oldSplitterLeft = splitter.getOffsetLeft();
      }

      // We want to collapse.
      targetNavWidth = 0;
      targetSplitterLeft = 0;
      targetContentAreaLeft = 0;
    }

    // If we ask to expand, but we are already expanded, do nothing.
    if (evt.shouldExpand() && !isCollapsed(splitter)) {
      return;
    }

    splitter.getStyle().setLeft(targetSplitterLeft, CSSStyleDeclaration.Unit.PX);
    splitter.getStyle().setDisplay("none");

    AnimationUtils.backupOverflow(navigatorArea.getStyle());
    AnimationUtils.animatePropertySet(navigatorArea, "width",
        targetNavWidth + CSSStyleDeclaration.Unit.PX, DURATION, new EventListener() {
          @Override
          public void handleEvent(Event evt) {
            splitter.getStyle().setDisplay("");
            AnimationUtils.restoreOverflow(navigatorArea.getStyle());
          }
        });
    AnimationUtils.animatePropertySet(
        contentArea, "left", targetContentAreaLeft + CSSStyleDeclaration.Unit.PX, DURATION);
  }

  @Override
  public void start() {
    super.start();
    attachDblClickListener();
    currentPlace.registerSimpleEventHandler(NavigationAreaExpansionEvent.TYPE, this);
  }

  @Override
  protected void resizeStarted() {
    // Make sure the content area is to the right of the splitter in the
    // case where we drag after collapsing.
    String contentAreaOffset =
        (splitterOverlap + getSplitter().getOffsetLeft()) + CSSStyleDeclaration.Unit.PX;
    contentArea.getStyle().setLeft(contentAreaOffset);
    super.resizeStarted();
  }

  private void attachDblClickListener() {

    // Double clicking animates the splitter to hide and show the nav area.
    // Equivalent to an automated resize.
    splitter.setOndblclick(new EventListener() {

      @Override
      public void handleEvent(Event evt) {

        // We just want to toggle. If it is collapsed, we want to expand.
        currentPlace.fireEvent(new NavigationAreaExpansionEvent(isCollapsed(splitter)));
      }
    });
  }

  private boolean isCollapsed(Element splitter) {
    return splitter.getOffsetLeft() == 0;
  }
}
