// Copyright (c) 2014, 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.

library trydart.interaction_manager;

import 'dart:html';

import 'dart:convert' show
    JSON;

import 'dart:math' show
    max,
    min;

import 'dart:async' show
    Completer,
    Future,
    Timer;

import 'dart:collection' show
    Queue;

import 'package:compiler/src/scanner/string_scanner.dart' show
    StringScanner;

import 'package:compiler/src/tokens/token.dart' show
    BeginGroupToken,
    ErrorToken,
    Token,
    UnmatchedToken,
    UnterminatedToken;

import 'package:compiler/src/tokens/token_constants.dart' show
    EOF_TOKEN,
    STRING_INTERPOLATION_IDENTIFIER_TOKEN,
    STRING_INTERPOLATION_TOKEN,
    STRING_TOKEN;

import 'package:compiler/src/io/source_file.dart' show
    StringSourceFile;

import 'package:compiler/src/string_validator.dart' show
    StringValidator;

import 'package:compiler/src/tree/tree.dart' show
    StringQuoting;

import 'compilation.dart' show
    currentSource,
    startCompilation;

import 'ui.dart' show
    currentTheme,
    hackDiv,
    mainEditorPane,
    observer,
    outputDiv,
    outputFrame,
    statusDiv;

import 'decoration.dart' show
    CodeCompletionDecoration,
    Decoration,
    DiagnosticDecoration,
    error,
    info,
    warning;

import 'html_to_text.dart' show
    htmlToText;

import 'compilation_unit.dart' show
    CompilationUnit;

import 'selection.dart' show
    TrySelection,
    isCollapsed;

import 'editor.dart' as editor;

import 'mock.dart' as mock;

import 'settings.dart' as settings;

import 'shadow_root.dart' show
    getShadowRoot,
    getText,
    setShadowRoot,
    containsNode;

import 'iframe_error_handler.dart' show
    ErrorMessage;

const String TRY_DART_NEW_DEFECT =
    'https://code.google.com/p/dart/issues/entry'
    '?template=Try+Dart+Internal+Error';

/// How frequently [InteractionManager.onHeartbeat] is called.
const Duration HEARTBEAT_INTERVAL = const Duration(milliseconds: 50);

/// Determines how frequently "project" files are saved.  The time is measured
/// from the time of last modification.
const Duration SAVE_INTERVAL = const Duration(seconds: 5);

/// Determines how frequently the compiler is invoked.  The time is measured
/// from the time of last modification.
const Duration COMPILE_INTERVAL = const Duration(seconds: 1);

/// Determines how frequently the compiler is invoked in "live" mode.  The time
/// is measured from the time of last modification.
const Duration LIVE_COMPILE_INTERVAL = const Duration(seconds: 0);

/// Determines if a compilation is slow.  The time is measured from the last
/// compilation started.  If a compilation is slow, progress information is
/// displayed to the user, but the console is untouched if the compilation
/// finished quickly.  The purpose is to reduce flicker in the UI.
const Duration SLOW_COMPILE = const Duration(seconds: 1);

const int TAB_WIDTH = 2;

/**
 * UI interaction manager for the entire application.
 */
abstract class InteractionManager {
  // Design note: All UI interactions go through one instance of this
  // class. This is by design.
  //
  // Simplicity in UI is in the eye of the beholder, not the implementor. Great
  // 'natural UI' is usually achieved with substantial implementation
  // complexity that doesn't modularize well and has nasty complicated state
  // dependencies.
  //
  // In rare cases, some UI components can be independent of this state
  // machine. For example, animation and auto-save loops.

  // Implementation note: The state machine is actually implemented by
  // [InteractionContext], this class represents public event handlers.

  factory InteractionManager() => new InteractionContext();

  InteractionManager.internal();

  // TODO(ahe): Remove this.
  Set<AnchorElement> get oldDiagnostics;

  void onInput(Event event);

  // TODO(ahe): Rename to onKeyDown (as it is called in response to keydown
  // event).
  void onKeyUp(KeyboardEvent event);

  void onMutation(List<MutationRecord> mutations, MutationObserver observer);

  void onSelectionChange(Event event);

  /// Called when the content of a CompilationUnit changed.
  void onCompilationUnitChanged(CompilationUnit unit);

  Future<List<String>> projectFileNames();

  /// Called when the user selected a new project file.
  void onProjectFileSelected(String projectFile);

  /// Called when notified about a project file changed (on the server).
  void onProjectFileFsEvent(MessageEvent e);

  /// Called every [HEARTBEAT_INTERVAL].
  void onHeartbeat(Timer timer);

  /// Called by [:window.onMessage.listen:].
  void onWindowMessage(MessageEvent event);

  void onCompilationFailed(String firstError);

  void onCompilationDone();

  /// Called when a compilation is starting, but just before sending the
  /// initiating message to the compiler isolate.
  void compilationStarting();

  // TODO(ahe): Remove this from InteractionManager, but not from InitialState.
  void consolePrintLine(line);

