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

import 'dart:convert';
import 'dart:io';
import 'dart:mirrors';

import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary/base.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:args/args.dart';

main(List<String> args) {
  ArgParser argParser = new ArgParser()..addFlag('raw');
  ArgResults argResults = argParser.parse(args);
  if (argResults.rest.length != 1) {
    print(argParser.usage);
    exitCode = 1;
    return;
  }
  String path = argResults.rest[0];
  List<int> bytes = new File(path).readAsBytesSync();
  PackageBundle bundle = new PackageBundle.fromBuffer(bytes);
  SummaryInspector inspector = new SummaryInspector(argResults['raw']);
  print(inspector.dumpPackageBundle(bundle).join('\n'));
}

const int MAX_LINE_LENGTH = 80;

/**
 * Cache used to speed up [isEnum].
 */
Map<Type, bool> _isEnumCache = <Type, bool>{};

/**
 * Determine if the given [obj] has an enumerated type.
 */
bool isEnum(Object obj) {
  return _isEnumCache.putIfAbsent(
      obj.runtimeType, () => reflect(obj).type.isEnum);
}

/**
 * Decoded reprensentation of a part of a summary that occupies multiple lines
 * of output.
 */
class BrokenEntity implements DecodedEntity {
  final String opener;
  final Map<String, DecodedEntity> parts;
  final String closer;

  BrokenEntity(this.opener, this.parts, this.closer);

  @override
  List<String> getLines() {
    List<String> result = <String>[opener];
    bool first = true;
    for (String key in parts.keys) {
      if (first) {
        first = false;
      } else {
        result[result.length - 1] += ',';
      }
      List<String> subResult = parts[key].getLines();
      subResult[0] = '$key: ${subResult[0]}';
      result.addAll(subResult.map((String s) => '  $s'));
    }
    result.add(closer);
    return result;
  }
}

/**
 * Decoded representation of a part of a summary.
 */
abstract class DecodedEntity {
  /**
   * Create a representation of a part of the summary that consists of a group
   * of entities (represented by [parts]) contained between [opener] and
   * [closer].
   *
   * If [forceKeys] is `true`, the keys in [parts] will always be shown.  If
   * [forceKeys] is `false`, they keys will only be shown if the output is
   * broken into multiple lines.
   */
  factory DecodedEntity.group(String opener, Map<String, DecodedEntity> parts,
      String closer, bool forceKeys) {
    // Attempt to format the entity in a single line; if not bail out and
    // construct a _BrokenEntity.
    DecodedEntity bailout() => new BrokenEntity(opener, parts, closer);
    String short = opener;
    bool first = true;
    for (String key in parts.keys) {
      if (first) {
        first = false;
      } else {
        short += ', ';
      }
      DecodedEntity value = parts[key];
      if (forceKeys) {
        short += '$key: ';
      }
      if (value is UnbrokenEntity) {
        short += value._s;
      } else {
        return bailout();
      }
      if (short.length > MAX_LINE_LENGTH) {
        return bailout();
      }
    }
    return new DecodedEntity.short(short + closer);
  }

  /**
   * Create a representation of a part of the summary that is represented by a
   * single unbroken string.
   */
  factory DecodedEntity.short(String s) = UnbrokenEntity;

  /**
   * Format this entity into a sequence of strings (one per output line).
   */
  List<String> getLines();
}

/**
 * Wrapper around a [LinkedLibrary] and its constituent [UnlinkedUnit]s.
 */
class LibraryWrapper {
  final LinkedLibrary _linked;
  final List<UnlinkedUnit> _unlinked;

  LibraryWrapper(this._linked, this._unlinked);
}

/**
 * Wrapper around a [LinkedReference] and its corresponding [UnlinkedReference].
 */
class ReferenceWrapper {
  final LinkedReference _linked;
  final UnlinkedReference _unlinked;

  ReferenceWrapper(this._linked, this._unlinked);

  String get name {
    if (_linked != null && _linked.name.isNotEmpty) {
      return _linked.name;
    } else if (_unlinked != null && _unlinked.name.isNotEmpty) {
      return _unlinked.name;
    } else {
      return '???';
    }
  }
}

/**
 * Instances of [SummaryInspector] are capable of traversing a summary and
 * converting it to semi-human-readable output.
 */
class SummaryInspector {
  /**
   * The dependencies of the library currently being visited.
   */
  List<LinkedDependency> _dependencies;

  /**
   * The references of the unit currently being visited.
   */
  List<ReferenceWrapper> _references;

  /**
   * Indicates whether summary inspection should operate in "raw" mode.  In this
   * mode, the structure of the summary file is not altered for easier
   * readability; everything is output in exactly the form in which it appears
   * in the file.
   */
  final bool raw;

