// 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 impl ied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.client.diff;

import static com.google.gerrit.extensions.client.DiffPreferencesInfo.WHOLE_FILE_CONTEXT;
import static java.lang.Double.POSITIVE_INFINITY;

import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.account.DiffPreferences;
import com.google.gerrit.client.change.ChangeScreen;
import com.google.gerrit.client.change.FileTable;
import com.google.gerrit.client.changes.ChangeApi;
import com.google.gerrit.client.changes.ChangeList;
import com.google.gerrit.client.diff.DiffInfo.FileMeta;
import com.google.gerrit.client.diff.LineMapper.LineOnOtherInfo;
import com.google.gerrit.client.info.ChangeInfo;
import com.google.gerrit.client.info.ChangeInfo.CommitInfo;
import com.google.gerrit.client.info.ChangeInfo.EditInfo;
import com.google.gerrit.client.info.ChangeInfo.RevisionInfo;
import com.google.gerrit.client.info.FileInfo;
import com.google.gerrit.client.patches.PatchUtil;
import com.google.gerrit.client.projects.ConfigInfoCache;
import com.google.gerrit.client.rpc.CallbackGroup;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.rpc.RestApi;
import com.google.gerrit.client.rpc.ScreenLoadCallback;
import com.google.gerrit.client.ui.Screen;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo.DiffView;
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Patch;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.RepeatingCommand;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwtexpui.globalkey.client.GlobalKey;
import com.google.gwtexpui.globalkey.client.KeyCommand;
import com.google.gwtexpui.globalkey.client.KeyCommandSet;
import com.google.gwtexpui.globalkey.client.ShowHelpCommand;

import net.codemirror.lib.CodeMirror;
import net.codemirror.lib.CodeMirror.BeforeSelectionChangeHandler;
import net.codemirror.lib.CodeMirror.GutterClickHandler;
import net.codemirror.lib.CodeMirror.LineHandle;
import net.codemirror.lib.KeyMap;
import net.codemirror.lib.Pos;
import net.codemirror.mode.ModeInfo;
import net.codemirror.mode.ModeInjector;
import net.codemirror.theme.ThemeLoader;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

/** Base class for SideBySide and Unified */
abstract class DiffScreen extends Screen {
  private static final KeyMap RENDER_ENTIRE_FILE_KEYMAP = KeyMap.create()
      .propagate("Ctrl-F").propagate("Ctrl-G").propagate("Shift-Ctrl-G");

  enum FileSize {
    SMALL(0),
    LARGE(500),
    HUGE(4000);

    final int lines;

    FileSize(int n) {
      this.lines = n;
    }
  }

  private final Change.Id changeId;
  final PatchSet.Id base;
  final PatchSet.Id revision;
  final String path;
  final DiffPreferences prefs;
  final SkipManager skipManager;

  private DisplaySide startSide;
  private int startLine;
  private Change.Status changeStatus;

  private HandlerRegistration resizeHandler;
  private DiffInfo diff;
  private FileSize fileSize;
  private EditInfo edit;

  private KeyCommandSet keysNavigation;
  private KeyCommandSet keysAction;
  private KeyCommandSet keysComment;
  private List<HandlerRegistration> handlers;
  private PreferencesAction prefsAction;
  private int reloadVersionId;
  private int parents;

  @UiField(provided = true)
  Header header;

  DiffScreen(
      PatchSet.Id base,
      PatchSet.Id revision,
      String path,
      DisplaySide startSide,
      int startLine,
      DiffView diffScreenType) {
    this.base = base;
    this.revision = revision;
    this.changeId = revision.getParentKey();
    this.path = path;
    this.startSide = startSide;
    this.startLine = startLine;

    prefs = DiffPreferences.create(Gerrit.getDiffPreferences());
    handlers = new ArrayList<>(6);
    keysNavigation = new KeyCommandSet(Gerrit.C.sectionNavigation());
    header = new Header(
        keysNavigation, base, revision, path, diffScreenType, prefs);
    skipManager = new SkipManager(this);
  }

  @Override
  protected void onInitUI() {
    super.onInitUI();
    setHeaderVisible(false);
    setWindowTitle(FileInfo.getFileName(path));
  }

