// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// TODO(mdebbar): To reduce the size of generated code, we could pack the data
//   into a smaller format, e.g:
//
// ```dart
// const _rawData = [
//   0x000A, 0x000A, 1,
//   0x000B, 0x000C, 2,
//   0x000D, 0x000D, 3,
//   0x0020, 0x0020, 4,
//   // ...
// ];
// ```
//
// Then we could lazily build the lookup instance on demand.
// @dart = 2.6
import 'dart:io';
import 'package:path/path.dart' as path;

/// A tuple that holds a [start] and [end] of a unicode range and a [property].
class PropertyTuple {
  const PropertyTuple(this.start, this.end, this.property);

  final int start;
  final int end;
  final String property;

  /// Checks if there's an overlap between this tuple's range and [other]'s
  /// range.
  bool isOverlapping(PropertyTuple other) {
    return start <= other.end && end >= other.start;
  }

  /// Checks if the [other] tuple is adjacent to this tuple.
  ///
  /// Two tuples are considered adjacent if:
  /// - The new tuple's range immediately follows this tuple's range, and
  /// - The new tuple has the same property as this tuple.
  bool isAdjacent(PropertyTuple other) {
    return other.start == end + 1 && property == other.property;
  }

  /// Merges the ranges of the 2 [PropertyTuples] if they are adjacent.
  PropertyTuple extendRange(PropertyTuple extension) {
    assert(isAdjacent(extension));
    return PropertyTuple(start, extension.end, property);
  }
}

/// Usage (from the root of the project):
///
/// ```
/// dart tool/unicode_sync_script.dart <path/to/word/break/properties>
/// ```
///
/// This script parses the unicode word break properties(1) and generates Dart
/// code(2) that can perform lookups in the unicode ranges to find what property
/// a letter has.
///
/// (1) The properties file can be downloaded from:
///     https://www.unicode.org/Public/11.0.0/ucd/auxiliary/WordBreakProperty.txt
///
/// (2) The codegen'd Dart file is located at:
///     lib/src/text/word_break_properties.dart
void main(List<String> arguments) async {
  final String propertiesFile = arguments[0];
  final String codegenFile = path.join(
    path.dirname(Platform.script.toFilePath()),
    '../lib/src/engine/text/word_break_properties.dart',
  );
  WordBreakPropertiesSyncer(propertiesFile, codegenFile).perform();
}

/// Base class that provides common logic for syncing all kinds of unicode
/// properties (e.g. word break properties, line break properties, etc).
///
/// Subclasses implement the [template] method which receives as argument the
/// list of data parsed by [processLines].
abstract class PropertiesSyncer {
  PropertiesSyncer(this._src, this._dest);

  final String _src;
  final String _dest;

  void perform() async {
    final List<String> lines = await File(_src).readAsLines();
    final List<String> header = extractHeader(lines);
    final List<PropertyTuple> data = processLines(lines);

    final IOSink sink = File(_dest).openWrite();
    sink.write(template(header, data));
  }

  String template(List<String> header, List<PropertyTuple> data);
}

/// Syncs Unicode's word break properties.
class WordBreakPropertiesSyncer extends PropertiesSyncer {
  WordBreakPropertiesSyncer(String src, String dest) : super(src, dest);

  @override
  String template(List<String> header, List<PropertyTuple> data) {
    return '''
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// AUTO-GENERATED FILE.
// Generated by: tool/unicode_sync_script.dart
//
// Source:
// ${header.join('\n// ')}

// @dart = 2.6
part of engine;

CharProperty getCharProperty(String text, int index) {
  if (index < 0 || index >= text.length) {
    return null;
  }
  return lookup.find(text.codeUnitAt(index));
}

enum CharProperty {
  ${getEnumValues(data).join(',\n  ')}
}

const UnicodePropertyLookup<CharProperty> lookup =
    UnicodePropertyLookup<CharProperty>(<UnicodeRange<CharProperty>>[
  ${getLookupEntries(data).join(',\n  ')}
]);
''';
  }