  /// Called just before running a freshly compiled program.
  void aboutToRun();

  /// Called when an error occurs when running user code in an iframe.
  void onIframeError(ErrorMessage message);

  void verboseCompilerMessage(String message);

  /// Called if the compiler crashes.
  void onCompilerCrash(data);

  /// Called if an internal error is detected.
  void onInternalError(message);
}

/**
 * State machine for UI interactions.
 */
class InteractionContext extends InteractionManager {
  InteractionState state;

  final Map<String, CompilationUnit> projectFiles = <String, CompilationUnit>{};

  final Set<CompilationUnit> modifiedUnits = new Set<CompilationUnit>();

  final Queue<CompilationUnit> unitsToSave = new Queue<CompilationUnit>();

  /// Tracks time since last modification of a "project" file.
  final Stopwatch saveTimer = new Stopwatch();

  /// Tracks time since last modification.
  final Stopwatch compileTimer = new Stopwatch();

  /// Tracks elapsed time of current compilation.
  final Stopwatch elapsedCompilationTime = new Stopwatch();

  CompilationUnit currentCompilationUnit =
      // TODO(ahe): Don't use a fake unit.
      new CompilationUnit('fake', '');

  Timer heartbeat;

  Completer<String> completeSaveOperation;

  bool shouldClearConsole = false;

  Element compilerConsole;

  bool isFirstCompile = true;

  final Set<AnchorElement> oldDiagnostics = new Set<AnchorElement>();

  final Duration compileInterval = settings.live.value
      ? LIVE_COMPILE_INTERVAL
      : COMPILE_INTERVAL;

  InteractionContext()
      : super.internal() {
    state = new InitialState(this);
    heartbeat = new Timer.periodic(HEARTBEAT_INTERVAL, onHeartbeat);
  }

  void onInput(Event event) => state.onInput(event);

  void onKeyUp(KeyboardEvent event) => state.onKeyUp(event);

  void onMutation(List<MutationRecord> mutations, MutationObserver observer) {
    workAroundFirefoxBug();
    try {
      try {
        return state.onMutation(mutations, observer);
      } finally {
        // Discard any mutations during the observer, as these can lead to
        // infinite loop.
        observer.takeRecords();
      }
    } catch (error, stackTrace) {
      try {
        editor.isMalformedInput = true;
        state.onInternalError(
            '\nError and stack trace:\n$error\n$stackTrace\n');
      } catch (e) {
        // Double faults ignored.
      }
      rethrow;
    }
  }

  void onSelectionChange(Event event) => state.onSelectionChange(event);

  void onCompilationUnitChanged(CompilationUnit unit) {
    return state.onCompilationUnitChanged(unit);
  }

  Future<List<String>> projectFileNames() => state.projectFileNames();

  void onProjectFileSelected(String projectFile) {
    return state.onProjectFileSelected(projectFile);
  }

  void onProjectFileFsEvent(MessageEvent e) {
    return state.onProjectFileFsEvent(e);
  }

  void onHeartbeat(Timer timer) => state.onHeartbeat(timer);

  void onWindowMessage(MessageEvent event) => state.onWindowMessage(event);

  void onCompilationFailed(String firstError) {
    return state.onCompilationFailed(firstError);
  }

  void onCompilationDone() => state.onCompilationDone();

  void compilationStarting() => state.compilationStarting();

  void consolePrintLine(line) => state.consolePrintLine(line);

  void aboutToRun() => state.aboutToRun();

  void onIframeError(ErrorMessage message) => state.onIframeError(message);

  void verboseCompilerMessage(String message) {
    return state.verboseCompilerMessage(message);
  }

  void onCompilerCrash(data) => state.onCompilerCrash(data);

  void onInternalError(message) => state.onInternalError(message);
}

abstract class InteractionState implements InteractionManager {
  InteractionContext get context;

  // TODO(ahe): Remove this.
  Set<AnchorElement> get oldDiagnostics {
    throw 'Use context.oldDiagnostics instead';
  }

  void set state(InteractionState newState);

  void onStateChanged(InteractionState previous) {
  }

  void transitionToInitialState() {
    state = new InitialState(context);
  }
}

class InitialState extends InteractionState {
  final InteractionContext context;
  bool requestCodeCompletion = false;

  InitialState(this.context);

  void set state(InteractionState state) {
    InteractionState previous = context.state;
    if (previous != state) {
      context.state = state;
      state.onStateChanged(previous);
    }
  }

  void onInput(Event event) {
    state = new PendingInputState(context);
  }

  void onKeyUp(KeyboardEvent event) {
    if (computeHasModifier(event)) {
      onModifiedKeyUp(event);
    } else {
      onUnmodifiedKeyUp(event);
    }
  }

  void onModifiedKeyUp(KeyboardEvent event) {
    if (event.getModifierState("Shift")) return onShiftedKeyUp(event);
    switch (event.keyCode) {
      case KeyCode.S:
        // Disable Ctrl-S, Cmd-S, etc. We have observed users hitting these
        // keys often when using Try Dart and getting frustrated.
        event.preventDefault();
        // TODO(ahe): Consider starting a compilation.
        break;
    }
  }