  @Override
  protected void onLoad() {
    super.onLoad();

    CallbackGroup group1 = new CallbackGroup();
    final CallbackGroup group2 = new CallbackGroup();

    CodeMirror.initLibrary(group1.add(new AsyncCallback<Void>() {
      final AsyncCallback<Void> themeCallback = group2.addEmpty();

      @Override
      public void onSuccess(Void result) {
        // Load theme after CM library to ensure theme can override CSS.
        ThemeLoader.loadTheme(prefs.theme(), themeCallback);
      }

      @Override
      public void onFailure(Throwable caught) {
      }
    }));

    DiffApi.diff(revision, path)
      .base(base)
      .wholeFile()
      .intraline(prefs.intralineDifference())
      .ignoreWhitespace(prefs.ignoreWhitespace())
      .get(group1.addFinal(new GerritCallback<DiffInfo>() {
        final AsyncCallback<Void> modeInjectorCb = group2.addEmpty();

        @Override
        public void onSuccess(DiffInfo diffInfo) {
          diff = diffInfo;
          fileSize = bucketFileSize(diffInfo);

          if (prefs.syntaxHighlighting()) {
            if (fileSize.compareTo(FileSize.SMALL) > 0) {
              modeInjectorCb.onSuccess(null);
            } else {
              injectMode(diffInfo, modeInjectorCb);
            }
          } else {
            modeInjectorCb.onSuccess(null);
          }
        }
      }));

    if (Gerrit.isSignedIn()) {
      ChangeApi.edit(changeId.get(), group2.add(
          new AsyncCallback<EditInfo>() {
            @Override
            public void onSuccess(EditInfo result) {
              edit = result;
            }

            @Override
            public void onFailure(Throwable caught) {
            }
          }));
    }

    final CommentsCollections comments =
        new CommentsCollections(base, revision, path);
    comments.load(group2);

    countParents(group2);

    RestApi call = ChangeApi.detail(changeId.get());
    ChangeList.addOptions(call, EnumSet.of(
        ListChangesOption.ALL_REVISIONS));
    call.get(group2.add(new AsyncCallback<ChangeInfo>() {
      @Override
      public void onSuccess(ChangeInfo info) {
        changeStatus = info.status();
        info.revisions().copyKeysIntoChildren("name");
        if (edit != null) {
          edit.setName(edit.commit().commit());
          info.setEdit(edit);
          info.revisions().put(edit.name(), RevisionInfo.fromEdit(edit));
        }
        String currentRevision = info.currentRevision();
        boolean current = currentRevision != null &&
            revision.get() == info.revision(currentRevision)._number();
        JsArray<RevisionInfo> list = info.revisions().values();
        RevisionInfo.sortRevisionInfoByNumber(list);
        getDiffTable().set(prefs, list, parents, diff, edit != null, current,
            changeStatus.isOpen(), diff.binary());
        header.setChangeInfo(info);
      }

      @Override
      public void onFailure(Throwable caught) {
      }
    }));

    ConfigInfoCache.get(changeId, group2.addFinal(
        getScreenLoadCallback(comments)));
  }

  private void countParents(CallbackGroup cbg) {
    ChangeApi.revision(changeId.get(), revision.getId())
        .view("commit")
        .get(cbg.add(new AsyncCallback<CommitInfo>() {
          @Override
          public void onSuccess(CommitInfo info) {
            parents = info.parents().length();
          }

          @Override
          public void onFailure(Throwable caught) {
            parents = 0;
          }
        }));
  }

  @Override
  public void onShowView() {
    super.onShowView();

    Window.enableScrolling(false);
    if (prefs.hideTopMenu()) {
      Gerrit.setHeaderVisible(false);
    }
    resizeHandler = Window.addResizeHandler(new ResizeHandler() {
      @Override
      public void onResize(ResizeEvent event) {
        resizeCodeMirror();
      }
    });
  }

  KeyCommandSet getKeysNavigation() {
    return keysNavigation;
  }

  KeyCommandSet getKeysAction() {
    return keysAction;
  }

  @Override
  protected void onUnload() {
    super.onUnload();

    removeKeyHandlerRegistrations();
    if (getCommentManager() != null) {
      CallbackGroup group = new CallbackGroup();
      getCommentManager().saveAllDrafts(group);
      group.done();
    }
    if (resizeHandler != null) {
      resizeHandler.removeHandler();
      resizeHandler = null;
    }
    for (CodeMirror cm : getCms()) {
      if (cm != null) {
        cm.getWrapperElement().removeFromParent();
      }
    }
    if (prefsAction != null) {
      prefsAction.hide();
    }

    Window.enableScrolling(true);
    Gerrit.setHeaderVisible(true);
  }

