// Copyright (c) 2017, 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:async';
import 'dart:convert';
import 'dart:math' show min;
import 'dart:typed_data';

import 'package:file/file.dart';
import 'package:file/src/common.dart' as common;
import 'package:file/src/io.dart' as io;
import 'package:meta/meta.dart';

import 'common.dart';
import 'memory_file_system_entity.dart';
import 'node.dart';
import 'utils.dart' as utils;

/// Internal implementation of [File].
class MemoryFile extends MemoryFileSystemEntity implements File {
  /// Instantiates a new [MemoryFile].
  const MemoryFile(NodeBasedFileSystem fileSystem, String path)
      : super(fileSystem, path);

  FileNode get _resolvedBackingOrCreate {
    Node node = backingOrNull;
    if (node == null) {
      node = _doCreate();
    } else {
      node = utils.isLink(node) ? utils.resolveLinks(node, () => path) : node;
      utils.checkType(expectedType, node.type, () => path);
    }
    return node;
  }

  @override
  io.FileSystemEntityType get expectedType => io.FileSystemEntityType.file;

  @override
  bool existsSync() => backingOrNull?.stat?.type == expectedType;

  @override
  Future<File> create({bool recursive = false}) async {
    createSync(recursive: recursive);
    return this;
  }

  @override
  void createSync({bool recursive = false}) {
    _doCreate(recursive: recursive);
  }

  Node _doCreate({bool recursive = false}) {
    Node node = internalCreateSync(
      followTailLink: true,
      createChild: (DirectoryNode parent, bool isFinalSegment) {
        if (isFinalSegment) {
          return FileNode(parent);
        } else if (recursive) {
          return DirectoryNode(parent);
        }
        return null;
      },
    );
    if (node.type != expectedType) {
      // There was an existing non-file entity at this object's path
      assert(node.type == FileSystemEntityType.directory);
      throw common.isADirectory(path);
    }
    return node;
  }

  @override
  Future<File> rename(String newPath) async => renameSync(newPath);

  @override
  File renameSync(String newPath) => internalRenameSync(
        newPath,
        followTailLink: true,
        checkType: (Node node) {
          FileSystemEntityType actualType = node.stat.type;
          if (actualType != expectedType) {
            throw actualType == FileSystemEntityType.notFound
                ? common.noSuchFileOrDirectory(path)
                : common.isADirectory(path);
          }
        },
      );

  @override
  Future<File> copy(String newPath) async => copySync(newPath);

  @override
  File copySync(String newPath) {
    FileNode sourceNode = resolvedBacking;
    fileSystem.findNode(
      newPath,
      segmentVisitor: (
        DirectoryNode parent,
        String childName,
        Node child,
        int currentSegment,
        int finalSegment,
      ) {
        if (currentSegment == finalSegment) {
          if (child != null) {
            if (utils.isLink(child)) {
              List<String> ledger = <String>[];
              child = utils.resolveLinks(child, () => newPath, ledger: ledger);
              checkExists(child, () => newPath);
              parent = child.parent;
              childName = ledger.last;
              assert(parent.children.containsKey(childName));
            }
            utils.checkType(expectedType, child.type, () => newPath);
            parent.children.remove(childName);
          }
          FileNode newNode = FileNode(parent);
          newNode.copyFrom(sourceNode);
          parent.children[childName] = newNode;
        }
        return child;
      },
    );
    return clone(newPath);
  }

  @override
  Future<int> length() async => lengthSync();

  @override
  int lengthSync() => (resolvedBacking as FileNode).size;

  @override
  File get absolute => super.absolute;

  @override
  Future<DateTime> lastAccessed() async => lastAccessedSync();

  @override
  DateTime lastAccessedSync() => (resolvedBacking as FileNode).stat.accessed;

  @override
  Future<dynamic> setLastAccessed(DateTime time) async =>
      setLastAccessedSync(time);

  @override
  void setLastAccessedSync(DateTime time) {
    FileNode node = resolvedBacking;
    node.accessed = time.millisecondsSinceEpoch;
  }

  @override
  Future<DateTime> lastModified() async => lastModifiedSync();

  @override
  DateTime lastModifiedSync() => (resolvedBacking as FileNode).stat.modified;

  @override
  Future<dynamic> setLastModified(DateTime time) async =>
      setLastModifiedSync(time);

  @override
  void setLastModifiedSync(DateTime time) {
    FileNode node = resolvedBacking;
    node.modified = time.millisecondsSinceEpoch;
  }

  @override
  Future<io.RandomAccessFile> open(
          {io.FileMode mode = io.FileMode.read}) async =>
      openSync(mode: mode);

  @override
  io.RandomAccessFile openSync({io.FileMode mode = io.FileMode.read}) =>
      throw UnimplementedError('TODO');

  @override
  Stream<Uint8List> openRead([int start, int end]) {
    try {
      FileNode node = resolvedBacking;
      Uint8List content = node.content;
      if (start != null) {
        content = end == null
            ? content.sublist(start)
            : content.sublist(start, min(end, content.length));
      }
      return Stream<Uint8List>.fromIterable(<Uint8List>[content]);
    } catch (e) {
      return Stream<Uint8List>.fromFuture(Future<Uint8List>.error(e));
    }
  }

  @override
  io.IOSink openWrite({
    io.FileMode mode = io.FileMode.write,
    Encoding encoding = utf8,
  }) {
    if (!utils.isWriteMode(mode)) {
      throw ArgumentError.value(mode, 'mode',
          'Must be either WRITE, APPEND, WRITE_ONLY, or WRITE_ONLY_APPEND');
    }
    return _FileSink.fromFile(this, mode, encoding);
  }