  void onShiftedKeyUp(KeyboardEvent event) {
    switch (event.keyCode) {
      case KeyCode.TAB:
        event.preventDefault();
        break;
    }
  }

  void onUnmodifiedKeyUp(KeyboardEvent event) {
    switch (event.keyCode) {
      case KeyCode.ENTER: {
        Selection selection = window.getSelection();
        if (isCollapsed(selection)) {
          event.preventDefault();
          Node node = selection.anchorNode;
          if (node is Text) {
            Text text = node;
            int offset = selection.anchorOffset;
            // If at end-of-file, insert an extra newline.  The the extra
            // newline ensures that the next line isn't empty.  At least Chrome
            // behaves as if "\n" is just a single line. "\nc" (where c is any
            // character) is two lines, according to Chrome.
            String newline = isAtEndOfFile(text, offset) ? '\n\n' : '\n';
            text.insertData(offset, newline);
            selection.collapse(text, offset + 1);
          } else if (node is Element) {
            node.appendText('\n\n');
            selection.collapse(node.firstChild, 1);
          } else {
            window.console
                ..error('Unexpected node')
                ..dir(node);
          }
        }
        break;
      }
      case KeyCode.TAB: {
        Selection selection = window.getSelection();
        if (isCollapsed(selection)) {
          event.preventDefault();
          Text text = new Text(' ' * TAB_WIDTH);
          selection.getRangeAt(0).insertNode(text);
          selection.collapse(text, TAB_WIDTH);
        }
        break;
      }
    }

    // This is a hack to get Safari (iOS) to send mutation events on
    // contenteditable.
    // TODO(ahe): Move to onInput?
    var newDiv = new DivElement();
    hackDiv.replaceWith(newDiv);
    hackDiv = newDiv;
  }

  void onMutation(List<MutationRecord> mutations, MutationObserver observer) {
    removeCodeCompletion();

    Selection selection = window.getSelection();
    TrySelection trySelection = new TrySelection(mainEditorPane, selection);

    Set<Node> normalizedNodes = new Set<Node>();
    for (MutationRecord record in mutations) {
      normalizeMutationRecord(record, trySelection, normalizedNodes);
    }

    if (normalizedNodes.length == 1) {
      Node node = normalizedNodes.single;
      if (node is Element && node.classes.contains('lineNumber')) {
        print('Single line change: ${node.outerHtml}');

        updateHighlighting(node, selection, trySelection, mainEditorPane);
        return;
      }
    }

    updateHighlighting(mainEditorPane, selection, trySelection);
  }

  void updateHighlighting(
      Element node,
      Selection selection,
      TrySelection trySelection,
      [Element root]) {
    String state = '';
    String currentText = getText(node);
    if (root != null) {
      // Single line change.
      trySelection = trySelection.copyWithRoot(node);
      Element previousLine = node.previousElementSibling;
      if (previousLine != null) {
        state = previousLine.getAttribute('dart-state');
      }

      node.parentNode.insertAllBefore(
          createHighlightedNodes(trySelection, currentText, state),
          node);
      node.remove();
    } else {
      root = node;
      editor.seenIdentifiers = new Set<String>.from(mock.identifiers);

      // Fail safe: new [nodes] are computed before clearing old nodes.
      List<Node> nodes =
          createHighlightedNodes(trySelection, currentText, state);

      node.nodes
          ..clear()
          ..addAll(nodes);
    }

    if (containsNode(mainEditorPane, trySelection.anchorNode)) {
      // Sometimes the anchor node is removed by the above call. This has
      // only been observed in Firefox, and is hard to reproduce.
      trySelection.adjust(selection);
    }

    // TODO(ahe): We know almost exactly what has changed.  It could be
    // more efficient to only communicate what changed.
    context.currentCompilationUnit.content = getText(root);

    // Discard highlighting mutations.
    observer.takeRecords();
  }

  List<Node> createHighlightedNodes(
      TrySelection trySelection,
      String currentText,
      String state) {
    trySelection.updateText(currentText);

    editor.isMalformedInput = false;
    int offset = 0;
    List<Node> nodes = <Node>[];

    for (String line in splitLines(currentText)) {
      List<Node> lineNodes = <Node>[];
      state =
          tokenizeAndHighlight(line, state, offset, trySelection, lineNodes);
      offset += line.length;
      nodes.add(makeLine(lineNodes, state));
    }

    return nodes;
  }

  void onSelectionChange(Event event) {
  }

  void onStateChanged(InteractionState previous) {
    super.onStateChanged(previous);
    context.compileTimer
        ..start()
        ..reset();
  }

  void onCompilationUnitChanged(CompilationUnit unit) {
    if (unit == context.currentCompilationUnit) {
      currentSource = unit.content;
      if (context.projectFiles.containsKey(unit.name)) {
        postProjectFileUpdate(unit);
      }
      context.compileTimer.start();
    } else {
      print("Unexpected change to compilation unit '${unit.name}'.");
    }
  }