  private void removeKeyHandlerRegistrations() {
    for (HandlerRegistration h : handlers) {
      h.removeHandler();
    }
    handlers.clear();
  }

  void registerCmEvents(final CodeMirror cm) {
    cm.on("cursorActivity", updateActiveLine(cm));
    cm.on("focus", updateActiveLine(cm));
    KeyMap keyMap = KeyMap.create()
        .on("A", upToChange(true))
        .on("U", upToChange(false))
        .on("'['", header.navigate(Direction.PREV))
        .on("']'", header.navigate(Direction.NEXT))
        .on("R", header.toggleReviewed())
        .on("O", getCommentManager().toggleOpenBox(cm))
        .on("N", maybeNextVimSearch(cm))
        .on("Ctrl-Alt-E", openEditScreen(cm))
        .on("P", getChunkManager().diffChunkNav(cm, Direction.PREV))
        .on("Shift-M", header.reviewedAndNext())
        .on("Shift-N", maybePrevVimSearch(cm))
        .on("Shift-P", getCommentManager().commentNav(cm, Direction.PREV))
        .on("Shift-O", getCommentManager().openCloseAll(cm))
        .on("I", new Runnable() {
          @Override
          public void run() {
            switch (getIntraLineStatus()) {
              case OFF:
              case OK:
                toggleShowIntraline();
                break;
              case FAILURE:
              case TIMEOUT:
              default:
                break;
            }
          }
        })
        .on("','", new Runnable() {
          @Override
          public void run() {
            prefsAction.show();
          }
        })
        .on("Shift-/", new Runnable() {
          @Override
          public void run() {
            new ShowHelpCommand().onKeyPress(null);
          }
        })
        .on("Space", new Runnable() {
          @Override
          public void run() {
            cm.vim().handleKey("<C-d>");
          }
        })
        .on("Shift-Space", new Runnable() {
          @Override
          public void run() {
            cm.vim().handleKey("<C-u>");
          }
        })
        .on("Ctrl-F", new Runnable() {
          @Override
          public void run() {
            cm.execCommand("find");
          }
        })
        .on("Ctrl-G", new Runnable() {
          @Override
          public void run() {
            cm.execCommand("findNext");
          }
        })
        .on("Enter", maybeNextCmSearch(cm))
        .on("Shift-Ctrl-G", new Runnable() {
          @Override
          public void run() {
            cm.execCommand("findPrev");
          }
        })
        .on("Shift-Enter", new Runnable() {
          @Override
          public void run() {
            cm.execCommand("findPrev");
          }
        })
        .on("Esc", new Runnable() {
          @Override
          public void run() {
            cm.setCursor(cm.getCursor());
            cm.execCommand("clearSearch");
            cm.vim().handleEx("nohlsearch");
          }
        })
        .on("Ctrl-A", new Runnable() {
          @Override
          public void run() {
            cm.execCommand("selectAll");
          }
        })
        .on("G O", new Runnable() {
          @Override
          public void run() {
            Gerrit.display(PageLinks.toChangeQuery("status:open"));
          }
        })
        .on("G M", new Runnable() {
          @Override
          public void run() {
            Gerrit.display(PageLinks.toChangeQuery("status:merged"));
          }
        })
        .on("G A", new Runnable() {
          @Override
          public void run() {
            Gerrit.display(PageLinks.toChangeQuery("status:abandoned"));
          }
        });
        if (Gerrit.isSignedIn()) {
          keyMap.on("G I", new Runnable() {
            @Override
            public void run() {
              Gerrit.display(PageLinks.MINE);
            }
          })
          .on("G D", new Runnable() {
            @Override
            public void run() {
              Gerrit.display(PageLinks.toChangeQuery("owner:self is:draft"));
            }
          })
          .on("G C", new Runnable() {
            @Override
            public void run() {
              Gerrit.display(PageLinks.toChangeQuery("has:draft"));
            }
          })
          .on("G W", new Runnable() {
            @Override
            public void run() {
              Gerrit.display(
                  PageLinks.toChangeQuery("is:watched status:open"));
            }
          })
          .on("G S", new Runnable() {
            @Override
            public void run() {
              Gerrit.display(PageLinks.toChangeQuery("is:starred"));
            }
          });
        }

    if (revision.get() != 0) {
      cm.on("beforeSelectionChange", onSelectionChange(cm));
      cm.on("gutterClick", onGutterClick(cm));
      keyMap.on("C", getCommentManager().newDraftCallback(cm));
    }
    CodeMirror.normalizeKeyMap(keyMap); // Needed to for multi-stroke keymaps
    cm.addKeyMap(keyMap);
  }

