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

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, {
  required 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 {}});

  @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(),
  required ElementScheme elementScheme,
}) {
  return (Iterable<Annotation> annotations, {required bool forSpan}) {
    return getAnnotationDataFromSchemes(
      annotations,
      forSpan: forSpan,
      colorScheme: colorScheme,
      elementScheme: elementScheme,
    );
  };
}

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

AnnotationData? getAnnotationDataFromSchemes(
  Iterable<Annotation> annotations, {
  required bool forSpan,
  CssColorScheme colorScheme = const SingleColorScheme(),
  ElementScheme elementScheme = const ElementScheme(),
}) {
  if (colorScheme.showLocationAsSpan != forSpan) return null;
  Map<String, String?> data = {};
  var id;
  if (annotations.length == 1) {
    Annotation annotation = annotations.single;
    id = annotation.id;
    data['style'] = colorScheme.singleLocationToCssColor(id);
    data['title'] = annotation.title;
  } else {
    id = annotations.first.id;
    List<int> 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<int> 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 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 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 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);
      }
    }
  }
}

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 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 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 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 = 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: [
              TagPart(
                annotationData.tag,
                properties: annotationData.properties,
                content: [new HtmlText(head)],
              ),
              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 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 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 = StringBuffer();
  final List<CodePart> codeParts = <CodePart>[];
  final List<Annotation> annotations = <Annotation>[];
  var lineAnnotation;

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

  @override
  HtmlPartKind get kind => HtmlPartKind.CODE;

  late final String code = codeBuffer.toString();

  @override
  void printHtmlOn(StringBuffer htmlBuffer, HtmlPrintContext context) {
    if (context.usePre) {
      LineData lineData = context.getLineData(lineAnnotation);
      htmlBuffer.write('<p class="${lineData.lineClass}">');
    }
    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 = 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 Annotation(
      json['id'],
      json['codeOffset'],
      json['title'],
      data: json['data'],
    );
  }

  encodeLineAnnotation(lineAnnotation) => lineAnnotation;

  decodeLineAnnotation(json) => json;
}
