// Copyright (c) 2013, 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 barback.errors;

import 'package:stack_trace/stack_trace.dart';

import 'asset/asset_id.dart';
import 'transformer/wrapping_aggregate_transformer.dart';
import 'utils.dart';

/// Error thrown when an asset with [id] cannot be found.
class AssetNotFoundException implements Exception {
  final AssetId id;

  AssetNotFoundException(this.id);

  String toString() => "Could not find asset $id.";
}

/// Replaces any occurrences of [AggregateException] in [errors] with the list
/// of errors it contains.
Iterable<BarbackException> flattenAggregateExceptions(
    Iterable<BarbackException> errors) {
  return errors.expand((error) {
    if (error is! AggregateException) return [error];
    return error.errors;
  });
}

/// The interface for exceptions from the barback graph or its transformers.
///
/// These exceptions are never produced by programming errors in barback.
abstract class BarbackException implements Exception {
  /// Takes a collection of [BarbackExceptions] and returns a single exception
  /// that contains them all.
  ///
  /// If [errors] is empty, returns `null`. If it only has one error, that
  /// error is returned. Otherwise, an [AggregateException] is returned.
  static BarbackException aggregate(Iterable<BarbackException> errors) {
    if (errors.isEmpty) return null;
    if (errors.length == 1) return errors.single;
    return new AggregateException(errors);
  }
}

/// An error that wraps a collection of other [BarbackException]s.
///
/// It implicitly flattens any [AggregateException]s that occur in the list of
/// exceptions it wraps.
class AggregateException implements BarbackException {
  final Set<BarbackException> errors;

  AggregateException(Iterable<BarbackException> errors)
      : errors = flattenAggregateExceptions(errors).toSet();

  String toString() {
    var buffer = new StringBuffer();
    buffer.writeln("Multiple errors occurred:\n");

    for (var error in errors) {
      buffer.writeln(prefixLines(error.toString(),
                                 prefix: "  ", firstPrefix: "- "));
    }

    return buffer.toString();
  }
}

/// Error thrown when two or more transformers both output an asset with [id].
class AssetCollisionException implements BarbackException {
  /// All the transforms that output an asset with [id].
  ///
  /// If this only contains a single transform, that indicates that a
  /// transformer produced an output that collides with a source asset or an
  /// asset from a previous phase.
  final Set<TransformInfo> transforms;
  final AssetId id;

  AssetCollisionException(Iterable<TransformInfo> transforms, this.id)
      : transforms = new Set.from(transforms);

  String toString() => "Transforms $transforms all emitted asset $id.";
}

/// Error thrown when a transformer requests an input [id] which cannot be
/// found.
class MissingInputException implements BarbackException {
  /// The transform that requested [id].
  final TransformInfo transform;
  final AssetId id;

  MissingInputException(this.transform, this.id);

  String toString() => "Transform $transform tried to load missing input $id.";
}

/// Error thrown when a transformer outputs an asset to a different package than
/// the primary input's.
class InvalidOutputException implements BarbackException {
  /// The transform that output the asset.
  final TransformInfo transform;
  final AssetId id;

  InvalidOutputException(this.transform, this.id);

  String toString() => "Transform $transform emitted $id, which wasn't in the "
      "same package (${transform.primaryId.package}).";
}

/// Base class for an error that wraps another.
abstract class _WrappedException implements BarbackException {
  /// The wrapped exception.
  final error;
  final Chain stackTrace;

  String get message => "$_message: ${getErrorMessage(error)}";

  String get _message;

  _WrappedException(error, StackTrace stackTrace)
      : this.error = error,
        this.stackTrace = _getChain(error, stackTrace);

  String toString() {
    var result = message;
    if (stackTrace != null) result = "$result\n${stackTrace.terse}";
    return result;
  }
}

/// Returns the stack chain for [error] and [stackTrace].
Chain _getChain(error, StackTrace stackTrace) {
  if (error is Error && stackTrace == null) stackTrace = error.stackTrace;
  if (stackTrace != null) return new Chain.forTrace(stackTrace);
  return null;
}

/// Error wrapping an exception thrown by a transform.
class TransformerException extends _WrappedException {
  /// The transform that threw the exception.
  final TransformInfo transform;

  TransformerException(this.transform, error, StackTrace stackTrace)
      : super(error, stackTrace);

  String get _message => "Transform $transform threw error";
}

/// Error thrown when a source asset [id] fails to load.
///
/// This can be thrown either because the source asset was expected to exist and
/// did not or because reading it failed somehow.
class AssetLoadException extends _WrappedException {
  final AssetId id;

  AssetLoadException(this.id, error, [StackTrace stackTrace])
      : super(error, stackTrace);

  String get _message => "Failed to load source asset $id";
}

/// Information about a single transform in the barback graph.
///
/// Identifies a single transformation in the barback graph.
///
/// A transformation is uniquely identified by the ID of its primary input, and
/// the transformer that is applied to it.
class TransformInfo {
  /// The transformer that's run for this transform.
  ///
  /// This may be a [Transformer] or a [WrappingAggregateTransformer]. It may
  /// also return additional types in the future.
  final transformer;

  /// The id of this transform's primary asset.
  final AssetId primaryId;

  TransformInfo(transformer, this.primaryId)
      : transformer = transformer is WrappingAggregateTransformer ?
            transformer.transformer : transformer;

  bool operator==(other) =>
      other is TransformInfo &&
      other.transformer == transformer &&
      other.primaryId == primaryId;

  int get hashCode => transformer.hashCode ^ primaryId.hashCode;

  String toString() => "$transformer on $primaryId";
}