  void maybeRegisterRenderEntireFileKeyMap(CodeMirror cm) {
    if (renderEntireFile()) {
      cm.addKeyMap(RENDER_ENTIRE_FILE_KEYMAP);
    }
  }

  private BeforeSelectionChangeHandler onSelectionChange(final CodeMirror cm) {
    return new BeforeSelectionChangeHandler() {
      private InsertCommentBubble bubble;

      @Override
      public void handle(CodeMirror cm, Pos anchor, Pos head) {
        if (anchor.equals(head)) {
          if (bubble != null) {
            bubble.setVisible(false);
          }
          return;
        } else if (bubble == null) {
          init(anchor);
        } else {
          bubble.setVisible(true);
        }
        bubble.position(cm.charCoords(head, "local"));
      }

      private void init(Pos anchor) {
        bubble = new InsertCommentBubble(getCommentManager(), cm);
        add(bubble);
        cm.addWidget(anchor, bubble.getElement());
      }
    };
  }

  @Override
  public void registerKeys() {
    super.registerKeys();

    keysNavigation.add(new UpToChangeCommand(revision, 0, 'u'));
    keysNavigation.add(
        new NoOpKeyCommand(0, 'j', PatchUtil.C.lineNext()),
        new NoOpKeyCommand(0, 'k', PatchUtil.C.linePrev()));
    keysNavigation.add(
        new NoOpKeyCommand(0, 'n', PatchUtil.C.chunkNext()),
        new NoOpKeyCommand(0, 'p', PatchUtil.C.chunkPrev()));
    keysNavigation.add(
        new NoOpKeyCommand(KeyCommand.M_SHIFT, 'n', PatchUtil.C.commentNext()),
        new NoOpKeyCommand(KeyCommand.M_SHIFT, 'p', PatchUtil.C.commentPrev()));
    keysNavigation.add(
        new NoOpKeyCommand(KeyCommand.M_CTRL, 'f', Gerrit.C.keySearch()));

    keysAction = new KeyCommandSet(Gerrit.C.sectionActions());
    keysAction.add(new NoOpKeyCommand(0, KeyCodes.KEY_ENTER,
        PatchUtil.C.expandComment()));
    keysAction.add(new NoOpKeyCommand(0, 'o', PatchUtil.C.expandComment()));
    keysAction.add(new NoOpKeyCommand(
        KeyCommand.M_SHIFT, 'o', PatchUtil.C.expandAllCommentsOnCurrentLine()));
    if (Gerrit.isSignedIn()) {
      keysAction.add(new KeyCommand(0, 'r', PatchUtil.C.toggleReviewed()) {
        @Override
        public void onKeyPress(KeyPressEvent event) {
          header.toggleReviewed().run();
        }
      });
      keysAction.add(new NoOpKeyCommand(KeyCommand.M_CTRL | KeyCommand.M_ALT,
          'e', Gerrit.C.keyEditor()));
    }
    keysAction.add(new KeyCommand(
        KeyCommand.M_SHIFT, 'm', PatchUtil.C.markAsReviewedAndGoToNext()) {
      @Override
      public void onKeyPress(KeyPressEvent event) {
        header.reviewedAndNext().run();
      }
    });
    keysAction.add(new KeyCommand(0, 'a', PatchUtil.C.openReply()) {
      @Override
      public void onKeyPress(KeyPressEvent event) {
        upToChange(true).run();
      }
    });
    keysAction.add(new KeyCommand(0, ',', PatchUtil.C.showPreferences()) {
      @Override
      public void onKeyPress(KeyPressEvent event) {
        prefsAction.show();
      }
    });
    if (getIntraLineStatus() == DiffInfo.IntraLineStatus.OFF
        || getIntraLineStatus() == DiffInfo.IntraLineStatus.OK) {
      keysAction.add(new KeyCommand(0, 'i', PatchUtil.C.toggleIntraline()) {
        @Override
        public void onKeyPress(KeyPressEvent event) {
          toggleShowIntraline();
        }
      });
    }

    if (Gerrit.isSignedIn()) {
      keysAction.add(new NoOpKeyCommand(0, 'c', PatchUtil.C.commentInsert()));
      keysComment = new KeyCommandSet(PatchUtil.C.commentEditorSet());
      keysComment.add(new NoOpKeyCommand(KeyCommand.M_CTRL, 's',
          PatchUtil.C.commentSaveDraft()));
      keysComment.add(new NoOpKeyCommand(0, KeyCodes.KEY_ESCAPE,
          PatchUtil.C.commentCancelEdit()));
    } else {
      keysComment = null;
    }
  }

