// 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.

// @dart = 2.7

library sourcemap.html_parts;

import 'sourcemap_html_helper.dart';

class Annotation {
  final id;
  final int codeOffset;
  final String title;
  final data;

  Annotation(this.id, this.codeOffset, this.title, {this.data});
}

typedef bool AnnotationFilter(Annotation annotation);
typedef AnnotationData AnnotationDataFunction(Iterable<Annotation> annotations,
    {bool forSpan});
typedef LineData LineDataFunction(lineAnnotation);

bool includeAllAnnotation(Annotation annotation) => true;

class LineData {
  final String lineClass;
  final String lineNumberClass;

  const LineData({this.lineClass: 'line', this.lineNumberClass: 'lineNumber'});
}

class AnnotationData {
  final String tag;
  final Map<String, String> properties;

  const AnnotationData(
      {this.tag: 'a', this.properties: const <String, String>{}});

  @override
  int get hashCode => tag.hashCode * 13 + properties.hashCode * 19;

  @override
  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! AnnotationData) return false;
    return tag == other.tag &&
        properties.length == other.properties.length &&
        properties.keys.every((k) => properties[k] == other.properties[k]);
  }
}

AnnotationDataFunction createAnnotationDataFunction(
    {CssColorScheme colorScheme: const SingleColorScheme(),
    ElementScheme elementScheme: const ElementScheme()}) {
  return (Iterable<Annotation> annotations, {bool forSpan}) {
    return getAnnotationDataFromSchemes(annotations,
        forSpan: forSpan,
        colorScheme: colorScheme,
        elementScheme: elementScheme);
  };
}

LineData getDefaultLineData(data) => const LineData();

AnnotationData getAnnotationDataFromSchemes(Iterable<Annotation> annotations,
    {bool forSpan,
    CssColorScheme colorScheme: const SingleColorScheme(),
    ElementScheme elementScheme: const ElementScheme()}) {
  if (colorScheme.showLocationAsSpan != forSpan) return null;
  Map<String, String> data = <String, String>{};
  var id;
  if (annotations.length == 1) {
    Annotation annotation = annotations.single;
    if (annotation != null) {
      id = annotation.id;
      data['style'] = colorScheme.singleLocationToCssColor(id);
      data['title'] = annotation.title;
    }
  } else {
    id = annotations.first.id;
    List ids = [];
    for (Annotation annotation in annotations) {
      ids.add(annotation.id);
    }
    data['style'] = colorScheme.multiLocationToCssColor(ids);
    data['title'] = annotations.map((l) => l.title).join(',');
  }
  if (id != null) {
    Set ids = annotations.map<int>((l) => l.id).toSet();
    data['name'] = elementScheme.getName(id, ids);
    data['href'] = elementScheme.getHref(id, ids);
    data['onclick'] = elementScheme.onClick(id, ids);
    data['onmouseover'] = elementScheme.onMouseOver(id, ids);
    data['onmouseout'] = elementScheme.onMouseOut(id, ids);
    return new AnnotationData(properties: data);
  }
  return null;
}

class HtmlPrintContext {
  final int lineNoWidth;
  final bool usePre;
  final AnnotationFilter includeAnnotation;
  final AnnotationDataFunction getAnnotationData;
  final LineDataFunction getLineData;

  HtmlPrintContext(
      {this.lineNoWidth,
      this.usePre: true,
      this.includeAnnotation: includeAllAnnotation,
      this.getAnnotationData: getAnnotationDataFromSchemes,
      this.getLineData: getDefaultLineData});

  HtmlPrintContext from(
      {int lineNoWidth,
      bool usePre,
      AnnotationFilter includeAnnotation,
      AnnotationDataFunction getAnnotationData,
      LineDataFunction getLineData}) {
    return new HtmlPrintContext(
        lineNoWidth: lineNoWidth ?? this.lineNoWidth,
        usePre: usePre ?? this.usePre,
        includeAnnotation: includeAnnotation ?? this.includeAnnotation,
        getAnnotationData: getAnnotationData ?? this.getAnnotationData,
        getLineData: getLineData ?? this.getLineData);
  }
}

enum HtmlPartKind {
  CODE,
  LINE,
  CONST,
  NEWLINE,
  TEXT,
  TAG,
  LINE_NUMBER,
}

abstract class HtmlPart {
  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context);

  HtmlPartKind get kind;

  toJson(JsonStrategy strategy);

  static HtmlPart fromJson(json, JsonStrategy strategy) {
    if (json is String) {
      return new ConstHtmlPart(json);
    } else {
      switch (HtmlPartKind.values[json['kind']]) {
        case HtmlPartKind.LINE:
          return HtmlLine.fromJson(json, strategy);
        case HtmlPartKind.CODE:
          return CodeLine.fromJson(json, strategy);
        case HtmlPartKind.CONST:
          return ConstHtmlPart.fromJson(json, strategy);
        case HtmlPartKind.NEWLINE:
          return const NewLine();
        case HtmlPartKind.TEXT:
          return HtmlText.fromJson(json, strategy);
        case HtmlPartKind.TAG:
          return TagPart.fromJson(json, strategy);
        case HtmlPartKind.LINE_NUMBER:
          return LineNumber.fromJson(json, strategy);
      }
      return null;
    }
  }
}