  SummaryInspector(this.raw);

  /**
   * Decode the object [obj], which was reached by examining [key] inside
   * another object.
   */
  DecodedEntity decode(Object obj, String key) {
    if (!raw && obj is PackageBundle) {
      return decodePackageBundle(obj);
    }
    if (obj is LibraryWrapper) {
      return decodeLibrary(obj);
    }
    if (obj is UnitWrapper) {
      return decodeUnit(obj);
    }
    if (obj is ReferenceWrapper) {
      return decodeReference(obj);
    }
    if (obj is DecodedEntity) {
      return obj;
    }
    if (obj is SummaryClass) {
      Map<String, Object> map = obj.toMap();
      return decodeMap(map);
    } else if (obj is List) {
      Map<String, DecodedEntity> parts = <String, DecodedEntity>{};
      for (int i = 0; i < obj.length; i++) {
        parts[i.toString()] = decode(obj[i], key);
      }
      return new DecodedEntity.group('[', parts, ']', false);
    } else if (obj is String) {
      return new DecodedEntity.short(json.encode(obj));
    } else if (isEnum(obj)) {
      return new DecodedEntity.short(obj.toString().split('.')[1]);
    } else if (obj is int &&
        key == 'dependency' &&
        _dependencies != null &&
        obj < _dependencies.length) {
      return new DecodedEntity.short('$obj (${_dependencies[obj].uri})');
    } else if (obj is int &&
        key == 'reference' &&
        _references != null &&
        obj < _references.length) {
      return new DecodedEntity.short('$obj (${_references[obj].name})');
    } else {
      return new DecodedEntity.short(obj.toString());
    }
  }

  /**
   * Decode the given [LibraryWrapper].
   */
  DecodedEntity decodeLibrary(LibraryWrapper obj) {
    try {
      LinkedLibrary linked = obj._linked;
      List<UnlinkedUnit> unlinked = obj._unlinked;
      _dependencies = linked.dependencies;
      Map<String, Object> result = linked.toMap();
      result.remove('units');
      result['defining compilation unit'] =
          new UnitWrapper(linked.units[0], unlinked[0]);
      for (int i = 1; i < linked.units.length; i++) {
        String partUri = unlinked[0].publicNamespace.parts[i - 1];
        result['part ${json.encode(partUri)}'] =
            new UnitWrapper(linked.units[i], unlinked[i]);
      }
      return decodeMap(result);
    } finally {
      _dependencies = null;
    }
  }

  /**
   * Decode the given [map].
   */
  DecodedEntity decodeMap(Map<String, Object> map) {
    Map<String, DecodedEntity> parts = <String, DecodedEntity>{};
    map = reorderMap(map);
    map.forEach((String key, Object value) {
      if (value is String && value.isEmpty) {
        return;
      }
      if (isEnum(value) && (value as dynamic).index == 0) {
        return;
      }
      if (value is int && value == 0) {
        return;
      }
      if (value is bool && value == false) {
        return;
      }
      if (value == null) {
        return;
      }
      if (value is List) {
        if (value.isEmpty) {
          return;
        }
        DecodedEntity entity = decode(value, key);
        if (entity is BrokenEntity) {
          for (int i = 0; i < value.length; i++) {
            parts['$key[$i]'] = decode(value[i], key);
          }
          return;
        } else {
          parts[key] = entity;
        }
      }
      parts[key] = decode(value, key);
    });
    return new DecodedEntity.group('{', parts, '}', true);
  }

