// Copyright (c) 2012, 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 mock_compiler;

import "package:expect/expect.dart";
import 'dart:async';
import 'dart:collection';

import 'package:compiler/compiler.dart' as api;
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/js_backend/js_backend.dart'
    show JavaScriptBackend;
import 'package:compiler/src/resolution/resolution.dart';
import 'package:compiler/src/io/source_file.dart';
import 'package:compiler/src/tree/tree.dart';
import 'package:compiler/src/util/util.dart';
import 'parser_helper.dart';

import 'package:compiler/src/elements/modelx.dart'
    show ElementX,
         LibraryElementX,
         ErroneousElementX,
         FunctionElementX;

import 'package:compiler/src/dart2jslib.dart'
    hide TreeElementMapping;

import 'package:compiler/src/deferred_load.dart'
    show DeferredLoadTask,
         OutputUnit;

import 'mock_libraries.dart';

class WarningMessage {
  Spannable node;
  Message message;
  WarningMessage(this.node, this.message);

  toString() => message.toString();
}

final Uri PATCH_CORE = new Uri(scheme: 'patch', path: 'core');

class MockCompiler extends Compiler {
  api.DiagnosticHandler diagnosticHandler;
  List<WarningMessage> warnings;
  List<WarningMessage> errors;
  List<WarningMessage> hints;
  List<WarningMessage> infos;
  List<WarningMessage> crashes;
  /// Expected number of warnings. If `null`, the number of warnings is
  /// not checked.
  final int expectedWarnings;
  /// Expected number of errors. If `null`, the number of errors is not checked.
  final int expectedErrors;
  final Map<String, SourceFile> sourceFiles;
  Node parsedTree;
  final String testedPatchVersion;

  MockCompiler.internal(
      {Map<String, String> coreSource,
       bool enableTypeAssertions: false,
       bool enableMinification: false,
       bool enableConcreteTypeInference: false,
       int maxConcreteTypeSize: 5,
       bool disableTypeInference: false,
       bool analyzeAll: false,
       bool analyzeOnly: false,
       bool emitJavaScript: true,
       bool preserveComments: false,
       // Our unit tests check code generation output that is
       // affected by inlining support.
       bool disableInlining: true,
       bool trustTypeAnnotations: false,
       bool enableAsyncAwait: false,
       int this.expectedWarnings,
       int this.expectedErrors,
       api.CompilerOutputProvider outputProvider,
       String patchVersion})
      : sourceFiles = new Map<String, SourceFile>(),
        testedPatchVersion = patchVersion,
        super(enableTypeAssertions: enableTypeAssertions,
              enableMinification: enableMinification,
              enableConcreteTypeInference: enableConcreteTypeInference,
              maxConcreteTypeSize: maxConcreteTypeSize,
              disableTypeInferenceFlag: disableTypeInference,
              analyzeAllFlag: analyzeAll,
              analyzeOnly: analyzeOnly,
              emitJavaScript: emitJavaScript,
              preserveComments: preserveComments,
              trustTypeAnnotations: trustTypeAnnotations,
              showPackageWarnings: true,
              outputProvider: outputProvider,
              enableAsyncAwait: enableAsyncAwait) {
    this.disableInlining = disableInlining;

    deferredLoadTask = new MockDeferredLoadTask(this);

    clearMessages();

    registerSource(Compiler.DART_CORE,
                   buildLibrarySource(DEFAULT_CORE_LIBRARY, coreSource));
    registerSource(PATCH_CORE, DEFAULT_PATCH_CORE_SOURCE);

    registerSource(JavaScriptBackend.DART_JS_HELPER,
                   buildLibrarySource(DEFAULT_JS_HELPER_LIBRARY));
    registerSource(JavaScriptBackend.DART_FOREIGN_HELPER,
                   buildLibrarySource(DEFAULT_FOREIGN_HELPER_LIBRARY));
    registerSource(JavaScriptBackend.DART_INTERCEPTORS,
                   buildLibrarySource(DEFAULT_INTERCEPTORS_LIBRARY));
    registerSource(JavaScriptBackend.DART_ISOLATE_HELPER,
                   buildLibrarySource(DEFAULT_ISOLATE_HELPER_LIBRARY));
    registerSource(Compiler.DART_MIRRORS,
                   buildLibrarySource(DEFAULT_MIRRORS_LIBRARY));
    registerSource(Compiler.DART_ASYNC,
                   buildLibrarySource(DEFAULT_ASYNC_LIBRARY));
  }

  String get patchVersion {
    return testedPatchVersion != null ? testedPatchVersion : super.patchVersion;
  }