class ConstHtmlPart implements HtmlPart {
  final String html;

  const ConstHtmlPart(this.html);

  @override
  HtmlPartKind get kind => HtmlPartKind.CONST;

  @override
  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {
    buffer.write(html);
  }

  @override
  toJson(JsonStrategy strategy) {
    return {'kind': kind.index, 'html': html};
  }

  static ConstHtmlPart fromJson(Map json, JsonStrategy strategy) {
    return new ConstHtmlPart(json['html']);
  }
}

class NewLine implements HtmlPart {
  const NewLine();

  @override
  HtmlPartKind get kind => HtmlPartKind.NEWLINE;

  @override
  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {
    if (context.usePre) {
      buffer.write('\n');
    } else {
      buffer.write('<br/>');
    }
  }

  @override
  toJson(JsonStrategy strategy) {
    return {'kind': kind.index};
  }
}

class HtmlText implements HtmlPart {
  final String text;

  const HtmlText(this.text);

  @override
  HtmlPartKind get kind => HtmlPartKind.TEXT;

  @override
  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {
    String escaped = escape(text);
    buffer.write(escaped);
  }

  @override
  toJson(JsonStrategy strategy) {
    return {'kind': kind.index, 'text': text};
  }

  static HtmlText fromJson(Map json, JsonStrategy strategy) {
    return new HtmlText(json['text']);
  }
}

class TagPart implements HtmlPart {
  final String tag;
  final Map<String, String> properties;
  final List<HtmlPart> content;

  TagPart(this.tag,
      {this.properties: const <String, String>{},
      this.content: const <HtmlPart>[]});

  @override
  HtmlPartKind get kind => HtmlPartKind.TAG;

  @override
  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {
    buffer.write('<$tag');
    properties.forEach((String key, String value) {
      if (value != null) {
        buffer.write(' $key="${value}"');
      }
    });
    buffer.write('>');
    for (HtmlPart child in content) {
      child.printHtmlOn(buffer, context);
    }
    buffer.write('</$tag>');
  }

  @override
  toJson(JsonStrategy strategy) {
    return {
      'kind': kind.index,
      'tag': tag,
      'properties': properties,
      'content': content.map((p) => p.toJson(strategy)).toList()
    };
  }

  static TagPart fromJson(Map json, JsonStrategy strategy) {
    return new TagPart(json['tag'],
        properties: json['properties'],
        content: json['content'].map(HtmlPart.fromJson).toList());
  }
}

class HtmlLine implements HtmlPart {
  final List<HtmlPart> htmlParts = <HtmlPart>[];

  @override
  HtmlPartKind get kind => HtmlPartKind.LINE;

  @override
  void printHtmlOn(StringBuffer htmlBuffer, HtmlPrintContext context) {
    for (HtmlPart part in htmlParts) {
      part.printHtmlOn(htmlBuffer, context);
    }
  }

  @override
  Map toJson(JsonStrategy strategy) {
    return {
      'kind': kind.index,
      'html': htmlParts.map((p) => p.toJson(strategy)).toList(),
    };
  }

  static HtmlLine fromJson(Map json, JsonStrategy strategy) {
    HtmlLine line = new HtmlLine();
    json['html'].forEach(
        (part) => line.htmlParts.add(HtmlPart.fromJson(part, strategy)));
    return line;
  }
}

class CodePart {
  final List<Annotation> annotations;
  final String subsequentCode;

  CodePart(this.annotations, this.subsequentCode);

  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {
    Iterable<Annotation> included =
        annotations.where(context.includeAnnotation);

    List<HtmlPart> htmlParts = <HtmlPart>[];
    if (included.isNotEmpty) {
      AnnotationData annotationData =
          context.getAnnotationData(included, forSpan: false);
      AnnotationData annotationDataForSpan =
          context.getAnnotationData(included, forSpan: true);

      String head = subsequentCode;
      String tail = '';
      if (subsequentCode.length > 1) {
        head = subsequentCode.substring(0, 1);
        tail = subsequentCode.substring(1);
      }

      if (annotationData != null && annotationDataForSpan != null) {
        htmlParts.add(new TagPart(annotationDataForSpan.tag,
            properties: annotationDataForSpan.properties,
            content: [
              new TagPart(annotationData.tag,
                  properties: annotationData.properties,
                  content: [new HtmlText(head)]),
              new HtmlText(tail)
            ]));
      } else if (annotationDataForSpan != null) {
        htmlParts.add(new TagPart(annotationDataForSpan.tag,
            properties: annotationDataForSpan.properties,
            content: [new HtmlText(subsequentCode)]));
      } else if (annotationData != null) {
        htmlParts.add(new TagPart(annotationData.tag,
            properties: annotationData.properties,
            content: [new HtmlText(head)]));
        htmlParts.add(new HtmlText(tail));
      } else {
        htmlParts.add(new HtmlText(subsequentCode));
      }
    } else {
      htmlParts.add(new HtmlText(subsequentCode));
    }

    for (HtmlPart part in htmlParts) {
      part.printHtmlOn(buffer, context);
    }
  }

