// 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 parser;

import 'dart:io';
import 'dart:typed_data';
import 'dart:collection';
import 'dart:utf';

import '../elements/elements.dart';
import '../scanner/scanner_implementation.dart';
import '../scanner/scannerlib.dart';
import '../tree/tree.dart';
import '../util/characters.dart';
import '../source_file.dart';
import '../ssa/ssa.dart';

import '../../compiler.dart' as api;

part '../diagnostic_listener.dart';
part '../scanner/byte_array_scanner.dart';
part '../scanner/byte_strings.dart';

int charCount = 0;
Stopwatch stopwatch;

void main() {
  toolMain(new Options().arguments);
}

void toolMain(List<String> arguments) {
  filesWithCrashes = [];
  stopwatch = new Stopwatch();
  MyOptions options = new MyOptions();

  void printStats() {
    int kb = (charCount / 1024).round();
    String stats =
        '$classCount classes (${kb}Kb) in ${stopwatch.elapsedMilliseconds}ms';
    if (errorCount != 0) {
      stats = '$stats with $errorCount errors';
    }
    if (options.diet) {
      print('Diet parsed $stats.');
    } else {
      print('Parsed $stats.');
    }
    if (filesWithCrashes.length != 0) {
      print('The following ${filesWithCrashes.length} files caused a crash:');
      for (String file in filesWithCrashes) {
        print(file);
      }
    }
  }

  for (String argument in arguments) {
    if (argument == "--diet") {
      options.diet = true;
      continue;
    }
    if (argument == "--throw") {
      options.throwOnError = true;
      continue;
    }
    if (argument == "--scan-only") {
      options.scanOnly = true;
      continue;
    }
    if (argument == "--read-only") {
      options.readOnly = true;
      continue;
    }
    if (argument == "--ast") {
      options.buildAst = true;
      continue;
    }
    if (argument == "-") {
      parseFilesFrom(stdin, options, printStats);
      return;
    }
    stopwatch.start();
    parseFile(argument, options);
    stopwatch.stop();
  }

  printStats();
}

void parseFile(String filename, MyOptions options) {
  List<int> bytes = read(filename);
  charCount += bytes.length;
  if (options.readOnly) return;
  MySourceFile file = new MySourceFile(filename, bytes);
  final Listener listener = options.buildAst
      ? new MyNodeListener(file, options)
      : new MyListener(file);
  final Parser parser = options.diet
      ? new PartialParser(listener)
      : new Parser(listener);
  try {
    Token token = scan(file);
    if (!options.scanOnly) parser.parseUnit(token);
  } on ParserError catch (ex) {
    if (options.throwOnError) {
      rethrow;
    } else {
      print(ex);
    }
  } catch (ex) {
    print('Error in file: $filename');
    rethrow;
  }
  if (options.buildAst) {
    MyNodeListener l = listener;
    if (!l.nodes.isEmpty) {
      String message = 'Stack not empty after parsing';
      print(formatError(message, l.nodes.head.getBeginToken(),
                        l.nodes.head.getEndToken(), file));
      throw message;
    }
  }
}

Token scan(MySourceFile source) {
  Scanner scanner = new ByteArrayScanner(source.rawText);
  return scanner.tokenize();
}

var filesWithCrashes;

void parseFilesFrom(InputStream input, MyOptions options, Function whenDone) {
  void readLine(String line) {
    stopwatch.start();
    try {
      parseFile(line, options);
    } catch (ex, trace) {
      filesWithCrashes.add(line);
      print(ex);
      print(trace);
    }
    stopwatch.stop();
  }
  forEachLine(input, readLine, whenDone);
}

void forEachLine(InputStream input,
                 void lineHandler(String line),
                 void closeHandler()) {
  StringInputStream stringStream = new StringInputStream(input);
  stringStream.onLine = () {
    String line;
    while ((line = stringStream.readLine()) != null) {
      lineHandler(line);
    }
  };
  stringStream.onClosed = closeHandler;
}

