// Copyright (C) 2013 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.

package com.google.gerrit.client.diff;

import com.google.gerrit.client.patches.PatchUtil;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import net.codemirror.lib.CodeMirror;
import net.codemirror.lib.Configuration;
import net.codemirror.lib.LineWidget;
import net.codemirror.lib.Pos;
import net.codemirror.lib.TextMarker;
import net.codemirror.lib.TextMarker.FromTo;

class SkipBar extends Composite {
  interface Binder extends UiBinder<HTMLPanel, SkipBar> {}

  private static final Binder uiBinder = GWT.create(Binder.class);
  private static final int NUM_ROWS_TO_EXPAND = 10;
  private static final int UP_DOWN_THRESHOLD = 30;

  interface SkipBarStyle extends CssResource {
    String noExpand();
  }

  @UiField(provided = true)
  Anchor skipNum;

  @UiField(provided = true)
  Anchor upArrow;

  @UiField(provided = true)
  Anchor downArrow;

  @UiField SkipBarStyle style;

  private final SkipManager manager;
  private final CodeMirror cm;

  private LineWidget lineWidget;
  private TextMarker textMarker;
  private SkipBar otherBar;

  SkipBar(SkipManager manager, final CodeMirror cm) {
    this.manager = manager;
    this.cm = cm;

    skipNum = new Anchor(true);
    upArrow = new Anchor(true);
    downArrow = new Anchor(true);
    initWidget(uiBinder.createAndBindUi(this));
    addDomHandler(
        new ClickHandler() {
          @Override
          public void onClick(ClickEvent event) {
            cm.focus();
          }
        },
        ClickEvent.getType());
  }

  void collapse(int start, int end, boolean attach) {
    if (attach) {
      boolean isNew = lineWidget == null;
      Configuration cfg = Configuration.create().set("coverGutter", true).set("noHScroll", true);
      if (start == 0) { // First line workaround
        lineWidget = cm.addLineWidget(end + 1, getElement(), cfg.set("above", true));
      } else {
        lineWidget = cm.addLineWidget(start - 1, getElement(), cfg);
      }
      if (isNew) {
        lineWidget.onFirstRedraw(
            new Runnable() {
              @Override
              public void run() {
                int w = cm.getGutterElement().getOffsetWidth();
                getElement().getStyle().setPaddingLeft(w, Unit.PX);
              }
            });
      }
    }

    textMarker =
        cm.markText(
            Pos.create(start, 0),
            Pos.create(end),
            Configuration.create()
                .set("collapsed", true)
                .set("inclusiveLeft", true)
                .set("inclusiveRight", true));

    textMarker.on(
        "beforeCursorEnter",
        new Runnable() {
          @Override
          public void run() {
            expandAll();
          }
        });

    int skipped = end - start + 1;
    if (skipped <= UP_DOWN_THRESHOLD) {
      addStyleName(style.noExpand());
    } else {
      upArrow.setHTML(PatchUtil.M.expandBefore(NUM_ROWS_TO_EXPAND));
      downArrow.setHTML(PatchUtil.M.expandAfter(NUM_ROWS_TO_EXPAND));
    }
    skipNum.setText(PatchUtil.M.patchSkipRegion(Integer.toString(skipped)));
  }

  static void link(SkipBar barA, SkipBar barB) {
    barA.otherBar = barB;
    barB.otherBar = barA;
  }

  private void clearMarkerAndWidget() {
    textMarker.clear();
    lineWidget.clear();
  }

  void expandBefore(int cnt) {
    expandSideBefore(cnt);

    if (otherBar != null) {
      otherBar.expandSideBefore(cnt);
    }
  }

  private void expandSideBefore(int cnt) {
    FromTo range = textMarker.find();
    int oldStart = range.from().line();
    int newStart = oldStart + cnt;
    int end = range.to().line();
    clearMarkerAndWidget();
    collapse(newStart, end, true);
    updateSelection();
  }

  void expandSideAll() {
    clearMarkerAndWidget();
    removeFromParent();
  }

  private void expandAfter() {
    FromTo range = textMarker.find();
    int start = range.from().line();
    int oldEnd = range.to().line();
    int newEnd = oldEnd - NUM_ROWS_TO_EXPAND;
    boolean attach = start == 0;
    if (attach) {
      clearMarkerAndWidget();
    } else {
      textMarker.clear();
    }
    collapse(start, newEnd, attach);
    updateSelection();
  }

  private void updateSelection() {
    if (cm.somethingSelected()) {
      FromTo sel = cm.getSelectedRange();
      cm.setSelection(sel.from(), sel.to());
    }
  }

  @UiHandler("skipNum")
  void onExpandAll(@SuppressWarnings("unused") ClickEvent e) {
    expandAll();
    updateSelection();
    if (otherBar != null) {
      otherBar.expandAll();
      otherBar.updateSelection();
    }
    cm.refresh();
    cm.focus();
  }

  private void expandAll() {
    expandSideAll();
    if (otherBar != null) {
      otherBar.expandSideAll();
    }
    manager.remove(this, otherBar);
  }

  @UiHandler("upArrow")
  void onExpandBefore(@SuppressWarnings("unused") ClickEvent e) {
    expandBefore(NUM_ROWS_TO_EXPAND);
    if (otherBar != null) {
      otherBar.expandBefore(NUM_ROWS_TO_EXPAND);
    }
    cm.refresh();
    cm.focus();
  }

  @UiHandler("downArrow")
  void onExpandAfter(@SuppressWarnings("unused") ClickEvent e) {
    expandAfter();

    if (otherBar != null) {
      otherBar.expandAfter();
    }
    cm.refresh();
    cm.focus();
  }
}