  void registerHandlers() {
    removeKeyHandlerRegistrations();
    handlers.add(GlobalKey.add(this, keysAction));
    handlers.add(GlobalKey.add(this, keysNavigation));
    if (keysComment != null) {
      handlers.add(GlobalKey.add(this, keysComment));
    }
    handlers.add(ShowHelpCommand.addFocusHandler(getFocusHandler()));
  }

  void setupSyntaxHighlighting() {
    if (prefs.syntaxHighlighting() && fileSize.compareTo(FileSize.SMALL) > 0) {
      Scheduler.get().scheduleFixedDelay(new RepeatingCommand() {
        @Override
        public boolean execute() {
          if (prefs.syntaxHighlighting() && isAttached()) {
            setSyntaxHighlighting(prefs.syntaxHighlighting());
          }
          return false;
        }
      }, 250);
    }
  }

  abstract CodeMirror newCm(
      DiffInfo.FileMeta meta, String contents, Element parent);

  void render(DiffInfo diff) {
    header.setNoDiff(diff);
    getChunkManager().render(diff);
  }

  void setShowLineNumbers(boolean b) {
    if (b) {
      getDiffTable().addStyleName(
          Resources.I.diffTableStyle().showLineNumbers());
    } else {
      getDiffTable().removeStyleName(
          Resources.I.diffTableStyle().showLineNumbers());
    }
  }

  void setShowIntraline(boolean b) {
    if (b && getIntraLineStatus() == DiffInfo.IntraLineStatus.OFF) {
      reloadDiffInfo();
    } else if (b) {
      getDiffTable().removeStyleName(Resources.I.diffTableStyle().noIntraline());
    } else {
      getDiffTable().addStyleName(Resources.I.diffTableStyle().noIntraline());
    }
  }

  private void toggleShowIntraline() {
    prefs.intralineDifference(!prefs.intralineDifference());
    setShowIntraline(prefs.intralineDifference());
    prefsAction.update();
  }

  abstract void setSyntaxHighlighting(boolean b);

  void setContext(final int context) {
    operation(new Runnable() {
      @Override
      public void run() {
        skipManager.removeAll();
        skipManager.render(context, diff);
        updateRenderEntireFile();
      }
    });
  }

  private int adjustCommitMessageLine(int line) {
    /* When commit messages are shown in the diff screen they include
      a header block that looks like this:

      1 Parent:     deadbeef (Parent commit title)
      2 Author:     A. U. Thor <author@example.com>
      3 AuthorDate: 2015-02-27 19:20:52 +0900
      4 Commit:     A. U. Thor <author@example.com>
      5 CommitDate: 2015-02-27 19:20:52 +0900
      6 [blank line]
      7 Commit message title
      8
      9 Commit message body
     10 ...
     11 ...

    If the commit is a merge commit, both parent commits are listed in the
    first two lines instead of a 'Parent' line:

      1 Merge Of:   deadbeef (Parent 1 commit title)
      2             beefdead (Parent 2 commit title)

    */

    // Offset to compensate for header lines until the blank line
    // after 'CommitDate'
    int offset = 6;

    // Adjust for merge commits, which have two parent lines
    if (diff.textB().startsWith("Merge")) {
      offset += 1;
    }

    // If the cursor is inside the header line, reset to the first line of the
    // commit message. Otherwise if the cursor is on an actual line of the commit
    // message, adjust the line number to compensate for the header lines, so the
    // focus is on the correct line.
    if (line <= offset) {
      return 1;
    }
    return line - offset;
  }