  void postProjectFileUpdate(CompilationUnit unit) {
    context.modifiedUnits.add(unit);
    context.saveTimer.start();
  }

  Future<List<String>> projectFileNames() {
    return getString('project?list').then((String response) {
      WebSocket socket = new WebSocket('ws://127.0.0.1:9090/ws/watch');
      socket.onMessage.listen(context.onProjectFileFsEvent);
      return new List<String>.from(JSON.decode(response));
    });
  }

  void onProjectFileSelected(String projectFile) {
    // Disable editing whilst fetching data.
    mainEditorPane.contentEditable = 'false';

    CompilationUnit unit = context.projectFiles[projectFile];
    Future<CompilationUnit> future;
    if (unit != null) {
      // This project file had been fetched already.
      future = new Future<CompilationUnit>.value(unit);

      // TODO(ahe): Probably better to fetch the sources again.
    } else {
      // This project file has to be fetched.
      future = getString('project/$projectFile').then((String text) {
        CompilationUnit unit = context.projectFiles[projectFile];
        if (unit == null) {
          // Only create a new unit if the value hadn't arrived already.
          unit = new CompilationUnit(projectFile, text);
          context.projectFiles[projectFile] = unit;
        } else {
          // TODO(ahe): Probably better to overwrite sources. Create a new
          // unit?
          // The server should push updates to the client.
        }
        return unit;
      });
    }
    future.then((CompilationUnit unit) {
      mainEditorPane
          ..contentEditable = 'true'
          ..nodes.clear();
      observer.takeRecords(); // Discard mutations.

      transitionToInitialState();
      context.currentCompilationUnit = unit;

      // Install the code, which will trigger a call to onMutation.
      mainEditorPane.appendText(unit.content);
    });
  }

  void transitionToInitialState() {}

  void onProjectFileFsEvent(MessageEvent e) {
    Map map = JSON.decode(e.data);
    List modified = map['modify'];
    if (modified == null) return;
    for (String name in modified) {
      Completer completer = context.completeSaveOperation;
      if (completer != null && !completer.isCompleted) {
        completer.complete(name);
      } else {
        onUnexpectedServerModification(name);
      }
    }
  }

  void onUnexpectedServerModification(String name) {
    if (context.currentCompilationUnit.name == name) {
      mainEditorPane.contentEditable = 'false';
      statusDiv.text = 'Modified on disk';
    }
  }

  void onHeartbeat(Timer timer) {
    if (context.unitsToSave.isEmpty &&
        context.saveTimer.elapsed > SAVE_INTERVAL) {
      context.saveTimer
          ..stop()
          ..reset();
      context.unitsToSave.addAll(context.modifiedUnits);
      context.modifiedUnits.clear();
      saveUnits();
    }
    if (!settings.compilationPaused &&
        context.compileTimer.elapsed > context.compileInterval) {
      if (startCompilation()) {
        context.compileTimer
            ..stop()
            ..reset();
      }
    }

    if (context.elapsedCompilationTime.elapsed > SLOW_COMPILE) {
      if (context.compilerConsole.parent == null) {
        outputDiv.append(context.compilerConsole);
      }
    }
  }

  void saveUnits() {
    if (context.unitsToSave.isEmpty) return;
    CompilationUnit unit = context.unitsToSave.removeFirst();
    onError(ProgressEvent event) {
      HttpRequest request = event.target;
      statusDiv.text = "Couldn't save '${unit.name}': ${request.responseText}";
      context.completeSaveOperation.complete(unit.name);
    }
    new HttpRequest()
        ..open("POST", "/project/${unit.name}")
        ..onError.listen(onError)
        ..send(unit.content);
    void setupCompleter() {
      context.completeSaveOperation = new Completer<String>.sync();
      context.completeSaveOperation.future.then((String name) {
        if (name == unit.name) {
          print("Saved source of '$name'");
          saveUnits();
        } else {
          setupCompleter();
        }
      });
    }
    setupCompleter();
  }

  void onWindowMessage(MessageEvent event) {
    if (event.source is! WindowBase || event.source == window) {
      return onBadMessage(event);
    }
    if (event.data is List) {
      List message = event.data;
      if (message.length > 0) {
        switch (message[0]) {
          case 'scrollHeight':
            return onScrollHeightMessage(message[1]);
        }
      }
      return onBadMessage(event);
    } else {
      return consolePrintLine(event.data);
    }
  }

  /// Called when an iframe is modified.
  void onScrollHeightMessage(int scrollHeight) {
    window.console.log('scrollHeight = $scrollHeight');
    if (scrollHeight > 8) {
      outputFrame.style
          ..height = '${scrollHeight}px'
          ..visibility = ''
          ..position = '';
      while (outputFrame.nextNode is IFrameElement) {
        outputFrame.nextNode.remove();
      }
    }
  }

  void onBadMessage(MessageEvent event) {
    window.console
        ..groupCollapsed('Bad message')
        ..dir(event)
        ..log(event.source.runtimeType)
        ..groupEnd();
  }