List<int> read(String filename) {
  RandomAccessFile file = new File(filename).openSync();
  bool threw = true;
  try {
    int size = file.lengthSync();
    List<int> bytes = new Uint8List(size + 1);
    file.readIntoSync(bytes, 0, size);
    bytes[size] = $EOF;
    threw = false;
    return bytes;
  } finally {
    try {
      file.closeSync();
    } catch (ex) {
      if (!threw) rethrow;
    }
  }
}

int classCount = 0;
int errorCount = 0;

class MyListener extends Listener {
  final SourceFile file;

  MyListener(this.file);

  void beginClassDeclaration(Token token) {
    classCount++;
  }

  void beginInterface(Token token) {
    classCount++;
  }

  void error(String message, Token token) {
    throw new ParserError(formatError(message, token, token, file));
  }
}

String formatError(String message, Token beginToken, Token endToken,
                   SourceFile file) {
  ++errorCount;
  if (beginToken == null) return '${file.filename}: $message';
  String tokenString = endToken.toString();
  int begin = beginToken.charOffset;
  int end = endToken.charOffset + tokenString.length;
  return file.getLocationMessage(message, begin, end, true, (x) => x);
}

class MyNodeListener extends NodeListener {
  MyNodeListener(SourceFile file, MyOptions options)
    : super(new MyCanceller(file, options), null);

  void beginClassDeclaration(Token token) {
    classCount++;
  }

  void beginInterface(Token token) {
    classCount++;
  }

  void endClassDeclaration(int interfacesCount, Token beginToken,
                           Token extendsKeyword, Token implementsKeyword,
                           Token endToken) {
    super.endClassDeclaration(interfacesCount, beginToken,
                              extendsKeyword, implementsKeyword,
                              endToken);
    ClassNode node = popNode(); // Discard ClassNode and assert the type.
  }

  void endTopLevelFields(int count, Token beginToken, Token endToken) {
    super.endTopLevelFields(count, beginToken, endToken);
    VariableDefinitions node = popNode(); // Discard node and assert the type.
  }

  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
    super.endFunctionTypeAlias(typedefKeyword, endToken);
    Typedef node = popNode(); // Discard Typedef and assert type type.
  }

  void endLibraryTag(bool hasPrefix, Token beginToken, Token endToken) {
    super.endLibraryTag(hasPrefix, beginToken, endToken);
    ScriptTag node = popNode(); // Discard ScriptTag and assert type type.
  }

  void log(message) {
    print(message);
  }
}

class MyCanceller implements DiagnosticListener {
  final SourceFile file;
  final MyOptions options;

  MyCanceller(this.file, this.options);

  void log(String message) {}

  void cancel(String reason, {node, token, instruction, element}) {
    Token beginToken;
    Token endToken;
    if (token != null) {
      beginToken = token;
      endToken = token;
    } else if (node != null) {
      beginToken = node.getBeginToken();
      endToken = node.getEndToken();
    }
    String message = formatError(reason, beginToken, endToken, file);
    if (options.throwOnError) throw new ParserError(message);
    print(message);
  }
}

class MyOptions {
  bool diet = false;
  bool throwOnError = false;
  bool scanOnly = false;
  bool readOnly = false;
  bool buildAst = false;
}

class MySourceFile extends SourceFile {
  final rawText;
  var stringText;

  MySourceFile(filename, this.rawText) : super(filename, null);

  String get text {
    if (rawText is String) {
      return rawText;
    } else {
      if (stringText == null) {
        stringText = new String.fromCharCodes(rawText);
        if (stringText.endsWith('\u0000')) {
          // Strip trailing NUL used by ByteArrayScanner to signal EOF.
          stringText = stringText.substring(0, stringText.length - 1);
        }
      }
      return stringText;
    }
  }

  set text(String newText) {
    throw "not supported";
  }
}

class Mock {
  const Mock();
  bool get useColors => true;
  internalError(message) { throw message.toString(); }
}