  private Runnable openEditScreen(final CodeMirror cm) {
    return new Runnable() {
      @Override
      public void run() {
        LineHandle handle = cm.extras().activeLine();
        int line = cm.getLineNumber(handle) + 1;
        if (Patch.COMMIT_MSG.equals(path)) {
          line = adjustCommitMessageLine(line);
        }
        String token = Dispatcher.toEditScreen(revision, path, line);
        if (!Gerrit.isSignedIn()) {
          Gerrit.doSignIn(token);
        } else {
          Gerrit.display(token);
        }
      }
    };
  }

  void updateRenderEntireFile() {
    boolean entireFile = renderEntireFile();
    for (CodeMirror cm : getCms()) {
      cm.removeKeyMap(RENDER_ENTIRE_FILE_KEYMAP);
      if (entireFile) {
        cm.addKeyMap(RENDER_ENTIRE_FILE_KEYMAP);
      }
      cm.setOption("viewportMargin", entireFile ? POSITIVE_INFINITY : 10);
    }
  }

  void resizeCodeMirror() {
    int height = header.getOffsetHeight() + getDiffTable().getHeaderHeight();
    for (CodeMirror cm : getCms()) {
      cm.adjustHeight(height);
    }
  }

  abstract ChunkManager getChunkManager();

  abstract CommentManager getCommentManager();

  Change.Status getChangeStatus() {
    return changeStatus;
  }

  int getStartLine() {
    return startLine;
  }

  void setStartLine(int startLine) {
    this.startLine = startLine;
  }

  DisplaySide getStartSide() {
    return startSide;
  }

  void setStartSide(DisplaySide startSide) {
    this.startSide = startSide;
  }

  DiffInfo getDiff() {
    return diff;
  }

  FileSize getFileSize() {
    return fileSize;
  }

  PreferencesAction getPrefsAction() {
    return prefsAction;
  }

  void setPrefsAction(PreferencesAction prefsAction) {
    this.prefsAction = prefsAction;
  }

  abstract void operation(final Runnable apply);

  private Runnable upToChange(final boolean openReplyBox) {
    return new Runnable() {
      @Override
      public void run() {
        CallbackGroup group = new CallbackGroup();
        getCommentManager().saveAllDrafts(group);
        group.done();
        group.addListener(new GerritCallback<Void>() {
          @Override
          public void onSuccess(Void result) {
            String b = base != null ? String.valueOf(base.get()) : null;
            String rev = String.valueOf(revision.get());
            Gerrit.display(
              PageLinks.toChange(changeId, b, rev),
              new ChangeScreen(changeId, b, rev, openReplyBox,
                  FileTable.Mode.REVIEW));
          }
        });
      }
    };
  }

  private Runnable maybePrevVimSearch(final CodeMirror cm) {
    return new Runnable() {
      @Override
      public void run() {
        if (cm.vim().hasSearchHighlight()) {
          cm.vim().handleKey("N");
        } else {
          getCommentManager().commentNav(cm, Direction.NEXT).run();
        }
      }
    };
  }

  private Runnable maybeNextVimSearch(final CodeMirror cm) {
    return new Runnable() {
      @Override
      public void run() {
        if (cm.vim().hasSearchHighlight()) {
          cm.vim().handleKey("n");
        } else {
          getChunkManager().diffChunkNav(cm, Direction.NEXT).run();
        }
      }
    };
  }

  Runnable maybeNextCmSearch(final CodeMirror cm) {
    return new Runnable() {
      @Override
      public void run() {
        if (cm.hasSearchHighlight()) {
          cm.execCommand("findNext");
        } else {
          cm.execCommand("clearSearch");
          getCommentManager().toggleOpenBox(cm).run();
        }
      }
    };
  }

  boolean renderEntireFile() {
    return prefs.renderEntireFile() && canRenderEntireFile(prefs);
  }

  boolean canRenderEntireFile(DiffPreferences prefs) {
    // CodeMirror is too slow to layout an entire huge file.
    return fileSize.compareTo(FileSize.HUGE) < 0
        || (prefs.context() != WHOLE_FILE_CONTEXT && prefs.context() < 100);
  }

  DiffInfo.IntraLineStatus getIntraLineStatus() {
    return diff.intralineStatus();
  }

  void setThemeStyles(boolean d) {
    if (d) {
      getDiffTable().addStyleName(Resources.I.diffTableStyle().dark());
    } else {
      getDiffTable().removeStyleName(Resources.I.diffTableStyle().dark());
    }
  }

  void setShowTabs(boolean show) {
    for (CodeMirror cm : getCms()) {
      cm.extras().showTabs(show);
    }
  }