  void consolePrintLine(line) {
    if (context.shouldClearConsole) {
      context.shouldClearConsole = false;
      outputDiv.nodes.clear();
    }
    if (window.parent != window) {
      // Test support.
      // TODO(ahe): Use '/' instead of '*' when Firefox is upgraded to version
      // 30 across build bots.  Support for '/' was added in version 29, and we
      // support the two most recent versions.
      window.parent.postMessage('$line\n', '*');
    }
    outputDiv.appendText('$line\n');
  }

  void onCompilationFailed(String firstError) {
    if (firstError == null) {
      consolePrintLine('Compilation failed.');
    } else {
      consolePrintLine('Compilation failed: $firstError');
    }
  }

  void onCompilationDone() {
    context.isFirstCompile = false;
    context.elapsedCompilationTime.stop();
    Duration compilationDuration = context.elapsedCompilationTime.elapsed;
    context.elapsedCompilationTime.reset();
    print('Compilation took $compilationDuration.');
    if (context.compilerConsole.parent != null) {
      context.compilerConsole.remove();
    }
    for (AnchorElement diagnostic in context.oldDiagnostics) {
      if (diagnostic.parent != null) {
        // Problem fixed, remove the diagnostic.
        diagnostic.replaceWith(new Text(getText(diagnostic)));
      }
    }
    context.oldDiagnostics.clear();
    observer.takeRecords(); // Discard mutations.
  }

  void compilationStarting() {
    var progress = new SpanElement()
        ..appendHtml('<i class="icon-spinner icon-spin"></i>')
        ..appendText(' Compiling Dart program.');
    if (settings.verboseCompiler) {
      progress.appendText('..');
    }
    context.compilerConsole = new SpanElement()
        ..append(progress)
        ..appendText('\n');
    context.shouldClearConsole = true;
    context.elapsedCompilationTime
        ..start()
        ..reset();
    if (context.isFirstCompile) {
      outputDiv.append(context.compilerConsole);
    }
    var diagnostics = mainEditorPane.querySelectorAll('a.diagnostic');
    context.oldDiagnostics
        ..clear()
        ..addAll(diagnostics);
  }

  void aboutToRun() {
    context.shouldClearConsole = true;
  }

  void onIframeError(ErrorMessage message) {
    // TODO(ahe): Consider replacing object URLs with something like <a
    // href='...'>out.js</a>.
    // TODO(ahe): Use source maps to translate stack traces.
    consolePrintLine(message);
  }

  void verboseCompilerMessage(String message) {
    if (settings.verboseCompiler) {
      context.compilerConsole.appendText('$message\n');
    } else {
      if (isCompilerStageMarker(message)) {
        Element progress = context.compilerConsole.firstChild;
        progress.appendText('.');
      }
    }
  }

  void onCompilerCrash(data) {
    onInternalError('Error and stack trace:\n$data');
  }

  void onInternalError(message) {
    outputDiv
        ..nodes.clear()
        ..append(new HeadingElement.h1()..appendText('Internal Error'))
        ..appendText('We would appreciate if you take a moment to report '
                     'this at ')
        ..append(
            new AnchorElement(href: TRY_DART_NEW_DEFECT)
            ..target = '_blank'
            ..appendText(TRY_DART_NEW_DEFECT))
        ..appendText('$message');
    if (window.parent != window) {
      // Test support.
      // TODO(ahe): Use '/' instead of '*' when Firefox is upgraded to version
      // 30 across build bots.  Support for '/' was added in version 29, and we
      // support the two most recent versions.
      window.parent.postMessage('$message\n', '*');
    }
  }
}

Future<String> getString(uri) {
  return new Future<String>.sync(() => HttpRequest.getString('$uri'));
}

class PendingInputState extends InitialState {
  PendingInputState(InteractionContext context)
      : super(context);

  void onInput(Event event) {
    // Do nothing.
  }

  void onMutation(List<MutationRecord> mutations, MutationObserver observer) {
    super.onMutation(mutations, observer);

    InteractionState nextState = new InitialState(context);
    if (settings.enableCodeCompletion.value) {
      Element parent = editor.getElementAtSelection();
      Element ui;
      if (parent != null) {
        ui = parent.querySelector('.dart-code-completion');
        if (ui != null) {
          nextState = new CodeCompletionState(context, parent, ui);
        }
      }
    }
    state = nextState;
  }
}

class CodeCompletionState extends InitialState {
  final Element activeCompletion;
  final Element ui;
  int minWidth = 0;
  DivElement staticResults;
  SpanElement inline;
  DivElement serverResults;
  String inlineSuggestion;

  CodeCompletionState(InteractionContext context,
                      this.activeCompletion,
                      this.ui)
      : super(context);

  void onInput(Event event) {
    // Do nothing.
  }

  void onModifiedKeyUp(KeyboardEvent event) {
    // TODO(ahe): Handle DOWN (jump to server results).
  }