  Map toJson(JsonStrategy strategy) {
    return {
      'annotations':
          annotations.map((a) => strategy.encodeAnnotation(a)).toList(),
      'subsequentCode': subsequentCode,
    };
  }

  static CodePart fromJson(Map json, JsonStrategy strategy) {
    return new CodePart(
        json['annotations'].map((j) => strategy.decodeAnnotation(j)).toList(),
        json['subsequentCode']);
  }
}

class LineNumber extends HtmlPart {
  final int lineNo;
  final lineAnnotation;

  LineNumber(this.lineNo, this.lineAnnotation);

  @override
  HtmlPartKind get kind => HtmlPartKind.LINE_NUMBER;

  @override
  toJson(JsonStrategy strategy) {
    return {
      'kind': kind.index,
      'lineNo': lineNo,
      'lineAnnotation': strategy.encodeLineAnnotation(lineAnnotation),
    };
  }

  static LineNumber fromJson(Map json, JsonStrategy strategy) {
    return new LineNumber(
        json['lineNo'], strategy.decodeLineAnnotation(json['lineAnnotation']));
  }

  @override
  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {
    buffer.write(lineNumber(lineNo,
        width: context.lineNoWidth,
        useNbsp: !context.usePre,
        className: context.getLineData(lineAnnotation).lineNumberClass));
  }
}

class CodeLine extends HtmlPart {
  final Uri uri;
  final int lineNo;
  final int offset;
  final StringBuffer codeBuffer = new StringBuffer();
  final List<CodePart> codeParts = <CodePart>[];
  final List<Annotation> annotations = <Annotation>[];
  var lineAnnotation;
  String _code;

  CodeLine(this.lineNo, this.offset, {this.uri});

  @override
  HtmlPartKind get kind => HtmlPartKind.CODE;

  String get code {
    if (_code == null) {
      _code = codeBuffer.toString();
    }
    return _code;
  }

  @override
  void printHtmlOn(StringBuffer htmlBuffer, HtmlPrintContext context) {
    if (context.usePre) {
      LineData lineData = context.getLineData(lineAnnotation);
      htmlBuffer.write('<p class="${lineData.lineClass}">');
    }
    new LineNumber(lineNo, lineAnnotation).printHtmlOn(htmlBuffer, context);
    for (CodePart part in codeParts) {
      part.printHtmlOn(htmlBuffer, context);
    }
    const NewLine().printHtmlOn(htmlBuffer, context);
    if (context.usePre) {
      htmlBuffer.write('</p>');
    }
  }

  @override
  Map toJson(JsonStrategy strategy) {
    return {
      'kind': kind.index,
      'lineNo': lineNo,
      'offset': offset,
      'code': code,
      'parts': codeParts.map((p) => p.toJson(strategy)).toList(),
      'annotations':
          annotations.map((a) => strategy.encodeAnnotation(a)).toList(),
      'lineAnnotation': lineAnnotation != null
          ? strategy.encodeLineAnnotation(lineAnnotation)
          : null,
    };
  }

  static CodeLine fromJson(Map json, JsonStrategy strategy) {
    CodeLine line = new CodeLine(json['lineNo'], json['offset'],
        uri: json['uri'] != null ? Uri.parse(json['uri']) : null);
    line.codeBuffer.write(json['code']);
    json['parts'].forEach(
        (part) => line.codeParts.add(CodePart.fromJson(part, strategy)));
    json['annotations']
        .forEach((a) => line.annotations.add(strategy.decodeAnnotation(a)));
    line.lineAnnotation = json['lineAnnotation'] != null
        ? strategy.decodeLineAnnotation(json['lineAnnotation'])
        : null;
    return line;
  }
}

class JsonStrategy {
  const JsonStrategy();

  Map encodeAnnotation(Annotation annotation) {
    return {
      'id': annotation.id,
      'codeOffset': annotation.codeOffset,
      'title': annotation.title,
      'data': annotation.data,
    };
  }

  Annotation decodeAnnotation(Map json) {
    return new Annotation(json['id'], json['codeOffset'], json['title'],
        data: json['data']);
  }

  encodeLineAnnotation(lineAnnotation) => lineAnnotation;

  decodeLineAnnotation(json) => json;
}
