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

const int _LF = 0x0A;
const int _CR = 0x0D;
const int _LBRACE = 0x7B;

class Annotation {
  /// 1-based line number of the annotation.
  final int lineNo;

  /// 1-based column number of the annotation.
  final int columnNo;

  /// 0-based character offset  of the annotation within the source text.
  final int offset;

  /// The text in the annotation.
  final String text;

  Annotation(this.lineNo, this.columnNo, this.offset, this.text);
}

/// A source code text with annotated positions.
///
/// An [AnnotatedCode] can be created from a [String] of source code where
/// annotated positions are embedded, by default using the syntax `@{text}`.
/// For instance
///
///     main() {
///       @{foo-call}foo();
///       bar@{bar-args}();
///     }
///
///  the position of `foo` call will hold an annotation with text 'foo-call' and
///  the position of `bar` arguments will hold an annotation with text
///  'bar-args'.
///
///  Annotation text cannot span multiple lines and cannot contain '}'.
class AnnotatedCode {
  /// The source code without annotations.
  final String sourceCode;

  /// The annotations for the source code.
  final List<Annotation> annotations;

  List<int> _lineStarts;

  AnnotatedCode(this.sourceCode, this.annotations);

  AnnotatedCode.internal(this.sourceCode, this.annotations, this._lineStarts);

  /// Creates an [AnnotatedCode] by processing [annotatedCode]. Annotation
  /// delimited by [start] and [end] are converted into [Annotation]s and
  /// removed from the [annotatedCode] to produce the source code.
  factory AnnotatedCode.fromText(String annotatedCode,
      [String start = '@{', String end = '}']) {
    StringBuffer codeBuffer = new StringBuffer();
    List<Annotation> annotations = <Annotation>[];
    int index = 0;
    int offset = 0;
    int lineNo = 1;
    int columnNo = 1;
    List<int> lineStarts = <int>[];
    lineStarts.add(offset);
    while (index < annotatedCode.length) {
      if (annotatedCode.startsWith(start, index)) {
        int endIndex = annotatedCode.indexOf(end, index + start.length);
        String text = annotatedCode.substring(index + start.length, endIndex);
        annotations.add(new Annotation(lineNo, columnNo, offset, text));
        index = endIndex + end.length;
      } else {
        int charCode = annotatedCode.codeUnitAt(index);
        switch (charCode) {
          case _LF:
            codeBuffer.write('\n');
            offset++;
            lineStarts.add(offset);
            lineNo++;
            columnNo = 1;
            break;
          case _CR:
            if (index + 1 < annotatedCode.length &&
                annotatedCode.codeUnitAt(index + 1) == _LF) {
              index++;
            }
            codeBuffer.write('\n');
            offset++;
            lineStarts.add(offset);
            lineNo++;
            columnNo = 1;
            break;
          default:
            codeBuffer.writeCharCode(charCode);
            offset++;
            columnNo++;
        }
        index++;
      }
    }
    lineStarts.add(offset);
    return new AnnotatedCode.internal(
        codeBuffer.toString(), annotations, lineStarts);
  }

  void _ensureLineStarts() {
    if (_lineStarts == null) {
      int index = 0;
      int offset = 0;
      _lineStarts = <int>[];
      _lineStarts.add(offset);
      while (index < sourceCode.length) {
        int charCode = sourceCode.codeUnitAt(index);
        switch (charCode) {
          case _LF:
            offset++;
            _lineStarts.add(offset);
            break;
          case _CR:
            if (index + 1 < sourceCode.length &&
                sourceCode.codeUnitAt(index + 1) == _LF) {
              index++;
            }
            offset++;
            _lineStarts.add(offset);
            break;
          default:
            offset++;
        }
        index++;
      }
      _lineStarts.add(offset);
    }
  }

  void addAnnotation(int lineNo, int columnNo, String text) {
    _ensureLineStarts();
    int offset = _lineStarts[lineNo - 1] + (columnNo - 1);
    annotations.add(new Annotation(lineNo, columnNo, offset, text));
  }

  String toText() {
    StringBuffer sb = new StringBuffer();
    List<Annotation> list = annotations.toList()
      ..sort((a, b) => a.offset.compareTo(b.offset));
    int offset = 0;
    for (Annotation annotation in list) {
      sb.write(sourceCode.substring(offset, annotation.offset));
      sb.write('@{${annotation.text}}');
      offset = annotation.offset;
    }
    sb.write(sourceCode.substring(offset));
    return sb.toString();
  }
}