  void onUnmodifiedKeyUp(KeyboardEvent event) {
    switch (event.keyCode) {
      case KeyCode.DOWN:
        return moveDown(event);

      case KeyCode.UP:
        return moveUp(event);

      case KeyCode.ESC:
        event.preventDefault();
        return endCompletion();

      case KeyCode.TAB:
      case KeyCode.RIGHT:
      case KeyCode.ENTER:
        event.preventDefault();
        return endCompletion(acceptSuggestion: true);

      case KeyCode.SPACE:
        return endCompletion();
    }
  }

  void moveDown(Event event) {
    event.preventDefault();
    move(1);
  }

  void moveUp(Event event) {
    event.preventDefault();
    move(-1);
  }

  void move(int direction) {
    Element element = editor.moveActive(direction, ui);
    if (element == null) return;
    var text = activeCompletion.firstChild;
    String prefix = "";
    if (text is Text) prefix = text.data.trim();
    updateInlineSuggestion(prefix, element.text);
  }

  void endCompletion({bool acceptSuggestion: false}) {
    if (acceptSuggestion) {
      suggestionAccepted();
    }
    activeCompletion.classes.remove('active');
    mainEditorPane.querySelectorAll('.hazed-suggestion')
        .forEach((e) => e.remove());
    // The above changes create mutation records. This implicitly fire mutation
    // events that result in saving the source code in local storage.
    // TODO(ahe): Consider making this more explicit.
    state = new InitialState(context);
  }

  void suggestionAccepted() {
    if (inlineSuggestion != null) {
      Text text = new Text(inlineSuggestion);
      activeCompletion.replaceWith(text);
      window.getSelection().collapse(text, inlineSuggestion.length);
    }
  }

  void onMutation(List<MutationRecord> mutations, MutationObserver observer) {
    for (MutationRecord record in mutations) {
      if (!activeCompletion.contains(record.target)) {
        endCompletion();
        return super.onMutation(mutations, observer);
      }
    }

    var text = activeCompletion.firstChild;
    if (text is! Text) return endCompletion();
    updateSuggestions(text.data.trim());
  }

  void onStateChanged(InteractionState previous) {
    super.onStateChanged(previous);
    displayCodeCompletion();
  }

  void displayCodeCompletion() {
    Selection selection = window.getSelection();
    if (selection.anchorNode is! Text) {
      return endCompletion();
    }
    Text text = selection.anchorNode;
    if (!activeCompletion.contains(text)) {
      return endCompletion();
    }

    int anchorOffset = selection.anchorOffset;

    String prefix = text.data.substring(0, anchorOffset).trim();
    if (prefix.isEmpty) {
      return endCompletion();
    }

    num height = activeCompletion.getBoundingClientRect().height;
    activeCompletion.classes.add('active');
    Node root = getShadowRoot(ui);

    inline = new SpanElement()
        ..classes.add('hazed-suggestion');
    Text rest = text.splitText(anchorOffset);
    text.parentNode.insertBefore(inline, text.nextNode);
    activeCompletion.parentNode.insertBefore(
        rest, activeCompletion.nextNode);

    staticResults = new DivElement()
        ..classes.addAll(['dart-static', 'dart-limited-height']);
    serverResults = new DivElement()
        ..style.display = 'none'
        ..classes.add('dart-server');
    root.nodes.addAll([staticResults, serverResults]);
    ui.style.top = '${height}px';

    staticResults.nodes.add(buildCompletionEntry(prefix));

    updateSuggestions(prefix);
  }

  void updateInlineSuggestion(String prefix, String suggestion) {
    inlineSuggestion = suggestion;

    minWidth = max(minWidth, activeCompletion.getBoundingClientRect().width);

    activeCompletion.style
        ..display = 'inline-block'
        ..minWidth = '${minWidth}px';

    setShadowRoot(inline, suggestion.substring(prefix.length));
    inline.style.display = '';

    observer.takeRecords(); // Discard mutations.
  }