  void setLineLength(int columns) {
    for (CodeMirror cm : getCms()) {
      cm.extras().lineLength(columns);
    }
  }

  String getContentType(DiffInfo.FileMeta meta) {
    if (prefs.syntaxHighlighting() && meta != null
        && meta.contentType() != null) {
     ModeInfo m = ModeInfo.findMode(meta.contentType(), path);
     return m != null ? m.mime() : null;
   }
   return null;
  }

  String getContentType() {
    return getContentType(diff.metaB());
  }

  void injectMode(DiffInfo diffInfo, AsyncCallback<Void> cb) {
    new ModeInjector()
        .add(getContentType(diffInfo.metaA()))
        .add(getContentType(diffInfo.metaB()))
        .inject(cb);
  }

  abstract void setAutoHideDiffHeader(boolean hide);

  void prefetchNextFile() {
    String nextPath = header.getNextPath();
    if (nextPath != null) {
      DiffApi.diff(revision, nextPath)
        .base(base)
        .wholeFile()
        .intraline(prefs.intralineDifference())
        .ignoreWhitespace(prefs.ignoreWhitespace())
        .get(new AsyncCallback<DiffInfo>() {
          @Override
          public void onSuccess(DiffInfo info) {
            new ModeInjector()
              .add(getContentType(info.metaA()))
              .add(getContentType(info.metaB()))
              .inject(CallbackGroup.<Void> emptyCallback());
          }

          @Override
          public void onFailure(Throwable caught) {
          }
        });
    }
  }

  void reloadDiffInfo() {
    final int id = ++reloadVersionId;
    DiffApi.diff(revision, path)
      .base(base)
      .wholeFile()
      .intraline(prefs.intralineDifference())
      .ignoreWhitespace(prefs.ignoreWhitespace())
      .get(new GerritCallback<DiffInfo>() {
        @Override
        public void onSuccess(DiffInfo diffInfo) {
          if (id == reloadVersionId && isAttached()) {
            diff = diffInfo;
            operation(new Runnable() {
              @Override
              public void run() {
                skipManager.removeAll();
                getChunkManager().reset();
                getDiffTable().scrollbar.removeDiffAnnotations();
                setShowIntraline(prefs.intralineDifference());
                render(diff);
                skipManager.render(prefs.context(), diff);
              }
            });
          }
        }
      });
  }

  private static FileSize bucketFileSize(DiffInfo diff) {
    FileMeta a = diff.metaA();
    FileMeta b = diff.metaB();
    FileSize[] sizes = FileSize.values();
    for (int i = sizes.length - 1; 0 <= i; i--) {
      FileSize s = sizes[i];
      if ((a != null && s.lines <= a.lines())
          || (b != null && s.lines <= b.lines())) {
        return s;
      }
    }
    return FileSize.SMALL;
  }

  abstract Runnable updateActiveLine(CodeMirror cm);

  private GutterClickHandler onGutterClick(final CodeMirror cm) {
    return new GutterClickHandler() {
      @Override
      public void handle(CodeMirror instance, final int line,
          final String gutterClass, NativeEvent clickEvent) {
        if (Element.as(clickEvent.getEventTarget())
                .hasClassName(getLineNumberClassName())
            && clickEvent.getButton() == NativeEvent.BUTTON_LEFT
            && !clickEvent.getMetaKey()
            && !clickEvent.getAltKey()
            && !clickEvent.getCtrlKey()
            && !clickEvent.getShiftKey()) {
          cm.setCursor(Pos.create(line));
          Scheduler.get().scheduleDeferred(new ScheduledCommand() {
            @Override
            public void execute() {
              getCommentManager().newDraftOnGutterClick(
                  cm, gutterClass, line + 1);
            }
          });
        }
      }
    };
  }

  abstract FocusHandler getFocusHandler();

  abstract CodeMirror[] getCms();

  abstract CodeMirror getCmFromSide(DisplaySide side);

  abstract DiffTable getDiffTable();

  abstract int getCmLine(int line, DisplaySide side);

  abstract String getLineNumberClassName();

  LineOnOtherInfo lineOnOther(DisplaySide side, int line) {
    return getChunkManager().lineMapper.lineOnOther(side, line);
  }

  abstract ScreenLoadCallback<ConfigInfoCache.Entry> getScreenLoadCallback(
      CommentsCollections comments);

  abstract boolean isSideBySide();
}