  /**
   * Decode the given [PackageBundle].
   */
  DecodedEntity decodePackageBundle(PackageBundle bundle) {
    Map<String, UnlinkedUnit> units = <String, UnlinkedUnit>{};
    Set<String> seenUnits = new Set<String>();
    for (int i = 0; i < bundle.unlinkedUnits.length; i++) {
      units[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
    }
    Map<String, Object> restOfMap = bundle.toMap();
    Map<String, Object> result = <String, Object>{};
    result['version'] = new DecodedEntity.short(
        '${bundle.majorVersion}.${bundle.minorVersion}');
    restOfMap.remove('majorVersion');
    restOfMap.remove('minorVersion');
    result['linkedLibraryUris'] = restOfMap['linkedLibraryUris'];
    result['unlinkedUnitUris'] = restOfMap['unlinkedUnitUris'];
    for (int i = 0; i < bundle.linkedLibraries.length; i++) {
      String libraryUriString = bundle.linkedLibraryUris[i];
      Uri libraryUri = Uri.parse(libraryUriString);
      UnlinkedUnit unlinkedDefiningUnit = units[libraryUriString];
      seenUnits.add(libraryUriString);
      List<UnlinkedUnit> libraryUnits = <UnlinkedUnit>[unlinkedDefiningUnit];
      LinkedLibrary linkedLibrary = bundle.linkedLibraries[i];
      for (int j = 1; j < linkedLibrary.units.length; j++) {
        String partUriString = resolveRelativeUri(libraryUri,
                Uri.parse(unlinkedDefiningUnit.publicNamespace.parts[j - 1]))
            .toString();
        libraryUnits.add(units[partUriString]);
        seenUnits.add(partUriString);
      }
      result['library ${json.encode(libraryUriString)}'] =
          new LibraryWrapper(linkedLibrary, libraryUnits);
    }
    for (String uriString in units.keys) {
      if (seenUnits.contains(uriString)) {
        continue;
      }
      result['orphan unit ${json.encode(uriString)}'] =
          new UnitWrapper(null, units[uriString]);
    }
    restOfMap.remove('linkedLibraries');
    restOfMap.remove('linkedLibraryUris');
    restOfMap.remove('unlinkedUnits');
    restOfMap.remove('unlinkedUnitUris');
    result.addAll(restOfMap);
    return decodeMap(result);
  }

  /**
   * Decode the given [ReferenceWrapper].
   */
  DecodedEntity decodeReference(ReferenceWrapper obj) {
    Map<String, Object> result = obj._unlinked != null
        ? obj._unlinked.toMap()
        : <String, Object>{'linkedOnly': true};
    if (obj._linked != null) {
      mergeMaps(result, obj._linked.toMap());
    }
    return decodeMap(result);
  }

  /**
   * Decode the given [UnitWrapper].
   */
  DecodedEntity decodeUnit(UnitWrapper obj) {
    try {
      LinkedUnit linked = obj._linked;
      UnlinkedUnit unlinked = obj._unlinked ?? new UnlinkedUnitBuilder();
      Map<String, Object> unlinkedMap = unlinked.toMap();
      Map<String, Object> linkedMap =
          linked != null ? linked.toMap() : <String, Object>{};
      Map<String, Object> result = <String, Object>{};
      List<ReferenceWrapper> references = <ReferenceWrapper>[];
      int numReferences = linked != null
          ? linked.references.length
          : unlinked.references.length;
      for (int i = 0; i < numReferences; i++) {
        references.add(new ReferenceWrapper(
            linked != null ? linked.references[i] : null,
            i < unlinked.references.length ? unlinked.references[i] : null));
      }
      result['references'] = references;
      _references = references;
      unlinkedMap.remove('references');
      linkedMap.remove('references');
      linkedMap.forEach((String key, Object value) {
        result['linked $key'] = value;
      });
      unlinkedMap.forEach((String key, Object value) {
        result[key] = value;
      });
      return decodeMap(result);
    } finally {
      _references = null;
    }
  }

  /**
   * Decode the given [PackageBundle] and dump it to a list of strings.
   */
  List<String> dumpPackageBundle(PackageBundle bundle) {
    DecodedEntity decoded = decode(bundle, 'PackageBundle');
    return decoded.getLines();
  }

  /**
   * Merge the contents of [other] into [result], discarding empty entries.
   */
  void mergeMaps(Map<String, Object> result, Map<String, Object> other) {
    other.forEach((String key, Object value) {
      if (value is String && value.isEmpty) {
        return;
      }
      if (result.containsKey(key)) {
        Object oldValue = result[key];
        if (oldValue is String && oldValue.isEmpty) {
          result[key] = value;
        } else {
          throw new Exception(
              'Duplicate values for $key: $oldValue and $value');
        }
      } else {
        result[key] = value;
      }
    });
  }

  /**
   * Reorder [map] for more intuitive display.
   */
  Map<String, Object> reorderMap(Map<String, Object> map) {
    Map<String, Object> result = <String, Object>{};
    if (map.containsKey('name')) {
      result['name'] = map['name'];
    }
    result.addAll(map);
    return result;
  }
}

/**
 * Decoded reprensentation of a part of a summary that occupies a single line of
 * output.
 */
class UnbrokenEntity implements DecodedEntity {
  final String _s;

  UnbrokenEntity(this._s);

  @override
  List<String> getLines() => <String>[_s];
}

/**
 * Wrapper around a [LinkedUnit] and its corresponding [UnlinkedUnit].
 */
class UnitWrapper {
  final LinkedUnit _linked;
  final UnlinkedUnit _unlinked;

  UnitWrapper(this._linked, this._unlinked);
}
