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

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

  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((l) => l.id).toSet();
    data['tag'] = 'a';
    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);
      }
    }
  }
}

class ConstHtmlPart implements HtmlPart {
  final String html;

  const ConstHtmlPart(this.html);

  HtmlPartKind get kind => HtmlPartKind.CONST;

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

  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();

  HtmlPartKind get kind => HtmlPartKind.NEWLINE;

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

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

class HtmlText implements HtmlPart {
  final String text;

  const HtmlText(this.text);

  HtmlPartKind get kind => HtmlPartKind.TEXT;

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

  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>[]});

  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>');
  }

  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>[];

  HtmlPartKind get kind => HtmlPartKind.LINE;

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

  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);
      }

      void addForSpan(AnnotationData data) {
        htmlParts.add(new TagPart(data.tag,
            properties: data.properties,
            content: [new HtmlText(subsequentCode)]));
      }

      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);

  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});

  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>');
    }
  }

  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;
}