  @override
  Future<Uint8List> readAsBytes() async => readAsBytesSync();

  @override
  Uint8List readAsBytesSync() =>
      Uint8List.fromList((resolvedBacking as FileNode).content);

  @override
  Future<String> readAsString({Encoding encoding = utf8}) async =>
      readAsStringSync(encoding: encoding);

  @override
  String readAsStringSync({Encoding encoding = utf8}) =>
      encoding.decode(readAsBytesSync());

  @override
  Future<List<String>> readAsLines({Encoding encoding = utf8}) async =>
      readAsLinesSync(encoding: encoding);

  @override
  List<String> readAsLinesSync({Encoding encoding = utf8}) {
    String str = readAsStringSync(encoding: encoding);
    return str.isEmpty ? <String>[] : str.split('\n');
  }

  @override
  Future<File> writeAsBytes(
    List<int> bytes, {
    io.FileMode mode = io.FileMode.write,
    bool flush = false,
  }) async {
    writeAsBytesSync(bytes, mode: mode, flush: flush);
    return this;
  }

  @override
  void writeAsBytesSync(
    List<int> bytes, {
    io.FileMode mode = io.FileMode.write,
    bool flush = false,
  }) {
    if (!utils.isWriteMode(mode)) {
      throw common.badFileDescriptor(path);
    }
    FileNode node = _resolvedBackingOrCreate;
    _truncateIfNecessary(node, mode);
    node.write(bytes);
    node.touch();
  }

  @override
  Future<File> writeAsString(
    String contents, {
    io.FileMode mode = io.FileMode.write,
    Encoding encoding = utf8,
    bool flush = false,
  }) async {
    writeAsStringSync(contents, mode: mode, encoding: encoding, flush: flush);
    return this;
  }

  @override
  void writeAsStringSync(
    String contents, {
    io.FileMode mode = io.FileMode.write,
    Encoding encoding = utf8,
    bool flush = false,
  }) =>
      writeAsBytesSync(encoding.encode(contents), mode: mode, flush: flush);

  @override
  @protected
  File clone(String path) => MemoryFile(fileSystem, path);

  void _truncateIfNecessary(FileNode node, io.FileMode mode) {
    if (mode == io.FileMode.write || mode == io.FileMode.writeOnly) {
      node.clear();
    }
  }

  @override
  String toString() => "MemoryFile: '$path'";
}

/// Implementation of an [io.IOSink] that's backed by a [FileNode].
class _FileSink implements io.IOSink {
  factory _FileSink.fromFile(
    MemoryFile file,
    io.FileMode mode,
    Encoding encoding,
  ) {
    Future<FileNode> node = Future<FileNode>.microtask(() {
      FileNode node = file._resolvedBackingOrCreate;
      file._truncateIfNecessary(node, mode);
      return node;
    });
    return _FileSink._(node, encoding);
  }

  _FileSink._(this._node, this.encoding) {
    _pendingWrites = _node;
  }

  final Future<FileNode> _node;
  final Completer<void> _completer = Completer<void>();

  Future<FileNode> _pendingWrites;
  Completer<void> _streamCompleter;
  bool _isClosed = false;

  @override
  Encoding encoding;

  bool get isStreaming => !(_streamCompleter?.isCompleted ?? true);

  @override
  void add(List<int> data) {
    _checkNotStreaming();
    if (!_isClosed) {
      _addData(data);
    }
  }

  @override
  void write(Object obj) => add(encoding.encode(obj?.toString() ?? 'null'));

  @override
  void writeAll(Iterable<dynamic> objects, [String separator = '']) {
    bool firstIter = true;
    for (dynamic obj in objects) {
      if (!firstIter && separator != null) {
        write(separator);
      }
      firstIter = false;
      write(obj);
    }
  }

  @override
  void writeln([Object obj = '']) {
    write(obj);
    write('\n');
  }

  @override
  void writeCharCode(int charCode) => write(String.fromCharCode(charCode));

  @override
  void addError(dynamic error, [StackTrace stackTrace]) {
    _checkNotStreaming();
    _completer.completeError(error, stackTrace);
  }

  @override
  Future<void> addStream(Stream<List<int>> stream) {
    _checkNotStreaming();
    _streamCompleter = Completer<void>();
    void finish() {
      _streamCompleter.complete();
      _streamCompleter = null;
    }

    stream.listen(
      (List<int> data) => _addData(data),
      cancelOnError: true,
      onError: (dynamic error, StackTrace stackTrace) {
        _completer.completeError(error, stackTrace);
        finish();
      },
      onDone: finish,
    );
    return _streamCompleter.future;
  }

  @override
  // TODO(tvolkert): Change to Future<Null> once Dart 1.22 is stable
  Future<dynamic> flush() {
    _checkNotStreaming();
    return _pendingWrites;
  }

  @override
  Future<void> close() {
    _checkNotStreaming();
    if (!_isClosed) {
      _isClosed = true;
      _pendingWrites.then(
        (_) => _completer.complete(),
        onError: (dynamic error, StackTrace stackTrace) =>
            _completer.completeError(error, stackTrace),
      );
    }
    return _completer.future;
  }

  @override
  Future<void> get done => _completer.future;

  void _addData(List<int> data) {
    _pendingWrites = _pendingWrites.then((FileNode node) {
      node.write(data);
      return node;
    });
  }

  void _checkNotStreaming() {
    if (isStreaming) {
      throw StateError('StreamSink is bound to a stream');
    }
  }
}