  void updateSuggestions(String prefix) {
    if (prefix.isEmpty) {
      return endCompletion();
    }

    Token first = tokenize(prefix);
    for (Token token = first; token.kind != EOF_TOKEN; token = token.next) {
      String tokenInfo = token.info.value;
      if (token != first ||
          tokenInfo != 'identifier' &&
          tokenInfo != 'keyword') {
        return endCompletion();
      }
    }

    var borderHeight = 2; // 1 pixel border top & bottom.
    num height = ui.getBoundingClientRect().height - borderHeight;
    ui.style.minHeight = '${height}px';

    minWidth =
        max(minWidth, activeCompletion.getBoundingClientRect().width);

    staticResults.nodes.clear();
    serverResults.nodes.clear();

    if (inlineSuggestion != null && inlineSuggestion.startsWith(prefix)) {
      setShadowRoot(inline, inlineSuggestion.substring(prefix.length));
    }

    List<String> results = editor.seenIdentifiers.where(
        (String identifier) {
          return identifier != prefix && identifier.startsWith(prefix);
        }).toList(growable: false);
    results.sort();
    if (results.isEmpty) results = <String>[prefix];

    results.forEach((String completion) {
      staticResults.nodes.add(buildCompletionEntry(completion));
    });

    if (settings.enableDartMind) {
      // TODO(ahe): Move this code to its own function or class.
      String encodedArg0 = Uri.encodeComponent('"$prefix"');
      String mindQuery =
          'http://dart-mind.appspot.com/rpc'
          '?action=GetExportingPubCompletions'
          '&arg0=$encodedArg0';
      try {
        var serverWatch = new Stopwatch()..start();
        HttpRequest.getString(mindQuery).then((String responseText) {
          serverWatch.stop();
          List<String> serverSuggestions = JSON.decode(responseText);
          if (!serverSuggestions.isEmpty) {
            updateInlineSuggestion(prefix, serverSuggestions.first);
          }
          var root = getShadowRoot(ui);
          for (int i = 1; i < serverSuggestions.length; i++) {
            String completion = serverSuggestions[i];
            DivElement where = staticResults;
            int index = results.indexOf(completion);
            if (index != -1) {
              List<Element> entries = root.querySelectorAll(
                  '.dart-static>.dart-entry');
              entries[index].classes.add('doubleplusgood');
            } else {
              if (results.length > 3) {
                serverResults.style.display = 'block';
                where = serverResults;
              }
              Element entry = buildCompletionEntry(completion);
              entry.classes.add('doubleplusgood');
              where.nodes.add(entry);
            }
          }
          serverResults.appendHtml(
              '<div>${serverWatch.elapsedMilliseconds}ms</div>');
          // Discard mutations.
          observer.takeRecords();
        }).catchError((error, stack) {
          window.console.dir(error);
          window.console.error('$stack');
        });
      } catch (error, stack) {
        window.console.dir(error);
        window.console.error('$stack');
      }
    }
    // Discard mutations.
    observer.takeRecords();
  }

  Element buildCompletionEntry(String completion) {
    return new DivElement()
        ..classes.add('dart-entry')
        ..appendText(completion);
  }

  void transitionToInitialState() {
    endCompletion();
  }
}

Token tokenize(String text) {
  var file = new StringSourceFile.fromName('', text);
  return new StringScanner(file, includeComments: true).tokenize();
}

bool computeHasModifier(KeyboardEvent event) {
  return
      event.getModifierState("Alt") ||
      event.getModifierState("AltGraph") ||
      event.getModifierState("CapsLock") ||
      event.getModifierState("Control") ||
      event.getModifierState("Fn") ||
      event.getModifierState("Meta") ||
      event.getModifierState("NumLock") ||
      event.getModifierState("ScrollLock") ||
      event.getModifierState("Scroll") ||
      event.getModifierState("Win") ||
      event.getModifierState("Shift") ||
      event.getModifierState("SymbolLock") ||
      event.getModifierState("OS");
}

String tokenizeAndHighlight(String line,
                            String state,
                            int start,
                            TrySelection trySelection,
                            List<Node> nodes) {
  String newState = '';
  int offset = state.length;
  int adjustedStart = start - state.length;

  //   + offset  + charOffset  + globalOffset   + (charOffset + charCount)
  //   v         v             v                v
  // do          identifier_abcdefghijklmnopqrst
  for (Token token = tokenize('$state$line');
       token.kind != EOF_TOKEN;
       token = token.next) {
    int charOffset = token.charOffset;
    int charCount = token.charCount;

    Token tokenToDecorate = token;
    if (token is UnterminatedToken && isUnterminatedMultiLineToken(token)) {
      newState += '${token.start}';
      continue; // This might not be an error.
    } else {
      Token follow = token.next;
      if (token is BeginGroupToken && token.endGroup != null) {
        follow = token.endGroup.next;
      }
      if (token.kind == STRING_TOKEN) {
        follow = followString(follow);
        if (follow is UnmatchedToken) {
          if ('${follow.begin.value}' == r'${') {
            newState += '${extractQuote(token.value)}';
          }
        }
      }
      if (follow is ErrorToken && follow.charOffset == token.charOffset) {
        if (follow is UnmatchedToken) {
          newState += '${follow.begin.value}';
        } else {
          tokenToDecorate = follow;
        }
      }
    }

    if (charOffset < offset) {
      // Happens for scanner errors, or for the [state] prefix.
      continue;
    }

    Decoration decoration;
    if (charOffset - state.length == line.length - 1 && line.endsWith('\n')) {
      // Don't add decorations to trailing newline.
      decoration = null;
    } else {
      decoration = editor.getDecoration(tokenToDecorate);
    }

    if (decoration == null) continue;

    // Add a node for text before current token.
    trySelection.addNodeFromSubstring(
        adjustedStart + offset, adjustedStart + charOffset, nodes);

    // Add a node for current token.
    trySelection.addNodeFromSubstring(
        adjustedStart + charOffset,
        adjustedStart + charOffset + charCount, nodes, decoration);

    offset = charOffset + charCount;
  }

  // Add a node for anything after the last (decorated) token.
  trySelection.addNodeFromSubstring(
      adjustedStart + offset, start + line.length, nodes);

  return newState;
}