  /// Initialize the mock compiler with an empty main library.
  Future<Uri> init([String mainSource = ""]) {
    Uri uri = new Uri(scheme: "mock");
    registerSource(uri, mainSource);
    return libraryLoader.loadLibrary(uri)
        .then((LibraryElement library) {
      mainApp = library;
      // We need to make sure the Object class is resolved. When registering a
      // dynamic invocation the ArgumentTypesRegistry eventually iterates over
      // the interfaces of the Object class which would be 'null' if the class
      // wasn't resolved.
      objectClass.ensureResolved(this);
    }).then((_) => uri);
  }

  Future runCompiler(Uri uri, [String mainSource = ""]) {
    return init(mainSource).then((Uri mainUri) {
      return super.runCompiler(uri == null ? mainUri : uri);
    }).then((result) {
      if (expectedErrors != null &&
          expectedErrors != errors.length) {
        throw "unexpected error during compilation ${errors}";
      } else if (expectedWarnings != null &&
                 expectedWarnings != warnings.length) {
        throw "unexpected warnings during compilation ${warnings}";
      } else {
        return result;
      }
    });
  }

  /**
   * Registers the [source] with [uri] making it possible load [source] as a
   * library.
   */
  void registerSource(Uri uri, String source) {
    sourceFiles[uri.toString()] = new MockFile(source);
  }

  // TODO(johnniwinther): Remove this when we don't filter certain type checker
  // warnings.
  void reportWarning(Spannable node, MessageKind messageKind,
                     [Map arguments = const {}]) {
    reportDiagnostic(node,
                     messageKind.message(arguments, terseDiagnostics),
                     api.Diagnostic.WARNING);
  }

  void reportDiagnostic(Spannable node,
                        Message message,
                        api.Diagnostic kind) {
    var diagnostic = new WarningMessage(node, message);
    if (kind == api.Diagnostic.CRASH) {
      crashes.add(diagnostic);
    } else if (kind == api.Diagnostic.ERROR) {
      errors.add(diagnostic);
    } else if (kind == api.Diagnostic.WARNING) {
      warnings.add(diagnostic);
    } else if (kind == api.Diagnostic.INFO) {
      infos.add(diagnostic);
    } else if (kind == api.Diagnostic.HINT) {
      hints.add(diagnostic);
    }
    if (diagnosticHandler != null) {
      SourceSpan span = spanFromSpannable(node);
      if (span != null) {
        diagnosticHandler(span.uri, span.begin, span.end, '$message', kind);
      } else {
        diagnosticHandler(null, null, null, '$message', kind);
      }
    }
  }

  bool get compilationFailed => !crashes.isEmpty || !errors.isEmpty;

  void clearMessages() {
    warnings = [];
    errors = [];
    hints = [];
    infos = [];
    crashes = [];
  }

  CollectingTreeElements resolveStatement(String text) {
    parsedTree = parseStatement(text);
    return resolveNodeStatement(parsedTree, new MockElement(mainApp));
  }

  TreeElementMapping resolveNodeStatement(Node tree,
                                          ExecutableElement element) {
    ResolverVisitor visitor =
        new ResolverVisitor(this, element,
            new ResolutionRegistry.internal(this,
                new CollectingTreeElements(element)));
    if (visitor.scope is LibraryScope) {
      visitor.scope = new MethodScope(visitor.scope, element);
    }
    visitor.visit(tree);
    visitor.scope = new LibraryScope(element.library);
    return visitor.registry.mapping;
  }

  resolverVisitor() {
    Element mockElement = new MockElement(mainApp.entryCompilationUnit);
    ResolverVisitor visitor =
        new ResolverVisitor(this, mockElement,
          new ResolutionRegistry.internal(this,
              new CollectingTreeElements(mockElement)));
    visitor.scope = new MethodScope(visitor.scope, mockElement);
    return visitor;
  }

  parseScript(String text, [LibraryElement library]) {
    if (library == null) library = mainApp;
    parseUnit(text, this, library, registerSource);
  }

  Future scanBuiltinLibraries() {
    // Do nothing. The mock core library is already handled in the constructor.
    return new Future.value();
  }

  Future<LibraryElement> scanBuiltinLibrary(String name) {
    // Do nothing. The mock core library is already handled in the constructor.
    return new Future.value();
  }

  Uri translateResolvedUri(LibraryElement importingLibrary,
                           Uri resolvedUri, Node node) => resolvedUri;

  // The mock library doesn't need any patches.
  Uri resolvePatchUri(String dartLibraryName) {
    if (dartLibraryName == 'core') {
      return PATCH_CORE;
    }
    return null;
  }