  Iterable<String> getEnumValues(List<PropertyTuple> data) {
    return Set<String>.from(
            data.map<String>((PropertyTuple tuple) => tuple.property))
        .map(normalizePropertyName);
  }

  Iterable<String> getLookupEntries(List<PropertyTuple> data) {
    data.sort(
      // Ranges don't overlap so it's safe to sort based on the start of each
      // range.
      (PropertyTuple tuple1, PropertyTuple tuple2) =>
          tuple1.start.compareTo(tuple2.start),
    );
    verifyNoOverlappingRanges(data);
    return combineAdjacentRanges(data)
        .map((PropertyTuple tuple) => generateLookupEntry(tuple));
  }

  String generateLookupEntry(PropertyTuple tuple) {
    final String propertyStr =
        'CharProperty.${normalizePropertyName(tuple.property)}';
    return 'UnicodeRange<CharProperty>(${toHex(tuple.start)}, ${toHex(tuple.end)}, $propertyStr)';
  }
}

/// Example:
///
/// ```
/// UnicodeRange<CharProperty>(0x01C4, 0x0293, CharProperty.ALetter),
/// UnicodeRange<CharProperty>(0x0294, 0x0294, CharProperty.ALetter),
/// UnicodeRange<CharProperty>(0x0295, 0x02AF, CharProperty.ALetter),
/// ```
///
/// will get combined into:
///
/// ```
/// UnicodeRange<CharProperty>(0x01C4, 0x02AF, CharProperty.ALetter)
/// ```
List<PropertyTuple> combineAdjacentRanges(List<PropertyTuple> data) {
  final List<PropertyTuple> result = <PropertyTuple>[data.first];
  for (int i = 1; i < data.length; i++) {
    if (result.last.isAdjacent(data[i])) {
      result.last = result.last.extendRange(data[i]);
    } else {
      result.add(data[i]);
    }
  }
  return result;
}

int getRangeStart(String range) {
  return int.parse(range.split('..')[0], radix: 16);
}

int getRangeEnd(String range) {
  if (range.contains('..')) {
    return int.parse(range.split('..')[1], radix: 16);
  }
  return int.parse(range, radix: 16);
}

String toHex(int value) {
  return '0x${value.toRadixString(16).padLeft(4, '0').toUpperCase()}';
}

void verifyNoOverlappingRanges(List<PropertyTuple> data) {
  for (int i = 1; i < data.length; i++) {
    if (data[i].isOverlapping(data[i - 1])) {
      throw Exception('Data contains overlapping ranges.');
    }
  }
}

List<String> extractHeader(List<String> lines) {
  final List<String> headerLines = <String>[];
  for (String line in lines) {
    if (line.contains('=======')) {
      break;
    }
    if (line.isNotEmpty) {
      headerLines.add(line);
    }
  }
  return headerLines;
}

List<PropertyTuple> processLines(List<String> lines) {
  return lines
      .map(removeCommentFromLine)
      .where((String line) => line.isNotEmpty)
      .map(parseLineIntoPropertyTuple)
      .toList();
}

String normalizePropertyName(String property) {
  return property.replaceAll('_', '');
}

String removeCommentFromLine(String line) {
  final int poundIdx = line.indexOf('#');
  return (poundIdx == -1) ? line : line.substring(0, poundIdx);
}

/// Examples:
///
/// 00C0..00D6    ; ALetter
/// 037F          ; ALetter
///
/// Would be parsed into:
///
/// ```dart
/// PropertyTuple(192, 214, 'ALetter');
/// PropertyTuple(895, 895, 'ALetter');
/// ```
PropertyTuple parseLineIntoPropertyTuple(String line) {
  final List<String> split = line.split(';');
  final String rangeStr = split[0].trim();
  final String propertyStr = split[1].trim();

  final List<String> rangeSplit = rangeStr.contains('..')
      ? rangeStr.split('..')
      : <String>[rangeStr, rangeStr];
  return PropertyTuple(
    int.parse(rangeSplit[0], radix: 16),
    int.parse(rangeSplit[1], radix: 16),
    propertyStr,
  );
}