bool isUnterminatedMultiLineToken(UnterminatedToken token) {
  return
      token.start == '/*' ||
      token.start == "'''" ||
      token.start == '"""' ||
      token.start == "r'''" ||
      token.start == 'r"""';
}

void normalizeMutationRecord(MutationRecord record,
                             TrySelection selection,
                             Set<Node> normalizedNodes) {
  for (Node node in record.addedNodes) {
    if (node.parentNode == null) continue;
    normalizedNodes.add(findLine(node));
    if (node is Text) continue;
    StringBuffer buffer = new StringBuffer();
    int selectionOffset = htmlToText(node, buffer, selection);
    Text newNode = new Text('$buffer');
    node.replaceWith(newNode);
    if (selectionOffset != -1) {
      selection.anchorNode = newNode;
      selection.anchorOffset = selectionOffset;
    }
  }
  if (!record.removedNodes.isEmpty) {
    var first = record.removedNodes.first;
    var line = findLine(record.target);

    if (first is Text && line.nextNode != null) {
      normalizedNodes.add(line.nextNode);
    }
    normalizedNodes.add(line);
  }
  if (record.type == "characterData" && record.target.parentNode != null) {
    // At least Firefox sends a "characterData" record whose target is the
    // deleted text node. It also sends a record where "removedNodes" isn't
    // empty whose target is the parent (which we are interested in).
    normalizedNodes.add(findLine(record.target));
  }
}

// Finds the line of [node] (a parent node with CSS class 'lineNumber').
// If no such parent exists, return mainEditorPane if it is a parent.
// Otherwise return [node].
Node findLine(Node node) {
  for (Node n = node; n != null; n = n.parentNode) {
    if (n is Element && n.classes.contains('lineNumber')) return n;
    if (n == mainEditorPane) return n;
  }
  return node;
}

Element makeLine(List<Node> lineNodes, String state) {
  return new SpanElement()
      ..setAttribute('dart-state', state)
      ..nodes.addAll(lineNodes)
      ..classes.add('lineNumber');
}

bool isAtEndOfFile(Text text, int offset) {
  Node line = findLine(text);
  return
      line.nextNode == null &&
      text.parentNode.nextNode == null &&
      offset == text.length;
}

List<String> splitLines(String text) {
  return text.split(new RegExp('^', multiLine: true));
}

void removeCodeCompletion() {
  List<Node> highlighting =
      mainEditorPane.querySelectorAll('.dart-code-completion');
  for (Element element in highlighting) {
    element.remove();
  }
}

bool isCompilerStageMarker(String message) {
  return
      message.startsWith('Package root is ') ||
      message.startsWith('Compiling ') ||
      message == "Resolving..." ||
      message.startsWith('Resolved ') ||
      message == "Inferring types..." ||
      message == "Compiling..." ||
      message.startsWith('Compiled ');
}

void workAroundFirefoxBug() {
  Selection selection = window.getSelection();
  if (!isCollapsed(selection)) return;
  Node node = selection.anchorNode;
  int offset = selection.anchorOffset;
  if (node is Element && offset != 0) {
    // In some cases, Firefox reports the wrong anchorOffset (always seems to
    // be 6) when anchorNode is an Element. Moving the cursor back and forth
    // adjusts the anchorOffset.
    // Safari can also reach this code, but the offset isn't wrong, just
    // inconsistent.  After moving the cursor back and forth, Safari will make
    // the offset relative to a text node.
    if (settings.hasSelectionModify.value) {
      // IE doesn't support selection.modify, but it's okay since the code
      // above is for Firefox, IE doesn't have problems with anchorOffset.
      selection
          ..modify('move', 'backward', 'character')
          ..modify('move', 'forward', 'character');
      print('Selection adjusted $node@$offset -> '
            '${selection.anchorNode}@${selection.anchorOffset}.');
    }
  }
}

/// Compute the token following a string. Compare to parseSingleLiteralString
/// in parser.dart.
Token followString(Token token) {
  // TODO(ahe): I should be able to get rid of this if I change the scanner to
  // create BeginGroupToken for strings.
  int kind = token.kind;
  while (kind != EOF_TOKEN) {
    if (kind == STRING_INTERPOLATION_TOKEN) {
      // Looking at ${expression}.
      BeginGroupToken begin = token;
      token = begin.endGroup.next;
    } else if (kind == STRING_INTERPOLATION_IDENTIFIER_TOKEN) {
      // Looking at $identifier.
      token = token.next.next;
    } else {
      return token;
    }
    kind = token.kind;
    if (kind != STRING_TOKEN) return token;
    token = token.next;
    kind = token.kind;
  }
  return token;
}

String extractQuote(String string) {
  StringQuoting q = StringValidator.quotingFromString(string);
  return (q.raw ? 'r' : '') + (q.quoteChar * q.leftQuoteLength);
}