  Future<Script> readScript(Spannable node, Uri uri) {
    SourceFile sourceFile = sourceFiles[uri.toString()];
    if (sourceFile == null) throw new ArgumentError(uri);
    return new Future.value(new Script(uri, uri, sourceFile));
  }

  Element lookupElementIn(ScopeContainerElement container, name) {
    Element element = container.localLookup(name);
    return element != null
        ? element
        : new ErroneousElementX(null, null, name, container);
  }

  /// Create a new [MockCompiler] and apply it asynchronously to [f].
  static Future create(f(MockCompiler compiler)) {
    MockCompiler compiler = new MockCompiler.internal();
    return compiler.init().then((_) => f(compiler));
  }
}

/// A function the checks [message]. If the check fails or if [message] is
/// `null`, an error string is returned. Otherwise `null` is returned.
typedef String CheckMessage(Message message);

CheckMessage checkMessage(MessageKind kind, Map arguments) {
  return (Message message) {
    if (message == null) return '$kind';
    if (message.kind != kind) return 'Expected message $kind, found $message.';
    for (var key in arguments.keys) {
      if (!message.arguments.containsKey(key)) {
        return 'Expected argument $key not found in $message.kind.';
      }
      String expectedValue = '${arguments[key]}';
      String foundValue = '${message.arguments[key]}';
      if (expectedValue != foundValue) {
        return 'Expected argument $key with value $expectedValue, '
               'found $foundValue.';
      }
    }
    return null;
  };
}

void compareWarningKinds(String text,
                         List expectedWarnings,
                         List<WarningMessage> foundWarnings) {
  compareMessageKinds(text, expectedWarnings, foundWarnings, 'warning');
}

/// [expectedMessages] must be a list of either [MessageKind] or [CheckMessage].
void compareMessageKinds(String text,
                         List expectedMessages,
                         List<WarningMessage> foundMessages,
                         String kind) {
  var fail = (message) => Expect.fail('$text: $message');
  HasNextIterator expectedIterator =
      new HasNextIterator(expectedMessages.iterator);
  HasNextIterator<WarningMessage> foundIterator =
      new HasNextIterator(foundMessages.iterator);
  while (expectedIterator.hasNext && foundIterator.hasNext) {
    var expected = expectedIterator.next();
    var found = foundIterator.next();
    if (expected is MessageKind) {
      Expect.equals(expected, found.message.kind);
    } else if (expected is CheckMessage) {
      String error = expected(found.message);
      Expect.isNull(error, error);
    } else {
      Expect.fail("Unexpected $kind value: $expected.");
    }
  }
  if (expectedIterator.hasNext) {
    do {
      var expected = expectedIterator.next();
      if (expected is CheckMessage) expected = expected(null);
      print('Expected $kind "${expected}" did not occur');
    } while (expectedIterator.hasNext);
    fail('Too few ${kind}s');
  }
  if (foundIterator.hasNext) {
    do {
      print('Additional $kind "${foundIterator.next()}"');
    } while (foundIterator.hasNext);
    fail('Too many ${kind}s');
  }
}

class CollectingTreeElements extends TreeElementMapping {
  final Map<Node, Element> map = new LinkedHashMap<Node, Element>();

  CollectingTreeElements(Element currentElement) : super(currentElement);

  operator []=(Node node, Element element) {
    map[node] = element;
  }

  operator [](Node node) => map[node];

  void remove(Node node) {
    map.remove(node);
  }
}

// The mock compiler does not split the program in output units.
class MockDeferredLoadTask extends DeferredLoadTask {
  MockDeferredLoadTask(Compiler compiler) : super(compiler);

  OutputUnit getElementOutputUnit(dynamic dependency) {
    return mainOutputUnit;
  }
}

api.DiagnosticHandler createHandler(MockCompiler compiler, String text,
                                    {bool verbose: false}) {
  return (uri, int begin, int end, String message, kind) {
    if (kind == api.Diagnostic.VERBOSE_INFO && !verbose) return;
    SourceFile sourceFile;
    if (uri == null) {
      sourceFile = new StringSourceFile('analysis', text);
    } else {
      sourceFile = compiler.sourceFiles[uri.toString()];
    }
    if (sourceFile != null && begin != null && end != null) {
      print(sourceFile.getLocationMessage(message, begin, end));
    } else {
      print(message);
    }
  };
}

class MockElement extends FunctionElementX {
  MockElement(Element enclosingElement)
      : super('', ElementKind.FUNCTION, Modifiers.EMPTY,
              enclosingElement, false);

  get node => null;

  parseNode(_) => null;

  bool get hasNode => false;
}
